as_compiler.cpp 518 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950139511395213953139541395513956139571395813959139601396113962139631396413965139661396713968139691397013971139721397313974139751397613977139781397913980139811398213983139841398513986139871398813989139901399113992139931399413995139961399713998139991400014001140021400314004140051400614007140081400914010140111401214013140141401514016140171401814019140201402114022140231402414025140261402714028140291403014031140321403314034140351403614037140381403914040140411404214043140441404514046140471404814049140501405114052140531405414055140561405714058140591406014061140621406314064140651406614067140681406914070140711407214073140741407514076140771407814079140801408114082140831408414085140861408714088140891409014091140921409314094140951409614097140981409914100141011410214103141041410514106141071410814109141101411114112141131411414115141161411714118141191412014121141221412314124141251412614127141281412914130141311413214133141341413514136141371413814139141401414114142141431414414145141461414714148141491415014151141521415314154141551415614157141581415914160141611416214163141641416514166141671416814169141701417114172141731417414175141761417714178141791418014181141821418314184141851418614187141881418914190141911419214193141941419514196141971419814199142001420114202142031420414205142061420714208142091421014211142121421314214142151421614217142181421914220142211422214223142241422514226142271422814229142301423114232142331423414235142361423714238142391424014241142421424314244142451424614247142481424914250142511425214253142541425514256142571425814259142601426114262142631426414265142661426714268142691427014271142721427314274142751427614277142781427914280142811428214283142841428514286142871428814289142901429114292142931429414295142961429714298142991430014301143021430314304143051430614307143081430914310143111431214313143141431514316143171431814319143201432114322143231432414325143261432714328143291433014331143321433314334143351433614337143381433914340143411434214343143441434514346143471434814349143501435114352143531435414355143561435714358143591436014361143621436314364143651436614367143681436914370143711437214373143741437514376143771437814379143801438114382143831438414385143861438714388143891439014391143921439314394143951439614397143981439914400144011440214403144041440514406144071440814409144101441114412144131441414415144161441714418144191442014421144221442314424144251442614427144281442914430144311443214433144341443514436144371443814439144401444114442144431444414445144461444714448144491445014451144521445314454144551445614457144581445914460144611446214463144641446514466144671446814469144701447114472144731447414475144761447714478144791448014481144821448314484144851448614487144881448914490144911449214493144941449514496144971449814499145001450114502145031450414505145061450714508145091451014511145121451314514145151451614517145181451914520145211452214523145241452514526145271452814529145301453114532145331453414535145361453714538145391454014541145421454314544145451454614547145481454914550145511455214553145541455514556145571455814559145601456114562145631456414565145661456714568145691457014571145721457314574145751457614577145781457914580145811458214583145841458514586145871458814589145901459114592145931459414595145961459714598145991460014601146021460314604146051460614607146081460914610146111461214613146141461514616146171461814619146201462114622146231462414625146261462714628146291463014631146321463314634146351463614637146381463914640146411464214643146441464514646146471464814649146501465114652146531465414655146561465714658146591466014661146621466314664146651466614667146681466914670146711467214673146741467514676146771467814679146801468114682146831468414685146861468714688146891469014691146921469314694146951469614697146981469914700147011470214703147041470514706147071470814709147101471114712147131471414715147161471714718147191472014721147221472314724147251472614727147281472914730147311473214733147341473514736147371473814739147401474114742147431474414745147461474714748147491475014751147521475314754147551475614757147581475914760147611476214763147641476514766147671476814769147701477114772147731477414775147761477714778147791478014781147821478314784147851478614787147881478914790147911479214793147941479514796147971479814799148001480114802148031480414805148061480714808148091481014811148121481314814148151481614817148181481914820148211482214823148241482514826148271482814829148301483114832148331483414835148361483714838148391484014841148421484314844148451484614847148481484914850148511485214853148541485514856148571485814859148601486114862148631486414865148661486714868148691487014871148721487314874148751487614877148781487914880148811488214883148841488514886148871488814889148901489114892148931489414895148961489714898148991490014901149021490314904149051490614907149081490914910149111491214913149141491514916149171491814919149201492114922149231492414925149261492714928149291493014931149321493314934149351493614937149381493914940149411494214943149441494514946149471494814949149501495114952149531495414955149561495714958149591496014961149621496314964149651496614967149681496914970149711497214973149741497514976149771497814979149801498114982149831498414985149861498714988149891499014991149921499314994149951499614997149981499915000150011500215003150041500515006150071500815009150101501115012150131501415015150161501715018150191502015021150221502315024150251502615027150281502915030150311503215033150341503515036150371503815039150401504115042150431504415045150461504715048150491505015051150521505315054150551505615057150581505915060150611506215063150641506515066150671506815069150701507115072150731507415075150761507715078150791508015081150821508315084150851508615087150881508915090150911509215093150941509515096150971509815099151001510115102151031510415105151061510715108151091511015111151121511315114151151511615117151181511915120151211512215123151241512515126151271512815129151301513115132151331513415135151361513715138151391514015141151421514315144151451514615147151481514915150151511515215153151541515515156151571515815159151601516115162151631516415165151661516715168151691517015171151721517315174151751517615177151781517915180151811518215183151841518515186151871518815189151901519115192151931519415195151961519715198151991520015201152021520315204152051520615207152081520915210152111521215213152141521515216152171521815219152201522115222152231522415225152261522715228152291523015231152321523315234152351523615237152381523915240152411524215243152441524515246152471524815249152501525115252152531525415255152561525715258152591526015261152621526315264152651526615267152681526915270152711527215273152741527515276152771527815279152801528115282152831528415285152861528715288152891529015291152921529315294152951529615297152981529915300153011530215303153041530515306153071530815309153101531115312153131531415315153161531715318153191532015321153221532315324153251532615327153281532915330153311533215333153341533515336153371533815339153401534115342153431534415345153461534715348153491535015351153521535315354153551535615357153581535915360153611536215363153641536515366153671536815369153701537115372153731537415375153761537715378153791538015381153821538315384153851538615387153881538915390153911539215393153941539515396153971539815399154001540115402154031540415405154061540715408154091541015411154121541315414154151541615417154181541915420154211542215423154241542515426154271542815429154301543115432154331543415435154361543715438154391544015441154421544315444154451544615447154481544915450154511545215453154541545515456154571545815459154601546115462154631546415465154661546715468154691547015471154721547315474154751547615477154781547915480154811548215483154841548515486154871548815489154901549115492154931549415495154961549715498154991550015501155021550315504155051550615507155081550915510155111551215513155141551515516155171551815519155201552115522155231552415525155261552715528155291553015531155321553315534155351553615537155381553915540155411554215543155441554515546155471554815549155501555115552155531555415555155561555715558155591556015561155621556315564155651556615567155681556915570155711557215573155741557515576155771557815579155801558115582155831558415585155861558715588155891559015591155921559315594155951559615597155981559915600156011560215603156041560515606156071560815609156101561115612156131561415615156161561715618156191562015621156221562315624156251562615627156281562915630156311563215633156341563515636156371563815639156401564115642156431564415645156461564715648156491565015651156521565315654156551565615657156581565915660156611566215663156641566515666156671566815669156701567115672156731567415675156761567715678156791568015681156821568315684156851568615687156881568915690156911569215693156941569515696156971569815699157001570115702157031570415705157061570715708157091571015711157121571315714157151571615717157181571915720157211572215723157241572515726157271572815729157301573115732157331573415735157361573715738157391574015741157421574315744157451574615747157481574915750157511575215753157541575515756157571575815759157601576115762157631576415765157661576715768157691577015771157721577315774157751577615777157781577915780157811578215783157841578515786157871578815789157901579115792157931579415795157961579715798157991580015801158021580315804158051580615807158081580915810158111581215813158141581515816158171581815819158201582115822158231582415825158261582715828158291583015831158321583315834158351583615837158381583915840158411584215843158441584515846158471584815849158501585115852158531585415855158561585715858158591586015861158621586315864158651586615867158681586915870158711587215873158741587515876158771587815879158801588115882158831588415885158861588715888158891589015891158921589315894158951589615897158981589915900159011590215903159041590515906159071590815909159101591115912159131591415915159161591715918159191592015921159221592315924159251592615927159281592915930159311593215933159341593515936159371593815939159401594115942159431594415945159461594715948159491595015951159521595315954159551595615957159581595915960159611596215963159641596515966159671596815969159701597115972159731597415975159761597715978159791598015981159821598315984159851598615987159881598915990159911599215993159941599515996159971599815999160001600116002160031600416005160061600716008160091601016011160121601316014160151601616017160181601916020160211602216023160241602516026160271602816029160301603116032160331603416035160361603716038160391604016041160421604316044160451604616047160481604916050160511605216053160541605516056160571605816059160601606116062160631606416065160661606716068160691607016071160721607316074160751607616077160781607916080160811608216083160841608516086160871608816089160901609116092160931609416095160961609716098160991610016101161021610316104161051610616107161081610916110161111611216113161141611516116161171611816119161201612116122161231612416125161261612716128161291613016131161321613316134161351613616137161381613916140161411614216143161441614516146161471614816149161501615116152161531615416155161561615716158161591616016161161621616316164161651616616167161681616916170161711617216173161741617516176161771617816179161801618116182161831618416185161861618716188161891619016191161921619316194161951619616197161981619916200162011620216203162041620516206162071620816209162101621116212162131621416215162161621716218162191622016221162221622316224162251622616227162281622916230162311623216233162341623516236162371623816239162401624116242162431624416245162461624716248162491625016251162521625316254162551625616257162581625916260162611626216263162641626516266162671626816269162701627116272162731627416275162761627716278162791628016281162821628316284162851628616287162881628916290162911629216293162941629516296162971629816299163001630116302163031630416305163061630716308163091631016311163121631316314163151631616317163181631916320163211632216323163241632516326163271632816329163301633116332163331633416335163361633716338163391634016341163421634316344163451634616347163481634916350163511635216353163541635516356163571635816359163601636116362163631636416365163661636716368163691637016371163721637316374163751637616377163781637916380163811638216383163841638516386163871638816389163901639116392163931639416395163961639716398163991640016401164021640316404164051640616407164081640916410164111641216413164141641516416164171641816419164201642116422164231642416425164261642716428164291643016431164321643316434164351643616437164381643916440164411644216443164441644516446164471644816449164501645116452164531645416455164561645716458164591646016461164621646316464164651646616467164681646916470164711647216473164741647516476164771647816479164801648116482164831648416485164861648716488164891649016491164921649316494164951649616497164981649916500165011650216503165041650516506165071650816509165101651116512165131651416515165161651716518165191652016521165221652316524165251652616527165281652916530165311653216533165341653516536
  1. /*
  2. AngelCode Scripting Library
  3. Copyright (c) 2003-2021 Andreas Jonsson
  4. This software is provided 'as-is', without any express or implied
  5. warranty. In no event will the authors be held liable for any
  6. damages arising from the use of this software.
  7. Permission is granted to anyone to use this software for any
  8. purpose, including commercial applications, and to alter it and
  9. redistribute it freely, subject to the following restrictions:
  10. 1. The origin of this software must not be misrepresented; you
  11. must not claim that you wrote the original software. If you use
  12. this software in a product, an acknowledgment in the product
  13. documentation would be appreciated but is not required.
  14. 2. Altered source versions must be plainly marked as such, and
  15. must not be misrepresented as being the original software.
  16. 3. This notice may not be removed or altered from any source
  17. distribution.
  18. The original version of this library can be located at:
  19. http://www.angelcode.com/angelscript/
  20. Andreas Jonsson
  21. [email protected]
  22. */
  23. // Modified for Urho3D
  24. //
  25. // as_compiler.cpp
  26. //
  27. // The class that does the actual compilation of the functions
  28. //
  29. #include <math.h> // fmodf() pow()
  30. #include "as_config.h"
  31. #ifndef AS_NO_COMPILER
  32. #include "as_compiler.h"
  33. #include "as_tokendef.h"
  34. #include "as_tokenizer.h"
  35. #include "as_string_util.h"
  36. #include "as_texts.h"
  37. #include "as_parser.h"
  38. #include "as_debug.h"
  39. #include "as_context.h" // as_powi()
  40. BEGIN_AS_NAMESPACE
  41. //
  42. // The calling convention rules for script functions:
  43. // - If a class method returns a reference, the caller must guarantee the object pointer stays alive until the function returns, and the reference is no longer going to be used
  44. // - If a class method doesn't return a reference, it must guarantee by itself that the this pointer stays alive during the function call. If no outside access is made, then the function is guaranteed to stay alive and nothing needs to be done
  45. // - The object pointer is always passed as the first argument, position 0
  46. // - If the function returns a value type the caller must reserve the memory for this and pass the pointer as the first argument after the object pointer
  47. //
  48. // TODO: I must correct the interpretation of a reference to objects in the compiler.
  49. // A reference should mean that a pointer to the object is on the stack.
  50. // No expression should end up as non-references to objects, as the actual object is
  51. // never put on the stack.
  52. // Local variables are declared as non-references, but the expression should be a reference to the variable.
  53. // Function parameters of called functions can also be non-references, but in that case it means the
  54. // object will be passed by value (currently on the heap, which will be moved to the application stack).
  55. //
  56. // The compiler shouldn't use the asCDataType::IsReference. The datatype should always be stored as non-references.
  57. // Instead the compiler should keep track of references in TypeInfo, where it should also state how the reference
  58. // is currently stored, i.e. in variable, in register, on stack, etc.
  59. asCCompiler::asCCompiler(asCScriptEngine *engine) : byteCode(engine)
  60. {
  61. builder = 0;
  62. script = 0;
  63. variables = 0;
  64. isProcessingDeferredParams = false;
  65. isCompilingDefaultArg = false;
  66. noCodeOutput = 0;
  67. }
  68. asCCompiler::~asCCompiler()
  69. {
  70. while( variables )
  71. {
  72. asCVariableScope *var = variables;
  73. variables = variables->parent;
  74. asDELETE(var,asCVariableScope);
  75. }
  76. // Clean up all the string constants that were allocated. By now the script
  77. // functions that were compiled successfully already holds their own references
  78. for (asUINT n = 0; n < usedStringConstants.GetLength(); n++)
  79. engine->stringFactory->ReleaseStringConstant(usedStringConstants[n]);
  80. usedStringConstants.SetLength(0);
  81. // Clean up the temporary script nodes that were allocated during compilation
  82. for (asUINT n = 0; n < nodesToFreeUponComplete.GetLength(); n++)
  83. nodesToFreeUponComplete[n]->Destroy(engine);
  84. }
  85. void asCCompiler::Reset(asCBuilder *in_builder, asCScriptCode *in_script, asCScriptFunction *in_outFunc)
  86. {
  87. this->builder = in_builder;
  88. this->engine = in_builder->engine;
  89. this->script = in_script;
  90. this->outFunc = in_outFunc;
  91. hasCompileErrors = false;
  92. m_isConstructor = false;
  93. m_isConstructorCalled = false;
  94. m_classDecl = 0;
  95. m_globalVar = 0;
  96. nextLabel = 0;
  97. breakLabels.SetLength(0);
  98. continueLabels.SetLength(0);
  99. numLambdas = 0;
  100. byteCode.ClearAll();
  101. }
  102. int asCCompiler::CompileDefaultConstructor(asCBuilder *in_builder, asCScriptCode *in_script, asCScriptNode *in_node, asCScriptFunction *in_outFunc, sClassDeclaration *in_classDecl)
  103. {
  104. Reset(in_builder, in_script, in_outFunc);
  105. m_classDecl = in_classDecl;
  106. // Insert a JitEntry at the start of the function for JIT compilers
  107. byteCode.InstrPTR(asBC_JitEntry, 0);
  108. // Add a variable scope that might be needed to declare dummy variables
  109. // in case the member initialization refers to undefined symbols.
  110. AddVariableScope();
  111. // Initialize the class members that have no explicit expression first. This will allow the
  112. // base class' constructor to access these members without worry they will be uninitialized.
  113. // This can happen if the base class' constructor calls a method that is overridden by the derived class
  114. CompileMemberInitialization(&byteCode, true);
  115. // If the class is derived from another, then the base class' default constructor must be called
  116. if( outFunc->objectType->derivedFrom )
  117. {
  118. // Make sure the base class really has a default constructor
  119. if( outFunc->objectType->derivedFrom->beh.construct == 0 )
  120. Error(TEXT_BASE_DOESNT_HAVE_DEF_CONSTR, in_node);
  121. // Call the base class' default constructor
  122. byteCode.InstrSHORT(asBC_PSF, 0);
  123. byteCode.Instr(asBC_RDSPtr);
  124. byteCode.Call(asBC_CALL, outFunc->objectType->derivedFrom->beh.construct, AS_PTR_SIZE);
  125. }
  126. // Initialize the class members that explicit expressions afterwards. This allow the expressions
  127. // to access the base class members without worry they will be uninitialized
  128. CompileMemberInitialization(&byteCode, false);
  129. byteCode.OptimizeLocally(tempVariableOffsets);
  130. // If there are compile errors, there is no reason to build the final code
  131. if( hasCompileErrors )
  132. return -1;
  133. // Pop the object pointer from the stack
  134. byteCode.Ret(AS_PTR_SIZE);
  135. // Count total variable size
  136. int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1;
  137. outFunc->scriptData->variableSpace = varSize;
  138. FinalizeFunction();
  139. #ifdef AS_DEBUG
  140. // DEBUG: output byte code
  141. byteCode.DebugOutput(("__" + outFunc->objectType->name + "_" + outFunc->name + "__defconstr.txt").AddressOf(), in_outFunc);
  142. #endif
  143. return 0;
  144. }
  145. int asCCompiler::CompileFactory(asCBuilder *in_builder, asCScriptCode *in_script, asCScriptFunction *in_outFunc)
  146. {
  147. Reset(in_builder, in_script, in_outFunc);
  148. // Insert a JitEntry at the start of the function for JIT compilers
  149. byteCode.InstrPTR(asBC_JitEntry, 0);
  150. // Find the corresponding constructor
  151. asCDataType dt = asCDataType::CreateType(outFunc->returnType.GetTypeInfo(), false);
  152. int constructor = 0;
  153. for( unsigned int n = 0; n < dt.GetBehaviour()->factories.GetLength(); n++ )
  154. {
  155. if( dt.GetBehaviour()->factories[n] == outFunc->id )
  156. {
  157. constructor = dt.GetBehaviour()->constructors[n];
  158. break;
  159. }
  160. }
  161. // Allocate the class and instantiate it with the constructor
  162. int varOffset = AllocateVariable(dt, true);
  163. outFunc->scriptData->variableSpace = AS_PTR_SIZE;
  164. byteCode.InstrSHORT(asBC_PSF, (short)varOffset);
  165. // Copy all arguments to the top of the stack
  166. // TODO: runtime optimize: Might be interesting to have a specific instruction for copying all arguments
  167. int offset = (int)outFunc->GetSpaceNeededForArguments();
  168. for( int a = int(outFunc->parameterTypes.GetLength()) - 1; a >= 0; a-- )
  169. {
  170. if( !outFunc->parameterTypes[a].IsPrimitive() ||
  171. outFunc->parameterTypes[a].IsReference() )
  172. {
  173. offset -= AS_PTR_SIZE;
  174. byteCode.InstrSHORT(asBC_PshVPtr, short(-offset));
  175. }
  176. else
  177. {
  178. if( outFunc->parameterTypes[a].GetSizeOnStackDWords() == 2 )
  179. {
  180. offset -= 2;
  181. byteCode.InstrSHORT(asBC_PshV8, short(-offset));
  182. }
  183. else
  184. {
  185. offset -= 1;
  186. byteCode.InstrSHORT(asBC_PshV4, short(-offset));
  187. }
  188. }
  189. }
  190. int argDwords = (int)outFunc->GetSpaceNeededForArguments();
  191. byteCode.Alloc(asBC_ALLOC, dt.GetTypeInfo(), constructor, argDwords + AS_PTR_SIZE);
  192. // Return a handle to the newly created object
  193. byteCode.InstrSHORT(asBC_LOADOBJ, (short)varOffset);
  194. byteCode.Ret(argDwords);
  195. FinalizeFunction();
  196. // Tell the virtual machine not to clean up parameters on exception
  197. outFunc->dontCleanUpOnException = true;
  198. /*
  199. #ifdef AS_DEBUG
  200. // DEBUG: output byte code
  201. asCString args;
  202. args.Format("%d", outFunc->parameterTypes.GetLength());
  203. byteCode.DebugOutput(("__" + outFunc->name + "__factory" + args + ".txt").AddressOf(), engine);
  204. #endif
  205. */
  206. return 0;
  207. }
  208. void asCCompiler::FinalizeFunction()
  209. {
  210. TimeIt("asCCompiler::FinalizeFunction");
  211. asASSERT( outFunc->scriptData );
  212. asUINT n;
  213. // Finalize the bytecode
  214. byteCode.Finalize(tempVariableOffsets);
  215. // extract the try/catch info before object variable info, as
  216. // some variable info is not needed if there are no try/catch blocks
  217. byteCode.ExtractTryCatchInfo(outFunc);
  218. byteCode.ExtractObjectVariableInfo(outFunc);
  219. // Compile the list of object variables for the exception handler and the bytecode serialization
  220. // Start with the variables allocated on the heap, and then the ones allocated on the stack
  221. for( n = 0; n < variableAllocations.GetLength(); n++ )
  222. {
  223. // The exception handler doesn't need to know about references, but the bytecode serialization must adjust the size of the pointer
  224. if( (variableAllocations[n].IsObject() || variableAllocations[n].IsFuncdef()) )
  225. {
  226. if( variableIsOnHeap[n] )
  227. {
  228. // For references, we just store a null pointer so the exception handler can identify that it shouldn't do anything,
  229. // but the bytecode serializer can still understand that it needs to adjust the size of the pointer
  230. if (variableAllocations[n].IsReference())
  231. outFunc->scriptData->objVariableTypes.PushLast(0);
  232. else
  233. outFunc->scriptData->objVariableTypes.PushLast(variableAllocations[n].GetTypeInfo());
  234. outFunc->scriptData->objVariablePos.PushLast(GetVariableOffset(n));
  235. }
  236. }
  237. }
  238. outFunc->scriptData->objVariablesOnHeap = asUINT(outFunc->scriptData->objVariablePos.GetLength());
  239. for( n = 0; n < variableAllocations.GetLength(); n++ )
  240. {
  241. // The exception handler doesn't need to know about references, but the bytecode serialization must adjust the size of the pointer
  242. if( (variableAllocations[n].IsObject() || variableAllocations[n].IsFuncdef()) )
  243. {
  244. if( !variableIsOnHeap[n] )
  245. {
  246. // For references, we just store a null pointer so the exception handler can identify that it shouldn't do anything,
  247. // but the bytecode serializer can still understand that it needs to adjust the size of the pointer
  248. if (variableAllocations[n].IsReference())
  249. outFunc->scriptData->objVariableTypes.PushLast(0);
  250. else
  251. outFunc->scriptData->objVariableTypes.PushLast(variableAllocations[n].GetTypeInfo());
  252. outFunc->scriptData->objVariablePos.PushLast(GetVariableOffset(n));
  253. }
  254. }
  255. }
  256. // Copy byte code to the function
  257. asASSERT( outFunc->scriptData->byteCode.GetLength() == 0 );
  258. outFunc->scriptData->byteCode.SetLength(byteCode.GetSize());
  259. byteCode.Output(outFunc->scriptData->byteCode.AddressOf());
  260. outFunc->AddReferences();
  261. outFunc->scriptData->stackNeeded = byteCode.largestStackUsed + outFunc->scriptData->variableSpace;
  262. outFunc->scriptData->lineNumbers = byteCode.lineNumbers;
  263. // Extract the script section indexes too if there are any entries that are different from the function's script section
  264. int lastIdx = outFunc->scriptData->scriptSectionIdx;
  265. for( n = 0; n < byteCode.sectionIdxs.GetLength(); n++ )
  266. {
  267. if( byteCode.sectionIdxs[n] != lastIdx )
  268. {
  269. lastIdx = byteCode.sectionIdxs[n];
  270. outFunc->scriptData->sectionIdxs.PushLast(byteCode.lineNumbers[n*2]);
  271. outFunc->scriptData->sectionIdxs.PushLast(lastIdx);
  272. }
  273. }
  274. }
  275. // internal
  276. int asCCompiler::SetupParametersAndReturnVariable(asCArray<asCString> &parameterNames, asCScriptNode *func)
  277. {
  278. int stackPos = 0;
  279. if( outFunc->objectType )
  280. stackPos = -AS_PTR_SIZE; // The first parameter is the pointer to the object
  281. // Add the first variable scope, which the parameters and
  282. // variables declared in the outermost statement block is
  283. // part of.
  284. AddVariableScope();
  285. bool isDestructor = false;
  286. asCDataType returnType;
  287. // Examine return type
  288. returnType = outFunc->returnType;
  289. // Check if this is a constructor or destructor
  290. if( returnType.GetTokenType() == ttVoid && outFunc->objectType )
  291. {
  292. if( outFunc->name[0] == '~' )
  293. isDestructor = true;
  294. else if( outFunc->objectType->name == outFunc->name )
  295. m_isConstructor = true;
  296. }
  297. // Is the return type allowed?
  298. if( returnType != asCDataType::CreatePrimitive(ttVoid, false) &&
  299. !returnType.CanBeInstantiated() &&
  300. !returnType.IsReference() &&
  301. !returnType.IsObjectHandle() )
  302. {
  303. // TODO: Hasn't this been validated by the builder already?
  304. asCString str;
  305. str.Format(TXT_RETURN_CANT_BE_s, returnType.Format(outFunc->nameSpace).AddressOf());
  306. Error(str, func);
  307. }
  308. // If the return type is a value type returned by value the address of the
  309. // location where the value will be stored is pushed on the stack before
  310. // the arguments
  311. if( !(isDestructor || m_isConstructor) && outFunc->DoesReturnOnStack() )
  312. stackPos -= AS_PTR_SIZE;
  313. asCVariableScope vs(0);
  314. // Declare parameters
  315. asUINT n;
  316. for( n = 0; n < parameterNames.GetLength(); n++ )
  317. {
  318. // Get the parameter type
  319. asCDataType &type = outFunc->parameterTypes[n];
  320. asETypeModifiers inoutFlag = n < outFunc->inOutFlags.GetLength() ? outFunc->inOutFlags[n] : asTM_NONE;
  321. // Is the data type allowed?
  322. // TODO: Hasn't this been validated by the builder already?
  323. if( (type.IsReference() && inoutFlag != asTM_INOUTREF && !type.CanBeInstantiated()) ||
  324. (!type.IsReference() && !type.CanBeInstantiated()) )
  325. {
  326. asCString parm = type.Format(outFunc->nameSpace);
  327. if( inoutFlag == asTM_INREF )
  328. parm += "in";
  329. else if( inoutFlag == asTM_OUTREF )
  330. parm += "out";
  331. asCString str;
  332. str.Format(TXT_PARAMETER_CANT_BE_s, parm.AddressOf());
  333. Error(str, func);
  334. }
  335. // If the parameter has a name then declare it as variable
  336. if( parameterNames[n] != "" )
  337. {
  338. asCString &name = parameterNames[n];
  339. if( vs.DeclareVariable(name.AddressOf(), type, stackPos, true) < 0 )
  340. {
  341. // TODO: It might be an out-of-memory too
  342. Error(TXT_PARAMETER_ALREADY_DECLARED, func);
  343. }
  344. // Add marker for variable declaration
  345. byteCode.VarDecl((int)outFunc->scriptData->variables.GetLength());
  346. outFunc->AddVariable(name, type, stackPos);
  347. }
  348. else
  349. vs.DeclareVariable("", type, stackPos, true);
  350. // Move to next parameter
  351. stackPos -= type.GetSizeOnStackDWords();
  352. }
  353. for( n = asUINT(vs.variables.GetLength()); n-- > 0; )
  354. variables->DeclareVariable(vs.variables[n]->name.AddressOf(), vs.variables[n]->type, vs.variables[n]->stackOffset, vs.variables[n]->onHeap);
  355. variables->DeclareVariable("return", returnType, stackPos, true);
  356. return stackPos;
  357. }
  358. void asCCompiler::CompileMemberInitialization(asCByteCode *bc, bool onlyDefaults)
  359. {
  360. asASSERT( m_classDecl );
  361. // Initialize each member in the order they were declared
  362. for( asUINT n = 0; n < outFunc->objectType->properties.GetLength(); n++ )
  363. {
  364. asCObjectProperty *prop = outFunc->objectType->properties[n];
  365. // Check if the property has an initialization expression
  366. asCParser parser(builder);
  367. asCScriptNode *declNode = 0;
  368. asCScriptNode *initNode = 0;
  369. asCScriptCode *initScript = 0;
  370. for( asUINT m = 0; m < m_classDecl->propInits.GetLength(); m++ )
  371. {
  372. if( m_classDecl->propInits[m].name == prop->name )
  373. {
  374. declNode = m_classDecl->propInits[m].declNode;
  375. initNode = m_classDecl->propInits[m].initNode;
  376. initScript = m_classDecl->propInits[m].file;
  377. break;
  378. }
  379. }
  380. // If declNode is null, the property was inherited in which case
  381. // it was already initialized by the base class' constructor
  382. if( declNode )
  383. {
  384. if( initNode )
  385. {
  386. if( onlyDefaults )
  387. continue;
  388. #ifdef AS_NO_MEMBER_INIT
  389. // Give an error as the initialization in the declaration has been disabled
  390. asCScriptCode *origScript = script;
  391. script = initScript;
  392. Error("Initialization of members in declaration is not supported", initNode);
  393. script = origScript;
  394. // Clear the initialization node
  395. initNode = 0;
  396. initScript = script;
  397. #else
  398. // Re-parse the initialization expression as the parser now knows the types, which it didn't earlier
  399. int r = parser.ParseVarInit(initScript, initNode);
  400. if( r < 0 )
  401. continue;
  402. initNode = parser.GetScriptNode();
  403. #endif
  404. }
  405. else
  406. {
  407. if( !onlyDefaults )
  408. continue;
  409. }
  410. #ifdef AS_NO_MEMBER_INIT
  411. // The initialization will be done in the asCScriptObject constructor, so
  412. // here we should just validate that the member has a default constructor
  413. if( prop->type.IsObject() &&
  414. !prop->type.IsObjectHandle() &&
  415. (((prop->type.GetTypeInfo()->flags & asOBJ_REF) &&
  416. prop->type.GetBehaviour()->factory == 0) ||
  417. ((prop->type.GetTypeInfo()->flags & asOBJ_VALUE) &&
  418. prop->type.GetBehaviour()->construct == 0 &&
  419. !(prop->type.GetTypeInfo()->flags & asOBJ_POD))) )
  420. {
  421. // Class has no default factory/constructor.
  422. asCString str;
  423. // TODO: funcdef: asCDataType should have a GetTypeName()
  424. if( prop->type.GetFuncDef() )
  425. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, prop->type.GetFuncDef()->GetName());
  426. else
  427. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, prop->type.GetTypeInfo()->GetName());
  428. Error(str, declNode);
  429. }
  430. #else
  431. // Temporarily set the script that is being compiled to where the member initialization is declared.
  432. // The script can be different when including mixin classes from a different script section
  433. asCScriptCode *origScript = script;
  434. script = initScript;
  435. // Add a line instruction with the position of the declaration
  436. LineInstr(bc, declNode->tokenPos);
  437. // Compile the initialization
  438. asQWORD constantValue;
  439. asCByteCode bcInit(engine);
  440. CompileInitialization(initNode, &bcInit, prop->type, declNode, prop->byteOffset, &constantValue, 2);
  441. bcInit.OptimizeLocally(tempVariableOffsets);
  442. bc->AddCode(&bcInit);
  443. script = origScript;
  444. #endif
  445. }
  446. }
  447. }
  448. // Entry
  449. int asCCompiler::CompileFunction(asCBuilder *in_builder, asCScriptCode *in_script, asCArray<asCString> &in_parameterNames, asCScriptNode *in_func, asCScriptFunction *in_outFunc, sClassDeclaration *in_classDecl)
  450. {
  451. TimeIt("asCCompiler::CompileFunction");
  452. Reset(in_builder, in_script, in_outFunc);
  453. int buildErrors = builder->numErrors;
  454. int stackPos = SetupParametersAndReturnVariable(in_parameterNames, in_func);
  455. //--------------------------------------------
  456. // Compile the statement block
  457. if( m_isConstructor )
  458. m_classDecl = in_classDecl;
  459. // We need to parse the statement block now
  460. asCScriptNode *blockBegin;
  461. // If the function signature was implicit, e.g. virtual property accessor or
  462. // lambda function, then the received node already is the statement block
  463. if( in_func->nodeType != snStatementBlock )
  464. blockBegin = in_func->lastChild;
  465. else
  466. blockBegin = in_func;
  467. // TODO: memory: We can parse the statement block one statement at a time, thus save even more memory
  468. // 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
  469. asCParser parser(builder);
  470. int r = parser.ParseStatementBlock(script, blockBegin);
  471. if( r < 0 ) return -1;
  472. asCScriptNode *block = parser.GetScriptNode();
  473. // Reserve a label for the cleanup code
  474. nextLabel++;
  475. bool hasReturn;
  476. asCByteCode bc(engine);
  477. LineInstr(&bc, blockBegin->tokenPos);
  478. CompileStatementBlock(block, false, &hasReturn, &bc);
  479. LineInstr(&bc, blockBegin->tokenPos + blockBegin->tokenLength);
  480. // Make sure there is a return in all paths (if not return type is void)
  481. // Don't bother with this check if there are compiler errors, e.g. Unreachable code
  482. if( !hasCompileErrors && outFunc->returnType != asCDataType::CreatePrimitive(ttVoid, false) )
  483. {
  484. if( hasReturn == false )
  485. Error(TXT_NOT_ALL_PATHS_RETURN, blockBegin);
  486. }
  487. //------------------------------------------------
  488. // Concatenate the bytecode
  489. // Insert a JitEntry at the start of the function for JIT compilers
  490. byteCode.InstrPTR(asBC_JitEntry, 0);
  491. if( outFunc->objectType )
  492. {
  493. if( m_isConstructor )
  494. {
  495. if( outFunc->objectType->derivedFrom )
  496. {
  497. // Call the base class' default constructor unless called manually in the code
  498. if( !m_isConstructorCalled )
  499. {
  500. if( outFunc->objectType->derivedFrom->beh.construct )
  501. {
  502. // Initialize members without explicit expression first
  503. CompileMemberInitialization(&byteCode, true);
  504. // Call base class' constructor
  505. asCByteCode tmpBC(engine);
  506. tmpBC.InstrSHORT(asBC_PSF, 0);
  507. tmpBC.Instr(asBC_RDSPtr);
  508. tmpBC.Call(asBC_CALL, outFunc->objectType->derivedFrom->beh.construct, AS_PTR_SIZE);
  509. tmpBC.OptimizeLocally(tempVariableOffsets);
  510. byteCode.AddCode(&tmpBC);
  511. // Add the initialization of the members with explicit expressions
  512. CompileMemberInitialization(&byteCode, false);
  513. }
  514. else
  515. Error(TEXT_BASE_DOESNT_HAVE_DEF_CONSTR, blockBegin);
  516. }
  517. else
  518. {
  519. // Only initialize members that don't have an explicit expression
  520. // The members that are explicitly initialized will be initialized after the call to base class' constructor
  521. CompileMemberInitialization(&byteCode, true);
  522. }
  523. }
  524. else
  525. {
  526. // Add the initialization of the members
  527. CompileMemberInitialization(&byteCode, true);
  528. CompileMemberInitialization(&byteCode, false);
  529. }
  530. }
  531. }
  532. // Add the code for the statement block
  533. byteCode.AddCode(&bc);
  534. // Count total variable size
  535. int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1;
  536. outFunc->scriptData->variableSpace = varSize;
  537. // Deallocate all local variables
  538. int n;
  539. for( n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  540. {
  541. sVariable *v = variables->variables[n];
  542. if( v->stackOffset > 0 )
  543. {
  544. // Call variables destructors
  545. if( v->name != "return" && v->name != "return address" )
  546. CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode);
  547. DeallocateVariable(v->stackOffset);
  548. }
  549. }
  550. // This is the label that return statements jump to
  551. // in order to exit the function
  552. byteCode.Label(0);
  553. // Call destructors for function parameters
  554. for( n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  555. {
  556. sVariable *v = variables->variables[n];
  557. if( v->stackOffset <= 0 )
  558. {
  559. // Call variable destructors here, for variables not yet destroyed
  560. if( v->name != "return" && v->name != "return address" )
  561. CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode);
  562. }
  563. // Do not deallocate parameters
  564. }
  565. // Check if the number of labels in the functions isn't too many to be handled
  566. if( nextLabel >= (1<<15) )
  567. Error(TXT_TOO_MANY_JUMP_LABELS, in_func);
  568. // If there are compile errors, there is no reason to build the final code
  569. if( hasCompileErrors || builder->numErrors != buildErrors )
  570. return -1;
  571. // At this point there should be no variables allocated
  572. asASSERT(variableAllocations.GetLength() == freeVariables.GetLength());
  573. // Remove the variable scope
  574. RemoveVariableScope();
  575. byteCode.Ret(-stackPos);
  576. FinalizeFunction();
  577. #ifdef AS_DEBUG
  578. // DEBUG: output byte code
  579. if( outFunc->objectType )
  580. byteCode.DebugOutput(("__" + outFunc->objectType->name + "_" + outFunc->name + ".txt").AddressOf(), in_outFunc);
  581. else
  582. byteCode.DebugOutput(("__" + outFunc->name + ".txt").AddressOf(), in_outFunc);
  583. #endif
  584. return 0;
  585. }
  586. int asCCompiler::CallCopyConstructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asCExprContext *arg, asCScriptNode *node, bool isGlobalVar, bool derefDest)
  587. {
  588. if( !type.IsObject() )
  589. return 0;
  590. // CallCopyConstructor should not be called for object handles.
  591. asASSERT( !type.IsObjectHandle() );
  592. asCArray<asCExprContext*> args;
  593. args.PushLast(arg);
  594. // The reference parameter must be pushed on the stack
  595. asASSERT( arg->type.dataType.GetTypeInfo() == type.GetTypeInfo() );
  596. // Since we're calling the copy constructor, we have to trust the function to not do
  597. // anything stupid otherwise we will just enter a loop, as we try to make temporary
  598. // copies of the argument in order to guarantee safety.
  599. if( type.GetTypeInfo()->flags & asOBJ_REF )
  600. {
  601. asCExprContext ctx(engine);
  602. int func = 0;
  603. asSTypeBehaviour *beh = type.GetBehaviour();
  604. if( beh ) func = beh->copyfactory;
  605. if( func > 0 )
  606. {
  607. if( !isGlobalVar )
  608. {
  609. // Call factory and store the handle in the given variable
  610. PerformFunctionCall(func, &ctx, false, &args, CastToObjectType(type.GetTypeInfo()), true, offset);
  611. // Pop the reference left by the function call
  612. ctx.bc.Instr(asBC_PopPtr);
  613. }
  614. else
  615. {
  616. // Call factory
  617. PerformFunctionCall(func, &ctx, false, &args, CastToObjectType(type.GetTypeInfo()));
  618. // Store the returned handle in the global variable
  619. ctx.bc.Instr(asBC_RDSPtr);
  620. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  621. ctx.bc.InstrPTR(asBC_REFCPY, type.GetTypeInfo());
  622. ctx.bc.Instr(asBC_PopPtr);
  623. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  624. }
  625. bc->AddCode(&ctx.bc);
  626. return 0;
  627. }
  628. }
  629. else
  630. {
  631. asSTypeBehaviour *beh = type.GetBehaviour();
  632. int func = beh ? beh->copyconstruct : 0;
  633. if( func > 0 )
  634. {
  635. // Push the address where the object will be stored on the stack, before the argument
  636. // TODO: When the context is serializable this probably has to be changed, since this
  637. // pointer can remain on the stack while the context is suspended. There is no
  638. // risk the pointer becomes invalid though, there is just no easy way to serialize it.
  639. asCByteCode tmp(engine);
  640. if( isGlobalVar )
  641. tmp.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  642. else if( isObjectOnHeap )
  643. tmp.InstrSHORT(asBC_PSF, (short)offset);
  644. tmp.AddCode(bc);
  645. bc->AddCode(&tmp);
  646. // When the object is allocated on the stack the object pointer
  647. // must be pushed on the stack after the arguments
  648. if( !isObjectOnHeap )
  649. {
  650. asASSERT( !isGlobalVar );
  651. bc->InstrSHORT(asBC_PSF, (short)offset);
  652. if( derefDest )
  653. {
  654. // The variable is a reference to the real location, so we need to dereference it
  655. bc->Instr(asBC_RDSPtr);
  656. }
  657. }
  658. asCExprContext ctx(engine);
  659. PerformFunctionCall(func, &ctx, isObjectOnHeap, &args, CastToObjectType(type.GetTypeInfo()));
  660. bc->AddCode(&ctx.bc);
  661. // TODO: value on stack: This probably needs to be done in PerformFunctionCall
  662. // Mark the object as initialized
  663. if( !isObjectOnHeap )
  664. bc->ObjInfo(offset, asOBJ_INIT);
  665. return 0;
  666. }
  667. }
  668. // Class has no copy constructor/factory.
  669. asCString str;
  670. str.Format(TXT_NO_COPY_CONSTRUCTOR_FOR_s, type.GetTypeInfo()->GetName());
  671. Error(str, node);
  672. return -1;
  673. }
  674. int asCCompiler::CallDefaultConstructor(const asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asCScriptNode *node, int isVarGlobOrMem, bool derefDest)
  675. {
  676. if( !type.IsObject() || type.IsObjectHandle() )
  677. return 0;
  678. if( type.GetTypeInfo()->flags & asOBJ_REF )
  679. {
  680. asCExprContext ctx(engine);
  681. ctx.exprNode = node;
  682. int func = 0;
  683. asSTypeBehaviour *beh = type.GetBehaviour();
  684. if( beh )
  685. {
  686. func = beh->factory;
  687. // If no trivial default factory is found, look for a factory where all params have default args
  688. if( func == 0 )
  689. {
  690. for( asUINT n = 0; n < beh->factories.GetLength(); n++ )
  691. {
  692. asCScriptFunction *f = engine->scriptFunctions[beh->factories[n]];
  693. if( f->defaultArgs.GetLength() == f->parameterTypes.GetLength() &&
  694. f->defaultArgs[0] != 0 )
  695. {
  696. func = beh->factories[n];
  697. break;
  698. }
  699. }
  700. }
  701. }
  702. if( func > 0 )
  703. {
  704. asCArray<asCExprContext *> args;
  705. asCScriptFunction *f = engine->scriptFunctions[func];
  706. if( f->parameterTypes.GetLength() )
  707. {
  708. // Add the default values for arguments not explicitly supplied
  709. CompileDefaultAndNamedArgs(node, args, func, CastToObjectType(type.GetTypeInfo()));
  710. PrepareFunctionCall(func, &ctx.bc, args);
  711. MoveArgsToStack(func, &ctx.bc, args, false);
  712. }
  713. if( isVarGlobOrMem == 0 )
  714. {
  715. // Call factory and store the handle in the given variable
  716. PerformFunctionCall(func, &ctx, false, &args, CastToObjectType(type.GetTypeInfo()), true, offset);
  717. // Pop the reference left by the function call
  718. ctx.bc.Instr(asBC_PopPtr);
  719. }
  720. else
  721. {
  722. // Call factory
  723. PerformFunctionCall(func, &ctx, false, &args, CastToObjectType(type.GetTypeInfo()));
  724. // TODO: runtime optimize: Should have a way of storing the object pointer directly to the destination
  725. // instead of first storing it in a local variable and then copying it to the
  726. // destination.
  727. if( !(type.GetTypeInfo()->flags & asOBJ_SCOPED) )
  728. {
  729. // Only dereference the variable if not a scoped type
  730. ctx.bc.Instr(asBC_RDSPtr);
  731. }
  732. if( isVarGlobOrMem == 1 )
  733. {
  734. // Store the returned handle in the global variable
  735. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  736. }
  737. else
  738. {
  739. // Store the returned handle in the class member
  740. ctx.bc.InstrSHORT(asBC_PSF, 0);
  741. ctx.bc.Instr(asBC_RDSPtr);
  742. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  743. }
  744. if( type.GetTypeInfo()->flags & asOBJ_SCOPED )
  745. {
  746. // For scoped typed we must move the reference from the local
  747. // variable rather than copy it as there is no AddRef behaviour
  748. ctx.bc.InstrSHORT_DW(asBC_COPY, AS_PTR_SIZE, asTYPEID_OBJHANDLE | engine->GetTypeIdFromDataType(type));
  749. // Clear the local variable so the reference isn't released
  750. ctx.bc.InstrSHORT(asBC_ClrVPtr, ctx.type.stackOffset);
  751. }
  752. else
  753. {
  754. if( type.IsFuncdef() )
  755. ctx.bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  756. else
  757. ctx.bc.InstrPTR(asBC_REFCPY, type.GetTypeInfo());
  758. }
  759. ctx.bc.Instr(asBC_PopPtr);
  760. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  761. }
  762. bc->AddCode(&ctx.bc);
  763. // Cleanup
  764. for( asUINT n = 0; n < args.GetLength(); n++ )
  765. if( args[n] )
  766. {
  767. asDELETE(args[n], asCExprContext);
  768. }
  769. return 0;
  770. }
  771. }
  772. else
  773. {
  774. asCExprContext ctx(engine);
  775. ctx.exprNode = node;
  776. asSTypeBehaviour *beh = type.GetBehaviour();
  777. int func = 0;
  778. if( beh )
  779. {
  780. func = beh->construct;
  781. // If no trivial default constructor is found, look for a constructor where all params have default args
  782. if( func == 0 )
  783. {
  784. for( asUINT n = 0; n < beh->constructors.GetLength(); n++ )
  785. {
  786. asCScriptFunction *f = engine->scriptFunctions[beh->constructors[n]];
  787. if( f->defaultArgs.GetLength() == f->parameterTypes.GetLength() &&
  788. f->defaultArgs[0] != 0 )
  789. {
  790. func = beh->constructors[n];
  791. break;
  792. }
  793. }
  794. }
  795. }
  796. // Allocate and initialize with the default constructor
  797. if( func != 0 || (type.GetTypeInfo()->flags & asOBJ_POD) )
  798. {
  799. asCArray<asCExprContext *> args;
  800. asCScriptFunction *f = engine->scriptFunctions[func];
  801. if( f && f->parameterTypes.GetLength() )
  802. {
  803. // Add the default values for arguments not explicitly supplied
  804. CompileDefaultAndNamedArgs(node, args, func, CastToObjectType(type.GetTypeInfo()));
  805. PrepareFunctionCall(func, &ctx.bc, args);
  806. MoveArgsToStack(func, &ctx.bc, args, false);
  807. }
  808. if( !isObjectOnHeap )
  809. {
  810. if( isVarGlobOrMem == 0 )
  811. {
  812. // There is nothing to do if there is no function,
  813. // as the memory is already allocated on the stack
  814. if( func )
  815. {
  816. // Call the constructor as a normal function
  817. bc->InstrSHORT(asBC_PSF, (short)offset);
  818. if( derefDest )
  819. bc->Instr(asBC_RDSPtr);
  820. asCExprContext ctxCall(engine);
  821. PerformFunctionCall(func, &ctxCall, false, 0, CastToObjectType(type.GetTypeInfo()));
  822. bc->AddCode(&ctxCall.bc);
  823. // TODO: value on stack: This probably needs to be done in PerformFunctionCall
  824. // Mark the object as initialized
  825. bc->ObjInfo(offset, asOBJ_INIT);
  826. }
  827. }
  828. else if( isVarGlobOrMem == 2 )
  829. {
  830. // Only POD types can be allocated inline in script classes
  831. asASSERT( type.GetTypeInfo()->flags & asOBJ_POD );
  832. if( func )
  833. {
  834. // Call the constructor as a normal function
  835. bc->InstrSHORT(asBC_PSF, 0);
  836. bc->Instr(asBC_RDSPtr);
  837. bc->InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  838. asCExprContext ctxCall(engine);
  839. PerformFunctionCall(func, &ctxCall, false, 0, CastToObjectType(type.GetTypeInfo()));
  840. bc->AddCode(&ctxCall.bc);
  841. }
  842. }
  843. else
  844. {
  845. asASSERT( false );
  846. }
  847. }
  848. else
  849. {
  850. if( isVarGlobOrMem == 0 )
  851. bc->InstrSHORT(asBC_PSF, (short)offset);
  852. else if( isVarGlobOrMem == 1 )
  853. bc->InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  854. else
  855. {
  856. bc->InstrSHORT(asBC_PSF, 0);
  857. bc->Instr(asBC_RDSPtr);
  858. bc->InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  859. }
  860. if( (type.GetTypeInfo()->flags & asOBJ_TEMPLATE) )
  861. {
  862. asCScriptFunction *descr = engine->scriptFunctions[func];
  863. asASSERT( descr->funcType == asFUNC_SCRIPT );
  864. // Find the id of the real constructor and not the generated stub
  865. asUINT id = 0;
  866. asDWORD *funcBc = descr->scriptData->byteCode.AddressOf();
  867. while( funcBc )
  868. {
  869. if( (*(asBYTE*)funcBc) == asBC_CALLSYS )
  870. {
  871. id = asBC_INTARG(funcBc);
  872. break;
  873. }
  874. funcBc += asBCTypeSize[asBCInfo[*(asBYTE*)funcBc].type];
  875. }
  876. asASSERT( id );
  877. bc->InstrPTR(asBC_OBJTYPE, type.GetTypeInfo());
  878. bc->Alloc(asBC_ALLOC, type.GetTypeInfo(), id, AS_PTR_SIZE + AS_PTR_SIZE);
  879. }
  880. else
  881. bc->Alloc(asBC_ALLOC, type.GetTypeInfo(), func, AS_PTR_SIZE);
  882. }
  883. // Cleanup
  884. for( asUINT n = 0; n < args.GetLength(); n++ )
  885. if( args[n] )
  886. {
  887. asDELETE(args[n], asCExprContext);
  888. }
  889. return 0;
  890. }
  891. }
  892. // Class has no default factory/constructor.
  893. asCString str;
  894. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, type.GetTypeInfo()->GetName());
  895. Error(str, node);
  896. return -1;
  897. }
  898. void asCCompiler::CallDestructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc)
  899. {
  900. if( !type.IsReference() )
  901. {
  902. // Call destructor for the data type
  903. if( type.IsObject() || type.IsFuncdef() )
  904. {
  905. // The null pointer doesn't need to be destroyed
  906. if( type.IsNullHandle() )
  907. return;
  908. // Nothing is done for list pattern types, as this is taken care of by the CompileInitList method
  909. if( type.GetTypeInfo()->flags & asOBJ_LIST_PATTERN )
  910. return;
  911. if( isObjectOnHeap || type.IsObjectHandle() )
  912. {
  913. // Free the memory
  914. if (type.IsFuncdef())
  915. bc->InstrW_PTR(asBC_FREE, (short)offset, &engine->functionBehaviours);
  916. else
  917. bc->InstrW_PTR(asBC_FREE, (short)offset, type.GetTypeInfo());
  918. }
  919. else
  920. {
  921. asASSERT( type.GetTypeInfo()->GetFlags() & asOBJ_VALUE );
  922. if( type.GetBehaviour()->destruct )
  923. {
  924. // Call the destructor as a regular function
  925. asCExprContext ctx(engine);
  926. ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
  927. PerformFunctionCall(type.GetBehaviour()->destruct, &ctx);
  928. ctx.bc.OptimizeLocally(tempVariableOffsets);
  929. bc->AddCode(&ctx.bc);
  930. }
  931. // TODO: Value on stack: This probably needs to be done in PerformFunctionCall
  932. // Mark the object as destroyed
  933. bc->ObjInfo(offset, asOBJ_UNINIT);
  934. }
  935. }
  936. }
  937. }
  938. void asCCompiler::LineInstr(asCByteCode *bc, size_t pos)
  939. {
  940. int r, c;
  941. script->ConvertPosToRowCol(pos, &r, &c);
  942. bc->Line(r, c, script->idx);
  943. }
  944. void asCCompiler::CompileStatementBlock(asCScriptNode *block, bool ownVariableScope, bool *hasReturn, asCByteCode *bc)
  945. {
  946. *hasReturn = false;
  947. bool isFinished = false;
  948. bool hasUnreachableCode = false;
  949. bool hasReturnBefore = false;
  950. if( ownVariableScope )
  951. {
  952. bc->Block(true);
  953. AddVariableScope();
  954. }
  955. asCScriptNode *node = block->firstChild;
  956. while( node )
  957. {
  958. #ifdef AS_DEBUG
  959. // Keep the current line in a variable so it will be easier
  960. // to determine where in a script an assert is occurring.
  961. int currentLine = 0;
  962. script->ConvertPosToRowCol(node->tokenPos, &currentLine, 0);
  963. #endif
  964. if( !hasUnreachableCode && (*hasReturn || isFinished) )
  965. {
  966. // Empty statements don't count
  967. if( node->nodeType != snExpressionStatement || node->firstChild )
  968. {
  969. hasUnreachableCode = true;
  970. Warning(TXT_UNREACHABLE_CODE, node);
  971. }
  972. if( *hasReturn )
  973. hasReturnBefore = true;
  974. }
  975. if( node->nodeType == snBreak || node->nodeType == snContinue )
  976. isFinished = true;
  977. asCByteCode statement(engine);
  978. if( node->nodeType == snDeclaration )
  979. CompileDeclaration(node, &statement);
  980. else
  981. CompileStatement(node, hasReturn, &statement);
  982. // Ignore missing returns in unreachable code paths
  983. if( !(*hasReturn) && hasReturnBefore )
  984. *hasReturn = true;
  985. LineInstr(bc, node->tokenPos);
  986. bc->AddCode(&statement);
  987. if( !hasCompileErrors )
  988. {
  989. asASSERT( tempVariables.GetLength() == 0 );
  990. asASSERT( reservedVariables.GetLength() == 0 );
  991. }
  992. node = node->next;
  993. }
  994. if( ownVariableScope )
  995. {
  996. // Deallocate variables in this block, in reverse order
  997. for( int n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  998. {
  999. sVariable *v = variables->variables[n];
  1000. // Call variable destructors here, for variables not yet destroyed
  1001. // If the block is terminated with a break, continue, or
  1002. // return the variables are already destroyed
  1003. if( !isFinished && !*hasReturn )
  1004. CallDestructor(v->type, v->stackOffset, v->onHeap, bc);
  1005. // Don't deallocate function parameters
  1006. if( v->stackOffset > 0 )
  1007. DeallocateVariable(v->stackOffset);
  1008. }
  1009. RemoveVariableScope();
  1010. bc->Block(false);
  1011. }
  1012. }
  1013. // Entry
  1014. int asCCompiler::CompileGlobalVariable(asCBuilder *in_builder, asCScriptCode *in_script, asCScriptNode *in_node, sGlobalVariableDescription *in_gvar, asCScriptFunction *in_outFunc)
  1015. {
  1016. Reset(in_builder, in_script, in_outFunc);
  1017. m_globalVar = in_gvar;
  1018. // Add a variable scope (even though variables can't be declared)
  1019. AddVariableScope();
  1020. in_gvar->isPureConstant = false;
  1021. // Parse the initialization nodes
  1022. asCParser parser(builder);
  1023. if (in_node)
  1024. {
  1025. int r = parser.ParseVarInit(in_script, in_node);
  1026. if (r < 0)
  1027. return r;
  1028. in_node = parser.GetScriptNode();
  1029. }
  1030. asCExprContext compiledCtx(engine);
  1031. bool preCompiled = false;
  1032. if (in_gvar->datatype.IsAuto())
  1033. {
  1034. preCompiled = CompileAutoType(in_gvar->datatype, compiledCtx, in_node, in_gvar->declaredAtNode);
  1035. if (!preCompiled)
  1036. {
  1037. // If it wasn't possible to determine the type from the expression then there
  1038. // is no need to continue with the initialization. The error was already reported
  1039. // in CompileAutoType.
  1040. return -1;
  1041. }
  1042. }
  1043. if( in_gvar->property == 0 )
  1044. {
  1045. in_gvar->property = builder->module->AllocateGlobalProperty(in_gvar->name.AddressOf(), in_gvar->datatype, in_gvar->ns);
  1046. in_gvar->index = in_gvar->property->id;
  1047. }
  1048. // Compile the expression
  1049. asCExprContext ctx(engine);
  1050. asQWORD constantValue = 0;
  1051. if( CompileInitialization(in_node, &ctx.bc, in_gvar->datatype, in_gvar->declaredAtNode, in_gvar->index, &constantValue, 1, preCompiled ? &compiledCtx : 0) )
  1052. {
  1053. // Should the variable be marked as pure constant?
  1054. if( in_gvar->datatype.IsPrimitive() && in_gvar->datatype.IsReadOnly() )
  1055. {
  1056. in_gvar->isPureConstant = true;
  1057. in_gvar->constantValue = constantValue;
  1058. }
  1059. }
  1060. // Concatenate the bytecode
  1061. int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1;
  1062. // Add information on the line number for the global variable
  1063. size_t pos = 0;
  1064. if( in_gvar->declaredAtNode )
  1065. pos = in_gvar->declaredAtNode->tokenPos;
  1066. else if( in_gvar->initializationNode )
  1067. pos = in_gvar->initializationNode->tokenPos;
  1068. LineInstr(&byteCode, pos);
  1069. // Reserve space for all local variables
  1070. outFunc->scriptData->variableSpace = varSize;
  1071. ctx.bc.OptimizeLocally(tempVariableOffsets);
  1072. byteCode.AddCode(&ctx.bc);
  1073. // Deallocate variables in this block, in reverse order
  1074. for( int n = (int)variables->variables.GetLength() - 1; n >= 0; --n )
  1075. {
  1076. sVariable *v = variables->variables[n];
  1077. // Call variable destructors here, for variables not yet destroyed
  1078. CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode);
  1079. DeallocateVariable(v->stackOffset);
  1080. }
  1081. if( hasCompileErrors ) return -1;
  1082. // At this point there should be no variables allocated
  1083. asASSERT(variableAllocations.GetLength() == freeVariables.GetLength());
  1084. // Remove the variable scope again
  1085. RemoveVariableScope();
  1086. byteCode.Ret(0);
  1087. FinalizeFunction();
  1088. #ifdef AS_DEBUG
  1089. // DEBUG: output byte code
  1090. byteCode.DebugOutput(("___init_" + in_gvar->name + ".txt").AddressOf(), outFunc);
  1091. #endif
  1092. return 0;
  1093. }
  1094. void asCCompiler::DetermineSingleFunc(asCExprContext *ctx, asCScriptNode *node)
  1095. {
  1096. // Don't do anything if this is not a deferred global function
  1097. if( !ctx->IsGlobalFunc() )
  1098. return;
  1099. // Determine the namespace
  1100. asSNameSpace *ns = 0;
  1101. asCString name = "";
  1102. int pos = ctx->methodName.FindLast("::");
  1103. if( pos >= 0 )
  1104. {
  1105. asCString nsName = ctx->methodName.SubString(0, pos+2);
  1106. // Cut off the ::
  1107. if( nsName.GetLength() > 2 )
  1108. nsName.SetLength(nsName.GetLength()-2);
  1109. ns = DetermineNameSpace(nsName);
  1110. name = ctx->methodName.SubString(pos+2);
  1111. }
  1112. else
  1113. {
  1114. DetermineNameSpace("");
  1115. name = ctx->methodName;
  1116. }
  1117. asCArray<int> funcs;
  1118. if( ns )
  1119. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  1120. // CompileVariableAccess should guarantee that at least one function is exists
  1121. asASSERT( funcs.GetLength() > 0 );
  1122. if( funcs.GetLength() > 1 )
  1123. {
  1124. asCString str;
  1125. str.Format(TXT_MULTIPLE_MATCHING_SIGNATURES_TO_s, ctx->methodName.AddressOf());
  1126. Error(str, node);
  1127. // Fall through so the compiler can continue as if only one function was matching
  1128. }
  1129. // A shared object may not access global functions unless they too are shared (e.g. registered functions)
  1130. if( !builder->GetFunctionDescription(funcs[0])->IsShared() &&
  1131. outFunc->IsShared() )
  1132. {
  1133. asCString msg;
  1134. msg.Format(TXT_SHARED_CANNOT_CALL_NON_SHARED_FUNC_s, builder->GetFunctionDescription(funcs[0])->GetDeclaration());
  1135. Error(msg, node);
  1136. // Fall through so the compiler can continue anyway
  1137. }
  1138. // Push the function pointer on the stack
  1139. ctx->bc.InstrPTR(asBC_FuncPtr, builder->GetFunctionDescription(funcs[0]));
  1140. ctx->type.Set(asCDataType::CreateType(engine->FindMatchingFuncdef(builder->GetFunctionDescription(funcs[0]), builder->module), false));
  1141. ctx->type.dataType.MakeHandle(true);
  1142. ctx->type.isExplicitHandle = true;
  1143. ctx->methodName = "";
  1144. }
  1145. void asCCompiler::CompileInitAsCopy(asCDataType &dt, int offset, asCByteCode *bc, asCExprContext *arg, asCScriptNode *node, bool derefDestination)
  1146. {
  1147. bool isObjectOnHeap = derefDestination ? false : IsVariableOnHeap(offset);
  1148. // Use copy constructor if available.
  1149. asCObjectType *ot = CastToObjectType(dt.GetTypeInfo());
  1150. if(!dt.IsObjectHandle() && ot && (ot->beh.copyconstruct || ot->beh.copyfactory))
  1151. {
  1152. PrepareForAssignment(&dt, arg, node, true);
  1153. int r = CallCopyConstructor(dt, offset, isObjectOnHeap, bc, arg, node, 0, derefDestination);
  1154. if( r < 0 && tempVariables.Exists(offset) )
  1155. Error(TXT_FAILED_TO_CREATE_TEMP_OBJ, node);
  1156. }
  1157. else
  1158. {
  1159. // TODO: Need to reserve variables, as the default constructor may need
  1160. // to allocate temporary variables to compute default args
  1161. // Allocate and construct the temporary object before whatever is already in the bytecode
  1162. asCByteCode tmpBC(engine);
  1163. int r = CallDefaultConstructor(dt, offset, isObjectOnHeap, &tmpBC, node, 0, derefDestination);
  1164. if( r < 0 )
  1165. {
  1166. if( tempVariables.Exists(offset) )
  1167. Error(TXT_FAILED_TO_CREATE_TEMP_OBJ, node);
  1168. return;
  1169. }
  1170. tmpBC.AddCode(bc);
  1171. bc->AddCode(&tmpBC);
  1172. // Assign the evaluated expression to the temporary variable
  1173. PrepareForAssignment(&dt, arg, node, true);
  1174. bc->AddCode(&arg->bc);
  1175. // Call the opAssign method to assign the value to the temporary object
  1176. dt.MakeReference(isObjectOnHeap);
  1177. asCExprValue type;
  1178. type.Set(dt);
  1179. type.isTemporary = true;
  1180. type.stackOffset = (short)offset;
  1181. if( dt.IsObjectHandle() )
  1182. type.isExplicitHandle = true;
  1183. bc->InstrSHORT(asBC_PSF, (short)offset);
  1184. if( derefDestination )
  1185. bc->Instr(asBC_RDSPtr);
  1186. r = PerformAssignment(&type, &arg->type, bc, node);
  1187. if( r < 0 )
  1188. {
  1189. if( tempVariables.Exists(offset) )
  1190. Error(TXT_FAILED_TO_CREATE_TEMP_OBJ, node);
  1191. return;
  1192. }
  1193. // Pop the reference that was pushed on the stack if the result is an object
  1194. if( type.dataType.IsObject() || type.dataType.IsFuncdef() )
  1195. bc->Instr(asBC_PopPtr);
  1196. // If the assignment operator returned an object by value it will
  1197. // be in a temporary variable which we need to destroy now
  1198. if( type.isTemporary && type.stackOffset != (short)offset )
  1199. ReleaseTemporaryVariable(type.stackOffset, bc);
  1200. // Release the original value too in case it is a temporary
  1201. ReleaseTemporaryVariable(arg->type, bc);
  1202. }
  1203. }
  1204. int asCCompiler::PrepareArgument(asCDataType *paramType, asCExprContext *ctx, asCScriptNode *node, bool isFunction, int refType, bool isMakingCopy)
  1205. {
  1206. asCDataType param = *paramType;
  1207. if( paramType->GetTokenType() == ttQuestion )
  1208. {
  1209. // The function is expecting a var type. If the argument is a function name, we must now decide which function it is
  1210. DetermineSingleFunc(ctx, node);
  1211. // Since the function is expecting a var type ?, then we don't want to convert the argument to anything else
  1212. param = ctx->type.dataType;
  1213. param.MakeHandle(ctx->type.isExplicitHandle || ctx->type.IsNullConstant());
  1214. // Treat the void expression like a null handle when working with var types
  1215. if( ctx->IsVoidExpression() )
  1216. param = asCDataType::CreateNullHandle();
  1217. // If value assign is disabled for reference types, then make
  1218. // sure to always pass the handle to ? parameters
  1219. if( builder->engine->ep.disallowValueAssignForRefType &&
  1220. ctx->type.dataType.GetTypeInfo() && (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCOPED) )
  1221. {
  1222. param.MakeHandle(true);
  1223. }
  1224. param.MakeReference(paramType->IsReference());
  1225. param.MakeReadOnly(paramType->IsReadOnly());
  1226. }
  1227. else
  1228. param = *paramType;
  1229. asCDataType dt = param;
  1230. // Need to protect arguments by reference
  1231. if( isFunction && dt.IsReference() )
  1232. {
  1233. // Allocate a temporary variable of the same type as the argument
  1234. dt.MakeReference(false);
  1235. int offset;
  1236. if( refType == asTM_INREF )
  1237. {
  1238. if( ProcessPropertyGetAccessor(ctx, node) < 0 )
  1239. return -1;
  1240. // Add the type id as hidden arg if the parameter is a ? type
  1241. if( paramType->GetTokenType() == ttQuestion )
  1242. {
  1243. asCByteCode tmpBC(engine);
  1244. // Place the type id on the stack as a hidden parameter
  1245. tmpBC.InstrDWORD(asBC_TYPEID, engine->GetTypeIdFromDataType(param));
  1246. // Insert the code before the expression code
  1247. tmpBC.AddCode(&ctx->bc);
  1248. ctx->bc.AddCode(&tmpBC);
  1249. }
  1250. if( dt.IsPrimitive() )
  1251. {
  1252. // If the reference is const, then it is not necessary to make a copy if the value already is a variable
  1253. // Even if the same variable is passed in another argument as non-const then there is no problem
  1254. IsVariableInitialized(&ctx->type, node);
  1255. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  1256. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true);
  1257. if( !(param.IsReadOnly() && ctx->type.isVariable) )
  1258. ConvertToTempVariable(ctx);
  1259. PushVariableOnStack(ctx, true);
  1260. ctx->type.dataType.MakeReadOnly(param.IsReadOnly());
  1261. }
  1262. else if( ctx->type.dataType.IsNullHandle() )
  1263. {
  1264. // Make sure the argument type can support handles (or is itself a handle)
  1265. // Don't allow null handle to be converted to an object type of ASHANDLE here, that would require more logic to call the constructor (which should be handled in ImplicitConversion)
  1266. if( (!dt.SupportHandles() && !dt.IsObjectHandle()) || (dt.GetTypeInfo() && (dt.GetTypeInfo()->GetFlags() & asOBJ_ASHANDLE)) )
  1267. {
  1268. asCString str;
  1269. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), param.Format(outFunc->nameSpace).AddressOf());
  1270. Error(str, node);
  1271. ctx->type.Set(param);
  1272. return -1;
  1273. }
  1274. // Need to initialize a local temporary variable to
  1275. // represent the null handle when passed as reference
  1276. asASSERT( ctx->bc.GetLastInstr() == asBC_PshNull );
  1277. ctx->bc.Instr(asBC_PopPtr);
  1278. dt.MakeHandle(true);
  1279. dt.MakeReadOnly(false);
  1280. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1281. // Push the reference to the variable on the stack
  1282. ctx->bc.InstrWORD(asBC_PSF, (short)offset);
  1283. ctx->type.SetVariable(dt, offset, true);
  1284. ctx->type.isExplicitHandle = true;
  1285. }
  1286. else
  1287. {
  1288. IsVariableInitialized(&ctx->type, node);
  1289. if( !isMakingCopy )
  1290. {
  1291. // For parameters expecting a reference to a handle we need to make sure the argument
  1292. // is really a handle, and not just a reference to the object. Do this check before the
  1293. // implicit conversion so it can be treated correctly.
  1294. if (dt.IsObjectHandle() && !ctx->type.dataType.IsObjectHandle())
  1295. {
  1296. // Make a refCopy into a local handle variable
  1297. // Allocate a handle variable
  1298. dt.MakeHandle(true);
  1299. dt.MakeReadOnly(false);
  1300. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1301. // Copy the handle
  1302. Dereference(ctx, true);
  1303. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1304. if (ctx->type.dataType.IsFuncdef())
  1305. ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  1306. else
  1307. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo());
  1308. ctx->bc.Instr(asBC_PopPtr);
  1309. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1310. // Release the original temporary variable
  1311. if( ctx->type.isTemporary )
  1312. ReleaseTemporaryVariable(ctx->type.stackOffset, &ctx->bc);
  1313. ctx->type.SetVariable(dt, offset, true);
  1314. }
  1315. // Even though the parameter expects a reference, it is only meant to be
  1316. // used as input value and doesn't have to refer to the actual object, so it
  1317. // is OK to do an implicit conversion.
  1318. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true);
  1319. if( !ctx->type.dataType.IsEqualExceptRefAndConst(param) )
  1320. {
  1321. asCString str;
  1322. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), param.Format(outFunc->nameSpace).AddressOf());
  1323. Error(str, node);
  1324. ctx->type.Set(param);
  1325. return -1;
  1326. }
  1327. // The compiler must guarantee that the object stays alive during the execution
  1328. // of the function, and it must also guarantee that the value isn't modified by
  1329. // the function.
  1330. // If the argument is a temporary local variable then it is safe to be passed to
  1331. // the function as it is, since the local variable will stay alive, and since it
  1332. // is temporary there is no side effect if the function modifies it.
  1333. // If the parameter is read-only and therefore guaranteed not to be modified by the
  1334. // function, then it is enough that the variable is local to guarantee the lifetime.
  1335. if( !ctx->type.isTemporary && !(param.IsReadOnly() && (ctx->type.isVariable || ctx->type.isRefSafe)) )
  1336. {
  1337. if( ctx->type.dataType.IsFuncdef() || ((ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && param.IsReadOnly() && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCOPED)) )
  1338. {
  1339. // Funcdefs only need an extra handle to guarantee the lifetime.
  1340. // If the object is a reference type (except scoped reference types), and the
  1341. // parameter is a const reference, then it is not necessary to make a copy of the
  1342. // object. The compiler just needs to hold a handle to guarantee the lifetime.
  1343. // Allocate a handle variable
  1344. dt.MakeHandle(true);
  1345. dt.MakeReadOnly(false);
  1346. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1347. // Copy the handle
  1348. Dereference(ctx, true);
  1349. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1350. if (ctx->type.dataType.IsFuncdef())
  1351. ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  1352. else
  1353. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo());
  1354. ctx->bc.Instr(asBC_PopPtr);
  1355. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1356. // The type should be set to the param type instead of dt to guarantee
  1357. // that the expression keeps the correct type for variable ? args. Otherwise
  1358. // MoveArgsToStack will use the wrong bytecode to move the arg to the stack
  1359. bool isExplicitHandle = ctx->type.isExplicitHandle;
  1360. ctx->type.SetVariable(param, offset, true);
  1361. ctx->type.dataType.MakeHandle(true);
  1362. ctx->type.isExplicitHandle = isExplicitHandle;
  1363. }
  1364. else
  1365. {
  1366. // Make a copy of the object to guarantee that the original isn't modified
  1367. asASSERT(!dt.IsFuncdef());
  1368. // Allocate and initialize a temporary local object
  1369. dt.MakeReadOnly(false);
  1370. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1371. CompileInitAsCopy(dt, offset, &ctx->bc, ctx, node, false);
  1372. // Push the object pointer on the stack
  1373. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  1374. if( dt.IsObject() && !dt.IsObjectHandle() )
  1375. ctx->bc.Instr(asBC_RDSPtr);
  1376. // Set the resulting type
  1377. ctx->type.Set(dt);
  1378. ctx->type.isTemporary = true;
  1379. ctx->type.stackOffset = short(offset);
  1380. if( dt.IsObjectHandle() )
  1381. ctx->type.isExplicitHandle = true;
  1382. ctx->type.dataType.MakeReference(false);
  1383. if( paramType->IsReadOnly() )
  1384. ctx->type.dataType.MakeReadOnly(true);
  1385. }
  1386. }
  1387. // When calling a function expecting a var arg with a parameter received as reference to handle
  1388. // then it is necessary to copy the handle to a local variable, otherwise MoveArgsToStack will
  1389. // not be able to do the correct double dereference to put the reference to the object on the stack.
  1390. if (paramType->GetTokenType() == ttQuestion && !param.IsObjectHandle() && ctx->type.isVariable)
  1391. {
  1392. sVariable *var = variables->GetVariableByOffset(ctx->type.stackOffset);
  1393. if (var && var->type.IsReference() && var->type.IsObjectHandle())
  1394. {
  1395. // Copy the handle to local variable
  1396. // Allocate a handle variable
  1397. dt.MakeHandle(true);
  1398. dt.MakeReadOnly(false);
  1399. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1400. // Copy the handle
  1401. Dereference(ctx, true);
  1402. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1403. if (ctx->type.dataType.IsFuncdef())
  1404. ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  1405. else
  1406. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo());
  1407. ctx->bc.Instr(asBC_PopPtr);
  1408. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1409. // The type should be set to the param type instead of dt to guarantee
  1410. // that the expression keeps the correct type for variable ? args. Otherwise
  1411. // MoveArgsToStack will use the wrong bytecode to move the arg to the stack
  1412. ctx->type.SetVariable(param, offset, true);
  1413. }
  1414. }
  1415. }
  1416. else
  1417. {
  1418. // We must guarantee that the address to the value is on the stack
  1419. if( (ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) &&
  1420. !ctx->type.dataType.IsObjectHandle() &&
  1421. ctx->type.dataType.IsReference() )
  1422. Dereference(ctx, true);
  1423. }
  1424. }
  1425. }
  1426. else if( refType == asTM_OUTREF )
  1427. {
  1428. // Add the type id as hidden arg if the parameter is a ? type
  1429. if( paramType->GetTokenType() == ttQuestion )
  1430. {
  1431. asCByteCode tmpBC(engine);
  1432. // Place the type id on the stack as a hidden parameter
  1433. tmpBC.InstrDWORD(asBC_TYPEID, engine->GetTypeIdFromDataType(param));
  1434. // Insert the code before the expression code
  1435. tmpBC.AddCode(&ctx->bc);
  1436. ctx->bc.AddCode(&tmpBC);
  1437. }
  1438. // If the expression is marked as clean, then it can be used directly
  1439. // without the need to allocate another temporary value as it is known
  1440. // that the argument has no other value than the default
  1441. if( ctx->isCleanArg )
  1442. {
  1443. // Must be a local variable
  1444. asASSERT( ctx->type.isVariable );
  1445. }
  1446. else
  1447. {
  1448. // Null handles and void expressions must be marked as explicit
  1449. // handles for correct treatement in MoveArgsToStack
  1450. if (dt.IsNullHandle())
  1451. ctx->type.isExplicitHandle = true;
  1452. // Make sure the variable is not used in the expression
  1453. dt.MakeReadOnly(false);
  1454. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1455. if( dt.IsPrimitive() )
  1456. {
  1457. ctx->type.SetVariable(dt, offset, true);
  1458. PushVariableOnStack(ctx, true);
  1459. }
  1460. else
  1461. {
  1462. // Allocate and construct the temporary object
  1463. asCByteCode tmpBC(engine);
  1464. CallDefaultConstructor(dt, offset, IsVariableOnHeap(offset), &tmpBC, node);
  1465. // Insert the code before the expression code
  1466. tmpBC.AddCode(&ctx->bc);
  1467. ctx->bc.AddCode(&tmpBC);
  1468. dt.MakeReference(!(dt.IsObject() || dt.IsFuncdef()) || dt.IsObjectHandle());
  1469. asCExprValue type;
  1470. type.Set(dt);
  1471. type.isTemporary = true;
  1472. type.stackOffset = (short)offset;
  1473. type.isExplicitHandle = ctx->type.isExplicitHandle;
  1474. ctx->type = type;
  1475. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  1476. if( (dt.IsObject() || dt.IsFuncdef()) && !dt.IsObjectHandle() )
  1477. ctx->bc.Instr(asBC_RDSPtr);
  1478. }
  1479. // After the function returns the temporary variable will
  1480. // be assigned to the expression, if it is a valid lvalue
  1481. }
  1482. }
  1483. else if( refType == asTM_INOUTREF )
  1484. {
  1485. if( ProcessPropertyGetAccessor(ctx, node) < 0 )
  1486. return -1;
  1487. // Add the type id as hidden arg if the parameter is a ? type
  1488. if( paramType->GetTokenType() == ttQuestion )
  1489. {
  1490. asCByteCode tmpBC(engine);
  1491. // Place the type id on the stack as a hidden parameter
  1492. tmpBC.InstrDWORD(asBC_TYPEID, engine->GetTypeIdFromDataType(param));
  1493. // Insert the code before the expression code
  1494. tmpBC.AddCode(&ctx->bc);
  1495. ctx->bc.AddCode(&tmpBC);
  1496. }
  1497. // Literal constants cannot be passed to inout ref arguments
  1498. if( !ctx->type.isVariable &&
  1499. ctx->type.isConstant &&
  1500. !ctx->type.dataType.IsEqualExceptRefAndConst(engine->stringType) )
  1501. {
  1502. // Unless unsafe references are turned on and the reference is const
  1503. if( param.IsReadOnly() && engine->ep.allowUnsafeReferences )
  1504. {
  1505. // Since the parameter is a const & make a copy.
  1506. ConvertToTempVariable(ctx);
  1507. ctx->type.dataType.MakeReadOnly(true);
  1508. }
  1509. else
  1510. {
  1511. Error(TXT_NOT_VALID_REFERENCE, node);
  1512. return -1;
  1513. }
  1514. }
  1515. // Allow anonymous init lists to be converted to the arg type
  1516. if( ctx->IsAnonymousInitList() )
  1517. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true, true);
  1518. if( (ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) && ctx->type.dataType.GetTypeInfo() != dt.GetTypeInfo() )
  1519. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true, false);
  1520. // Only objects that support object handles
  1521. // can be guaranteed to be safe. Local variables are
  1522. // already safe, so there is no need to add an extra
  1523. // references
  1524. if( !engine->ep.allowUnsafeReferences &&
  1525. !ctx->type.isVariable &&
  1526. (ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) &&
  1527. !ctx->type.dataType.IsObjectHandle() &&
  1528. ((ctx->type.dataType.GetBehaviour()->addref &&
  1529. ctx->type.dataType.GetBehaviour()->release) ||
  1530. (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_NOCOUNT) ||
  1531. ctx->type.dataType.IsFuncdef()) )
  1532. {
  1533. // Store a handle to the object as local variable
  1534. asCExprContext tmp(engine);
  1535. dt = ctx->type.dataType;
  1536. dt.MakeHandle(true);
  1537. dt.MakeReference(false);
  1538. dt.MakeReadOnly(false);
  1539. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1540. // Copy the handle
  1541. if( !ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReference() )
  1542. ctx->bc.Instr(asBC_RDSPtr);
  1543. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1544. if( ctx->type.dataType.IsFuncdef() )
  1545. ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  1546. else
  1547. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo());
  1548. ctx->bc.Instr(asBC_PopPtr);
  1549. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1550. dt.MakeHandle(false);
  1551. dt.MakeReference(true);
  1552. // Release previous temporary variable stored in the context (if any)
  1553. if( ctx->type.isTemporary )
  1554. ReleaseTemporaryVariable(ctx->type.stackOffset, &ctx->bc);
  1555. ctx->type.SetVariable(dt, offset, true);
  1556. }
  1557. // Make sure the reference to the value is on the stack
  1558. // For objects, the reference needs to be dereferenced so the pointer on the stack is to the actual object
  1559. // For handles, the reference shouldn't be changed because the pointer on the stack should be to the handle
  1560. if( (ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) && ctx->type.dataType.IsReference() && !param.IsObjectHandle() )
  1561. Dereference(ctx, true);
  1562. else if( ctx->type.isVariable && !(ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) )
  1563. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  1564. else if( ctx->type.dataType.IsPrimitive() )
  1565. ctx->bc.Instr(asBC_PshRPtr);
  1566. else if( ctx->type.dataType.IsObjectHandle() && !ctx->type.dataType.IsReference() )
  1567. ImplicitConversion(ctx, param, node, asIC_IMPLICIT_CONV, true, false);
  1568. }
  1569. }
  1570. else
  1571. {
  1572. if( ProcessPropertyGetAccessor(ctx, node) < 0 )
  1573. return -1;
  1574. if( dt.IsPrimitive() )
  1575. {
  1576. IsVariableInitialized(&ctx->type, node);
  1577. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  1578. // Implicitly convert primitives to the parameter type
  1579. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV);
  1580. if( ctx->type.isVariable )
  1581. {
  1582. PushVariableOnStack(ctx, dt.IsReference());
  1583. }
  1584. else if( ctx->type.isConstant )
  1585. {
  1586. ConvertToVariable(ctx);
  1587. PushVariableOnStack(ctx, dt.IsReference());
  1588. }
  1589. }
  1590. else
  1591. {
  1592. IsVariableInitialized(&ctx->type, node);
  1593. // Implicitly convert primitives to the parameter type
  1594. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV);
  1595. // Was the conversion successful?
  1596. if( !ctx->type.dataType.IsEqualExceptRef(dt) )
  1597. {
  1598. asCString str;
  1599. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), dt.Format(outFunc->nameSpace).AddressOf());
  1600. Error(str, node);
  1601. ctx->type.Set(dt);
  1602. return -1;
  1603. }
  1604. if( dt.IsObjectHandle() )
  1605. ctx->type.isExplicitHandle = true;
  1606. if( (dt.IsObject() || dt.IsFuncdef()) && !dt.IsNullHandle() && !dt.IsReference() )
  1607. {
  1608. // Objects passed by value must be placed in temporary variables
  1609. // so that they are guaranteed to not be referenced anywhere else.
  1610. // The object must also be allocated on the heap, as the memory will
  1611. // be deleted by the called function.
  1612. // Handles passed by value must also be placed in a temporary variable
  1613. // to guarantee that the object referred to isn't freed too early.
  1614. // TODO: value on stack: How can we avoid this unnecessary allocation?
  1615. // Don't make temporary copies of handles if it is going to be used
  1616. // for handle assignment anyway, i.e. REFCPY.
  1617. if( !(!isFunction && isMakingCopy && ctx->type.dataType.IsObjectHandle() && ctx->type.isVariable) )
  1618. PrepareTemporaryVariable(node, ctx, true);
  1619. }
  1620. }
  1621. }
  1622. // Don't put any pointer on the stack yet
  1623. if( param.IsReference() || ((param.IsObject() || param.IsFuncdef()) && !param.IsNullHandle()) )
  1624. {
  1625. // &inout parameter may leave the reference on the stack already
  1626. // references considered safe too, i.e. when the life time is known
  1627. if( refType != asTM_INOUTREF && !ctx->type.isRefSafe )
  1628. {
  1629. asASSERT( ctx->type.isVariable || ctx->type.isRefSafe || ctx->type.isTemporary || isMakingCopy );
  1630. if( ctx->type.isVariable || ctx->type.isTemporary )
  1631. {
  1632. ctx->bc.Instr(asBC_PopPtr);
  1633. ctx->bc.InstrSHORT(asBC_VAR, ctx->type.stackOffset);
  1634. ProcessDeferredParams(ctx);
  1635. }
  1636. }
  1637. }
  1638. return 0;
  1639. }
  1640. int asCCompiler::PrepareFunctionCall(int funcId, asCByteCode *bc, asCArray<asCExprContext *> &args)
  1641. {
  1642. // When a match has been found, compile the final byte code using correct parameter types
  1643. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  1644. asASSERT( descr->parameterTypes.GetLength() == args.GetLength() );
  1645. // If the function being called is the opAssign or copy constructor for the same type
  1646. // as the argument, then we should avoid making temporary copy of the argument
  1647. bool makingCopy = false;
  1648. if( descr->parameterTypes.GetLength() == 1 &&
  1649. descr->parameterTypes[0].IsEqualExceptRefAndConst(args[0]->type.dataType) &&
  1650. (((descr->name == "opAssign" || descr->name == "$beh0") && descr->objectType && descr->objectType == args[0]->type.dataType.GetTypeInfo()) ||
  1651. (descr->objectType == 0 && args[0]->type.dataType.GetTypeInfo() && descr->name == args[0]->type.dataType.GetTypeInfo()->name)) )
  1652. makingCopy = true;
  1653. // Add code for arguments
  1654. asCExprContext e(engine);
  1655. for( int n = (int)args.GetLength()-1; n >= 0; n-- )
  1656. {
  1657. // Make sure PrepareArgument doesn't use any variable that is already
  1658. // being used by the argument or any of the following argument expressions
  1659. int l = int(reservedVariables.GetLength());
  1660. for( int m = n; m >= 0; m-- )
  1661. args[m]->bc.GetVarsUsed(reservedVariables);
  1662. int r = PrepareArgument2(&e, args[n], &descr->parameterTypes[n], true, descr->inOutFlags[n], makingCopy);
  1663. reservedVariables.SetLength(l);
  1664. if (r < 0)
  1665. return r;
  1666. }
  1667. bc->AddCode(&e.bc);
  1668. return 0;
  1669. }
  1670. void asCCompiler::MoveArgsToStack(int funcId, asCByteCode *bc, asCArray<asCExprContext *> &args, bool addOneToOffset)
  1671. {
  1672. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  1673. int offset = 0;
  1674. if( addOneToOffset )
  1675. offset += AS_PTR_SIZE;
  1676. // The address of where the return value should be stored is push on top of the arguments
  1677. if( descr->DoesReturnOnStack() )
  1678. offset += AS_PTR_SIZE;
  1679. #ifdef AS_DEBUG
  1680. // If the function being called is the opAssign or copy constructor for the same type
  1681. // as the argument, then we should avoid making temporary copy of the argument
  1682. bool makingCopy = false;
  1683. if( descr->parameterTypes.GetLength() == 1 &&
  1684. descr->parameterTypes[0].IsEqualExceptRefAndConst(args[0]->type.dataType) &&
  1685. (((descr->name == "opAssign" || descr->name == "$beh0") && descr->objectType && descr->objectType == args[0]->type.dataType.GetTypeInfo()) ||
  1686. (descr->objectType == 0 && args[0]->type.dataType.GetTypeInfo() && descr->name == args[0]->type.dataType.GetTypeInfo()->name)) )
  1687. makingCopy = true;
  1688. #endif
  1689. // Move the objects that are sent by value to the stack just before the call
  1690. for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ )
  1691. {
  1692. if( descr->parameterTypes[n].IsReference() )
  1693. {
  1694. if( (descr->parameterTypes[n].IsObject() || descr->parameterTypes[n].IsFuncdef()) && !descr->parameterTypes[n].IsObjectHandle() )
  1695. {
  1696. if( descr->inOutFlags[n] != asTM_INOUTREF && !args[n]->type.isRefSafe )
  1697. {
  1698. #ifdef AS_DEBUG
  1699. // This assert is inside AS_DEBUG because of the variable makingCopy which is only defined in debug mode
  1700. asASSERT( args[n]->type.isVariable || args[n]->type.isTemporary || makingCopy );
  1701. #endif
  1702. if( (args[n]->type.isVariable || args[n]->type.isTemporary) )
  1703. {
  1704. if( !IsVariableOnHeap(args[n]->type.stackOffset) )
  1705. // TODO: runtime optimize: Actually the reference can be pushed on the stack directly
  1706. // as the value allocated on the stack is guaranteed to be safe
  1707. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1708. else
  1709. bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset);
  1710. }
  1711. }
  1712. if( args[n]->type.dataType.IsObjectHandle() )
  1713. bc->InstrWORD(asBC_ChkNullS, (asWORD)offset);
  1714. }
  1715. else if( descr->inOutFlags[n] != asTM_INOUTREF )
  1716. {
  1717. // If the argument is already known to be safe, i.e. has a guaranteed lifetime,
  1718. // then the address on the stack is already pointing to the correct object so no
  1719. // need to do anything else
  1720. if (!args[n]->type.isRefSafe)
  1721. {
  1722. if (descr->parameterTypes[n].GetTokenType() == ttQuestion &&
  1723. (args[n]->type.dataType.IsObject() || args[n]->type.dataType.IsFuncdef()) &&
  1724. !args[n]->type.dataType.IsObjectHandle())
  1725. {
  1726. // Send the object as a reference to the object,
  1727. // and not to the variable holding the object
  1728. if (!IsVariableOnHeap(args[n]->type.stackOffset))
  1729. // TODO: runtime optimize: Actually the reference can be pushed on the stack directly
  1730. // as the value allocated on the stack is guaranteed to be safe
  1731. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1732. else
  1733. bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset);
  1734. }
  1735. else if (descr->parameterTypes[n].GetTokenType() == ttQuestion &&
  1736. args[n]->type.dataType.IsObjectHandle() && !args[n]->type.isExplicitHandle)
  1737. {
  1738. // The object handle is being passed as an object, so dereference it before
  1739. // the call so the reference will be to the object rather than to the handle
  1740. if (engine->ep.disallowValueAssignForRefType)
  1741. {
  1742. // With disallow value assign all ref type objects are always passed by handle
  1743. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1744. }
  1745. else
  1746. bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset);
  1747. }
  1748. else
  1749. {
  1750. // If the variable is really an argument of @& type, then it is necessary
  1751. // to use asBC_GETOBJREF so the pointer is correctly dereferenced.
  1752. sVariable *var = variables->GetVariableByOffset(args[n]->type.stackOffset);
  1753. if (var == 0 || !var->type.IsReference() || !var->type.IsObjectHandle())
  1754. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1755. else
  1756. bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset);
  1757. }
  1758. }
  1759. }
  1760. }
  1761. else if( descr->parameterTypes[n].IsObject() || descr->parameterTypes[n].IsFuncdef() )
  1762. {
  1763. asASSERT(!args[n]->type.isRefSafe);
  1764. // TODO: value on stack: What can we do to avoid this unnecessary allocation?
  1765. // The object must be allocated on the heap, because this memory will be deleted in as_callfunc_xxx
  1766. asASSERT(IsVariableOnHeap(args[n]->type.stackOffset));
  1767. // The pointer in the variable will be moved to the stack
  1768. bc->InstrWORD(asBC_GETOBJ, (asWORD)offset);
  1769. // Deallocate the variable slot so it can be reused, but do not attempt to
  1770. // free the content of the variable since it was moved to the stack for the call
  1771. DeallocateVariable(args[n]->type.stackOffset);
  1772. args[n]->type.isTemporary = false;
  1773. }
  1774. offset += descr->parameterTypes[n].GetSizeOnStackDWords();
  1775. }
  1776. }
  1777. int asCCompiler::CompileArgumentList(asCScriptNode *node, asCArray<asCExprContext*> &args, asCArray<asSNamedArgument> &namedArgs)
  1778. {
  1779. asASSERT(node->nodeType == snArgList);
  1780. // Count arguments
  1781. asCScriptNode *arg = node->firstChild;
  1782. int argCount = 0;
  1783. while( arg )
  1784. {
  1785. if( arg->nodeType != snNamedArgument )
  1786. argCount++;
  1787. arg = arg->next;
  1788. }
  1789. // Prepare the arrays
  1790. args.SetLength(argCount);
  1791. int n;
  1792. for( n = 0; n < argCount; n++ )
  1793. args[n] = 0;
  1794. n = argCount-1;
  1795. // Compile the arguments in reverse order (as they will be pushed on the stack)
  1796. bool anyErrors = false, inPositionalArguments = false;
  1797. arg = node->lastChild;
  1798. while( arg )
  1799. {
  1800. asCScriptNode *asgNode = arg, *namedNode = 0;
  1801. if( asgNode->nodeType == snNamedArgument )
  1802. {
  1803. if( inPositionalArguments )
  1804. {
  1805. Error(TXT_POS_ARG_AFTER_NAMED_ARG, node);
  1806. return -1;
  1807. }
  1808. asgNode = arg->firstChild->next;
  1809. namedNode = arg->firstChild;
  1810. asASSERT( namedNode->nodeType == snIdentifier );
  1811. }
  1812. else
  1813. inPositionalArguments = true;
  1814. asCExprContext expr(engine);
  1815. int r = CompileAssignment(asgNode, &expr);
  1816. if( r < 0 ) anyErrors = true;
  1817. asCExprContext *ctx = asNEW(asCExprContext)(engine);
  1818. if( ctx == 0 )
  1819. {
  1820. // Out of memory
  1821. return -1;
  1822. }
  1823. MergeExprBytecodeAndType(ctx, &expr);
  1824. if( inPositionalArguments )
  1825. {
  1826. args[n] = ctx;
  1827. n--;
  1828. }
  1829. else
  1830. {
  1831. asSNamedArgument namedArg;
  1832. namedArg.name = asCString(&script->code[namedNode->tokenPos], namedNode->tokenLength);
  1833. namedArg.ctx = ctx;
  1834. // Error out when multiple arguments with the same name are passed
  1835. for( asUINT a = 0; a < namedArgs.GetLength(); ++a )
  1836. {
  1837. if( namedArgs[a].name == namedArg.name )
  1838. {
  1839. Error(TXT_DUPLICATE_NAMED_ARG, asgNode);
  1840. anyErrors = true;
  1841. break;
  1842. }
  1843. }
  1844. namedArgs.PushLast(namedArg);
  1845. }
  1846. arg = arg->prev;
  1847. }
  1848. return anyErrors ? -1 : 0;
  1849. }
  1850. int asCCompiler::CompileDefaultAndNamedArgs(asCScriptNode *node, asCArray<asCExprContext*> &args, int funcId, asCObjectType *objectType, asCArray<asSNamedArgument> *namedArgs)
  1851. {
  1852. asCScriptFunction *func = builder->GetFunctionDescription(funcId);
  1853. if( func == 0 || args.GetLength() >= (asUINT)func->GetParamCount() )
  1854. return 0;
  1855. // Make sure to use the real function for virtual functions
  1856. if( func->funcType == asFUNC_VIRTUAL )
  1857. {
  1858. asASSERT( objectType );
  1859. func = objectType->virtualFunctionTable[func->vfTableIdx];
  1860. }
  1861. // Make sure none of the variables used in the previous arguments are reused in the default arguments
  1862. bool anyErrors = false;
  1863. int prevReservedVars = reservedVariables.GetLength();
  1864. int explicitArgs = (int)args.GetLength();
  1865. for( int p = 0; p < explicitArgs; p++ )
  1866. args[p]->bc.GetVarsUsed(reservedVariables);
  1867. // Make space for all the new arguments
  1868. args.SetLength(func->parameterTypes.GetLength());
  1869. for( asUINT c = explicitArgs; c < args.GetLength(); c++ )
  1870. args[c] = 0;
  1871. // Add the named arguments to the argument list in the right position
  1872. if( namedArgs )
  1873. {
  1874. for( asUINT n = 0; n < namedArgs->GetLength(); ++n )
  1875. {
  1876. asSNamedArgument &named = (*namedArgs)[n];
  1877. named.ctx->bc.GetVarsUsed(reservedVariables);
  1878. // Find the right spot to put it in
  1879. asUINT index = asUINT(-1);
  1880. for( asUINT j = 0; j < func->parameterTypes.GetLength(); ++j )
  1881. {
  1882. if( func->parameterNames[j] == (*namedArgs)[n].name )
  1883. {
  1884. index = j;
  1885. break;
  1886. }
  1887. }
  1888. asASSERT( index < args.GetLength() );
  1889. args[index] = named.ctx;
  1890. named.ctx = 0;
  1891. }
  1892. }
  1893. // Compile the arguments in reverse order (as they will be pushed on the stack)
  1894. for( int n = (int)func->parameterTypes.GetLength() - 1; n >= explicitArgs; n-- )
  1895. {
  1896. if( args[n] != 0 ) continue;
  1897. if( func->defaultArgs[n] == 0 ) { anyErrors = true; continue; }
  1898. // Parse the default arg string
  1899. asCParser parser(builder);
  1900. asCScriptCode *code = builder->FindOrAddCode("default arg", func->defaultArgs[n]->AddressOf(), func->defaultArgs[n]->GetLength());
  1901. int r = parser.ParseExpression(code);
  1902. if( r < 0 )
  1903. {
  1904. asCString msg;
  1905. msg.Format(TXT_FAILED_TO_COMPILE_DEF_ARG_d_IN_FUNC_s, n, func->GetDeclaration());
  1906. Error(msg, node);
  1907. anyErrors = true;
  1908. continue;
  1909. }
  1910. asCScriptNode *arg = parser.GetScriptNode();
  1911. // Temporarily set the script code to the default arg expression
  1912. asCScriptCode *origScript = script;
  1913. script = code;
  1914. // Don't allow the expression to access local variables
  1915. isCompilingDefaultArg = true;
  1916. // Temporarily set the namespace in the output function to the namespace of the called
  1917. // function so that the default arguments are evaluated in the correct namespace
  1918. asSNameSpace *origNameSpace = outFunc->nameSpace;
  1919. outFunc->nameSpace = func->nameSpace;
  1920. asCExprContext expr(engine);
  1921. r = CompileExpression(arg, &expr);
  1922. // Restore the namespace
  1923. outFunc->nameSpace = origNameSpace;
  1924. // Don't allow address of class method
  1925. if( expr.IsClassMethod() )
  1926. {
  1927. // TODO: Improve error message
  1928. Error(TXT_DEF_ARG_TYPE_DOESNT_MATCH, arg);
  1929. r = -1;
  1930. }
  1931. // Make sure the expression can be implicitly converted to the parameter type
  1932. if( r >= 0 )
  1933. {
  1934. asCArray<int> funcs;
  1935. funcs.PushLast(func->id);
  1936. asCArray<asSOverloadCandidate> matches;
  1937. if( MatchArgument(funcs, matches, &expr, n) == 0 )
  1938. {
  1939. Error(TXT_DEF_ARG_TYPE_DOESNT_MATCH, arg);
  1940. r = -1;
  1941. }
  1942. }
  1943. isCompilingDefaultArg = false;
  1944. script = origScript;
  1945. if( r < 0 )
  1946. {
  1947. asCString msg;
  1948. msg.Format(TXT_FAILED_TO_COMPILE_DEF_ARG_d_IN_FUNC_s, n, func->GetDeclaration());
  1949. Error(msg, node);
  1950. anyErrors = true;
  1951. continue;
  1952. }
  1953. args[n] = asNEW(asCExprContext)(engine);
  1954. if( args[n] == 0 )
  1955. {
  1956. // Out of memory
  1957. reservedVariables.SetLength(prevReservedVars);
  1958. return -1;
  1959. }
  1960. MergeExprBytecodeAndType(args[n], &expr);
  1961. if (args[n]->exprNode)
  1962. {
  1963. // Disconnect the node from the parser, and tell the compiler to free it when complete
  1964. args[n]->exprNode->DisconnectParent();
  1965. nodesToFreeUponComplete.PushLast(args[n]->exprNode);
  1966. }
  1967. }
  1968. reservedVariables.SetLength(prevReservedVars);
  1969. return anyErrors ? -1 : 0;
  1970. }
  1971. 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)
  1972. {
  1973. asCArray<int> origFuncs = funcs; // Keep the original list for error message
  1974. asUINT cost = 0;
  1975. asUINT n;
  1976. if( funcs.GetLength() > 0 )
  1977. {
  1978. // Check the number of parameters in the found functions
  1979. asUINT totalArgs = (asUINT)args.GetLength();
  1980. if( namedArgs != 0 )
  1981. totalArgs += (asUINT)namedArgs->GetLength();
  1982. for( n = 0; n < funcs.GetLength(); ++n )
  1983. {
  1984. asCScriptFunction *desc = builder->GetFunctionDescription(funcs[n]);
  1985. if( desc->parameterTypes.GetLength() != totalArgs )
  1986. {
  1987. bool noMatch = true;
  1988. if( totalArgs < desc->parameterTypes.GetLength() )
  1989. {
  1990. // For virtual functions, the default args are defined in the real function of the object
  1991. if( desc->funcType == asFUNC_VIRTUAL )
  1992. desc = objectType->virtualFunctionTable[desc->vfTableIdx];
  1993. // Count the number of default args
  1994. asUINT defaultArgs = 0;
  1995. for( asUINT d = 0; d < desc->defaultArgs.GetLength(); d++ )
  1996. if( desc->defaultArgs[d] )
  1997. defaultArgs++;
  1998. if( totalArgs >= desc->parameterTypes.GetLength() - defaultArgs )
  1999. noMatch = false;
  2000. }
  2001. if( noMatch )
  2002. {
  2003. // remove it from the list
  2004. if( n == funcs.GetLength()-1 )
  2005. funcs.PopLast();
  2006. else
  2007. funcs[n] = funcs.PopLast();
  2008. n--;
  2009. }
  2010. }
  2011. }
  2012. // Match functions with the parameters, and discard those that do not match
  2013. asCArray<asSOverloadCandidate> matchingFuncs;
  2014. matchingFuncs.SetLengthNoConstruct( funcs.GetLength() );
  2015. for ( n = 0; n < funcs.GetLength(); ++n )
  2016. {
  2017. matchingFuncs[n].funcId = funcs[n];
  2018. matchingFuncs[n].cost = 0;
  2019. }
  2020. // Match positionally passed arguments
  2021. for( n = 0; n < args.GetLength(); ++n )
  2022. {
  2023. asCArray<asSOverloadCandidate> tempFuncs;
  2024. MatchArgument(funcs, tempFuncs, args[n], n, allowObjectConstruct);
  2025. // Intersect the found functions with the list of matching functions
  2026. for( asUINT f = 0; f < matchingFuncs.GetLength(); f++ )
  2027. {
  2028. asUINT c;
  2029. for( c = 0; c < tempFuncs.GetLength(); c++ )
  2030. {
  2031. if( matchingFuncs[f].funcId == tempFuncs[c].funcId )
  2032. {
  2033. // Sum argument cost
  2034. matchingFuncs[f].cost += tempFuncs[c].cost;
  2035. break;
  2036. } // End if match
  2037. }
  2038. // Was the function a match?
  2039. if( c == tempFuncs.GetLength() )
  2040. {
  2041. // No, remove it from the list
  2042. if( f == matchingFuncs.GetLength()-1 )
  2043. matchingFuncs.PopLast();
  2044. else
  2045. matchingFuncs[f] = matchingFuncs.PopLast();
  2046. f--;
  2047. }
  2048. }
  2049. }
  2050. // Match named arguments
  2051. if( namedArgs != 0 )
  2052. {
  2053. for( asUINT i = 0; i < matchingFuncs.GetLength(); ++i )
  2054. {
  2055. asCScriptFunction *desc = builder->GetFunctionDescription(matchingFuncs[i].funcId);
  2056. if( desc->funcType == asFUNC_VIRTUAL )
  2057. desc = objectType->virtualFunctionTable[desc->vfTableIdx];
  2058. // Match every named argument to an argument in the function
  2059. for( n = 0; n < namedArgs->GetLength(); ++n )
  2060. (*namedArgs)[n].match = asUINT(-1);
  2061. bool matchedAll = true;
  2062. for( asUINT j = 0; j < desc->parameterTypes.GetLength(); ++j )
  2063. {
  2064. asUINT match = asUINT(-1);
  2065. for( n = 0; n < namedArgs->GetLength(); ++n )
  2066. {
  2067. asSNamedArgument &namedArg = (*namedArgs)[n];
  2068. if( desc->parameterNames[j] == namedArg.name )
  2069. {
  2070. namedArg.match = j;
  2071. match = n;
  2072. break;
  2073. }
  2074. }
  2075. // Check that every position is filled somehow
  2076. if( j >= args.GetLength() )
  2077. {
  2078. if( match == asUINT(-1) && !desc->defaultArgs[j] )
  2079. {
  2080. // No argument was found for this, and there is no
  2081. // default, so it doesn't work.
  2082. matchedAll = false;
  2083. break;
  2084. }
  2085. }
  2086. else
  2087. {
  2088. if( match != asUINT(-1) )
  2089. {
  2090. // Can't name an argument that was already passed
  2091. matchedAll = false;
  2092. break;
  2093. }
  2094. }
  2095. }
  2096. // Check that every named argument was matched
  2097. if( matchedAll )
  2098. {
  2099. for( n = 0; n < namedArgs->GetLength(); ++n )
  2100. {
  2101. asSNamedArgument &named = (*namedArgs)[n];
  2102. if( named.match == asUINT(-1) )
  2103. {
  2104. matchedAll = false;
  2105. break;
  2106. }
  2107. // Add to the cost
  2108. cost = MatchArgument(desc, named.ctx, named.match, allowObjectConstruct);
  2109. if( cost == asUINT(-1) )
  2110. {
  2111. matchedAll = false;
  2112. break;
  2113. }
  2114. matchingFuncs[i].cost += cost;
  2115. }
  2116. }
  2117. if( !matchedAll )
  2118. {
  2119. // Remove the function, we didn't match all the arguments.
  2120. if( i == matchingFuncs.GetLength()-1 )
  2121. matchingFuncs.PopLast();
  2122. else
  2123. matchingFuncs[i] = matchingFuncs.PopLast();
  2124. i--;
  2125. }
  2126. }
  2127. }
  2128. // Select the overload(s) with the lowest overall cost
  2129. funcs.SetLength(0);
  2130. asUINT bestCost = asUINT(-1);
  2131. for( n = 0; n < matchingFuncs.GetLength(); ++n )
  2132. {
  2133. cost = matchingFuncs[n].cost;
  2134. if( cost < bestCost )
  2135. {
  2136. funcs.SetLength(0);
  2137. bestCost = cost;
  2138. }
  2139. if( cost == bestCost )
  2140. funcs.PushLast( matchingFuncs[n].funcId );
  2141. }
  2142. // Cost returned is equivalent to the best cost discovered
  2143. cost = bestCost;
  2144. }
  2145. if( !isConstMethod )
  2146. FilterConst(funcs);
  2147. if( funcs.GetLength() != 1 && !silent )
  2148. {
  2149. // Build a readable string of the function with parameter types
  2150. bool attemptsPassingClassMethod = false;
  2151. asCString str;
  2152. if( scope != "" && scope != "::" )
  2153. str = scope + "::";
  2154. str += name;
  2155. str += "(";
  2156. for( n = 0; n < args.GetLength(); n++ )
  2157. {
  2158. if( n > 0 )
  2159. str += ", ";
  2160. if( args[n]->methodName != "" )
  2161. {
  2162. if( args[n]->IsClassMethod() )
  2163. {
  2164. attemptsPassingClassMethod = true;
  2165. str += args[n]->type.dataType.GetTypeInfo()->GetName();
  2166. str += "::";
  2167. }
  2168. str += args[n]->methodName;
  2169. }
  2170. else if (args[n]->IsAnonymousInitList())
  2171. {
  2172. str += "{...}";
  2173. }
  2174. else
  2175. str += args[n]->type.dataType.Format(outFunc->nameSpace);
  2176. }
  2177. if( namedArgs != 0 )
  2178. {
  2179. for( n = 0; n < namedArgs->GetLength(); n++ )
  2180. {
  2181. if( n > 0 || args.GetLength() )
  2182. str += ", ";
  2183. asSNamedArgument &named = (*namedArgs)[n];
  2184. str += named.name;
  2185. str += ": ";
  2186. if( named.ctx->methodName != "" )
  2187. str += named.ctx->methodName;
  2188. else
  2189. str += named.ctx->type.dataType.Format(outFunc->nameSpace);
  2190. }
  2191. }
  2192. str += ")";
  2193. if( isConstMethod )
  2194. str += " const";
  2195. if( objectType && scope == "" )
  2196. str = objectType->name + "::" + str;
  2197. if( funcs.GetLength() == 0 )
  2198. {
  2199. str.Format(TXT_NO_MATCHING_SIGNATURES_TO_s, str.AddressOf());
  2200. Error(str, node);
  2201. if( attemptsPassingClassMethod )
  2202. {
  2203. // Class methods must use delegate objects
  2204. Error(TXT_CANNOT_PASS_CLASS_METHOD_AS_ARG, node);
  2205. }
  2206. else
  2207. {
  2208. // Print the list of candidates
  2209. if( origFuncs.GetLength() > 0 )
  2210. {
  2211. int r = 0, c = 0;
  2212. asASSERT( node );
  2213. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  2214. builder->WriteInfo(script->name.AddressOf(), TXT_CANDIDATES_ARE, r, c, false);
  2215. PrintMatchingFuncs(origFuncs, node, objectType);
  2216. }
  2217. }
  2218. }
  2219. else
  2220. {
  2221. asASSERT( attemptsPassingClassMethod == false );
  2222. str.Format(TXT_MULTIPLE_MATCHING_SIGNATURES_TO_s, str.AddressOf());
  2223. Error(str, node);
  2224. PrintMatchingFuncs(funcs, node, objectType);
  2225. }
  2226. }
  2227. return cost;
  2228. }
  2229. bool asCCompiler::CompileAutoType(asCDataType &type, asCExprContext &compiledCtx, asCScriptNode *node, asCScriptNode *errNode)
  2230. {
  2231. if( node && node->nodeType == snAssignment )
  2232. {
  2233. int r = CompileAssignment(node, &compiledCtx);
  2234. if( r >= 0 )
  2235. {
  2236. // Must not have unused ambiguous names
  2237. if (compiledCtx.IsClassMethod() || compiledCtx.IsGlobalFunc())
  2238. {
  2239. // TODO: Should mention that the problem is the ambiguous name
  2240. Error(TXT_CANNOT_RESOLVE_AUTO, errNode);
  2241. return false;
  2242. }
  2243. // Must not have unused anonymous functions
  2244. if (compiledCtx.IsLambda())
  2245. {
  2246. // TODO: Should mention that the problem is the anonymous function
  2247. Error(TXT_CANNOT_RESOLVE_AUTO, errNode);
  2248. return false;
  2249. }
  2250. // Must not be a null handle
  2251. if (compiledCtx.type.dataType.IsNullHandle())
  2252. {
  2253. // TODO: Should mention that the problem is the null pointer
  2254. Error(TXT_CANNOT_RESOLVE_AUTO, errNode);
  2255. return false;
  2256. }
  2257. asCDataType newType = compiledCtx.type.dataType;
  2258. // Handle const qualifier on auto
  2259. if (type.IsReadOnly())
  2260. newType.MakeReadOnly(true);
  2261. else if (type.IsHandleToConst())
  2262. newType.MakeHandleToConst(true);
  2263. else if (newType.IsPrimitive())
  2264. newType.MakeReadOnly(false);
  2265. // Handle reference/value stuff
  2266. newType.MakeReference(false);
  2267. if (!newType.IsObjectHandle())
  2268. {
  2269. // We got a value object or an object reference.
  2270. // Turn the variable into a handle if specified
  2271. // as auto@, otherwise make it a 'value'.
  2272. if (type.IsHandleToAuto())
  2273. {
  2274. if (newType.MakeHandle(true) < 0)
  2275. {
  2276. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, errNode);
  2277. return false;
  2278. }
  2279. }
  2280. }
  2281. // Implicit handle types should always be handles
  2282. if (newType.GetTypeInfo() &&
  2283. (newType.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE))
  2284. newType.MakeHandle(true);
  2285. // For types that support handles auto should prefer handle
  2286. // as it is more efficient than making a copy
  2287. if( newType.SupportHandles() )
  2288. newType.MakeHandle(true);
  2289. type = newType;
  2290. return true;
  2291. }
  2292. return false;
  2293. }
  2294. else
  2295. {
  2296. Error(TXT_CANNOT_RESOLVE_AUTO, errNode);
  2297. type = asCDataType::CreatePrimitive(ttInt, false);
  2298. return false;
  2299. }
  2300. }
  2301. void asCCompiler::CompileDeclaration(asCScriptNode *decl, asCByteCode *bc)
  2302. {
  2303. // Get the data type
  2304. asCDataType type = builder->CreateDataTypeFromNode(decl->firstChild, script, outFunc->nameSpace, false, outFunc->objectType);
  2305. // Declare all variables in this declaration
  2306. asCScriptNode *node = decl->firstChild->next;
  2307. while( node )
  2308. {
  2309. // If this is an auto type, we have to compile the assignment now to figure out the type
  2310. asCExprContext compiledCtx(engine);
  2311. bool preCompiled = false;
  2312. if (type.IsAuto())
  2313. {
  2314. preCompiled = CompileAutoType(type, compiledCtx, node->next, node);
  2315. if (!preCompiled)
  2316. {
  2317. // If it wasn't possible to determine the type from the expression then there
  2318. // is no need to continue with the initialization. The error was already reported
  2319. // in CompileAutoType.
  2320. return;
  2321. }
  2322. }
  2323. // Is the type allowed?
  2324. if( !type.CanBeInstantiated() )
  2325. {
  2326. asCString str;
  2327. if( type.IsAbstractClass() )
  2328. str.Format(TXT_ABSTRACT_CLASS_s_CANNOT_BE_INSTANTIATED, type.Format(outFunc->nameSpace).AddressOf());
  2329. else if( type.IsInterface() )
  2330. str.Format(TXT_INTERFACE_s_CANNOT_BE_INSTANTIATED, type.Format(outFunc->nameSpace).AddressOf());
  2331. else
  2332. // TODO: Improve error message to explain why
  2333. str.Format(TXT_DATA_TYPE_CANT_BE_s, type.Format(outFunc->nameSpace).AddressOf());
  2334. Error(str, node);
  2335. // Don't continue, as it will most likely lead to further
  2336. // errors that may just mislead the script writer
  2337. return;
  2338. }
  2339. // A shared object may not declare variables of non-shared types
  2340. if( outFunc->IsShared() )
  2341. {
  2342. asCTypeInfo *ot = type.GetTypeInfo();
  2343. if( ot && !ot->IsShared() )
  2344. {
  2345. asCString msg;
  2346. msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, ot->name.AddressOf());
  2347. Error(msg, decl);
  2348. }
  2349. }
  2350. // Get the name of the identifier
  2351. asCString name(&script->code[node->tokenPos], node->tokenLength);
  2352. // Verify that the name isn't used by a dynamic data type
  2353. // TODO: Must check against registered funcdefs too
  2354. if( engine->GetRegisteredType(name.AddressOf(), outFunc->nameSpace) != 0 )
  2355. {
  2356. asCString str;
  2357. str.Format(TXT_ILLEGAL_VARIABLE_NAME_s, name.AddressOf());
  2358. Error(str, node);
  2359. }
  2360. int offset = AllocateVariable(type, false);
  2361. if( variables->DeclareVariable(name.AddressOf(), type, offset, IsVariableOnHeap(offset)) < 0 )
  2362. {
  2363. // TODO: It might be an out-of-memory too
  2364. asCString str;
  2365. str.Format(TXT_s_ALREADY_DECLARED, name.AddressOf());
  2366. Error(str, node);
  2367. // Don't continue after this error, as it will just
  2368. // lead to more errors that are likely false
  2369. return;
  2370. }
  2371. else
  2372. {
  2373. // Warn if this variable hides another variable in a higher scope
  2374. if( variables->parent && variables->parent->GetVariable(name.AddressOf()) )
  2375. {
  2376. asCString str;
  2377. str.Format(TXT_s_HIDES_VAR_IN_OUTER_SCOPE, name.AddressOf());
  2378. Warning(str, node);
  2379. }
  2380. }
  2381. // Add marker that the variable has been declared
  2382. bc->VarDecl((int)outFunc->scriptData->variables.GetLength());
  2383. outFunc->AddVariable(name, type, offset);
  2384. // Keep the node for the variable decl
  2385. asCScriptNode *varNode = node;
  2386. node = node->next;
  2387. if( node == 0 || node->nodeType == snIdentifier )
  2388. {
  2389. // Initialize with default constructor
  2390. CompileInitialization(0, bc, type, varNode, offset, 0, 0);
  2391. }
  2392. else
  2393. {
  2394. // Compile the initialization expression
  2395. asQWORD constantValue = 0;
  2396. if( CompileInitialization(node, bc, type, varNode, offset, &constantValue, 0, preCompiled ? &compiledCtx : 0) )
  2397. {
  2398. // Check if the variable should be marked as pure constant
  2399. if( type.IsPrimitive() && type.IsReadOnly() )
  2400. {
  2401. sVariable *v = variables->GetVariable(name.AddressOf());
  2402. v->isPureConstant = true;
  2403. v->constantValue = constantValue;
  2404. }
  2405. }
  2406. node = node->next;
  2407. }
  2408. }
  2409. bc->OptimizeLocally(tempVariableOffsets);
  2410. }
  2411. // Returns true if the initialization expression is a constant expression
  2412. bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, const asCDataType &type, asCScriptNode *errNode, int offset, asQWORD *constantValue, int isVarGlobOrMem, asCExprContext *preCompiled)
  2413. {
  2414. bool isConstantExpression = false;
  2415. if( node && node->nodeType == snArgList )
  2416. {
  2417. // Make sure it is an object and not a handle
  2418. if( type.GetTypeInfo() == 0 || type.IsObjectHandle() )
  2419. {
  2420. Error(TXT_MUST_BE_OBJECT, node);
  2421. }
  2422. else
  2423. {
  2424. // Compile the arguments
  2425. asCArray<asCExprContext *> args;
  2426. asCArray<asSNamedArgument> namedArgs;
  2427. if( CompileArgumentList(node, args, namedArgs) >= 0 )
  2428. {
  2429. // Find all constructors
  2430. asCArray<int> funcs;
  2431. asSTypeBehaviour *beh = type.GetBehaviour();
  2432. if( beh )
  2433. {
  2434. if( type.GetTypeInfo()->flags & asOBJ_REF )
  2435. funcs = beh->factories;
  2436. else
  2437. funcs = beh->constructors;
  2438. }
  2439. asCString str = type.Format(outFunc->nameSpace);
  2440. MatchFunctions(funcs, args, node, str.AddressOf(), &namedArgs);
  2441. if( funcs.GetLength() == 1 )
  2442. {
  2443. // Add the default values for arguments not explicitly supplied
  2444. int r = CompileDefaultAndNamedArgs(node, args, funcs[0], CastToObjectType(type.GetTypeInfo()), &namedArgs);
  2445. if( r == asSUCCESS )
  2446. {
  2447. asCExprContext ctx(engine);
  2448. if( type.GetTypeInfo() && (type.GetTypeInfo()->flags & asOBJ_REF) )
  2449. {
  2450. if( isVarGlobOrMem == 0 )
  2451. MakeFunctionCall(&ctx, funcs[0], 0, args, node, true, offset);
  2452. else
  2453. {
  2454. MakeFunctionCall(&ctx, funcs[0], 0, args, node);
  2455. ctx.bc.Instr(asBC_RDSPtr);
  2456. if( isVarGlobOrMem == 1 )
  2457. {
  2458. // Store the returned handle in the global variable
  2459. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  2460. }
  2461. else
  2462. {
  2463. // Store the returned handle in the member
  2464. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2465. ctx.bc.Instr(asBC_RDSPtr);
  2466. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2467. }
  2468. if( type.IsFuncdef())
  2469. ctx.bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  2470. else
  2471. ctx.bc.InstrPTR(asBC_REFCPY, type.GetTypeInfo());
  2472. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  2473. }
  2474. // Pop the reference left by the function call
  2475. ctx.bc.Instr(asBC_PopPtr);
  2476. }
  2477. else
  2478. {
  2479. bool onHeap = false;
  2480. if( isVarGlobOrMem == 0 )
  2481. {
  2482. // When the object is allocated on the heap, the address where the
  2483. // reference will be stored must be pushed on the stack before the
  2484. // arguments. This reference on the stack is safe, even if the script
  2485. // is suspended during the evaluation of the arguments.
  2486. onHeap = IsVariableOnHeap(offset);
  2487. if( onHeap )
  2488. ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
  2489. }
  2490. else if( isVarGlobOrMem == 1 )
  2491. {
  2492. // Push the address of the location where the variable will be stored on the stack.
  2493. // This reference is safe, because the addresses of the global variables cannot change.
  2494. onHeap = true;
  2495. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  2496. }
  2497. else
  2498. {
  2499. // Value types may be allocated inline if they are POD types
  2500. onHeap = !(type.IsObject() || type.IsFuncdef()) || type.IsReference() || (type.GetTypeInfo()->flags & asOBJ_REF);
  2501. if( onHeap )
  2502. {
  2503. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2504. ctx.bc.Instr(asBC_RDSPtr);
  2505. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2506. }
  2507. }
  2508. PrepareFunctionCall(funcs[0], &ctx.bc, args);
  2509. MoveArgsToStack(funcs[0], &ctx.bc, args, false);
  2510. // When the object is allocated on the stack, the address to the
  2511. // object is pushed on the stack after the arguments as the object pointer
  2512. if( !onHeap )
  2513. {
  2514. if( isVarGlobOrMem == 2 )
  2515. {
  2516. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2517. ctx.bc.Instr(asBC_RDSPtr);
  2518. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2519. }
  2520. else
  2521. {
  2522. ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
  2523. }
  2524. }
  2525. PerformFunctionCall(funcs[0], &ctx, onHeap, &args, CastToObjectType(type.GetTypeInfo()));
  2526. if( isVarGlobOrMem == 0 )
  2527. {
  2528. // Mark the object in the local variable as initialized
  2529. ctx.bc.ObjInfo(offset, asOBJ_INIT);
  2530. }
  2531. }
  2532. bc->AddCode(&ctx.bc);
  2533. }
  2534. }
  2535. }
  2536. // Cleanup
  2537. for( asUINT n = 0; n < args.GetLength(); n++ )
  2538. if( args[n] )
  2539. {
  2540. asDELETE(args[n], asCExprContext);
  2541. }
  2542. for( asUINT n = 0; n < namedArgs.GetLength(); n++ )
  2543. if( namedArgs[n].ctx )
  2544. {
  2545. asDELETE(namedArgs[n].ctx, asCExprContext);
  2546. }
  2547. }
  2548. }
  2549. else if( node && node->nodeType == snInitList )
  2550. {
  2551. asCExprValue ti;
  2552. ti.Set(type);
  2553. ti.isVariable = (isVarGlobOrMem == 0);
  2554. ti.isTemporary = false;
  2555. ti.stackOffset = (short)offset;
  2556. ti.isLValue = true;
  2557. CompileInitList(&ti, node, bc, isVarGlobOrMem);
  2558. }
  2559. else if( node && node->nodeType == snAssignment )
  2560. {
  2561. // Compile the expression
  2562. asCExprContext newExpr(engine);
  2563. asCExprContext* expr;
  2564. int r = 0;
  2565. if( preCompiled )
  2566. {
  2567. expr = preCompiled;
  2568. }
  2569. else
  2570. {
  2571. expr = &newExpr;
  2572. r = CompileAssignment(node, expr);
  2573. }
  2574. // handles initialized with null doesn't need any bytecode
  2575. // since handles will be initialized to null by default anyway
  2576. if (type.IsObjectHandle() && expr->type.IsNullConstant() && expr->bc.IsSimpleExpression() )
  2577. return false;
  2578. // Look for appropriate constructor
  2579. asCArray<int> funcs;
  2580. asCArray<asCExprContext *> args;
  2581. // Handles must use the handle assignment operation.
  2582. // Types that are ASHANDLE must not allow the use of the constructor in this case,
  2583. // because it is ambiguous whether a value assignment or handle assignment will be done.
  2584. // Only do this if the expression is of the same type, as the expression is an assignment
  2585. // and an initialization constructor may not have the same meaning.
  2586. // TODO: Should allow initialization constructor if it is declared as allowed for implicit conversions.
  2587. if( !type.IsObjectHandle() && !expr->type.isExplicitHandle &&
  2588. !(type.GetTypeInfo() && (type.GetTypeInfo()->GetFlags() & asOBJ_ASHANDLE)) &&
  2589. type.IsEqualExceptRefAndConst(expr->type.dataType) )
  2590. {
  2591. asSTypeBehaviour *beh = type.GetBehaviour();
  2592. if( beh )
  2593. {
  2594. if( type.GetTypeInfo()->flags & asOBJ_REF )
  2595. funcs = beh->factories;
  2596. else
  2597. funcs = beh->constructors;
  2598. }
  2599. asCString str = type.Format(outFunc->nameSpace);
  2600. args.PushLast(expr);
  2601. MatchFunctions(funcs, args, node, str.AddressOf(), 0, 0, 0, true);
  2602. // Make sure the argument is of the right type (and not just compatible with the expression)
  2603. if (funcs.GetLength() == 1)
  2604. {
  2605. asCScriptFunction *f = engine->scriptFunctions[funcs[0]];
  2606. if (!f->parameterTypes[0].IsEqualExceptRefAndConst(expr->type.dataType))
  2607. funcs.PopLast();
  2608. }
  2609. }
  2610. if( funcs.GetLength() == 1 )
  2611. {
  2612. // Use the constructor
  2613. // TODO: clean-up: A large part of this is identical to the initalization with argList above
  2614. // Add the default values for arguments not explicitly supplied
  2615. r = CompileDefaultAndNamedArgs(node, args, funcs[0], CastToObjectType(type.GetTypeInfo()));
  2616. if( r == asSUCCESS )
  2617. {
  2618. asCExprContext ctx(engine);
  2619. if( type.GetTypeInfo() && (type.GetTypeInfo()->flags & asOBJ_REF) )
  2620. {
  2621. if( isVarGlobOrMem == 0 )
  2622. MakeFunctionCall(&ctx, funcs[0], 0, args, node, true, offset);
  2623. else
  2624. {
  2625. MakeFunctionCall(&ctx, funcs[0], 0, args, node);
  2626. ctx.bc.Instr(asBC_RDSPtr);
  2627. if( isVarGlobOrMem == 1 )
  2628. {
  2629. // Store the returned handle in the global variable
  2630. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  2631. }
  2632. else
  2633. {
  2634. // Store the returned handle in the member
  2635. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2636. ctx.bc.Instr(asBC_RDSPtr);
  2637. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2638. }
  2639. if( type.IsFuncdef() )
  2640. ctx.bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  2641. else
  2642. ctx.bc.InstrPTR(asBC_REFCPY, type.GetTypeInfo());
  2643. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  2644. }
  2645. // Pop the reference left by the function call
  2646. ctx.bc.Instr(asBC_PopPtr);
  2647. }
  2648. else
  2649. {
  2650. bool onHeap = false;
  2651. if( isVarGlobOrMem == 0 )
  2652. {
  2653. // When the object is allocated on the heap, the address where the
  2654. // reference will be stored must be pushed on the stack before the
  2655. // arguments. This reference on the stack is safe, even if the script
  2656. // is suspended during the evaluation of the arguments.
  2657. onHeap = IsVariableOnHeap(offset);
  2658. if( onHeap )
  2659. ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
  2660. }
  2661. else if( isVarGlobOrMem == 1 )
  2662. {
  2663. // Push the address of the location where the variable will be stored on the stack.
  2664. // This reference is safe, because the addresses of the global variables cannot change.
  2665. onHeap = true;
  2666. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  2667. }
  2668. else
  2669. {
  2670. // Value types may be allocated inline if they are POD types
  2671. onHeap = !(type.IsObject() || type.IsFuncdef()) || type.IsReference() || (type.GetTypeInfo()->flags & asOBJ_REF);
  2672. if( onHeap )
  2673. {
  2674. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2675. ctx.bc.Instr(asBC_RDSPtr);
  2676. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2677. }
  2678. }
  2679. PrepareFunctionCall(funcs[0], &ctx.bc, args);
  2680. MoveArgsToStack(funcs[0], &ctx.bc, args, false);
  2681. // When the object is allocated on the stack, the address to the
  2682. // object is pushed on the stack after the arguments as the object pointer
  2683. if( !onHeap )
  2684. {
  2685. if( isVarGlobOrMem == 2 )
  2686. {
  2687. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2688. ctx.bc.Instr(asBC_RDSPtr);
  2689. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2690. }
  2691. else
  2692. {
  2693. ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
  2694. }
  2695. }
  2696. PerformFunctionCall(funcs[0], &ctx, onHeap, &args, CastToObjectType(type.GetTypeInfo()));
  2697. if( isVarGlobOrMem == 0 )
  2698. {
  2699. // Mark the object in the local variable as initialized
  2700. ctx.bc.ObjInfo(offset, asOBJ_INIT);
  2701. }
  2702. }
  2703. bc->AddCode(&ctx.bc);
  2704. }
  2705. }
  2706. else
  2707. {
  2708. // Call the default constructor, then call the assignment operator
  2709. asCExprContext ctx(engine);
  2710. // Call the default constructor here
  2711. if( isVarGlobOrMem == 0 )
  2712. CallDefaultConstructor(type, offset, IsVariableOnHeap(offset), &ctx.bc, errNode);
  2713. else if( isVarGlobOrMem == 1 )
  2714. CallDefaultConstructor(type, offset, true, &ctx.bc, errNode, isVarGlobOrMem);
  2715. else if( isVarGlobOrMem == 2 )
  2716. CallDefaultConstructor(type, offset, type.IsReference(), &ctx.bc, errNode, isVarGlobOrMem);
  2717. if( r >= 0 )
  2718. {
  2719. if( type.IsPrimitive() )
  2720. {
  2721. if( type.IsReadOnly() && expr->type.isConstant )
  2722. {
  2723. ImplicitConversion(expr, type, node, asIC_IMPLICIT_CONV);
  2724. // Tell caller that the expression is a constant so it can mark the variable as pure constant
  2725. isConstantExpression = true;
  2726. *constantValue = expr->type.GetConstantData();
  2727. }
  2728. asCExprContext lctx(engine);
  2729. if( isVarGlobOrMem == 0 )
  2730. lctx.type.SetVariable(type, offset, false);
  2731. else if( isVarGlobOrMem == 1 )
  2732. {
  2733. lctx.type.Set(type);
  2734. lctx.type.dataType.MakeReference(true);
  2735. // If it is an enum value, i.e. offset is negative, that is being compiled then
  2736. // we skip this as the bytecode won't be used anyway, only the constant value
  2737. if( offset >= 0 )
  2738. lctx.bc.InstrPTR(asBC_LDG, engine->globalProperties[offset]->GetAddressOfValue());
  2739. }
  2740. else
  2741. {
  2742. asASSERT( isVarGlobOrMem == 2 );
  2743. lctx.type.Set(type);
  2744. lctx.type.dataType.MakeReference(true);
  2745. // Load the reference of the primitive member into the register
  2746. lctx.bc.InstrSHORT(asBC_PSF, 0);
  2747. lctx.bc.Instr(asBC_RDSPtr);
  2748. lctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2749. lctx.bc.Instr(asBC_PopRPtr);
  2750. }
  2751. lctx.type.dataType.MakeReadOnly(false);
  2752. lctx.type.isLValue = true;
  2753. DoAssignment(&ctx, &lctx, expr, node, node, ttAssignment, node);
  2754. ProcessDeferredParams(&ctx);
  2755. }
  2756. else
  2757. {
  2758. // TODO: runtime optimize: Here we should look for the best matching constructor, instead of
  2759. // just the copy constructor. Only if no appropriate constructor is
  2760. // available should the assignment operator be used.
  2761. asCExprContext lexpr(engine);
  2762. lexpr.type.Set(type);
  2763. if( isVarGlobOrMem == 0 )
  2764. lexpr.type.dataType.MakeReference(IsVariableOnHeap(offset));
  2765. else if( isVarGlobOrMem == 1 )
  2766. lexpr.type.dataType.MakeReference(true);
  2767. else if( isVarGlobOrMem == 2 )
  2768. {
  2769. if( !lexpr.type.dataType.IsObject() || lexpr.type.dataType.IsFuncdef() || (lexpr.type.dataType.GetTypeInfo()->flags & asOBJ_REF) )
  2770. lexpr.type.dataType.MakeReference(true);
  2771. }
  2772. // Allow initialization of constant variables
  2773. lexpr.type.dataType.MakeReadOnly(false);
  2774. if( type.IsObjectHandle() )
  2775. lexpr.type.isExplicitHandle = true;
  2776. if( isVarGlobOrMem == 0 )
  2777. {
  2778. lexpr.bc.InstrSHORT(asBC_PSF, (short)offset);
  2779. lexpr.type.stackOffset = (short)offset;
  2780. lexpr.type.isVariable = true;
  2781. }
  2782. else if( isVarGlobOrMem == 1 )
  2783. {
  2784. lexpr.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  2785. }
  2786. else
  2787. {
  2788. lexpr.bc.InstrSHORT(asBC_PSF, 0);
  2789. lexpr.bc.Instr(asBC_RDSPtr);
  2790. lexpr.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2791. lexpr.type.stackOffset = -1;
  2792. }
  2793. lexpr.type.isLValue = true;
  2794. // If left expression resolves into a registered type
  2795. // check if the assignment operator is overloaded, and check
  2796. // the type of the right hand expression. If none is found
  2797. // the default action is a direct copy if it is the same type
  2798. // and a simple assignment.
  2799. bool assigned = false;
  2800. // Even though an ASHANDLE can be an explicit handle the overloaded operator needs to be called
  2801. if( (lexpr.type.dataType.IsObject() || lexpr.type.dataType.IsFuncdef()) && (!lexpr.type.isExplicitHandle || (lexpr.type.dataType.GetTypeInfo() && (lexpr.type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE))) )
  2802. {
  2803. bool useHndlAssign = false;
  2804. if (lexpr.type.dataType.IsHandleToAsHandleType())
  2805. {
  2806. useHndlAssign = true;
  2807. // Make sure the right hand expression is treated as a handle
  2808. if (!expr->type.isExplicitHandle && !expr->type.IsNullConstant() )
  2809. {
  2810. // TODO: Clean-up: This code is from CompileExpressionPreOp. Create a reusable function
  2811. // Convert the expression to a handle
  2812. if (!expr->type.dataType.IsObjectHandle() && expr->type.dataType.GetTypeInfo() && !(expr->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE))
  2813. {
  2814. asCDataType to = expr->type.dataType;
  2815. to.MakeHandle(true);
  2816. to.MakeReference(true);
  2817. to.MakeHandleToConst(expr->type.dataType.IsReadOnly());
  2818. ImplicitConversion(expr, to, node, asIC_IMPLICIT_CONV, true, false);
  2819. asASSERT(expr->type.dataType.IsObjectHandle());
  2820. }
  2821. else if (expr->type.dataType.GetTypeInfo() && expr->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE)
  2822. {
  2823. // For the ASHANDLE type we'll simply set the expression as a handle
  2824. expr->type.dataType.MakeHandle(true);
  2825. }
  2826. if( !expr->type.dataType.IsObjectHandle() && !expr->type.dataType.SupportHandles())
  2827. {
  2828. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node);
  2829. }
  2830. expr->type.isExplicitHandle = true;
  2831. }
  2832. }
  2833. assigned = CompileOverloadedDualOperator(node, &lexpr, expr, false, &ctx, useHndlAssign);
  2834. if( assigned )
  2835. {
  2836. // Pop the resulting value
  2837. if( !ctx.type.dataType.IsPrimitive() )
  2838. ctx.bc.Instr(asBC_PopPtr);
  2839. // Release the argument
  2840. ProcessDeferredParams(&ctx);
  2841. // Release temporary variable that may be allocated by the overloaded operator
  2842. ReleaseTemporaryVariable(ctx.type, &ctx.bc);
  2843. }
  2844. }
  2845. if( !assigned )
  2846. {
  2847. PrepareForAssignment(&lexpr.type.dataType, expr, node, false);
  2848. // If the expression is constant and the variable also is constant
  2849. // then mark the variable as pure constant. This will allow the compiler
  2850. // to optimize expressions with this variable.
  2851. if( type.IsReadOnly() && expr->type.isConstant )
  2852. {
  2853. isConstantExpression = true;
  2854. *constantValue = expr->type.GetConstantQW();
  2855. }
  2856. // Add expression code to bytecode
  2857. MergeExprBytecode(&ctx, expr);
  2858. // Add byte code for storing value of expression in variable
  2859. ctx.bc.AddCode(&lexpr.bc);
  2860. PerformAssignment(&lexpr.type, &expr->type, &ctx.bc, errNode);
  2861. // Release temporary variables used by expression
  2862. ReleaseTemporaryVariable(expr->type, &ctx.bc);
  2863. ctx.bc.Instr(asBC_PopPtr);
  2864. ProcessDeferredParams(&ctx);
  2865. }
  2866. }
  2867. }
  2868. bc->AddCode(&ctx.bc);
  2869. }
  2870. }
  2871. else
  2872. {
  2873. asASSERT( node == 0 );
  2874. // Call the default constructor here, as no explicit initialization is done
  2875. if( isVarGlobOrMem == 0 )
  2876. CallDefaultConstructor(type, offset, IsVariableOnHeap(offset), bc, errNode);
  2877. else if( isVarGlobOrMem == 1 )
  2878. CallDefaultConstructor(type, offset, true, bc, errNode, isVarGlobOrMem);
  2879. else if( isVarGlobOrMem == 2 )
  2880. {
  2881. if( !(type.IsObject() || type.IsFuncdef()) || type.IsReference() || (type.GetTypeInfo()->flags & asOBJ_REF) )
  2882. CallDefaultConstructor(type, offset, true, bc, errNode, isVarGlobOrMem);
  2883. else
  2884. CallDefaultConstructor(type, offset, false, bc, errNode, isVarGlobOrMem);
  2885. }
  2886. }
  2887. return isConstantExpression;
  2888. }
  2889. void asCCompiler::CompileInitList(asCExprValue *var, asCScriptNode *node, asCByteCode *bc, int isVarGlobOrMem)
  2890. {
  2891. // Check if the type supports initialization lists
  2892. if( var->dataType.GetTypeInfo() == 0 ||
  2893. var->dataType.GetBehaviour()->listFactory == 0 )
  2894. {
  2895. asCString str;
  2896. str.Format(TXT_INIT_LIST_CANNOT_BE_USED_WITH_s, var->dataType.Format(outFunc->nameSpace).AddressOf());
  2897. Error(str, node);
  2898. return;
  2899. }
  2900. // Construct the buffer with the elements
  2901. // Find the list factory
  2902. int funcId = var->dataType.GetBehaviour()->listFactory;
  2903. asASSERT( engine->scriptFunctions[funcId]->listPattern );
  2904. // TODO: runtime optimize: A future optimization should be to use the stack space directly
  2905. // for small buffers so that the dynamic allocation is skipped
  2906. // Create a new special object type for the lists. Both asCRestore and the
  2907. // context exception handler will need this to know how to parse the buffer.
  2908. asCObjectType *listPatternType = engine->GetListPatternType(funcId);
  2909. // Allocate a temporary variable to hold the pointer to the buffer
  2910. int bufferVar = AllocateVariable(asCDataType::CreateType(listPatternType, false), true);
  2911. asUINT bufferSize = 0;
  2912. // Evaluate all elements of the list
  2913. asCExprContext valueExpr(engine);
  2914. asCScriptNode *el = node;
  2915. asSListPatternNode *patternNode = engine->scriptFunctions[listPatternType->templateSubTypes[0].GetBehaviour()->listFactory]->listPattern;
  2916. int elementsInSubList = -1;
  2917. int r = CompileInitListElement(patternNode, el, engine->GetTypeIdFromDataType(asCDataType::CreateType(listPatternType, false)), short(bufferVar), bufferSize, valueExpr.bc, elementsInSubList);
  2918. asASSERT( r || patternNode == 0 );
  2919. if (r < 0)
  2920. {
  2921. asCString msg;
  2922. msg.Format(TXT_PREV_ERROR_WHILE_COMP_LIST_FOR_TYPE_s, var->dataType.Format(outFunc->nameSpace).AddressOf());
  2923. Error(msg, node);
  2924. }
  2925. // After all values have been evaluated we know the final size of the buffer
  2926. asCExprContext allocExpr(engine);
  2927. allocExpr.bc.InstrSHORT_DW(asBC_AllocMem, short(bufferVar), bufferSize);
  2928. // Merge the bytecode into the final sequence
  2929. bc->AddCode(&allocExpr.bc);
  2930. bc->AddCode(&valueExpr.bc);
  2931. // The object itself is the last to be created and will receive the pointer to the buffer
  2932. asCArray<asCExprContext *> args;
  2933. asCExprContext arg1(engine);
  2934. arg1.type.Set(asCDataType::CreatePrimitive(ttUInt, false));
  2935. arg1.type.dataType.MakeReference(true);
  2936. arg1.bc.InstrSHORT(asBC_PshVPtr, short(bufferVar));
  2937. args.PushLast(&arg1);
  2938. asCExprContext ctx(engine);
  2939. if( var->isVariable )
  2940. {
  2941. asASSERT( isVarGlobOrMem == 0 );
  2942. if( var->dataType.GetTypeInfo()->GetFlags() & asOBJ_REF )
  2943. {
  2944. ctx.bc.AddCode(&arg1.bc);
  2945. // Call factory and store the handle in the given variable
  2946. PerformFunctionCall(funcId, &ctx, false, &args, 0, true, var->stackOffset);
  2947. ctx.bc.Instr(asBC_PopPtr);
  2948. }
  2949. else
  2950. {
  2951. // Call the constructor
  2952. // When the object is allocated on the heap, the address where the
  2953. // reference will be stored must be pushed on the stack before the
  2954. // arguments. This reference on the stack is safe, even if the script
  2955. // is suspended during the evaluation of the arguments.
  2956. bool onHeap = IsVariableOnHeap(var->stackOffset);
  2957. if( onHeap )
  2958. ctx.bc.InstrSHORT(asBC_PSF, var->stackOffset);
  2959. ctx.bc.AddCode(&arg1.bc);
  2960. // When the object is allocated on the stack, the address to the
  2961. // object is pushed on the stack after the arguments as the object pointer
  2962. if( !onHeap )
  2963. ctx.bc.InstrSHORT(asBC_PSF, var->stackOffset);
  2964. PerformFunctionCall(funcId, &ctx, onHeap, &args, CastToObjectType(var->dataType.GetTypeInfo()));
  2965. // Mark the object in the local variable as initialized
  2966. ctx.bc.ObjInfo(var->stackOffset, asOBJ_INIT);
  2967. }
  2968. }
  2969. else
  2970. {
  2971. if( var->dataType.GetTypeInfo()->GetFlags() & asOBJ_REF )
  2972. {
  2973. ctx.bc.AddCode(&arg1.bc);
  2974. PerformFunctionCall(funcId, &ctx, false, &args);
  2975. ctx.bc.Instr(asBC_RDSPtr);
  2976. if( isVarGlobOrMem == 1 )
  2977. {
  2978. // Store the returned handle in the global variable
  2979. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[var->stackOffset]->GetAddressOfValue());
  2980. }
  2981. else
  2982. {
  2983. // Store the returned handle in the member
  2984. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2985. ctx.bc.Instr(asBC_RDSPtr);
  2986. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)var->stackOffset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2987. }
  2988. if (var->dataType.IsFuncdef())
  2989. ctx.bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  2990. else
  2991. ctx.bc.InstrPTR(asBC_REFCPY, var->dataType.GetTypeInfo());
  2992. ctx.bc.Instr(asBC_PopPtr);
  2993. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  2994. }
  2995. else
  2996. {
  2997. bool onHeap = true;
  2998. // Put the address where the object pointer will be placed on the stack
  2999. if( isVarGlobOrMem == 1 )
  3000. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[var->stackOffset]->GetAddressOfValue());
  3001. else
  3002. {
  3003. onHeap = !(var->dataType.IsObject() || var->dataType.IsFuncdef()) || var->dataType.IsReference() || (var->dataType.GetTypeInfo()->flags & asOBJ_REF);
  3004. if( onHeap )
  3005. {
  3006. ctx.bc.InstrSHORT(asBC_PSF, 0);
  3007. ctx.bc.Instr(asBC_RDSPtr);
  3008. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)var->stackOffset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  3009. }
  3010. }
  3011. // Add the address of the list buffer as the argument
  3012. ctx.bc.AddCode(&arg1.bc);
  3013. if( !onHeap )
  3014. {
  3015. ctx.bc.InstrSHORT(asBC_PSF, 0);
  3016. ctx.bc.Instr(asBC_RDSPtr);
  3017. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)var->stackOffset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  3018. }
  3019. // Call the ALLOC instruction to allocate memory and invoke constructor
  3020. PerformFunctionCall(funcId, &ctx, onHeap, &args, CastToObjectType(var->dataType.GetTypeInfo()));
  3021. }
  3022. }
  3023. bc->AddCode(&ctx.bc);
  3024. // Free the temporary buffer. The FREE instruction will make sure to destroy
  3025. // each element in the buffer so there is no need to do this manually
  3026. bc->InstrW_PTR(asBC_FREE, short(bufferVar), listPatternType);
  3027. ReleaseTemporaryVariable(bufferVar, bc);
  3028. }
  3029. int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScriptNode *&valueNode, int bufferTypeId, short bufferVar, asUINT &bufferSize, asCByteCode &bcInit, int &elementsInSubList)
  3030. {
  3031. if( patternNode->type == asLPT_START )
  3032. {
  3033. if( valueNode == 0 || valueNode->nodeType != snInitList )
  3034. {
  3035. Error(TXT_EXPECTED_LIST, valueNode);
  3036. return -1;
  3037. }
  3038. // Compile all values until asLPT_END
  3039. patternNode = patternNode->next;
  3040. asCScriptNode *node = valueNode->firstChild;
  3041. while( patternNode->type != asLPT_END )
  3042. {
  3043. // Check for missing value here, else the error reporting will not have a source position to report the error for
  3044. if( node == 0 && patternNode->type == asLPT_TYPE )
  3045. {
  3046. Error(TXT_NOT_ENOUGH_VALUES_FOR_LIST, valueNode);
  3047. return -1;
  3048. }
  3049. asCScriptNode *errNode = node;
  3050. int r = CompileInitListElement(patternNode, node, bufferTypeId, bufferVar, bufferSize, bcInit, elementsInSubList);
  3051. if( r < 0 ) return r;
  3052. if( r == 1 )
  3053. {
  3054. asASSERT( engine->ep.disallowEmptyListElements );
  3055. // Empty elements in the middle are not allowed
  3056. Error(TXT_EMPTY_LIST_ELEMENT_IS_NOT_ALLOWED, errNode);
  3057. }
  3058. asASSERT( patternNode );
  3059. }
  3060. if( node )
  3061. {
  3062. Error(TXT_TOO_MANY_VALUES_FOR_LIST, valueNode);
  3063. return -1;
  3064. }
  3065. // Move to the next node
  3066. valueNode = valueNode->next;
  3067. patternNode = patternNode->next;
  3068. }
  3069. else if( patternNode->type == asLPT_REPEAT || patternNode->type == asLPT_REPEAT_SAME )
  3070. {
  3071. // TODO: list: repeat_inner should make sure the list has the same size as the inner list, i.e. square area
  3072. // TODO: list: repeat_prev should make sure the list is the same size as the previous
  3073. asEListPatternNodeType repeatType = patternNode->type;
  3074. asCScriptNode *firstValue = valueNode;
  3075. // The following values will be repeated N times
  3076. patternNode = patternNode->next;
  3077. // Keep track of the patternNode so it can be reset
  3078. asSListPatternNode *nextNode = patternNode;
  3079. // Align the buffer size to 4 bytes in case previous value was smaller than 4 bytes
  3080. if( bufferSize & 0x3 )
  3081. bufferSize += 4 - (bufferSize & 0x3);
  3082. // The first dword will hold the number of elements in the list
  3083. asDWORD currSize = bufferSize;
  3084. bufferSize += 4;
  3085. asUINT countElements = 0;
  3086. int elementsInSubSubList = -1;
  3087. asCExprContext ctx(engine);
  3088. while( valueNode )
  3089. {
  3090. patternNode = nextNode;
  3091. asCScriptNode *errNode = valueNode;
  3092. int r = CompileInitListElement(patternNode, valueNode, bufferTypeId, bufferVar, bufferSize, ctx.bc, elementsInSubSubList);
  3093. if( r < 0 ) return r;
  3094. if( r == 0 )
  3095. countElements++;
  3096. else
  3097. {
  3098. asASSERT( r == 1 && engine->ep.disallowEmptyListElements );
  3099. if( valueNode )
  3100. {
  3101. // Empty elements in the middle are not allowed
  3102. Error(TXT_EMPTY_LIST_ELEMENT_IS_NOT_ALLOWED, errNode);
  3103. }
  3104. }
  3105. }
  3106. if( countElements == 0 )
  3107. {
  3108. // Skip the sub pattern that was expected to be repeated, otherwise the caller will try to match these when we return
  3109. patternNode = nextNode;
  3110. if( patternNode->type == asLPT_TYPE )
  3111. patternNode = patternNode->next;
  3112. else if( patternNode->type == asLPT_START )
  3113. {
  3114. int subCount = 1;
  3115. do
  3116. {
  3117. patternNode = patternNode->next;
  3118. if( patternNode->type == asLPT_START )
  3119. subCount++;
  3120. else if( patternNode->type == asLPT_END )
  3121. subCount--;
  3122. } while( subCount > 0 );
  3123. patternNode = patternNode->next;
  3124. }
  3125. }
  3126. // For repeat_same each repeated sublist must have the same size to form a rectangular array
  3127. if( repeatType == asLPT_REPEAT_SAME && elementsInSubList != -1 && asUINT(elementsInSubList) != countElements )
  3128. {
  3129. if( countElements < asUINT(elementsInSubList) )
  3130. Error(TXT_NOT_ENOUGH_VALUES_FOR_LIST, firstValue);
  3131. else
  3132. Error(TXT_TOO_MANY_VALUES_FOR_LIST, firstValue);
  3133. return -1;
  3134. }
  3135. else
  3136. {
  3137. // Return to caller the amount of elments in this sublist
  3138. elementsInSubList = countElements;
  3139. }
  3140. // The first dword in the buffer will hold the number of elements
  3141. bcInit.InstrSHORT_DW_DW(asBC_SetListSize, bufferVar, currSize, countElements);
  3142. // Add the values
  3143. bcInit.AddCode(&ctx.bc);
  3144. }
  3145. else if( patternNode->type == asLPT_TYPE )
  3146. {
  3147. bool isEmpty = false;
  3148. // Determine the size of the element
  3149. asUINT size = 0;
  3150. asCDataType dt = reinterpret_cast<asSListPatternDataTypeNode*>(patternNode)->dataType;
  3151. if( valueNode->nodeType == snAssignment || valueNode->nodeType == snInitList )
  3152. {
  3153. asCExprContext lctx(engine);
  3154. asCExprContext rctx(engine);
  3155. if( valueNode->nodeType == snAssignment )
  3156. {
  3157. // Compile the assignment expression
  3158. CompileAssignment(valueNode, &rctx);
  3159. if( dt.GetTokenType() == ttQuestion )
  3160. {
  3161. // Make sure the type is not ambiguous
  3162. DetermineSingleFunc(&rctx, valueNode);
  3163. // We now know the type
  3164. dt = rctx.type.dataType;
  3165. dt.MakeReadOnly(false);
  3166. dt.MakeReference(false);
  3167. // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit.
  3168. if( bufferSize & 0x3 )
  3169. bufferSize += 4 - (bufferSize & 0x3);
  3170. // When value assignment for reference types us disabled, make sure all ref types are passed in as handles
  3171. if (engine->ep.disallowValueAssignForRefType && dt.SupportHandles())
  3172. dt.MakeHandle(true);
  3173. // Place the type id in the buffer
  3174. bcInit.InstrSHORT_DW_DW(asBC_SetListType, bufferVar, bufferSize, engine->GetTypeIdFromDataType(dt));
  3175. bufferSize += 4;
  3176. }
  3177. }
  3178. else if( valueNode->nodeType == snInitList )
  3179. {
  3180. if( dt.GetTokenType() == ttQuestion )
  3181. {
  3182. // Can't use init lists with var type as it is not possible to determine what type should be allocated
  3183. asCString str;
  3184. str.Format(TXT_INIT_LIST_CANNOT_BE_USED_WITH_s, "?");
  3185. Error(str.AddressOf(), valueNode);
  3186. rctx.type.SetDummy();
  3187. dt = rctx.type.dataType;
  3188. }
  3189. else
  3190. {
  3191. // Allocate a temporary variable that will be initialized with the list
  3192. int offset = AllocateVariable(dt, true);
  3193. rctx.type.Set(dt);
  3194. rctx.type.isVariable = true;
  3195. rctx.type.isTemporary = true;
  3196. rctx.type.stackOffset = (short)offset;
  3197. CompileInitList(&rctx.type, valueNode, &rctx.bc, 0);
  3198. // Put the object on the stack
  3199. rctx.bc.InstrSHORT(asBC_PSF, rctx.type.stackOffset);
  3200. // It is a reference that we place on the stack
  3201. rctx.type.dataType.MakeReference(true);
  3202. }
  3203. }
  3204. // Determine size of the element
  3205. if( dt.IsPrimitive() || (!dt.IsNullHandle() && (dt.GetTypeInfo()->flags & asOBJ_VALUE)) )
  3206. size = dt.GetSizeInMemoryBytes();
  3207. else
  3208. size = AS_PTR_SIZE*4;
  3209. // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit.
  3210. if( size >= 4 && (bufferSize & 0x3) )
  3211. bufferSize += 4 - (bufferSize & 0x3);
  3212. // Compile the lvalue
  3213. lctx.bc.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize);
  3214. lctx.type.Set(dt);
  3215. lctx.type.isLValue = true;
  3216. if( dt.IsPrimitive() )
  3217. {
  3218. lctx.bc.Instr(asBC_PopRPtr);
  3219. lctx.type.dataType.MakeReference(true);
  3220. }
  3221. else if( dt.IsObjectHandle() ||
  3222. dt.GetTypeInfo()->flags & asOBJ_REF )
  3223. {
  3224. lctx.type.isExplicitHandle = true;
  3225. lctx.type.dataType.MakeReference(true);
  3226. }
  3227. else
  3228. {
  3229. asASSERT( dt.GetTypeInfo()->flags & asOBJ_VALUE );
  3230. // Make sure the object has been constructed before the assignment
  3231. // TODO: runtime optimize: Use copy constructor instead of assignment to initialize the objects
  3232. asSTypeBehaviour *beh = dt.GetBehaviour();
  3233. int func = 0;
  3234. if( beh ) func = beh->construct;
  3235. if( func == 0 && (dt.GetTypeInfo()->flags & asOBJ_POD) == 0 )
  3236. {
  3237. asCString str;
  3238. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetTypeInfo()->GetName());
  3239. Error(str, valueNode);
  3240. }
  3241. else if( func )
  3242. {
  3243. // Call the constructor as a normal function
  3244. bcInit.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize);
  3245. asCExprContext ctx(engine);
  3246. PerformFunctionCall(func, &ctx, false, 0, CastToObjectType(dt.GetTypeInfo()));
  3247. bcInit.AddCode(&ctx.bc);
  3248. }
  3249. }
  3250. if( lctx.type.dataType.IsNullHandle() )
  3251. {
  3252. // Don't add any code to assign a null handle. RefCpy doesn't work without a known type.
  3253. // The buffer is already initialized to zero in asBC_AllocMem anyway.
  3254. asASSERT( rctx.bc.GetLastInstr() == asBC_PshNull );
  3255. asASSERT( reinterpret_cast<asSListPatternDataTypeNode*>(patternNode)->dataType.GetTokenType() == ttQuestion );
  3256. }
  3257. else
  3258. {
  3259. asCExprContext ctx(engine);
  3260. DoAssignment(&ctx, &lctx, &rctx, valueNode, valueNode, ttAssignment, valueNode);
  3261. if( !ctx.type.dataType.IsPrimitive() )
  3262. ctx.bc.Instr(asBC_PopPtr);
  3263. // Release temporary variables used by expression
  3264. ReleaseTemporaryVariable(ctx.type, &ctx.bc);
  3265. ProcessDeferredParams(&ctx);
  3266. bcInit.AddCode(&ctx.bc);
  3267. }
  3268. }
  3269. else
  3270. {
  3271. if( builder->engine->ep.disallowEmptyListElements )
  3272. {
  3273. // Empty elements are not allowed, except if it is the last in the list
  3274. isEmpty = true;
  3275. }
  3276. else
  3277. {
  3278. // There is no specific value so we need to fill it with a default value
  3279. if( dt.GetTokenType() == ttQuestion )
  3280. {
  3281. // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit.
  3282. if( bufferSize & 0x3 )
  3283. bufferSize += 4 - (bufferSize & 0x3);
  3284. // Place the type id for a null handle in the buffer
  3285. bcInit.InstrSHORT_DW_DW(asBC_SetListType, bufferVar, bufferSize, 0);
  3286. bufferSize += 4;
  3287. dt = asCDataType::CreateNullHandle();
  3288. // No need to initialize the handle as the buffer is already initialized with zeroes
  3289. }
  3290. else if( dt.GetTypeInfo() && dt.GetTypeInfo()->flags & asOBJ_VALUE )
  3291. {
  3292. // For value types with default constructor we need to call the constructor
  3293. asSTypeBehaviour *beh = dt.GetBehaviour();
  3294. int func = 0;
  3295. if( beh ) func = beh->construct;
  3296. if( func == 0 && (dt.GetTypeInfo()->flags & asOBJ_POD) == 0 )
  3297. {
  3298. asCString str;
  3299. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetTypeInfo()->GetName());
  3300. Error(str, valueNode);
  3301. }
  3302. else if( func )
  3303. {
  3304. // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit.
  3305. if( bufferSize & 0x3 )
  3306. bufferSize += 4 - (bufferSize & 0x3);
  3307. // Call the constructor as a normal function
  3308. bcInit.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize);
  3309. asCExprContext ctx(engine);
  3310. PerformFunctionCall(func, &ctx, false, 0, CastToObjectType(dt.GetTypeInfo()));
  3311. bcInit.AddCode(&ctx.bc);
  3312. }
  3313. }
  3314. else if( !dt.IsObjectHandle() && dt.GetTypeInfo() && dt.GetTypeInfo()->flags & asOBJ_REF )
  3315. {
  3316. // For ref types (not handles) we need to call the default factory
  3317. asSTypeBehaviour *beh = dt.GetBehaviour();
  3318. int func = 0;
  3319. if( beh ) func = beh->factory;
  3320. if( func == 0 )
  3321. {
  3322. asCString str;
  3323. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetTypeInfo()->GetName());
  3324. Error(str, valueNode);
  3325. }
  3326. else if( func )
  3327. {
  3328. asCExprContext rctx(engine);
  3329. PerformFunctionCall(func, &rctx, false, 0, CastToObjectType(dt.GetTypeInfo()));
  3330. // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit.
  3331. if( bufferSize & 0x3 )
  3332. bufferSize += 4 - (bufferSize & 0x3);
  3333. asCExprContext lctx(engine);
  3334. lctx.bc.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize);
  3335. lctx.type.Set(dt);
  3336. lctx.type.isLValue = true;
  3337. lctx.type.isExplicitHandle = true;
  3338. lctx.type.dataType.MakeReference(true);
  3339. asCExprContext ctx(engine);
  3340. DoAssignment(&ctx, &lctx, &rctx, valueNode, valueNode, ttAssignment, valueNode);
  3341. if( !ctx.type.dataType.IsPrimitive() )
  3342. ctx.bc.Instr(asBC_PopPtr);
  3343. // Release temporary variables used by expression
  3344. ReleaseTemporaryVariable(ctx.type, &ctx.bc);
  3345. ProcessDeferredParams(&ctx);
  3346. bcInit.AddCode(&ctx.bc);
  3347. }
  3348. }
  3349. }
  3350. }
  3351. if( !isEmpty )
  3352. {
  3353. // Determine size of the element
  3354. if( dt.IsPrimitive() || (!dt.IsNullHandle() && (dt.GetTypeInfo()->flags & asOBJ_VALUE)) )
  3355. size = dt.GetSizeInMemoryBytes();
  3356. else
  3357. size = AS_PTR_SIZE*4;
  3358. asASSERT( size <= 4 || (size & 0x3) == 0 );
  3359. bufferSize += size;
  3360. }
  3361. // Move to the next element
  3362. patternNode = patternNode->next;
  3363. valueNode = valueNode->next;
  3364. if( isEmpty )
  3365. {
  3366. // The caller will determine if the empty element should be ignored or not
  3367. return 1;
  3368. }
  3369. }
  3370. else
  3371. asASSERT( false );
  3372. return 0;
  3373. }
  3374. void asCCompiler::CompileStatement(asCScriptNode *statement, bool *hasReturn, asCByteCode *bc)
  3375. {
  3376. // Don't clear the hasReturn flag if this is an empty statement
  3377. // to avoid false errors of 'not all paths return'
  3378. if( statement->nodeType != snExpressionStatement || statement->firstChild )
  3379. *hasReturn = false;
  3380. if (statement->nodeType == snStatementBlock)
  3381. CompileStatementBlock(statement, true, hasReturn, bc);
  3382. else if (statement->nodeType == snIf)
  3383. CompileIfStatement(statement, hasReturn, bc);
  3384. else if (statement->nodeType == snFor)
  3385. CompileForStatement(statement, bc);
  3386. else if (statement->nodeType == snWhile)
  3387. CompileWhileStatement(statement, bc);
  3388. else if (statement->nodeType == snDoWhile)
  3389. CompileDoWhileStatement(statement, bc);
  3390. else if (statement->nodeType == snExpressionStatement)
  3391. CompileExpressionStatement(statement, bc);
  3392. else if (statement->nodeType == snBreak)
  3393. CompileBreakStatement(statement, bc);
  3394. else if (statement->nodeType == snContinue)
  3395. CompileContinueStatement(statement, bc);
  3396. else if (statement->nodeType == snSwitch)
  3397. CompileSwitchStatement(statement, hasReturn, bc);
  3398. else if (statement->nodeType == snTryCatch)
  3399. CompileTryCatch(statement, hasReturn, bc);
  3400. else if (statement->nodeType == snReturn)
  3401. {
  3402. CompileReturnStatement(statement, bc);
  3403. *hasReturn = true;
  3404. }
  3405. else
  3406. asASSERT(false);
  3407. }
  3408. void asCCompiler::CompileSwitchStatement(asCScriptNode *snode, bool *, asCByteCode *bc)
  3409. {
  3410. // TODO: inheritance: Must guarantee that all options in the switch case call a constructor, or that none call it.
  3411. // Reserve label for break statements
  3412. int breakLabel = nextLabel++;
  3413. breakLabels.PushLast(breakLabel);
  3414. // Add a variable scope that will be used by CompileBreak
  3415. // to know where to stop deallocating variables
  3416. AddVariableScope(true, false);
  3417. //---------------------------
  3418. // Compile the switch expression
  3419. //-------------------------------
  3420. // Compile the switch expression
  3421. asCExprContext expr(engine);
  3422. CompileAssignment(snode->firstChild, &expr);
  3423. // Verify that the expression is a primitive type
  3424. if( !expr.type.dataType.IsIntegerType() && !expr.type.dataType.IsUnsignedType() )
  3425. {
  3426. Error(TXT_SWITCH_MUST_BE_INTEGRAL, snode->firstChild);
  3427. return;
  3428. }
  3429. if( ProcessPropertyGetAccessor(&expr, snode) < 0 )
  3430. return;
  3431. // TODO: Need to support 64bit integers
  3432. // Convert the expression to a 32bit variable
  3433. asCDataType to;
  3434. if( expr.type.dataType.IsIntegerType() )
  3435. to.SetTokenType(ttInt);
  3436. else if( expr.type.dataType.IsUnsignedType() )
  3437. to.SetTokenType(ttUInt);
  3438. // Make sure the value is in a variable
  3439. if( expr.type.dataType.IsReference() )
  3440. ConvertToVariable(&expr);
  3441. ImplicitConversion(&expr, to, snode->firstChild, asIC_IMPLICIT_CONV, true);
  3442. ConvertToVariable(&expr);
  3443. int offset = expr.type.stackOffset;
  3444. ProcessDeferredParams(&expr);
  3445. //-------------------------------
  3446. // Determine case values and labels
  3447. //--------------------------------
  3448. // Remember the first label so that we can later pass the
  3449. // correct label to each CompileCase()
  3450. int firstCaseLabel = nextLabel;
  3451. int defaultLabel = 0;
  3452. asCArray<int> caseValues;
  3453. asCArray<int> caseLabels;
  3454. // Compile all case comparisons and make them jump to the right label
  3455. asCScriptNode *cnode = snode->firstChild->next;
  3456. while( cnode )
  3457. {
  3458. // Each case should have a constant expression
  3459. if( cnode->firstChild && cnode->firstChild->nodeType == snExpression )
  3460. {
  3461. // Compile expression
  3462. asCExprContext c(engine);
  3463. CompileExpression(cnode->firstChild, &c);
  3464. // Verify that the result is a constant
  3465. if( !c.type.isConstant )
  3466. Error(TXT_SWITCH_CASE_MUST_BE_CONSTANT, cnode->firstChild);
  3467. // Verify that the result is an integral number
  3468. if (!c.type.dataType.IsIntegerType() && !c.type.dataType.IsUnsignedType())
  3469. Error(TXT_SWITCH_MUST_BE_INTEGRAL, cnode->firstChild);
  3470. else
  3471. {
  3472. ImplicitConversion(&c, to, cnode->firstChild, asIC_IMPLICIT_CONV, true);
  3473. // Has this case been declared already?
  3474. if (caseValues.IndexOf(c.type.GetConstantDW()) >= 0)
  3475. Error(TXT_DUPLICATE_SWITCH_CASE, cnode->firstChild);
  3476. // TODO: Optimize: We can insert the numbers sorted already
  3477. // Store constant for later use
  3478. caseValues.PushLast(c.type.GetConstantDW());
  3479. // Reserve label for this case
  3480. caseLabels.PushLast(nextLabel++);
  3481. }
  3482. }
  3483. else
  3484. {
  3485. // TODO: It shouldn't be necessary for the default case to be the last one.
  3486. // Is default the last case?
  3487. if( cnode->next )
  3488. {
  3489. Error(TXT_DEFAULT_MUST_BE_LAST, cnode);
  3490. break;
  3491. }
  3492. // Reserve label for this case
  3493. defaultLabel = nextLabel++;
  3494. }
  3495. cnode = cnode->next;
  3496. }
  3497. // check for empty switch
  3498. if (caseValues.GetLength() == 0)
  3499. {
  3500. Error(TXT_EMPTY_SWITCH, snode);
  3501. return;
  3502. }
  3503. if( defaultLabel == 0 )
  3504. defaultLabel = breakLabel;
  3505. //---------------------------------
  3506. // Output the optimized case comparisons
  3507. // with jumps to the case code
  3508. //------------------------------------
  3509. // Sort the case values by increasing value. Do the sort together with the labels
  3510. // A simple bubble sort is sufficient since we don't expect a huge number of values
  3511. for( asUINT fwd = 1; fwd < caseValues.GetLength(); fwd++ )
  3512. {
  3513. for( int bck = fwd - 1; bck >= 0; bck-- )
  3514. {
  3515. int bckp = bck + 1;
  3516. if( caseValues[bck] > caseValues[bckp] )
  3517. {
  3518. // Swap the values in both arrays
  3519. int swap = caseValues[bckp];
  3520. caseValues[bckp] = caseValues[bck];
  3521. caseValues[bck] = swap;
  3522. swap = caseLabels[bckp];
  3523. caseLabels[bckp] = caseLabels[bck];
  3524. caseLabels[bck] = swap;
  3525. }
  3526. else
  3527. break;
  3528. }
  3529. }
  3530. // Find ranges of consecutive numbers
  3531. asCArray<int> ranges;
  3532. ranges.PushLast(0);
  3533. asUINT n;
  3534. for( n = 1; n < caseValues.GetLength(); ++n )
  3535. {
  3536. // We can join numbers that are less than 5 numbers
  3537. // apart since the output code will still be smaller
  3538. if( caseValues[n] > caseValues[n-1] + 5 )
  3539. ranges.PushLast(n);
  3540. }
  3541. // If the value is larger than the largest case value, jump to default
  3542. int tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  3543. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[caseValues.GetLength()-1]);
  3544. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  3545. expr.bc.InstrDWORD(asBC_JP, defaultLabel);
  3546. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  3547. // TODO: runtime optimize: We could possibly optimize this even more by doing a
  3548. // binary search instead of a linear search through the ranges
  3549. // For each range
  3550. int range;
  3551. for( range = 0; range < (int)ranges.GetLength(); range++ )
  3552. {
  3553. // Find the largest value in this range
  3554. int maxRange = caseValues[ranges[range]];
  3555. int index = ranges[range];
  3556. for( ; (index < (int)caseValues.GetLength()) && (caseValues[index] <= maxRange + 5); index++ )
  3557. maxRange = caseValues[index];
  3558. // If there are only 2 numbers then it is better to compare them directly
  3559. if( index - ranges[range] > 2 )
  3560. {
  3561. // If the value is smaller than the smallest case value in the range, jump to default
  3562. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  3563. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[ranges[range]]);
  3564. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  3565. expr.bc.InstrDWORD(asBC_JS, defaultLabel);
  3566. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  3567. int nextRangeLabel = nextLabel++;
  3568. // If this is the last range we don't have to make this test
  3569. if( range < (int)ranges.GetLength() - 1 )
  3570. {
  3571. // If the value is larger than the largest case value in the range, jump to the next range
  3572. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  3573. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, maxRange);
  3574. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  3575. expr.bc.InstrDWORD(asBC_JP, nextRangeLabel);
  3576. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  3577. }
  3578. // Jump forward according to the value
  3579. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  3580. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[ranges[range]]);
  3581. expr.bc.InstrW_W_W(asBC_SUBi, tmpOffset, offset, tmpOffset);
  3582. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  3583. expr.bc.JmpP(tmpOffset, maxRange - caseValues[ranges[range]]);
  3584. // Add the list of jumps to the correct labels (any holes, jump to default)
  3585. index = ranges[range];
  3586. for( int i = caseValues[index]; i <= maxRange; i++ )
  3587. {
  3588. if( caseValues[index] == i )
  3589. expr.bc.InstrINT(asBC_JMP, caseLabels[index++]);
  3590. else
  3591. expr.bc.InstrINT(asBC_JMP, defaultLabel);
  3592. }
  3593. expr.bc.Label((short)nextRangeLabel);
  3594. }
  3595. else
  3596. {
  3597. // Simply make a comparison with each value
  3598. for( int i = ranges[range]; i < index; ++i )
  3599. {
  3600. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  3601. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[i]);
  3602. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  3603. expr.bc.InstrDWORD(asBC_JZ, caseLabels[i]);
  3604. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  3605. }
  3606. }
  3607. }
  3608. // Catch any value that falls trough
  3609. expr.bc.InstrINT(asBC_JMP, defaultLabel);
  3610. // Release the temporary variable previously stored
  3611. ReleaseTemporaryVariable(expr.type, &expr.bc);
  3612. // TODO: optimize: Should optimize each piece individually
  3613. expr.bc.OptimizeLocally(tempVariableOffsets);
  3614. //----------------------------------
  3615. // Output case implementations
  3616. //----------------------------------
  3617. // Compile case implementations, each one with the label before it
  3618. cnode = snode->firstChild->next;
  3619. while( cnode )
  3620. {
  3621. // Each case should have a constant expression
  3622. if( cnode->firstChild && cnode->firstChild->nodeType == snExpression )
  3623. {
  3624. expr.bc.Label((short)firstCaseLabel++);
  3625. CompileCase(cnode->firstChild->next, &expr.bc);
  3626. }
  3627. else
  3628. {
  3629. expr.bc.Label((short)defaultLabel);
  3630. // Is default the last case?
  3631. if( cnode->next )
  3632. {
  3633. // We've already reported this error
  3634. break;
  3635. }
  3636. CompileCase(cnode->firstChild, &expr.bc);
  3637. }
  3638. cnode = cnode->next;
  3639. }
  3640. //--------------------------------
  3641. bc->AddCode(&expr.bc);
  3642. // Add break label
  3643. bc->Label((short)breakLabel);
  3644. breakLabels.PopLast();
  3645. RemoveVariableScope();
  3646. }
  3647. void asCCompiler::CompileCase(asCScriptNode *node, asCByteCode *bc)
  3648. {
  3649. bool isFinished = false;
  3650. bool hasReturn = false;
  3651. bool hasUnreachableCode = false;
  3652. while( node )
  3653. {
  3654. if( !hasUnreachableCode && (hasReturn || isFinished) )
  3655. {
  3656. hasUnreachableCode = true;
  3657. Warning(TXT_UNREACHABLE_CODE, node);
  3658. break;
  3659. }
  3660. if( node->nodeType == snBreak || node->nodeType == snContinue )
  3661. isFinished = true;
  3662. asCByteCode statement(engine);
  3663. if( node->nodeType == snDeclaration )
  3664. {
  3665. Error(TXT_DECL_IN_SWITCH, node);
  3666. // Compile it anyway to avoid further compiler errors
  3667. CompileDeclaration(node, &statement);
  3668. }
  3669. else
  3670. CompileStatement(node, &hasReturn, &statement);
  3671. LineInstr(bc, node->tokenPos);
  3672. bc->AddCode(&statement);
  3673. if( !hasCompileErrors )
  3674. asASSERT( tempVariables.GetLength() == 0 );
  3675. node = node->next;
  3676. }
  3677. }
  3678. void asCCompiler::CompileTryCatch(asCScriptNode *node, bool *hasReturn, asCByteCode *bc)
  3679. {
  3680. // We will use one label before and another after the catch statement
  3681. int beforeCatchLabel = nextLabel++;
  3682. int afterCatchLabel = nextLabel++;
  3683. // Compile the try block
  3684. bool hasReturnTry;
  3685. asCByteCode tryBC(engine);
  3686. CompileStatement(node->firstChild, &hasReturnTry, &tryBC);
  3687. // Add marker to unwind exception until here, then jump to catch block
  3688. bc->TryBlock((short)beforeCatchLabel);
  3689. // Add the byte code
  3690. LineInstr(bc, node->firstChild->tokenPos);
  3691. bc->AddCode(&tryBC);
  3692. // Add jump to after catch
  3693. bc->InstrINT(asBC_JMP, afterCatchLabel);
  3694. // Compile the catch block
  3695. bool hasReturnCatch;
  3696. asCByteCode catchBC(engine);
  3697. CompileStatement(node->firstChild->next, &hasReturnCatch, &catchBC);
  3698. // Add marker to tell bytecode optimizer that this is a catch
  3699. // block so the code is not removed as unreachable code
  3700. bc->Label((short)beforeCatchLabel);
  3701. // Add the byte code
  3702. LineInstr(bc, node->firstChild->next->tokenPos);
  3703. bc->AddCode(&catchBC);
  3704. // Add the label after catch
  3705. bc->Label((short)afterCatchLabel);
  3706. // The try/catch statement only has return (i.e. no code after
  3707. // the try/catch block will be executed) if both blocks have
  3708. *hasReturn = hasReturnTry && hasReturnCatch;
  3709. }
  3710. void asCCompiler::CompileIfStatement(asCScriptNode *inode, bool *hasReturn, asCByteCode *bc)
  3711. {
  3712. // We will use one label for the if statement
  3713. // and possibly another for the else statement
  3714. int afterLabel = nextLabel++;
  3715. // Compile the expression
  3716. asCExprContext expr(engine);
  3717. int r = CompileAssignment(inode->firstChild, &expr);
  3718. if( r == 0 )
  3719. {
  3720. // Allow value types to be converted to bool using 'bool opImplConv()'
  3721. if( expr.type.dataType.GetTypeInfo() && (expr.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
  3722. ImplicitConversion(&expr, asCDataType::CreatePrimitive(ttBool, false), inode, asIC_IMPLICIT_CONV);
  3723. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  3724. Error(TXT_EXPR_MUST_BE_BOOL, inode->firstChild);
  3725. else
  3726. {
  3727. if( !expr.type.isConstant )
  3728. {
  3729. if( ProcessPropertyGetAccessor(&expr, inode) < 0 )
  3730. return;
  3731. ConvertToVariable(&expr);
  3732. ProcessDeferredParams(&expr);
  3733. // Add a test
  3734. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  3735. expr.bc.Instr(asBC_ClrHi);
  3736. expr.bc.InstrDWORD(asBC_JZ, afterLabel);
  3737. ReleaseTemporaryVariable(expr.type, &expr.bc);
  3738. expr.bc.OptimizeLocally(tempVariableOffsets);
  3739. bc->AddCode(&expr.bc);
  3740. }
  3741. #if AS_SIZEOF_BOOL == 1
  3742. else if( expr.type.GetConstantB() == 0 )
  3743. #else
  3744. else if (expr.type.GetConstantDW() == 0)
  3745. #endif
  3746. {
  3747. // Jump to the else case
  3748. bc->InstrINT(asBC_JMP, afterLabel);
  3749. // TODO: Should we warn that the expression will always go to the else?
  3750. }
  3751. }
  3752. }
  3753. // Compile the if statement
  3754. bool origIsConstructorCalled = m_isConstructorCalled;
  3755. bool hasReturn1;
  3756. asCByteCode ifBC(engine);
  3757. CompileStatement(inode->firstChild->next, &hasReturn1, &ifBC);
  3758. // Add the byte code
  3759. LineInstr(bc, inode->firstChild->next->tokenPos);
  3760. bc->AddCode(&ifBC);
  3761. if( inode->firstChild->next->nodeType == snExpressionStatement && inode->firstChild->next->firstChild == 0 )
  3762. {
  3763. // Don't allow if( expr );
  3764. Error(TXT_IF_WITH_EMPTY_STATEMENT, inode->firstChild->next);
  3765. }
  3766. // If one of the statements call the constructor, the other must as well
  3767. // otherwise it is possible the constructor is never called
  3768. bool constructorCall1 = false;
  3769. bool constructorCall2 = false;
  3770. if( !origIsConstructorCalled && m_isConstructorCalled )
  3771. constructorCall1 = true;
  3772. // Do we have an else statement?
  3773. if( inode->firstChild->next != inode->lastChild )
  3774. {
  3775. // Reset the constructor called flag so the else statement can call the constructor too
  3776. m_isConstructorCalled = origIsConstructorCalled;
  3777. int afterElse = 0;
  3778. if( !hasReturn1 )
  3779. {
  3780. afterElse = nextLabel++;
  3781. // Add jump to after the else statement
  3782. bc->InstrINT(asBC_JMP, afterElse);
  3783. }
  3784. // Add label for the else statement
  3785. bc->Label((short)afterLabel);
  3786. bool hasReturn2;
  3787. asCByteCode elseBC(engine);
  3788. CompileStatement(inode->lastChild, &hasReturn2, &elseBC);
  3789. // Add byte code for the else statement
  3790. LineInstr(bc, inode->lastChild->tokenPos);
  3791. bc->AddCode(&elseBC);
  3792. if( inode->lastChild->nodeType == snExpressionStatement && inode->lastChild->firstChild == 0 )
  3793. {
  3794. // Don't allow if( expr ) {} else;
  3795. Error(TXT_ELSE_WITH_EMPTY_STATEMENT, inode->lastChild);
  3796. }
  3797. if( !hasReturn1 )
  3798. {
  3799. // Add label for the end of else statement
  3800. bc->Label((short)afterElse);
  3801. }
  3802. // The if statement only has return if both alternatives have
  3803. *hasReturn = hasReturn1 && hasReturn2;
  3804. if( !origIsConstructorCalled && m_isConstructorCalled )
  3805. constructorCall2 = true;
  3806. }
  3807. else
  3808. {
  3809. // Add label for the end of if statement
  3810. bc->Label((short)afterLabel);
  3811. *hasReturn = false;
  3812. }
  3813. // Make sure both or neither conditions call a constructor
  3814. if( (constructorCall1 && !constructorCall2) ||
  3815. (constructorCall2 && !constructorCall1) )
  3816. {
  3817. Error(TXT_BOTH_CONDITIONS_MUST_CALL_CONSTRUCTOR, inode);
  3818. }
  3819. m_isConstructorCalled = origIsConstructorCalled || constructorCall1 || constructorCall2;
  3820. }
  3821. void asCCompiler::CompileForStatement(asCScriptNode *fnode, asCByteCode *bc)
  3822. {
  3823. // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables
  3824. AddVariableScope(true, true);
  3825. // We will use three labels for the for loop
  3826. int conditionLabel = nextLabel++;
  3827. int afterLabel = nextLabel++;
  3828. int continueLabel = nextLabel++;
  3829. int insideLabel = nextLabel++;
  3830. continueLabels.PushLast(continueLabel);
  3831. breakLabels.PushLast(afterLabel);
  3832. //---------------------------------------
  3833. // Compile the initialization statement
  3834. asCByteCode initBC(engine);
  3835. LineInstr(&initBC, fnode->firstChild->tokenPos);
  3836. if( fnode->firstChild->nodeType == snDeclaration )
  3837. CompileDeclaration(fnode->firstChild, &initBC);
  3838. else
  3839. CompileExpressionStatement(fnode->firstChild, &initBC);
  3840. //-----------------------------------
  3841. // Compile the condition statement
  3842. asCExprContext expr(engine);
  3843. asCScriptNode *second = fnode->firstChild->next;
  3844. if( second->firstChild )
  3845. {
  3846. int r = CompileAssignment(second->firstChild, &expr);
  3847. if( r >= 0 )
  3848. {
  3849. // Allow value types to be converted to bool using 'bool opImplConv()'
  3850. if( expr.type.dataType.GetTypeInfo() && (expr.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
  3851. ImplicitConversion(&expr, asCDataType::CreatePrimitive(ttBool, false), second->firstChild, asIC_IMPLICIT_CONV);
  3852. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  3853. Error(TXT_EXPR_MUST_BE_BOOL, second);
  3854. else
  3855. {
  3856. if( ProcessPropertyGetAccessor(&expr, second) < 0 )
  3857. return;
  3858. ConvertToVariable(&expr);
  3859. ProcessDeferredParams(&expr);
  3860. // If expression is false exit the loop
  3861. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  3862. expr.bc.Instr(asBC_ClrHi);
  3863. expr.bc.InstrDWORD(asBC_JNZ, insideLabel);
  3864. ReleaseTemporaryVariable(expr.type, &expr.bc);
  3865. expr.bc.OptimizeLocally(tempVariableOffsets);
  3866. // Prepend the line instruction for the condition
  3867. asCByteCode tmp(engine);
  3868. LineInstr(&tmp, second->firstChild->tokenPos);
  3869. tmp.AddCode(&expr.bc);
  3870. expr.bc.AddCode(&tmp);
  3871. }
  3872. }
  3873. }
  3874. //---------------------------
  3875. // Compile the increment statement(s)
  3876. asCByteCode nextBC(engine);
  3877. asCScriptNode *cnode = second->next;
  3878. while( cnode && cnode->nodeType == snExpressionStatement && cnode != fnode->lastChild )
  3879. {
  3880. LineInstr(&nextBC, cnode->tokenPos);
  3881. CompileExpressionStatement(cnode, &nextBC);
  3882. cnode = cnode->next;
  3883. }
  3884. //------------------------------
  3885. // Compile loop statement
  3886. bool hasReturn;
  3887. asCByteCode forBC(engine);
  3888. CompileStatement(fnode->lastChild, &hasReturn, &forBC);
  3889. //-------------------------------
  3890. // Join the code pieces
  3891. bc->AddCode(&initBC);
  3892. bc->InstrDWORD(asBC_JMP, conditionLabel);
  3893. bc->Label((short)insideLabel);
  3894. // Add a suspend bytecode inside the loop to guarantee
  3895. // that the application can suspend the execution
  3896. bc->Instr(asBC_SUSPEND);
  3897. bc->InstrPTR(asBC_JitEntry, 0);
  3898. LineInstr(bc, fnode->lastChild->tokenPos);
  3899. bc->AddCode(&forBC);
  3900. bc->Label((short)continueLabel);
  3901. bc->AddCode(&nextBC);
  3902. bc->Label((short)conditionLabel);
  3903. if( expr.bc.GetLastInstr() == -1 )
  3904. // There is no condition, so we just always jump
  3905. bc->InstrDWORD(asBC_JMP, insideLabel);
  3906. else
  3907. bc->AddCode(&expr.bc);
  3908. bc->Label((short)afterLabel);
  3909. continueLabels.PopLast();
  3910. breakLabels.PopLast();
  3911. // Deallocate variables in this block, in reverse order
  3912. for( int n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  3913. {
  3914. sVariable *v = variables->variables[n];
  3915. // Call variable destructors here, for variables not yet destroyed
  3916. CallDestructor(v->type, v->stackOffset, v->onHeap, bc);
  3917. // Don't deallocate function parameters
  3918. if( v->stackOffset > 0 )
  3919. DeallocateVariable(v->stackOffset);
  3920. }
  3921. RemoveVariableScope();
  3922. }
  3923. void asCCompiler::CompileWhileStatement(asCScriptNode *wnode, asCByteCode *bc)
  3924. {
  3925. // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables
  3926. AddVariableScope(true, true);
  3927. // We will use two labels for the while loop
  3928. int beforeLabel = nextLabel++;
  3929. int afterLabel = nextLabel++;
  3930. continueLabels.PushLast(beforeLabel);
  3931. breakLabels.PushLast(afterLabel);
  3932. // Add label before the expression
  3933. bc->Label((short)beforeLabel);
  3934. // Compile expression
  3935. asCExprContext expr(engine);
  3936. int r = CompileAssignment(wnode->firstChild, &expr);
  3937. if( r == 0 )
  3938. {
  3939. // Allow value types to be converted to bool using 'bool opImplConv()'
  3940. if( expr.type.dataType.GetTypeInfo() && (expr.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
  3941. ImplicitConversion(&expr, asCDataType::CreatePrimitive(ttBool, false), wnode->firstChild, asIC_IMPLICIT_CONV);
  3942. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  3943. Error(TXT_EXPR_MUST_BE_BOOL, wnode->firstChild);
  3944. else
  3945. {
  3946. if( ProcessPropertyGetAccessor(&expr, wnode) < 0 )
  3947. return;
  3948. ConvertToVariable(&expr);
  3949. ProcessDeferredParams(&expr);
  3950. // Jump to end of statement if expression is false
  3951. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  3952. expr.bc.Instr(asBC_ClrHi);
  3953. expr.bc.InstrDWORD(asBC_JZ, afterLabel);
  3954. ReleaseTemporaryVariable(expr.type, &expr.bc);
  3955. expr.bc.OptimizeLocally(tempVariableOffsets);
  3956. bc->AddCode(&expr.bc);
  3957. }
  3958. }
  3959. // Add a suspend bytecode inside the loop to guarantee
  3960. // that the application can suspend the execution
  3961. bc->Instr(asBC_SUSPEND);
  3962. bc->InstrPTR(asBC_JitEntry, 0);
  3963. // Compile statement
  3964. bool hasReturn;
  3965. asCByteCode whileBC(engine);
  3966. CompileStatement(wnode->lastChild, &hasReturn, &whileBC);
  3967. // Add byte code for the statement
  3968. LineInstr(bc, wnode->lastChild->tokenPos);
  3969. bc->AddCode(&whileBC);
  3970. // Jump to the expression
  3971. bc->InstrINT(asBC_JMP, beforeLabel);
  3972. // Add label after the statement
  3973. bc->Label((short)afterLabel);
  3974. continueLabels.PopLast();
  3975. breakLabels.PopLast();
  3976. RemoveVariableScope();
  3977. }
  3978. void asCCompiler::CompileDoWhileStatement(asCScriptNode *wnode, asCByteCode *bc)
  3979. {
  3980. // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables
  3981. AddVariableScope(true, true);
  3982. // We will use two labels for the while loop
  3983. int beforeLabel = nextLabel++;
  3984. int beforeTest = nextLabel++;
  3985. int afterLabel = nextLabel++;
  3986. continueLabels.PushLast(beforeTest);
  3987. breakLabels.PushLast(afterLabel);
  3988. // Add label before the statement
  3989. bc->Label((short)beforeLabel);
  3990. // Compile statement
  3991. bool hasReturn;
  3992. asCByteCode whileBC(engine);
  3993. CompileStatement(wnode->firstChild, &hasReturn, &whileBC);
  3994. // Add byte code for the statement
  3995. LineInstr(bc, wnode->firstChild->tokenPos);
  3996. bc->AddCode(&whileBC);
  3997. // Add label before the expression
  3998. bc->Label((short)beforeTest);
  3999. // Add a suspend bytecode inside the loop to guarantee
  4000. // that the application can suspend the execution
  4001. bc->Instr(asBC_SUSPEND);
  4002. bc->InstrPTR(asBC_JitEntry, 0);
  4003. // Add a line instruction
  4004. LineInstr(bc, wnode->lastChild->tokenPos);
  4005. // Compile expression
  4006. asCExprContext expr(engine);
  4007. CompileAssignment(wnode->lastChild, &expr);
  4008. // Allow value types to be converted to bool using 'bool opImplConv()'
  4009. if( expr.type.dataType.GetTypeInfo() && (expr.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
  4010. ImplicitConversion(&expr, asCDataType::CreatePrimitive(ttBool, false), wnode->lastChild, asIC_IMPLICIT_CONV);
  4011. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  4012. Error(TXT_EXPR_MUST_BE_BOOL, wnode->firstChild);
  4013. else
  4014. {
  4015. if( ProcessPropertyGetAccessor(&expr, wnode) < 0 )
  4016. return;
  4017. ConvertToVariable(&expr);
  4018. ProcessDeferredParams(&expr);
  4019. // Jump to next iteration if expression is true
  4020. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  4021. expr.bc.Instr(asBC_ClrHi);
  4022. expr.bc.InstrDWORD(asBC_JNZ, beforeLabel);
  4023. ReleaseTemporaryVariable(expr.type, &expr.bc);
  4024. expr.bc.OptimizeLocally(tempVariableOffsets);
  4025. bc->AddCode(&expr.bc);
  4026. }
  4027. // Add label after the statement
  4028. bc->Label((short)afterLabel);
  4029. continueLabels.PopLast();
  4030. breakLabels.PopLast();
  4031. RemoveVariableScope();
  4032. }
  4033. void asCCompiler::CompileBreakStatement(asCScriptNode *node, asCByteCode *bc)
  4034. {
  4035. if( breakLabels.GetLength() == 0 )
  4036. {
  4037. Error(TXT_INVALID_BREAK, node);
  4038. return;
  4039. }
  4040. // Add destructor calls for all variables that will go out of scope
  4041. // Put this clean up in a block to allow exception handler to understand them
  4042. bc->Block(true);
  4043. asCVariableScope *vs = variables;
  4044. while( !vs->isBreakScope )
  4045. {
  4046. for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- )
  4047. CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc);
  4048. vs = vs->parent;
  4049. }
  4050. bc->Block(false);
  4051. bc->InstrINT(asBC_JMP, breakLabels[breakLabels.GetLength()-1]);
  4052. }
  4053. void asCCompiler::CompileContinueStatement(asCScriptNode *node, asCByteCode *bc)
  4054. {
  4055. if( continueLabels.GetLength() == 0 )
  4056. {
  4057. Error(TXT_INVALID_CONTINUE, node);
  4058. return;
  4059. }
  4060. // Add destructor calls for all variables that will go out of scope
  4061. // Put this clean up in a block to allow exception handler to understand them
  4062. bc->Block(true);
  4063. asCVariableScope *vs = variables;
  4064. while( !vs->isContinueScope )
  4065. {
  4066. for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- )
  4067. CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc);
  4068. vs = vs->parent;
  4069. }
  4070. bc->Block(false);
  4071. bc->InstrINT(asBC_JMP, continueLabels[continueLabels.GetLength()-1]);
  4072. }
  4073. void asCCompiler::CompileExpressionStatement(asCScriptNode *enode, asCByteCode *bc)
  4074. {
  4075. if( enode->firstChild )
  4076. {
  4077. // Compile the expression
  4078. asCExprContext expr(engine);
  4079. CompileAssignment(enode->firstChild, &expr);
  4080. // Must not have unused ambiguous names
  4081. if( expr.IsClassMethod() || expr.IsGlobalFunc() )
  4082. Error(TXT_INVALID_EXPRESSION_AMBIGUOUS_NAME, enode);
  4083. // Must not have unused anonymous functions
  4084. if( expr.IsLambda() )
  4085. Error(TXT_INVALID_EXPRESSION_LAMBDA, enode);
  4086. // If we get here and there is still an unprocessed property
  4087. // accessor, then process it as a get access. Don't call if there is
  4088. // already a compile error, or we might report an error that is not valid
  4089. if( !hasCompileErrors )
  4090. if( ProcessPropertyGetAccessor(&expr, enode) < 0 )
  4091. return;
  4092. // Pop the value from the stack
  4093. if( !expr.type.dataType.IsPrimitive() )
  4094. expr.bc.Instr(asBC_PopPtr);
  4095. // Release temporary variables used by expression
  4096. ReleaseTemporaryVariable(expr.type, &expr.bc);
  4097. ProcessDeferredParams(&expr);
  4098. expr.bc.OptimizeLocally(tempVariableOffsets);
  4099. bc->AddCode(&expr.bc);
  4100. }
  4101. }
  4102. void asCCompiler::PrepareTemporaryVariable(asCScriptNode *node, asCExprContext *ctx, bool forceOnHeap)
  4103. {
  4104. // The input can be either an object or funcdef, either as handle or reference
  4105. asASSERT(ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef());
  4106. // If the object already is stored in temporary variable then nothing needs to be done
  4107. // Note, a type can be temporary without being a variable, in which case it is holding off
  4108. // on releasing a previously used object.
  4109. if( ctx->type.isTemporary && ctx->type.isVariable &&
  4110. !(forceOnHeap && !IsVariableOnHeap(ctx->type.stackOffset)) )
  4111. {
  4112. // If the temporary object is currently not a reference
  4113. // the expression needs to be reevaluated to a reference
  4114. if( !ctx->type.dataType.IsReference() )
  4115. {
  4116. ctx->bc.Instr(asBC_PopPtr);
  4117. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  4118. ctx->type.dataType.MakeReference(IsVariableOnHeap(ctx->type.stackOffset));
  4119. }
  4120. return;
  4121. }
  4122. // Allocate temporary variable
  4123. asCDataType dt = ctx->type.dataType;
  4124. dt.MakeReference(false);
  4125. dt.MakeReadOnly(false);
  4126. int offset = AllocateVariable(dt, true, forceOnHeap);
  4127. // Objects stored on the stack are not considered references
  4128. dt.MakeReference(IsVariableOnHeap(offset));
  4129. asCExprValue lvalue;
  4130. lvalue.Set(dt);
  4131. lvalue.isExplicitHandle = ctx->type.isExplicitHandle;
  4132. bool isExplicitHandle = ctx->type.isExplicitHandle;
  4133. bool prevIsTemp = ctx->type.isTemporary;
  4134. int prevStackOffset = ctx->type.stackOffset;
  4135. CompileInitAsCopy(dt, offset, &ctx->bc, ctx, node, false);
  4136. // Release the previous temporary variable if it hasn't already been released
  4137. if( prevIsTemp && tempVariables.Exists(prevStackOffset) )
  4138. ReleaseTemporaryVariable(prevStackOffset, &ctx->bc);
  4139. // Push the reference to the temporary variable on the stack
  4140. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  4141. ctx->type.Set(dt);
  4142. ctx->type.isTemporary = true;
  4143. ctx->type.stackOffset = (short)offset;
  4144. ctx->type.isVariable = true;
  4145. ctx->type.isExplicitHandle = isExplicitHandle;
  4146. ctx->type.dataType.MakeReference(IsVariableOnHeap(offset));
  4147. }
  4148. void asCCompiler::CompileReturnStatement(asCScriptNode *rnode, asCByteCode *bc)
  4149. {
  4150. // Get return type and location
  4151. sVariable *v = variables->GetVariable("return");
  4152. // Basic validations
  4153. if( v->type.GetSizeOnStackDWords() > 0 && !rnode->firstChild )
  4154. {
  4155. Error(TXT_MUST_RETURN_VALUE, rnode);
  4156. return;
  4157. }
  4158. else if( v->type.GetSizeOnStackDWords() == 0 && rnode->firstChild )
  4159. {
  4160. Error(TXT_CANT_RETURN_VALUE, rnode);
  4161. return;
  4162. }
  4163. // Compile the expression
  4164. if( rnode->firstChild )
  4165. {
  4166. // Compile the expression
  4167. asCExprContext expr(engine);
  4168. int r = CompileAssignment(rnode->firstChild, &expr);
  4169. if( r < 0 ) return;
  4170. if( v->type.IsReference() )
  4171. {
  4172. // The expression that gives the reference must not use any of the
  4173. // variables that must be destroyed upon exit, because then it means
  4174. // reference will stay alive while the clean-up is done, which could
  4175. // potentially mean that the reference is invalidated by the clean-up.
  4176. //
  4177. // When the function is returning a reference, the clean-up of the
  4178. // variables must be done before the evaluation of the expression.
  4179. //
  4180. // A reference to a global variable, or a class member for class methods
  4181. // should be allowed to be returned.
  4182. if( !(expr.type.dataType.IsReference() ||
  4183. (expr.type.dataType.IsObject() && !expr.type.dataType.IsObjectHandle())) )
  4184. {
  4185. // Clean up the potential deferred parameters
  4186. ProcessDeferredParams(&expr);
  4187. Error(TXT_NOT_VALID_REFERENCE, rnode);
  4188. return;
  4189. }
  4190. // No references to local variables, temporary variables, or parameters
  4191. // are allowed to be returned, since they go out of scope when the function
  4192. // returns. Even reference parameters are disallowed, since it is not possible
  4193. // to know the scope of them. The exception is the 'this' pointer, which
  4194. // is treated by the compiler as a local variable, but isn't really so.
  4195. if( (expr.type.isVariable && !(expr.type.stackOffset == 0 && outFunc->objectType)) || expr.type.isTemporary )
  4196. {
  4197. // Clean up the potential deferred parameters
  4198. ProcessDeferredParams(&expr);
  4199. Error(TXT_CANNOT_RETURN_REF_TO_LOCAL, rnode);
  4200. return;
  4201. }
  4202. // The type must match exactly as we cannot convert
  4203. // the reference without loosing the original value
  4204. if( !(v->type.IsEqualExceptConst(expr.type.dataType) ||
  4205. ((expr.type.dataType.IsObject() || expr.type.dataType.IsFuncdef()) &&
  4206. !expr.type.dataType.IsObjectHandle() &&
  4207. v->type.IsEqualExceptRefAndConst(expr.type.dataType))) ||
  4208. (!v->type.IsReadOnly() && expr.type.dataType.IsReadOnly()) )
  4209. {
  4210. // Clean up the potential deferred parameters
  4211. ProcessDeferredParams(&expr);
  4212. asCString str;
  4213. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, expr.type.dataType.Format(outFunc->nameSpace).AddressOf(), v->type.Format(outFunc->nameSpace).AddressOf());
  4214. Error(str, rnode);
  4215. return;
  4216. }
  4217. // The expression must not have any deferred expressions, because the evaluation
  4218. // of these cannot be done without keeping the reference which is not safe
  4219. if( expr.deferredParams.GetLength() )
  4220. {
  4221. // Clean up the potential deferred parameters
  4222. ProcessDeferredParams(&expr);
  4223. Error(TXT_REF_CANT_BE_RETURNED_DEFERRED_PARAM, rnode);
  4224. return;
  4225. }
  4226. // Make sure the expression isn't using any local variables that
  4227. // will need to be cleaned up before the function completes
  4228. asCArray<int> usedVars;
  4229. expr.bc.GetVarsUsed(usedVars);
  4230. for( asUINT n = 0; n < usedVars.GetLength(); n++ )
  4231. {
  4232. int var = GetVariableSlot(usedVars[n]);
  4233. if( var != -1 )
  4234. {
  4235. asCDataType dt = variableAllocations[var];
  4236. if( dt.IsObject() )
  4237. {
  4238. ProcessDeferredParams(&expr);
  4239. Error(TXT_REF_CANT_BE_RETURNED_LOCAL_VARS, rnode);
  4240. return;
  4241. }
  4242. }
  4243. }
  4244. // Can't return the reference if could point to a local variable
  4245. if( expr.type.isRefToLocal )
  4246. {
  4247. ProcessDeferredParams(&expr);
  4248. Error(TXT_REF_CANT_BE_TO_LOCAL_VAR, rnode);
  4249. return;
  4250. }
  4251. // All objects in the function must be cleaned up before the expression
  4252. // is evaluated, otherwise there is a possibility that the cleanup will
  4253. // invalidate the reference.
  4254. // Destroy the local variables before loading
  4255. // the reference into the register. This will
  4256. // be done before the expression is evaluated.
  4257. DestroyVariables(bc);
  4258. // For primitives the reference is already in the register,
  4259. // but for non-primitives the reference is on the stack so we
  4260. // need to load it into the register
  4261. if( !expr.type.dataType.IsPrimitive() )
  4262. {
  4263. if( !expr.type.dataType.IsObjectHandle() &&
  4264. expr.type.dataType.IsReference() )
  4265. expr.bc.Instr(asBC_RDSPtr);
  4266. expr.bc.Instr(asBC_PopRPtr);
  4267. }
  4268. // There are no temporaries to release so we're done
  4269. }
  4270. else // if( !v->type.IsReference() )
  4271. {
  4272. if( ProcessPropertyGetAccessor(&expr, rnode) < 0 )
  4273. return;
  4274. // Prepare the value for assignment
  4275. IsVariableInitialized(&expr.type, rnode->firstChild);
  4276. if( v->type.IsPrimitive() )
  4277. {
  4278. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  4279. // Implicitly convert the value to the return type
  4280. ImplicitConversion(&expr, v->type, rnode->firstChild, asIC_IMPLICIT_CONV);
  4281. // Verify that the conversion was successful
  4282. if( expr.type.dataType != v->type )
  4283. {
  4284. asCString str;
  4285. str.Format(TXT_NO_CONVERSION_s_TO_s, expr.type.dataType.Format(outFunc->nameSpace).AddressOf(), v->type.Format(outFunc->nameSpace).AddressOf());
  4286. Error(str, rnode);
  4287. return;
  4288. }
  4289. else
  4290. {
  4291. ConvertToVariable(&expr);
  4292. // Clean up the local variables and process deferred parameters
  4293. DestroyVariables(&expr.bc);
  4294. ProcessDeferredParams(&expr);
  4295. ReleaseTemporaryVariable(expr.type, &expr.bc);
  4296. // Load the variable in the register
  4297. if( v->type.GetSizeOnStackDWords() == 1 )
  4298. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  4299. else
  4300. expr.bc.InstrSHORT(asBC_CpyVtoR8, expr.type.stackOffset);
  4301. }
  4302. }
  4303. else if( v->type.IsObject() || v->type.IsFuncdef() )
  4304. {
  4305. // Value types are returned on the stack, in a location
  4306. // that has been reserved by the calling function.
  4307. if( outFunc->DoesReturnOnStack() )
  4308. {
  4309. // TODO: runtime optimize: If the return type has a constructor that takes the type of the expression,
  4310. // it should be called directly instead of first converting the expression and
  4311. // then copy the value.
  4312. if( !v->type.IsEqualExceptRefAndConst(expr.type.dataType) )
  4313. {
  4314. ImplicitConversion(&expr, v->type, rnode->firstChild, asIC_IMPLICIT_CONV);
  4315. if( !v->type.IsEqualExceptRefAndConst(expr.type.dataType) )
  4316. {
  4317. asCString str;
  4318. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, expr.type.dataType.Format(outFunc->nameSpace).AddressOf(), v->type.Format(outFunc->nameSpace).AddressOf());
  4319. Error(str, rnode->firstChild);
  4320. return;
  4321. }
  4322. }
  4323. int offset = outFunc->objectType ? -AS_PTR_SIZE : 0;
  4324. CompileInitAsCopy(v->type, offset, &expr.bc, &expr, rnode->firstChild, true);
  4325. // Clean up the local variables and process deferred parameters
  4326. DestroyVariables(&expr.bc);
  4327. ProcessDeferredParams(&expr);
  4328. }
  4329. else
  4330. {
  4331. asASSERT( (v->type.GetTypeInfo()->flags & asOBJ_REF) || v->type.IsFuncdef() );
  4332. // Prepare the expression to be loaded into the object
  4333. // register. This will place the reference in local variable
  4334. PrepareArgument(&v->type, &expr, rnode->firstChild, false, 0);
  4335. // Pop the reference to the temporary variable
  4336. expr.bc.Instr(asBC_PopPtr);
  4337. // Clean up the local variables and process deferred parameters
  4338. DestroyVariables(&expr.bc);
  4339. ProcessDeferredParams(&expr);
  4340. // Load the object pointer into the object register
  4341. // LOADOBJ also clears the address in the variable
  4342. expr.bc.InstrSHORT(asBC_LOADOBJ, expr.type.stackOffset);
  4343. // LOADOBJ cleared the address in the variable so the object will not be freed
  4344. // here, but the temporary variable must still be freed so the slot can be reused
  4345. // By releasing without the bytecode we do just that.
  4346. ReleaseTemporaryVariable(expr.type, 0);
  4347. }
  4348. }
  4349. }
  4350. expr.bc.OptimizeLocally(tempVariableOffsets);
  4351. bc->AddCode(&expr.bc);
  4352. }
  4353. else
  4354. {
  4355. // For functions that don't return anything
  4356. // we just detroy the local variables
  4357. DestroyVariables(bc);
  4358. }
  4359. // Jump to the end of the function
  4360. bc->InstrINT(asBC_JMP, 0);
  4361. }
  4362. void asCCompiler::DestroyVariables(asCByteCode *bc)
  4363. {
  4364. // Call destructor on all variables except for the function parameters
  4365. // Put the clean-up in a block to allow exception handler to understand this
  4366. bc->Block(true);
  4367. asCVariableScope *vs = variables;
  4368. while( vs )
  4369. {
  4370. for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- )
  4371. if( vs->variables[n]->stackOffset > 0 )
  4372. CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc);
  4373. vs = vs->parent;
  4374. }
  4375. bc->Block(false);
  4376. }
  4377. void asCCompiler::AddVariableScope(bool isBreakScope, bool isContinueScope)
  4378. {
  4379. variables = asNEW(asCVariableScope)(variables);
  4380. if( variables == 0 )
  4381. {
  4382. // Out of memory
  4383. return;
  4384. }
  4385. variables->isBreakScope = isBreakScope;
  4386. variables->isContinueScope = isContinueScope;
  4387. }
  4388. void asCCompiler::RemoveVariableScope()
  4389. {
  4390. if( variables )
  4391. {
  4392. asCVariableScope *var = variables;
  4393. variables = variables->parent;
  4394. asDELETE(var,asCVariableScope);
  4395. }
  4396. }
  4397. void asCCompiler::Error(const asCString &msg, asCScriptNode *node)
  4398. {
  4399. asCString str;
  4400. int r = 0, c = 0;
  4401. asASSERT( node );
  4402. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  4403. builder->WriteError(script->name, msg, r, c);
  4404. hasCompileErrors = true;
  4405. }
  4406. void asCCompiler::Warning(const asCString &msg, asCScriptNode *node)
  4407. {
  4408. asCString str;
  4409. int r = 0, c = 0;
  4410. asASSERT( node );
  4411. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  4412. builder->WriteWarning(script->name, msg, r, c);
  4413. }
  4414. void asCCompiler::Information(const asCString &msg, asCScriptNode *node)
  4415. {
  4416. asCString str;
  4417. int r = 0, c = 0;
  4418. asASSERT( node );
  4419. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  4420. builder->WriteInfo(script->name, msg, r, c, false);
  4421. }
  4422. void asCCompiler::PrintMatchingFuncs(asCArray<int> &funcs, asCScriptNode *node, asCObjectType *inType)
  4423. {
  4424. int r = 0, c = 0;
  4425. asASSERT( node );
  4426. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  4427. for( unsigned int n = 0; n < funcs.GetLength(); n++ )
  4428. {
  4429. asCScriptFunction *func = builder->GetFunctionDescription(funcs[n]);
  4430. if( inType && func->funcType == asFUNC_VIRTUAL )
  4431. func = inType->virtualFunctionTable[func->vfTableIdx];
  4432. builder->WriteInfo(script->name, func->GetDeclaration(true, false, true), r, c, false);
  4433. if (func->objectType && (func->objectType->flags & asOBJ_TEMPLATE))
  4434. {
  4435. // Check for funcdefs in the arguments that may have been generated by the template instance, so these can be shown to user
  4436. for (unsigned int p = 0; p < func->GetParamCount(); p++)
  4437. {
  4438. int typeId = 0;
  4439. func->GetParam(p, &typeId);
  4440. asITypeInfo *ti = engine->GetTypeInfoById(typeId);
  4441. if (ti && (ti->GetFlags() & asOBJ_FUNCDEF))
  4442. {
  4443. asCString msg;
  4444. msg.Format(TXT_WHERE_s_IS_s, ti->GetName(), ti->GetFuncdefSignature()->GetDeclaration());
  4445. builder->WriteInfo(script->name, msg.AddressOf(), r, c, false);
  4446. }
  4447. }
  4448. }
  4449. }
  4450. }
  4451. int asCCompiler::AllocateVariableNotIn(const asCDataType &type, bool isTemporary, bool forceOnHeap, asCExprContext *ctx)
  4452. {
  4453. int l = int(reservedVariables.GetLength());
  4454. ctx->bc.GetVarsUsed(reservedVariables);
  4455. int var = AllocateVariable(type, isTemporary, forceOnHeap);
  4456. reservedVariables.SetLength(l);
  4457. return var;
  4458. }
  4459. int asCCompiler::AllocateVariable(const asCDataType &type, bool isTemporary, bool forceOnHeap, bool asReference)
  4460. {
  4461. asCDataType t(type);
  4462. t.MakeReference(asReference);
  4463. if( t.IsPrimitive() && t.GetSizeOnStackDWords() == 1 )
  4464. t.SetTokenType(ttInt);
  4465. if( t.IsPrimitive() && t.GetSizeOnStackDWords() == 2 )
  4466. t.SetTokenType(ttDouble);
  4467. // Only null handles have the token type unrecognized token
  4468. asASSERT( t.IsObjectHandle() || t.GetTokenType() != ttUnrecognizedToken );
  4469. bool isOnHeap = true;
  4470. if( t.IsPrimitive() ||
  4471. (t.GetTypeInfo() && (t.GetTypeInfo()->GetFlags() & asOBJ_VALUE) && !forceOnHeap && !asReference) )
  4472. {
  4473. // Primitives and value types (unless overridden) are allocated on the stack
  4474. isOnHeap = false;
  4475. }
  4476. // Find a free location with the same type
  4477. for( asUINT n = 0; n < freeVariables.GetLength(); n++ )
  4478. {
  4479. int slot = freeVariables[n];
  4480. if( variableAllocations[slot].IsEqualExceptConst(t) &&
  4481. variableIsTemporary[slot] == isTemporary &&
  4482. variableIsOnHeap[slot] == isOnHeap )
  4483. {
  4484. // We can't return by slot, must count variable sizes
  4485. int offset = GetVariableOffset(slot);
  4486. // Verify that it is not in the list of reserved variables
  4487. bool isUsed = false;
  4488. if( reservedVariables.GetLength() )
  4489. isUsed = reservedVariables.Exists(offset);
  4490. if( !isUsed )
  4491. {
  4492. if( n != freeVariables.GetLength() - 1 )
  4493. freeVariables[n] = freeVariables.PopLast();
  4494. else
  4495. freeVariables.PopLast();
  4496. if( isTemporary )
  4497. tempVariables.PushLast(offset);
  4498. return offset;
  4499. }
  4500. }
  4501. }
  4502. variableAllocations.PushLast(t);
  4503. variableIsTemporary.PushLast(isTemporary);
  4504. variableIsOnHeap.PushLast(isOnHeap);
  4505. int offset = GetVariableOffset((int)variableAllocations.GetLength()-1);
  4506. if( isTemporary )
  4507. {
  4508. // Add offset to the currently allocated temporary variables
  4509. tempVariables.PushLast(offset);
  4510. // Add offset to all known offsets to temporary variables, whether allocated or not
  4511. tempVariableOffsets.PushLast(offset);
  4512. }
  4513. return offset;
  4514. }
  4515. int asCCompiler::GetVariableOffset(int varIndex)
  4516. {
  4517. // Return offset to the last dword on the stack
  4518. // Start at 1 as offset 0 is reserved for the this pointer (or first argument for global functions)
  4519. int varOffset = 1;
  4520. // Skip lower variables
  4521. for( int n = 0; n < varIndex; n++ )
  4522. {
  4523. if( !variableIsOnHeap[n] && variableAllocations[n].IsObject() )
  4524. varOffset += variableAllocations[n].GetSizeInMemoryDWords();
  4525. else
  4526. varOffset += variableAllocations[n].GetSizeOnStackDWords();
  4527. }
  4528. if( varIndex < (int)variableAllocations.GetLength() )
  4529. {
  4530. // For variables larger than 1 dword the returned offset should be to the last dword
  4531. int size;
  4532. if( !variableIsOnHeap[varIndex] && variableAllocations[varIndex].IsObject() )
  4533. size = variableAllocations[varIndex].GetSizeInMemoryDWords();
  4534. else
  4535. size = variableAllocations[varIndex].GetSizeOnStackDWords();
  4536. if( size > 1 )
  4537. varOffset += size-1;
  4538. }
  4539. return varOffset;
  4540. }
  4541. int asCCompiler::GetVariableSlot(int offset)
  4542. {
  4543. int varOffset = 1;
  4544. for( asUINT n = 0; n < variableAllocations.GetLength(); n++ )
  4545. {
  4546. if( !variableIsOnHeap[n] && variableAllocations[n].IsObject() )
  4547. varOffset += -1 + variableAllocations[n].GetSizeInMemoryDWords();
  4548. else
  4549. varOffset += -1 + variableAllocations[n].GetSizeOnStackDWords();
  4550. if( varOffset == offset )
  4551. return n;
  4552. varOffset++;
  4553. }
  4554. return -1;
  4555. }
  4556. bool asCCompiler::IsVariableOnHeap(int offset)
  4557. {
  4558. int varSlot = GetVariableSlot(offset);
  4559. if( varSlot < 0 )
  4560. {
  4561. // This happens for function arguments that are considered as on the heap
  4562. return true;
  4563. }
  4564. return variableIsOnHeap[varSlot];
  4565. }
  4566. void asCCompiler::DeallocateVariable(int offset)
  4567. {
  4568. // Remove temporary variable
  4569. int n;
  4570. for( n = 0; n < (int)tempVariables.GetLength(); n++ )
  4571. {
  4572. if( offset == tempVariables[n] )
  4573. {
  4574. if( n == (int)tempVariables.GetLength()-1 )
  4575. tempVariables.PopLast();
  4576. else
  4577. tempVariables[n] = tempVariables.PopLast();
  4578. break;
  4579. }
  4580. }
  4581. // Mark the variable slot available for new allocations
  4582. n = GetVariableSlot(offset);
  4583. if( n != -1 )
  4584. {
  4585. freeVariables.PushLast(n);
  4586. return;
  4587. }
  4588. // We might get here if the variable was implicitly declared
  4589. // because it was used before a formal declaration, in this case
  4590. // the offset is 0x7FFF
  4591. asASSERT(offset == 0x7FFF);
  4592. }
  4593. void asCCompiler::ReleaseTemporaryVariable(asCExprValue &t, asCByteCode *bc)
  4594. {
  4595. if( t.isTemporary )
  4596. {
  4597. ReleaseTemporaryVariable(t.stackOffset, bc);
  4598. t.isTemporary = false;
  4599. }
  4600. }
  4601. void asCCompiler::ReleaseTemporaryVariable(int offset, asCByteCode *bc)
  4602. {
  4603. asASSERT( tempVariables.Exists(offset) );
  4604. if( bc )
  4605. {
  4606. // We need to call the destructor on the true variable type
  4607. int n = GetVariableSlot(offset);
  4608. asASSERT( n >= 0 );
  4609. if( n >= 0 )
  4610. {
  4611. asCDataType dt = variableAllocations[n];
  4612. bool isOnHeap = variableIsOnHeap[n];
  4613. // Call destructor
  4614. CallDestructor(dt, offset, isOnHeap, bc);
  4615. }
  4616. }
  4617. DeallocateVariable(offset);
  4618. }
  4619. void asCCompiler::Dereference(asCExprContext *ctx, bool generateCode)
  4620. {
  4621. if( ctx->type.dataType.IsReference() )
  4622. {
  4623. if( ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef() )
  4624. {
  4625. ctx->type.dataType.MakeReference(false);
  4626. if( generateCode )
  4627. ctx->bc.Instr(asBC_RDSPtr);
  4628. }
  4629. else
  4630. {
  4631. // This should never happen as primitives are treated differently
  4632. asASSERT(false);
  4633. }
  4634. }
  4635. }
  4636. bool asCCompiler::IsVariableInitialized(asCExprValue *type, asCScriptNode *node)
  4637. {
  4638. // No need to check if there is no variable scope
  4639. if( variables == 0 ) return true;
  4640. // Temporary variables are assumed to be initialized
  4641. if( type->isTemporary ) return true;
  4642. // Verify that it is a variable
  4643. if( !type->isVariable ) return true;
  4644. // Find the variable
  4645. sVariable *v = variables->GetVariableByOffset(type->stackOffset);
  4646. // The variable isn't found if it is a constant, in which case it is guaranteed to be initialized
  4647. if( v == 0 ) return true;
  4648. if( v->isInitialized ) return true;
  4649. // Complex types don't need this test
  4650. if( v->type.IsObject() || v->type.IsFuncdef() ) return true;
  4651. // Mark as initialized so that the user will not be bothered again
  4652. v->isInitialized = true;
  4653. // Write warning
  4654. asCString str;
  4655. str.Format(TXT_s_NOT_INITIALIZED, (const char *)v->name.AddressOf());
  4656. Warning(str, node);
  4657. return false;
  4658. }
  4659. void asCCompiler::PrepareOperand(asCExprContext *ctx, asCScriptNode *node)
  4660. {
  4661. // Check if the variable is initialized (if it indeed is a variable)
  4662. IsVariableInitialized(&ctx->type, node);
  4663. asCDataType to = ctx->type.dataType;
  4664. to.MakeReference(false);
  4665. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV);
  4666. ProcessDeferredParams(ctx);
  4667. }
  4668. void asCCompiler::PrepareForAssignment(asCDataType *lvalue, asCExprContext *rctx, asCScriptNode *node, bool toTemporary, asCExprContext *lvalueExpr)
  4669. {
  4670. // Reserve the temporary variables used in the lvalue expression so they won't end up being used by the rvalue too
  4671. int l = int(reservedVariables.GetLength());
  4672. if( lvalueExpr ) lvalueExpr->bc.GetVarsUsed(reservedVariables);
  4673. if( ProcessPropertyGetAccessor(rctx, node) < 0 )
  4674. return;
  4675. // Make sure the rvalue is initialized if it is a variable
  4676. IsVariableInitialized(&rctx->type, node);
  4677. if( lvalue->IsPrimitive() )
  4678. {
  4679. if( rctx->type.dataType.IsPrimitive() )
  4680. {
  4681. if( rctx->type.dataType.IsReference() )
  4682. {
  4683. // Cannot do implicit conversion of references so we first convert the reference to a variable
  4684. ConvertToVariableNotIn(rctx, lvalueExpr);
  4685. }
  4686. }
  4687. // Implicitly convert the value to the right type
  4688. ImplicitConversion(rctx, *lvalue, node, asIC_IMPLICIT_CONV);
  4689. // Check data type
  4690. if( !lvalue->IsEqualExceptRefAndConst(rctx->type.dataType) )
  4691. {
  4692. asCString str;
  4693. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lvalue->Format(outFunc->nameSpace).AddressOf());
  4694. Error(str, node);
  4695. rctx->type.SetDummy();
  4696. }
  4697. // Make sure the rvalue is a variable
  4698. if( !rctx->type.isVariable )
  4699. ConvertToVariableNotIn(rctx, lvalueExpr);
  4700. }
  4701. else
  4702. {
  4703. asCDataType to = *lvalue;
  4704. to.MakeReference(false);
  4705. // TODO: ImplicitConversion should know to do this by itself
  4706. // First convert to a handle which will do a reference cast
  4707. if( !lvalue->IsObjectHandle() &&
  4708. (lvalue->GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) )
  4709. to.MakeHandle(true);
  4710. // Don't allow the implicit conversion to create an object
  4711. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true, !toTemporary);
  4712. if( !lvalue->IsObjectHandle() &&
  4713. (lvalue->GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) )
  4714. {
  4715. // Then convert to a reference, which will validate the handle
  4716. to.MakeHandle(false);
  4717. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true, !toTemporary);
  4718. }
  4719. // Check data type
  4720. if( !lvalue->IsEqualExceptRefAndConst(rctx->type.dataType) )
  4721. {
  4722. asCString str;
  4723. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lvalue->Format(outFunc->nameSpace).AddressOf());
  4724. Error(str, node);
  4725. }
  4726. else
  4727. {
  4728. // If the assignment will be made with the copy behaviour then the rvalue must not be a reference
  4729. asASSERT(!lvalue->IsObject() || !rctx->type.dataType.IsReference());
  4730. }
  4731. }
  4732. // Unreserve variables
  4733. reservedVariables.SetLength(l);
  4734. }
  4735. bool asCCompiler::IsLValue(asCExprValue &type)
  4736. {
  4737. if( !type.isLValue ) return false;
  4738. if( type.dataType.IsReadOnly() ) return false;
  4739. if( !type.dataType.IsObject() && !type.isVariable && !type.dataType.IsReference() ) return false;
  4740. return true;
  4741. }
  4742. int asCCompiler::PerformAssignment(asCExprValue *lvalue, asCExprValue *rvalue, asCByteCode *bc, asCScriptNode *node)
  4743. {
  4744. if( lvalue->dataType.IsReadOnly() )
  4745. {
  4746. Error(TXT_REF_IS_READ_ONLY, node);
  4747. return -1;
  4748. }
  4749. if( lvalue->dataType.IsPrimitive() )
  4750. {
  4751. if( lvalue->isVariable )
  4752. {
  4753. // Copy the value between the variables directly
  4754. if( lvalue->dataType.GetSizeInMemoryDWords() == 1 )
  4755. bc->InstrW_W(asBC_CpyVtoV4, lvalue->stackOffset, rvalue->stackOffset);
  4756. else
  4757. bc->InstrW_W(asBC_CpyVtoV8, lvalue->stackOffset, rvalue->stackOffset);
  4758. // Mark variable as initialized
  4759. sVariable *v = variables->GetVariableByOffset(lvalue->stackOffset);
  4760. if( v ) v->isInitialized = true;
  4761. }
  4762. else if( lvalue->dataType.IsReference() )
  4763. {
  4764. // Copy the value of the variable to the reference in the register
  4765. int s = lvalue->dataType.GetSizeInMemoryBytes();
  4766. if( s == 1 )
  4767. bc->InstrSHORT(asBC_WRTV1, rvalue->stackOffset);
  4768. else if( s == 2 )
  4769. bc->InstrSHORT(asBC_WRTV2, rvalue->stackOffset);
  4770. else if( s == 4 )
  4771. bc->InstrSHORT(asBC_WRTV4, rvalue->stackOffset);
  4772. else if( s == 8 )
  4773. bc->InstrSHORT(asBC_WRTV8, rvalue->stackOffset);
  4774. }
  4775. else
  4776. {
  4777. Error(TXT_NOT_VALID_LVALUE, node);
  4778. return -1;
  4779. }
  4780. }
  4781. else if( !lvalue->isExplicitHandle )
  4782. {
  4783. asCExprContext ctx(engine);
  4784. ctx.type = *lvalue;
  4785. Dereference(&ctx, true);
  4786. *lvalue = ctx.type;
  4787. bc->AddCode(&ctx.bc);
  4788. asSTypeBehaviour *beh = lvalue->dataType.GetBehaviour();
  4789. if( beh && beh->copy && beh->copy != engine->scriptTypeBehaviours.beh.copy )
  4790. {
  4791. asCExprContext res(engine);
  4792. PerformFunctionCall(beh->copy, &res, false, 0, CastToObjectType(lvalue->dataType.GetTypeInfo()));
  4793. bc->AddCode(&res.bc);
  4794. *lvalue = res.type;
  4795. }
  4796. else if( beh && beh->copy == engine->scriptTypeBehaviours.beh.copy )
  4797. {
  4798. // Call the default copy operator for script classes
  4799. // This is done differently because the default copy operator
  4800. // is registered as returning int&, but in reality it returns
  4801. // a reference to the object.
  4802. // TODO: Avoid this special case by implementing a copystub for
  4803. // script classes that uses the default copy operator
  4804. bc->Call(asBC_CALLSYS, beh->copy, 2*AS_PTR_SIZE);
  4805. bc->Instr(asBC_PshRPtr);
  4806. }
  4807. else
  4808. {
  4809. // Default copy operator
  4810. if( lvalue->dataType.GetSizeInMemoryDWords() == 0 ||
  4811. !(lvalue->dataType.GetTypeInfo()->flags & asOBJ_POD) )
  4812. {
  4813. asCString msg;
  4814. msg.Format(TXT_NO_DEFAULT_COPY_OP_FOR_s, lvalue->dataType.GetTypeInfo()->name.AddressOf());
  4815. Error(msg, node);
  4816. return -1;
  4817. }
  4818. // Copy larger data types from a reference
  4819. // TODO: runtime optimize: COPY should pop both arguments and store the reference in the register.
  4820. bc->InstrSHORT_DW(asBC_COPY, (short)lvalue->dataType.GetSizeInMemoryDWords(), engine->GetTypeIdFromDataType(lvalue->dataType));
  4821. }
  4822. }
  4823. else
  4824. {
  4825. // TODO: The object handle can be stored in a variable as well
  4826. if( !lvalue->dataType.IsReference() )
  4827. {
  4828. Error(TXT_NOT_VALID_REFERENCE, node);
  4829. return -1;
  4830. }
  4831. if( lvalue->dataType.IsFuncdef() )
  4832. bc->InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  4833. else
  4834. bc->InstrPTR(asBC_REFCPY, lvalue->dataType.GetTypeInfo());
  4835. // Mark variable as initialized
  4836. if( variables )
  4837. {
  4838. sVariable *v = variables->GetVariableByOffset(lvalue->stackOffset);
  4839. if( v ) v->isInitialized = true;
  4840. }
  4841. }
  4842. return 0;
  4843. }
  4844. bool asCCompiler::CompileRefCast(asCExprContext *ctx, const asCDataType &to, bool isExplicit, asCScriptNode *node, bool generateCode)
  4845. {
  4846. bool conversionDone = false;
  4847. asCArray<int> ops;
  4848. // A ref cast must not remove the constness
  4849. bool isConst = ctx->type.dataType.IsObjectConst();
  4850. // Find a suitable opCast or opImplCast method
  4851. asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  4852. for( asUINT n = 0; ot && n < ot->methods.GetLength(); n++ )
  4853. {
  4854. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  4855. if( (isExplicit && func->name == "opCast") ||
  4856. func->name == "opImplCast" )
  4857. {
  4858. // Is the operator for the output type?
  4859. if( func->returnType.GetTypeInfo() != to.GetTypeInfo() )
  4860. continue;
  4861. // Can't call a non-const function on a const object
  4862. if( isConst && !func->IsReadOnly() )
  4863. continue;
  4864. ops.PushLast(func->id);
  4865. }
  4866. }
  4867. // Filter the list by constness to remove const methods if there are matching non-const methods
  4868. FilterConst(ops, !isConst);
  4869. // If there is multiple matches, then pick the most appropriate one
  4870. if (ops.GetLength() > 1)
  4871. {
  4872. // This should only happen if an explicit cast is compiled
  4873. // and the type has both the opCast and opImplCast
  4874. asASSERT(isExplicit);
  4875. asASSERT(ops.GetLength() == 2);
  4876. for (asUINT n = 0; n < ops.GetLength(); n++)
  4877. {
  4878. asCScriptFunction *func = engine->scriptFunctions[ops[n]];
  4879. if (func->name == "opImplCast")
  4880. {
  4881. ops.RemoveIndex(n);
  4882. n--;
  4883. }
  4884. }
  4885. }
  4886. // Should only have one behaviour for each output type
  4887. if( ops.GetLength() == 1 )
  4888. {
  4889. conversionDone = true;
  4890. if( generateCode )
  4891. {
  4892. // TODO: runtime optimize: Instead of producing bytecode for checking if the handle is
  4893. // null, we can create a special CALLSYS instruction that checks
  4894. // if the object pointer is null and if so sets the object register
  4895. // to null directly without executing the function.
  4896. //
  4897. // Alternatively I could force the ref cast behaviours be global
  4898. // functions with 1 parameter, even though they should still be
  4899. // registered with RegisterObjectBehaviour()
  4900. if( (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_NOHANDLE))
  4901. {
  4902. // Add code to avoid calling the cast behaviour if the handle is already null,
  4903. // because that will raise a null pointer exception due to the cast behaviour
  4904. // being a class method, and the this pointer cannot be null.
  4905. if (!ctx->type.isVariable)
  4906. {
  4907. Dereference(ctx, true);
  4908. ConvertToVariable(ctx);
  4909. }
  4910. // The reference on the stack will not be used
  4911. ctx->bc.Instr(asBC_PopPtr);
  4912. // TODO: runtime optimize: should have immediate comparison for null pointer
  4913. int offset = AllocateVariable(asCDataType::CreateNullHandle(), true);
  4914. // 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)
  4915. ctx->bc.InstrSHORT(asBC_ClrVPtr, (asWORD)offset);
  4916. ctx->bc.InstrW_W(asBC_CmpPtr, ctx->type.stackOffset, offset);
  4917. DeallocateVariable(offset);
  4918. int afterLabel = nextLabel++;
  4919. ctx->bc.InstrDWORD(asBC_JZ, afterLabel);
  4920. // Call the cast operator
  4921. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  4922. ctx->bc.Instr(asBC_RDSPtr);
  4923. ctx->type.dataType.MakeReference(false);
  4924. asCArray<asCExprContext *> args;
  4925. MakeFunctionCall(ctx, ops[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
  4926. ctx->bc.Instr(asBC_PopPtr);
  4927. int endLabel = nextLabel++;
  4928. ctx->bc.InstrINT(asBC_JMP, endLabel);
  4929. ctx->bc.Label((short)afterLabel);
  4930. // Make a NULL pointer
  4931. ctx->bc.InstrSHORT(asBC_ClrVPtr, ctx->type.stackOffset);
  4932. ctx->bc.Label((short)endLabel);
  4933. // Push the reference to the handle on the stack
  4934. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  4935. }
  4936. else
  4937. {
  4938. // Value types cannot be null, so there is no need to check for this.
  4939. // Likewise for reference types that are registered with asOBJ_NOHANDLE
  4940. // as those are only expected as registered global properties that cannot
  4941. // be modified anyway.
  4942. // Call the cast operator
  4943. asCArray<asCExprContext *> args;
  4944. MakeFunctionCall(ctx, ops[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
  4945. }
  4946. }
  4947. else
  4948. {
  4949. asCScriptFunction *func = engine->scriptFunctions[ops[0]];
  4950. ctx->type.Set(func->returnType);
  4951. }
  4952. }
  4953. else if( ops.GetLength() == 0 && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) && to.IsObjectHandle() )
  4954. {
  4955. // Check for the generic ref cast method: void opCast(?&out)
  4956. // This option only works if the expected type is a handle
  4957. for( asUINT n = 0; ot && n < ot->methods.GetLength(); n++ )
  4958. {
  4959. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  4960. if( (isExplicit && func->name == "opCast") ||
  4961. func->name == "opImplCast" )
  4962. {
  4963. // Does the operator take the ?&out parameter?
  4964. if( func->returnType.GetTokenType() != ttVoid ||
  4965. func->parameterTypes.GetLength() != 1 ||
  4966. func->parameterTypes[0].GetTokenType() != ttQuestion ||
  4967. func->inOutFlags[0] != asTM_OUTREF )
  4968. continue;
  4969. ops.PushLast(func->id);
  4970. }
  4971. }
  4972. // Filter the list by constness to remove const methods if there are matching non-const methods
  4973. FilterConst(ops, !isConst);
  4974. // If there is multiple matches, then pick the most appropriate one
  4975. if (ops.GetLength() > 1)
  4976. {
  4977. // This should only happen if an explicit cast is compiled
  4978. // and the type has both the opCast and opImplCast
  4979. asASSERT(isExplicit);
  4980. asASSERT(ops.GetLength() == 2);
  4981. for (asUINT n = 0; n < ops.GetLength(); n++)
  4982. {
  4983. asCScriptFunction *func = engine->scriptFunctions[ops[n]];
  4984. if (func->name == "opImplCast")
  4985. {
  4986. ops.RemoveIndex(n);
  4987. n--;
  4988. }
  4989. }
  4990. }
  4991. if( ops.GetLength() == 1 )
  4992. {
  4993. conversionDone = true;
  4994. if( generateCode )
  4995. {
  4996. int afterLabel = 0;
  4997. bool doNullCheck = false;
  4998. bool releaseTempVariable = false;
  4999. asCExprContext tmp(engine);
  5000. if ((ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_NOHANDLE))
  5001. {
  5002. tmp.bc.AddCode(&ctx->bc);
  5003. tmp.Merge(ctx);
  5004. // Add code to avoid calling the cast behaviour if the handle is already null,
  5005. // because that will raise a null pointer exception due to the cast behaviour
  5006. // being a class method, and the this pointer cannot be null.
  5007. doNullCheck = true;
  5008. if (!ctx->type.isVariable)
  5009. {
  5010. Dereference(&tmp, true);
  5011. ConvertToVariable(&tmp);
  5012. releaseTempVariable = true;
  5013. }
  5014. // The reference on the stack will not be used
  5015. tmp.bc.Instr(asBC_PopPtr);
  5016. // TODO: runtime optimize: should have immediate comparison for null pointer
  5017. int offset = AllocateVariable(asCDataType::CreateNullHandle(), true);
  5018. // 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)
  5019. tmp.bc.InstrSHORT(asBC_ClrVPtr, (asWORD)offset);
  5020. tmp.bc.InstrW_W(asBC_CmpPtr, tmp.type.stackOffset, offset);
  5021. DeallocateVariable(offset);
  5022. afterLabel = nextLabel++;
  5023. tmp.bc.InstrDWORD(asBC_JZ, afterLabel);
  5024. // Place the object pointer on the stack
  5025. ctx->bc.InstrSHORT(asBC_PSF, (short)tmp.type.stackOffset);
  5026. }
  5027. // Allocate a temporary variable of the requested handle type
  5028. int stackOffset = AllocateVariableNotIn(to, true, false, ctx);
  5029. // Pass the reference of that variable to the function as output parameter
  5030. asCDataType toRef(to);
  5031. toRef.MakeReference(true);
  5032. asCArray<asCExprContext *> args;
  5033. asCExprContext arg(engine);
  5034. arg.bc.InstrSHORT(asBC_PSF, (short)stackOffset);
  5035. // Don't mark the variable as temporary, so it won't be freed too early
  5036. arg.type.SetVariable(toRef, stackOffset, false);
  5037. arg.type.isLValue = true;
  5038. arg.type.isExplicitHandle = true;
  5039. args.PushLast(&arg);
  5040. // Call the behaviour method
  5041. MakeFunctionCall(ctx, ops[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
  5042. if (doNullCheck)
  5043. {
  5044. // Add the call after the null check
  5045. tmp.bc.AddCode(&ctx->bc);
  5046. ctx->bc.AddCode(&tmp.bc);
  5047. int endLabel = nextLabel++;
  5048. ctx->bc.InstrINT(asBC_JMP, endLabel);
  5049. ctx->bc.Label((short)afterLabel);
  5050. // Make a NULL pointer
  5051. ctx->bc.InstrSHORT(asBC_ClrVPtr, (short)stackOffset);
  5052. ctx->bc.Label((short)endLabel);
  5053. }
  5054. // If a temporary variable was allocated in the tmp to convert
  5055. // the input expression to a variable, it must be released here
  5056. if (releaseTempVariable && tmp.type.isTemporary)
  5057. ReleaseTemporaryVariable(tmp.type.stackOffset, &ctx->bc);
  5058. // Use the reference to the variable as the result of the expression
  5059. // Now we can mark the variable as temporary
  5060. ctx->type.SetVariable(toRef, stackOffset, true);
  5061. ctx->bc.InstrSHORT(asBC_PSF, (short)stackOffset);
  5062. }
  5063. else
  5064. {
  5065. // All casts are legal
  5066. ctx->type.Set(to);
  5067. }
  5068. }
  5069. }
  5070. // If the script object didn't implement a matching opCast or opImplCast
  5071. // then check if the desired type is part of the hierarchy
  5072. if( !conversionDone && (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) )
  5073. {
  5074. // We need it to be a reference
  5075. if( !ctx->type.dataType.IsReference() )
  5076. {
  5077. asCDataType toRef = ctx->type.dataType;
  5078. toRef.MakeReference(true);
  5079. ImplicitConversion(ctx, toRef, 0, isExplicit ? asIC_EXPLICIT_REF_CAST : asIC_IMPLICIT_CONV, generateCode);
  5080. }
  5081. if( isExplicit )
  5082. {
  5083. // Allow dynamic cast between object handles (only for script objects).
  5084. // At run time this may result in a null handle,
  5085. // which when used will throw an exception
  5086. conversionDone = true;
  5087. if( generateCode )
  5088. {
  5089. ctx->bc.InstrDWORD(asBC_Cast, engine->GetTypeIdFromDataType(to));
  5090. // Allocate a temporary variable for the returned object
  5091. int returnOffset = AllocateVariable(to, true);
  5092. // Move the pointer from the object register to the temporary variable
  5093. ctx->bc.InstrSHORT(asBC_STOREOBJ, (short)returnOffset);
  5094. ctx->bc.InstrSHORT(asBC_PSF, (short)returnOffset);
  5095. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5096. ctx->type.SetVariable(to, returnOffset, true);
  5097. ctx->type.dataType.MakeReference(true);
  5098. }
  5099. else
  5100. {
  5101. ctx->type.dataType = to;
  5102. ctx->type.dataType.MakeReference(true);
  5103. }
  5104. }
  5105. else
  5106. {
  5107. if( CastToObjectType(ctx->type.dataType.GetTypeInfo())->DerivesFrom(to.GetTypeInfo()) )
  5108. {
  5109. conversionDone = true;
  5110. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5111. }
  5112. }
  5113. // A ref cast must not remove the constness
  5114. if( isConst )
  5115. ctx->type.dataType.MakeHandleToConst(true);
  5116. }
  5117. return conversionDone;
  5118. }
  5119. asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asCExprContext *ctx, const asCDataType &toOrig, asCScriptNode *node, EImplicitConv convType, bool generateCode)
  5120. {
  5121. asCDataType to = toOrig;
  5122. to.MakeReference(false);
  5123. asASSERT( !ctx->type.dataType.IsReference() );
  5124. // Maybe no conversion is needed
  5125. if( to.IsEqualExceptConst(ctx->type.dataType) )
  5126. {
  5127. // A primitive is const or not
  5128. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  5129. return asCC_NO_CONV;
  5130. }
  5131. // Is the conversion an ambiguous enum value?
  5132. if( ctx->enumValue != "" )
  5133. {
  5134. if( to.IsEnumType() )
  5135. {
  5136. // Attempt to resolve an ambiguous enum value
  5137. asCDataType out;
  5138. asDWORD value;
  5139. if( builder->GetEnumValueFromType(CastToEnumType(to.GetTypeInfo()), ctx->enumValue.AddressOf(), out, value) )
  5140. {
  5141. ctx->type.SetConstantDW(out, value);
  5142. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  5143. // Reset the enum value since we no longer need it
  5144. ctx->enumValue = "";
  5145. // It wasn't really a conversion. The compiler just resolved the ambiguity (or not)
  5146. return asCC_NO_CONV;
  5147. }
  5148. }
  5149. // The enum value is ambiguous
  5150. if( node && generateCode )
  5151. Error(TXT_FOUND_MULTIPLE_ENUM_VALUES, node);
  5152. // Set a dummy to allow the compiler to try to continue the conversion
  5153. ctx->type.SetDummy();
  5154. }
  5155. // Determine the cost of this conversion
  5156. asUINT cost = asCC_NO_CONV;
  5157. if( (to.IsIntegerType() || to.IsUnsignedType()) && (ctx->type.dataType.IsFloatType() || ctx->type.dataType.IsDoubleType()) )
  5158. cost = asCC_INT_FLOAT_CONV;
  5159. else if ((to.IsFloatType() || to.IsDoubleType()) && (ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType()))
  5160. cost = asCC_INT_FLOAT_CONV;
  5161. else if (ctx->type.dataType.IsEnumType() && to.IsIntegerType() && to.GetSizeInMemoryBytes() == ctx->type.dataType.GetSizeInMemoryBytes() )
  5162. cost = asCC_ENUM_SAME_SIZE_CONV;
  5163. else if (ctx->type.dataType.IsEnumType() && to.IsIntegerType() && to.GetSizeInMemoryBytes() != ctx->type.dataType.GetSizeInMemoryBytes())
  5164. cost = asCC_ENUM_DIFF_SIZE_CONV;
  5165. else if( to.IsUnsignedType() && ctx->type.dataType.IsIntegerType() )
  5166. cost = asCC_SIGNED_CONV;
  5167. else if( to.IsIntegerType() && ctx->type.dataType.IsUnsignedType() )
  5168. cost = asCC_SIGNED_CONV;
  5169. else if( to.GetSizeInMemoryBytes() != ctx->type.dataType.GetSizeInMemoryBytes() )
  5170. cost = asCC_PRIMITIVE_SIZE_CONV;
  5171. // Start by implicitly converting constant values
  5172. if( ctx->type.isConstant )
  5173. {
  5174. ImplicitConversionConstant(ctx, to, generateCode ? node : 0, convType);
  5175. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  5176. return cost;
  5177. }
  5178. // Allow implicit conversion between numbers
  5179. if( generateCode )
  5180. {
  5181. // When generating the code the decision has already been made, so we don't bother determining the cost
  5182. // Convert smaller types to 32bit first
  5183. int s = ctx->type.dataType.GetSizeInMemoryBytes();
  5184. if( s < 4 )
  5185. {
  5186. ConvertToTempVariable(ctx);
  5187. if( ctx->type.dataType.IsIntegerType() )
  5188. {
  5189. if( s == 1 )
  5190. ctx->bc.InstrSHORT(asBC_sbTOi, ctx->type.stackOffset);
  5191. else if( s == 2 )
  5192. ctx->bc.InstrSHORT(asBC_swTOi, ctx->type.stackOffset);
  5193. ctx->type.dataType.SetTokenType(ttInt);
  5194. }
  5195. else if( ctx->type.dataType.IsUnsignedType() )
  5196. {
  5197. if( s == 1 )
  5198. ctx->bc.InstrSHORT(asBC_ubTOi, ctx->type.stackOffset);
  5199. else if( s == 2 )
  5200. ctx->bc.InstrSHORT(asBC_uwTOi, ctx->type.stackOffset);
  5201. ctx->type.dataType.SetTokenType(ttUInt);
  5202. }
  5203. }
  5204. if( (to.IsIntegerType() && to.GetSizeInMemoryDWords() == 1 && !to.IsEnumType()) ||
  5205. (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST) )
  5206. {
  5207. if( ctx->type.dataType.IsIntegerType() ||
  5208. ctx->type.dataType.IsUnsignedType() )
  5209. {
  5210. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  5211. {
  5212. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5213. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5214. }
  5215. else
  5216. {
  5217. ConvertToTempVariable(ctx);
  5218. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5219. int offset = AllocateVariable(to, true);
  5220. ctx->bc.InstrW_W(asBC_i64TOi, offset, ctx->type.stackOffset);
  5221. ctx->type.SetVariable(to, offset, true);
  5222. }
  5223. }
  5224. else if( ctx->type.dataType.IsFloatType() )
  5225. {
  5226. ConvertToTempVariable(ctx);
  5227. ctx->bc.InstrSHORT(asBC_fTOi, ctx->type.stackOffset);
  5228. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5229. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5230. if( convType != asIC_EXPLICIT_VAL_CAST )
  5231. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  5232. }
  5233. else if( ctx->type.dataType.IsDoubleType() )
  5234. {
  5235. ConvertToTempVariable(ctx);
  5236. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5237. int offset = AllocateVariable(to, true);
  5238. ctx->bc.InstrW_W(asBC_dTOi, offset, ctx->type.stackOffset);
  5239. ctx->type.SetVariable(to, offset, true);
  5240. if( convType != asIC_EXPLICIT_VAL_CAST )
  5241. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  5242. }
  5243. // Convert to smaller integer if necessary
  5244. s = to.GetSizeInMemoryBytes();
  5245. if( s < 4 )
  5246. {
  5247. ConvertToTempVariable(ctx);
  5248. if( s == 1 )
  5249. ctx->bc.InstrSHORT(asBC_iTOb, ctx->type.stackOffset);
  5250. else if( s == 2 )
  5251. ctx->bc.InstrSHORT(asBC_iTOw, ctx->type.stackOffset);
  5252. }
  5253. }
  5254. else if( to.IsIntegerType() && to.GetSizeInMemoryDWords() == 2 )
  5255. {
  5256. if( ctx->type.dataType.IsIntegerType() ||
  5257. ctx->type.dataType.IsUnsignedType() )
  5258. {
  5259. if( ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  5260. {
  5261. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5262. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5263. }
  5264. else
  5265. {
  5266. ConvertToTempVariable(ctx);
  5267. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5268. int offset = AllocateVariable(to, true);
  5269. if( ctx->type.dataType.IsUnsignedType() )
  5270. ctx->bc.InstrW_W(asBC_uTOi64, offset, ctx->type.stackOffset);
  5271. else
  5272. ctx->bc.InstrW_W(asBC_iTOi64, offset, ctx->type.stackOffset);
  5273. ctx->type.SetVariable(to, offset, true);
  5274. }
  5275. }
  5276. else if( ctx->type.dataType.IsFloatType() )
  5277. {
  5278. ConvertToTempVariable(ctx);
  5279. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5280. int offset = AllocateVariable(to, true);
  5281. ctx->bc.InstrW_W(asBC_fTOi64, offset, ctx->type.stackOffset);
  5282. ctx->type.SetVariable(to, offset, true);
  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. ctx->bc.InstrSHORT(asBC_dTOi64, ctx->type.stackOffset);
  5290. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5291. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5292. if( convType != asIC_EXPLICIT_VAL_CAST )
  5293. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  5294. }
  5295. }
  5296. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 1 )
  5297. {
  5298. if( ctx->type.dataType.IsIntegerType() ||
  5299. ctx->type.dataType.IsUnsignedType() )
  5300. {
  5301. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  5302. {
  5303. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5304. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5305. }
  5306. else
  5307. {
  5308. ConvertToTempVariable(ctx);
  5309. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5310. int offset = AllocateVariable(to, true);
  5311. ctx->bc.InstrW_W(asBC_i64TOi, offset, ctx->type.stackOffset);
  5312. ctx->type.SetVariable(to, offset, true);
  5313. }
  5314. }
  5315. else if( ctx->type.dataType.IsFloatType() )
  5316. {
  5317. ConvertToTempVariable(ctx);
  5318. ctx->bc.InstrSHORT(asBC_fTOu, ctx->type.stackOffset);
  5319. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5320. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5321. if( convType != asIC_EXPLICIT_VAL_CAST )
  5322. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  5323. }
  5324. else if( ctx->type.dataType.IsDoubleType() )
  5325. {
  5326. ConvertToTempVariable(ctx);
  5327. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5328. int offset = AllocateVariable(to, true);
  5329. ctx->bc.InstrW_W(asBC_dTOu, offset, ctx->type.stackOffset);
  5330. ctx->type.SetVariable(to, offset, true);
  5331. if( convType != asIC_EXPLICIT_VAL_CAST )
  5332. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  5333. }
  5334. // Convert to smaller integer if necessary
  5335. s = to.GetSizeInMemoryBytes();
  5336. if( s < 4 )
  5337. {
  5338. ConvertToTempVariable(ctx);
  5339. if( s == 1 )
  5340. ctx->bc.InstrSHORT(asBC_iTOb, ctx->type.stackOffset);
  5341. else if( s == 2 )
  5342. ctx->bc.InstrSHORT(asBC_iTOw, ctx->type.stackOffset);
  5343. }
  5344. }
  5345. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 2 )
  5346. {
  5347. if( ctx->type.dataType.IsIntegerType() ||
  5348. ctx->type.dataType.IsUnsignedType() )
  5349. {
  5350. if( ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  5351. {
  5352. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5353. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5354. }
  5355. else
  5356. {
  5357. ConvertToTempVariable(ctx);
  5358. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5359. int offset = AllocateVariable(to, true);
  5360. if( ctx->type.dataType.IsUnsignedType() )
  5361. ctx->bc.InstrW_W(asBC_uTOi64, offset, ctx->type.stackOffset);
  5362. else
  5363. ctx->bc.InstrW_W(asBC_iTOi64, offset, ctx->type.stackOffset);
  5364. ctx->type.SetVariable(to, offset, true);
  5365. }
  5366. }
  5367. else if( ctx->type.dataType.IsFloatType() )
  5368. {
  5369. ConvertToTempVariable(ctx);
  5370. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5371. int offset = AllocateVariable(to, true);
  5372. ctx->bc.InstrW_W(asBC_fTOu64, offset, ctx->type.stackOffset);
  5373. ctx->type.SetVariable(to, offset, true);
  5374. if( convType != asIC_EXPLICIT_VAL_CAST )
  5375. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  5376. }
  5377. else if( ctx->type.dataType.IsDoubleType() )
  5378. {
  5379. ConvertToTempVariable(ctx);
  5380. ctx->bc.InstrSHORT(asBC_dTOu64, ctx->type.stackOffset);
  5381. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5382. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5383. if( convType != asIC_EXPLICIT_VAL_CAST )
  5384. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  5385. }
  5386. }
  5387. else if( to.IsFloatType() )
  5388. {
  5389. if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  5390. {
  5391. ConvertToTempVariable(ctx);
  5392. ctx->bc.InstrSHORT(asBC_iTOf, ctx->type.stackOffset);
  5393. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5394. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5395. }
  5396. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  5397. {
  5398. ConvertToTempVariable(ctx);
  5399. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5400. int offset = AllocateVariable(to, true);
  5401. ctx->bc.InstrW_W(asBC_i64TOf, offset, ctx->type.stackOffset);
  5402. ctx->type.SetVariable(to, offset, true);
  5403. }
  5404. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  5405. {
  5406. ConvertToTempVariable(ctx);
  5407. ctx->bc.InstrSHORT(asBC_uTOf, ctx->type.stackOffset);
  5408. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5409. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5410. }
  5411. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  5412. {
  5413. ConvertToTempVariable(ctx);
  5414. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5415. int offset = AllocateVariable(to, true);
  5416. ctx->bc.InstrW_W(asBC_u64TOf, offset, ctx->type.stackOffset);
  5417. ctx->type.SetVariable(to, offset, true);
  5418. }
  5419. else if( ctx->type.dataType.IsDoubleType() )
  5420. {
  5421. ConvertToTempVariable(ctx);
  5422. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5423. int offset = AllocateVariable(to, true);
  5424. ctx->bc.InstrW_W(asBC_dTOf, offset, ctx->type.stackOffset);
  5425. ctx->type.SetVariable(to, offset, true);
  5426. }
  5427. }
  5428. else if( to.IsDoubleType() )
  5429. {
  5430. if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  5431. {
  5432. ConvertToTempVariable(ctx);
  5433. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5434. int offset = AllocateVariable(to, true);
  5435. ctx->bc.InstrW_W(asBC_iTOd, offset, ctx->type.stackOffset);
  5436. ctx->type.SetVariable(to, offset, true);
  5437. }
  5438. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  5439. {
  5440. ConvertToTempVariable(ctx);
  5441. ctx->bc.InstrSHORT(asBC_i64TOd, ctx->type.stackOffset);
  5442. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5443. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5444. }
  5445. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  5446. {
  5447. ConvertToTempVariable(ctx);
  5448. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5449. int offset = AllocateVariable(to, true);
  5450. ctx->bc.InstrW_W(asBC_uTOd, offset, ctx->type.stackOffset);
  5451. ctx->type.SetVariable(to, offset, true);
  5452. }
  5453. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  5454. {
  5455. ConvertToTempVariable(ctx);
  5456. ctx->bc.InstrSHORT(asBC_u64TOd, ctx->type.stackOffset);
  5457. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5458. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5459. }
  5460. else if( ctx->type.dataType.IsFloatType() )
  5461. {
  5462. ConvertToTempVariable(ctx);
  5463. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5464. int offset = AllocateVariable(to, true);
  5465. ctx->bc.InstrW_W(asBC_fTOd, offset, ctx->type.stackOffset);
  5466. ctx->type.SetVariable(to, offset, true);
  5467. }
  5468. }
  5469. }
  5470. else
  5471. {
  5472. if( ((to.IsIntegerType() && !to.IsEnumType()) || to.IsUnsignedType() ||
  5473. to.IsFloatType() || to.IsDoubleType() ||
  5474. (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST)) &&
  5475. (ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType() ||
  5476. ctx->type.dataType.IsFloatType() || ctx->type.dataType.IsDoubleType()) )
  5477. {
  5478. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5479. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5480. }
  5481. }
  5482. // Primitive types on the stack, can be const or non-const
  5483. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  5484. return cost;
  5485. }
  5486. asUINT asCCompiler::ImplicitConvLambdaToFunc(asCExprContext *ctx, const asCDataType &to, asCScriptNode * /*node*/, EImplicitConv /*convType*/, bool generateCode)
  5487. {
  5488. asASSERT( to.IsFuncdef() && ctx->IsLambda() );
  5489. asCScriptFunction *funcDef = CastToFuncdefType(to.GetTypeInfo())->funcdef;
  5490. // Check that the lambda has the correct amount of arguments
  5491. asUINT count = 0;
  5492. asCScriptNode *argNode = ctx->exprNode->firstChild;
  5493. while( argNode->nodeType != snStatementBlock )
  5494. {
  5495. // Check if the specified parameter types match the funcdef
  5496. if (argNode->nodeType == snDataType)
  5497. {
  5498. asCDataType dt = builder->CreateDataTypeFromNode(argNode, script, outFunc->nameSpace, false, outFunc->objectType);
  5499. asETypeModifiers inOutFlag;
  5500. dt = builder->ModifyDataTypeFromNode(dt, argNode->next, script, &inOutFlag, 0);
  5501. if (count >= funcDef->parameterTypes.GetLength() ||
  5502. funcDef->parameterTypes[count] != dt ||
  5503. funcDef->inOutFlags[count] != inOutFlag)
  5504. return asCC_NO_CONV;
  5505. argNode = argNode->next;
  5506. }
  5507. if( argNode->nodeType == snIdentifier )
  5508. count++;
  5509. argNode = argNode->next;
  5510. }
  5511. if (funcDef->parameterTypes.GetLength() != count)
  5512. return asCC_NO_CONV;
  5513. asASSERT(argNode->nodeType == snStatementBlock);
  5514. // The Lambda can be used as this funcdef
  5515. ctx->type.dataType = to;
  5516. if( generateCode )
  5517. {
  5518. // Build a unique name for the anonymous function
  5519. asCString name;
  5520. if( m_globalVar )
  5521. name.Format("$%s$%d", m_globalVar->name.AddressOf(), numLambdas++);
  5522. else
  5523. name.Format("$%s$%d", outFunc->GetDeclaration(), numLambdas++);
  5524. // Register the lambda with the builder for later compilation
  5525. asCScriptFunction *func = builder->RegisterLambda(ctx->exprNode, script, funcDef, name, outFunc->nameSpace, outFunc->IsShared());
  5526. asASSERT( func == 0 || funcDef->IsSignatureExceptNameEqual(func) );
  5527. ctx->bc.InstrPTR(asBC_FuncPtr, func);
  5528. // Clear the expression node as it is no longer valid
  5529. ctx->exprNode = 0;
  5530. }
  5531. return asCC_CONST_CONV;
  5532. }
  5533. asUINT asCCompiler::ImplicitConversion(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode, bool allowObjectConstruct)
  5534. {
  5535. asASSERT( ctx->type.dataType.GetTokenType() != ttUnrecognizedToken ||
  5536. ctx->type.dataType.IsNullHandle() ||
  5537. ctx->IsAnonymousInitList() );
  5538. if( to.IsFuncdef() && ctx->IsLambda() )
  5539. return ImplicitConvLambdaToFunc(ctx, to, node, convType, generateCode);
  5540. if (ctx->IsAnonymousInitList())
  5541. {
  5542. if (to.GetBehaviour() && to.GetBehaviour()->listFactory)
  5543. {
  5544. if (generateCode)
  5545. CompileAnonymousInitList(ctx->exprNode, ctx, to);
  5546. else
  5547. ctx->type.dataType = to;
  5548. }
  5549. return asCC_NO_CONV;
  5550. }
  5551. // No conversion from void to any other type
  5552. if( ctx->type.dataType.GetTokenType() == ttVoid )
  5553. return asCC_NO_CONV;
  5554. // No conversion from class method to any type (it requires delegate)
  5555. if( ctx->IsClassMethod() )
  5556. return asCC_NO_CONV;
  5557. // Do we want a var type?
  5558. if( to.GetTokenType() == ttQuestion )
  5559. {
  5560. // Any type can be converted to a var type, but only when not generating code
  5561. asASSERT( !generateCode );
  5562. ctx->type.dataType = to;
  5563. return asCC_VARIABLE_CONV;
  5564. }
  5565. // Do we want a primitive?
  5566. else if( to.IsPrimitive() )
  5567. {
  5568. if( !ctx->type.dataType.IsPrimitive() )
  5569. return ImplicitConvObjectToPrimitive(ctx, to, node, convType, generateCode);
  5570. else
  5571. return ImplicitConvPrimitiveToPrimitive(ctx, to, node, convType, generateCode);
  5572. }
  5573. else // The target is a complex type
  5574. {
  5575. if( ctx->type.dataType.IsPrimitive() )
  5576. return ImplicitConvPrimitiveToObject(ctx, to, node, convType, generateCode, allowObjectConstruct);
  5577. else if( ctx->type.IsNullConstant() || ctx->type.dataType.GetTypeInfo() )
  5578. return ImplicitConvObjectToObject(ctx, to, node, convType, generateCode, allowObjectConstruct);
  5579. }
  5580. return asCC_NO_CONV;
  5581. }
  5582. asUINT asCCompiler::ImplicitConvObjectToPrimitive(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode)
  5583. {
  5584. if( ctx->type.isExplicitHandle )
  5585. {
  5586. // An explicit handle cannot be converted to a primitive
  5587. if( convType != asIC_IMPLICIT_CONV && node )
  5588. {
  5589. asCString str;
  5590. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  5591. Error(str, node);
  5592. }
  5593. return asCC_NO_CONV;
  5594. }
  5595. // Find matching value cast behaviours
  5596. // Here we're only interested in those that convert the type to a primitive type
  5597. asCArray<int> funcs;
  5598. asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  5599. if( ot == 0 )
  5600. {
  5601. if( convType != asIC_IMPLICIT_CONV && node )
  5602. {
  5603. asCString str;
  5604. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  5605. Error(str, node);
  5606. }
  5607. return asCC_NO_CONV;
  5608. }
  5609. if( convType == asIC_EXPLICIT_VAL_CAST )
  5610. {
  5611. for( unsigned int n = 0; n < ot->methods.GetLength(); n++ )
  5612. {
  5613. // accept both implicit and explicit cast
  5614. asCScriptFunction *mthd = engine->scriptFunctions[ot->methods[n]];
  5615. if( (mthd->name == "opConv" || mthd->name == "opImplConv") &&
  5616. mthd->parameterTypes.GetLength() == 0 &&
  5617. mthd->returnType.IsPrimitive() )
  5618. funcs.PushLast(ot->methods[n]);
  5619. }
  5620. }
  5621. else
  5622. {
  5623. for( unsigned int n = 0; n < ot->methods.GetLength(); n++ )
  5624. {
  5625. // accept only implicit cast
  5626. asCScriptFunction *mthd = engine->scriptFunctions[ot->methods[n]];
  5627. if( mthd->name == "opImplConv" &&
  5628. mthd->parameterTypes.GetLength() == 0 &&
  5629. mthd->returnType.IsPrimitive() )
  5630. funcs.PushLast(ot->methods[n]);
  5631. }
  5632. }
  5633. FilterConst(funcs, !ctx->type.dataType.IsReadOnly());
  5634. int funcId = 0;
  5635. if( to.IsMathType() )
  5636. {
  5637. // This matrix describes the priorities of the types to search for, for each target type
  5638. // The first column is the target type, the priorities goes from left to right
  5639. eTokenType matchMtx[10][10] =
  5640. {
  5641. {ttDouble, ttFloat, ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8},
  5642. {ttFloat, ttDouble, ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8},
  5643. {ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8, ttDouble, ttFloat},
  5644. {ttUInt64, ttInt64, ttUInt, ttInt, ttUInt16, ttInt16, ttUInt8, ttInt8, ttDouble, ttFloat},
  5645. {ttInt, ttUInt, ttInt64, ttUInt64, ttInt16, ttUInt16, ttInt8, ttUInt8, ttDouble, ttFloat},
  5646. {ttUInt, ttInt, ttUInt64, ttInt64, ttUInt16, ttInt16, ttUInt8, ttInt8, ttDouble, ttFloat},
  5647. {ttInt16, ttUInt16, ttInt, ttUInt, ttInt64, ttUInt64, ttInt8, ttUInt8, ttDouble, ttFloat},
  5648. {ttUInt16, ttInt16, ttUInt, ttInt, ttUInt64, ttInt64, ttUInt8, ttInt8, ttDouble, ttFloat},
  5649. {ttInt8, ttUInt8, ttInt16, ttUInt16, ttInt, ttUInt, ttInt64, ttUInt64, ttDouble, ttFloat},
  5650. {ttUInt8, ttInt8, ttUInt16, ttInt16, ttUInt, ttInt, ttUInt64, ttInt64, ttDouble, ttFloat},
  5651. };
  5652. // Which row to use?
  5653. eTokenType *row = 0;
  5654. for( unsigned int type = 0; type < 10; type++ )
  5655. {
  5656. if( to.GetTokenType() == matchMtx[type][0] )
  5657. {
  5658. row = &matchMtx[type][0];
  5659. break;
  5660. }
  5661. }
  5662. // Find the best matching cast operator
  5663. if( row )
  5664. {
  5665. asCDataType target(to);
  5666. // Priority goes from left to right in the matrix
  5667. for( unsigned int attempt = 0; attempt < 10 && funcId == 0; attempt++ )
  5668. {
  5669. target.SetTokenType(row[attempt]);
  5670. for( unsigned int n = 0; n < funcs.GetLength(); n++ )
  5671. {
  5672. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[n]);
  5673. if( descr->returnType.IsEqualExceptRefAndConst(target) )
  5674. {
  5675. funcId = funcs[n];
  5676. break;
  5677. }
  5678. }
  5679. }
  5680. }
  5681. }
  5682. else
  5683. {
  5684. // Only accept the exact conversion for non-math types
  5685. // Find the matching cast operator
  5686. for( unsigned int n = 0; n < funcs.GetLength(); n++ )
  5687. {
  5688. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[n]);
  5689. if( descr->returnType.IsEqualExceptRefAndConst(to) )
  5690. {
  5691. funcId = funcs[n];
  5692. break;
  5693. }
  5694. }
  5695. }
  5696. // Did we find a suitable function?
  5697. if( funcId != 0 )
  5698. {
  5699. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  5700. if( generateCode )
  5701. {
  5702. Dereference(ctx, true);
  5703. PerformFunctionCall(funcId, ctx);
  5704. }
  5705. else
  5706. ctx->type.Set(descr->returnType);
  5707. // Allow one more implicit conversion to another primitive type
  5708. return asCC_OBJ_TO_PRIMITIVE_CONV + ImplicitConversion(ctx, to, node, convType, generateCode, false);
  5709. }
  5710. // TODO: clean-up: This part is similar to what is in ImplicitConvObjectValue
  5711. // If no direct conversion is found we should look for the generic form 'void opConv(?&out)'
  5712. funcs.SetLength(0);
  5713. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  5714. {
  5715. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  5716. if( ((convType == asIC_EXPLICIT_VAL_CAST) && func->name == "opConv") ||
  5717. func->name == "opImplConv" )
  5718. {
  5719. // Does the operator take the ?&out parameter?
  5720. if( func->returnType != asCDataType::CreatePrimitive(ttVoid, false) ||
  5721. func->parameterTypes.GetLength() != 1 ||
  5722. func->parameterTypes[0].GetTokenType() != ttQuestion ||
  5723. func->inOutFlags[0] != asTM_OUTREF )
  5724. continue;
  5725. funcs.PushLast(ot->methods[n]);
  5726. }
  5727. }
  5728. FilterConst(funcs, !ctx->type.dataType.IsReadOnly());
  5729. // If there are multiple valid value casts, then we must choose the most appropriate one
  5730. if (funcs.GetLength() > 1)
  5731. {
  5732. // This should only happen in case of explicit value cast and
  5733. // the application has registered both opImplConv and opConv
  5734. asASSERT(convType == asIC_EXPLICIT_VAL_CAST);
  5735. asASSERT(funcs.GetLength() == 2);
  5736. for (asUINT n = 0; n < funcs.GetLength(); n++)
  5737. {
  5738. asCScriptFunction *func = engine->scriptFunctions[funcs[n]];
  5739. if (func->name == "opImplConv")
  5740. {
  5741. funcs.RemoveIndex(n);
  5742. n--;
  5743. }
  5744. }
  5745. }
  5746. if( funcs.GetLength() == 1 )
  5747. {
  5748. if( generateCode )
  5749. {
  5750. // Allocate a temporary variable of the requested type
  5751. int stackOffset = AllocateVariableNotIn(to, true, false, ctx);
  5752. CallDefaultConstructor(to, stackOffset, IsVariableOnHeap(stackOffset), &ctx->bc, node);
  5753. // Pass the reference of that variable to the function as output parameter
  5754. asCDataType toRef(to);
  5755. toRef.MakeReference(true);
  5756. toRef.MakeReadOnly(false);
  5757. asCArray<asCExprContext *> args;
  5758. asCExprContext arg(engine);
  5759. // Don't mark the variable as temporary, so it won't be freed too early
  5760. arg.type.SetVariable(toRef, stackOffset, false);
  5761. arg.type.isLValue = true;
  5762. arg.exprNode = node;
  5763. args.PushLast(&arg);
  5764. // Call the behaviour method
  5765. MakeFunctionCall(ctx, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
  5766. // Use the reference to the variable as the result of the expression
  5767. // Now we can mark the variable as temporary
  5768. toRef.MakeReference(false);
  5769. ctx->type.SetVariable(toRef, stackOffset, true);
  5770. }
  5771. else
  5772. ctx->type.Set(to);
  5773. return asCC_OBJ_TO_PRIMITIVE_CONV;
  5774. }
  5775. if( convType != asIC_IMPLICIT_CONV && node )
  5776. {
  5777. asCString str;
  5778. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  5779. Error(str, node);
  5780. }
  5781. return asCC_NO_CONV;
  5782. }
  5783. asUINT asCCompiler::ImplicitConvObjectRef(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode)
  5784. {
  5785. // Convert null to any object type handle, but not to a non-handle type
  5786. if( ctx->type.IsNullConstant() && ctx->methodName == "" )
  5787. {
  5788. if( to.IsObjectHandle() )
  5789. {
  5790. ctx->type.dataType = to;
  5791. return asCC_REF_CONV;
  5792. }
  5793. return asCC_NO_CONV;
  5794. }
  5795. asASSERT(ctx->type.dataType.GetTypeInfo() || ctx->methodName != "");
  5796. // First attempt to convert the base type without instantiating another instance
  5797. if( to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() && ctx->methodName == "" )
  5798. {
  5799. // If the to type is an interface and the from type implements it, then we can convert it immediately
  5800. if( ctx->type.dataType.GetTypeInfo()->Implements(to.GetTypeInfo()) )
  5801. {
  5802. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5803. return asCC_REF_CONV;
  5804. }
  5805. // If the to type is a class and the from type derives from it, then we can convert it immediately
  5806. else if( ctx->type.dataType.GetTypeInfo()->DerivesFrom(to.GetTypeInfo()) )
  5807. {
  5808. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5809. return asCC_REF_CONV;
  5810. }
  5811. // If the types are not equal yet, then we may still be able to find a reference cast
  5812. else if( ctx->type.dataType.GetTypeInfo() != to.GetTypeInfo() )
  5813. {
  5814. // We may still be able to find an implicit ref cast behaviour
  5815. CompileRefCast(ctx, to, convType == asIC_EXPLICIT_REF_CAST, node, generateCode);
  5816. // Was the conversion done?
  5817. if( ctx->type.dataType.GetTypeInfo() == to.GetTypeInfo() )
  5818. return asCC_REF_CONV;
  5819. }
  5820. }
  5821. // Convert matching function types
  5822. if( to.IsFuncdef() )
  5823. {
  5824. // If the input expression is already a funcdef, check if it can be converted
  5825. if( ctx->type.dataType.IsFuncdef() &&
  5826. to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() )
  5827. {
  5828. asCScriptFunction *toFunc = CastToFuncdefType(to.GetTypeInfo())->funcdef;
  5829. asCScriptFunction *fromFunc = CastToFuncdefType(ctx->type.dataType.GetTypeInfo())->funcdef;
  5830. if( toFunc->IsSignatureExceptNameEqual(fromFunc) )
  5831. {
  5832. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5833. return asCC_REF_CONV;
  5834. }
  5835. }
  5836. // If the input expression is a deferred function ref, check if there is a matching func
  5837. if( ctx->methodName != "" )
  5838. {
  5839. // Determine the namespace
  5840. asSNameSpace *ns = 0;
  5841. asCString name = "";
  5842. int pos = ctx->methodName.FindLast("::");
  5843. if( pos >= 0 )
  5844. {
  5845. asCString nsName = ctx->methodName.SubString(0, pos+2);
  5846. // Trim off the last ::
  5847. if( nsName.GetLength() > 2 )
  5848. nsName.SetLength(nsName.GetLength()-2);
  5849. ns = DetermineNameSpace(nsName);
  5850. name = ctx->methodName.SubString(pos+2);
  5851. }
  5852. else
  5853. {
  5854. DetermineNameSpace("");
  5855. name = ctx->methodName;
  5856. }
  5857. asCArray<int> funcs;
  5858. if( ns )
  5859. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  5860. // Check if any of the functions have perfect match
  5861. asCScriptFunction *toFunc = CastToFuncdefType(to.GetTypeInfo())->funcdef;
  5862. for( asUINT n = 0; n < funcs.GetLength(); n++ )
  5863. {
  5864. asCScriptFunction *func = builder->GetFunctionDescription(funcs[n]);
  5865. if( toFunc->IsSignatureExceptNameEqual(func) )
  5866. {
  5867. if( generateCode )
  5868. {
  5869. ctx->bc.InstrPTR(asBC_FuncPtr, func);
  5870. // Make sure the identified function is shared if we're compiling a shared function
  5871. if( !func->IsShared() && outFunc->IsShared() )
  5872. {
  5873. asCString msg;
  5874. msg.Format(TXT_SHARED_CANNOT_CALL_NON_SHARED_FUNC_s, func->GetDeclaration());
  5875. Error(msg, node);
  5876. }
  5877. }
  5878. ctx->type.dataType = asCDataType::CreateType(to.GetTypeInfo(), false);
  5879. return asCC_REF_CONV;
  5880. }
  5881. }
  5882. }
  5883. }
  5884. return asCC_NO_CONV;
  5885. }
  5886. asUINT asCCompiler::ImplicitConvObjectValue(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode)
  5887. {
  5888. asUINT cost = asCC_NO_CONV;
  5889. // If the base type is still different, and we are allowed to instance
  5890. // another object then we can try an implicit value cast
  5891. if( to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() )
  5892. {
  5893. // TODO: Implement support for implicit constructor/factory
  5894. asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  5895. if( ot == 0 )
  5896. return cost;
  5897. asCArray<int> funcs;
  5898. if( convType == asIC_EXPLICIT_VAL_CAST )
  5899. {
  5900. for( unsigned int n = 0; n < ot->methods.GetLength(); n++ )
  5901. {
  5902. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  5903. // accept both implicit and explicit cast
  5904. if( (func->name == "opConv" ||
  5905. func->name == "opImplConv") &&
  5906. func->returnType.GetTypeInfo() == to.GetTypeInfo() &&
  5907. func->parameterTypes.GetLength() == 0 )
  5908. funcs.PushLast(ot->methods[n]);
  5909. }
  5910. }
  5911. else
  5912. {
  5913. for( unsigned int n = 0; n < ot->methods.GetLength(); n++ )
  5914. {
  5915. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  5916. // accept only implicit cast
  5917. if( func->name == "opImplConv" &&
  5918. func->returnType.GetTypeInfo() == to.GetTypeInfo() &&
  5919. func->parameterTypes.GetLength() == 0 )
  5920. funcs.PushLast(ot->methods[n]);
  5921. }
  5922. }
  5923. FilterConst(funcs, !ctx->type.dataType.IsReadOnly());
  5924. // If there are multiple valid value casts, then we must choose the most appropriate one
  5925. if (funcs.GetLength() > 1)
  5926. {
  5927. // This should only happen in case of explicit value cast and
  5928. // the application has registered both opImplConv and opConv
  5929. asASSERT(convType == asIC_EXPLICIT_VAL_CAST);
  5930. asASSERT(funcs.GetLength() == 2);
  5931. for (asUINT n = 0; n < funcs.GetLength(); n++)
  5932. {
  5933. asCScriptFunction *func = engine->scriptFunctions[funcs[n]];
  5934. if (func->name == "opImplConv")
  5935. {
  5936. funcs.RemoveIndex(n);
  5937. n--;
  5938. }
  5939. }
  5940. }
  5941. if( funcs.GetLength() == 1 )
  5942. {
  5943. asCScriptFunction *f = builder->GetFunctionDescription(funcs[0]);
  5944. if( generateCode )
  5945. {
  5946. Dereference(ctx, true);
  5947. bool useVariable = false;
  5948. int stackOffset = 0;
  5949. if( f->DoesReturnOnStack() )
  5950. {
  5951. useVariable = true;
  5952. stackOffset = AllocateVariable(f->returnType, true);
  5953. // Push the pointer to the pre-allocated space for the return value
  5954. ctx->bc.InstrSHORT(asBC_PSF, short(stackOffset));
  5955. // The object pointer is already on the stack, but should be the top
  5956. // one, so we need to swap the pointers in order to get the correct
  5957. ctx->bc.Instr(asBC_SwapPtr);
  5958. }
  5959. PerformFunctionCall(funcs[0], ctx, false, 0, 0, useVariable, stackOffset);
  5960. }
  5961. else
  5962. ctx->type.Set(f->returnType);
  5963. cost = asCC_TO_OBJECT_CONV;
  5964. }
  5965. else
  5966. {
  5967. // TODO: cleanup: This part is similar to the second half of ImplicitConvObjectToPrimitive
  5968. // Look for a value cast with variable type
  5969. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  5970. {
  5971. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  5972. if( ((convType == asIC_EXPLICIT_VAL_CAST) && func->name == "opConv") ||
  5973. func->name == "opImplConv" )
  5974. {
  5975. // Does the operator take the ?&out parameter?
  5976. if( func->returnType != asCDataType::CreatePrimitive(ttVoid, false) ||
  5977. func->parameterTypes.GetLength() != 1 ||
  5978. func->parameterTypes[0].GetTokenType() != ttQuestion ||
  5979. func->inOutFlags[0] != asTM_OUTREF )
  5980. continue;
  5981. funcs.PushLast(ot->methods[n]);
  5982. }
  5983. }
  5984. FilterConst(funcs, !ctx->type.dataType.IsReadOnly());
  5985. // If there are multiple valid value casts, then we must choose the most appropriate one
  5986. if (funcs.GetLength() > 1)
  5987. {
  5988. // This should only happen in case of explicit value cast and
  5989. // the application has registered both opImplConv and opConv
  5990. asASSERT(convType == asIC_EXPLICIT_VAL_CAST);
  5991. asASSERT(funcs.GetLength() == 2);
  5992. for (asUINT n = 0; n < funcs.GetLength(); n++)
  5993. {
  5994. asCScriptFunction *func = engine->scriptFunctions[funcs[n]];
  5995. if (func->name == "opImplConv")
  5996. {
  5997. funcs.RemoveIndex(n);
  5998. n--;
  5999. }
  6000. }
  6001. }
  6002. if( funcs.GetLength() == 1 )
  6003. {
  6004. cost = asCC_TO_OBJECT_CONV;
  6005. if( generateCode )
  6006. {
  6007. // Allocate a temporary variable of the requested type
  6008. int stackOffset = AllocateVariableNotIn(to, true, false, ctx);
  6009. CallDefaultConstructor(to, stackOffset, IsVariableOnHeap(stackOffset), &ctx->bc, node);
  6010. // Pass the reference of that variable to the function as output parameter
  6011. asCDataType toRef(to);
  6012. toRef.MakeReference(false);
  6013. asCExprContext arg(engine);
  6014. arg.bc.InstrSHORT(asBC_PSF, (short)stackOffset);
  6015. // If this an object on the heap, the pointer must be dereferenced
  6016. if( IsVariableOnHeap(stackOffset) )
  6017. arg.bc.Instr(asBC_RDSPtr);
  6018. // Don't mark the variable as temporary, so it won't be freed too early
  6019. arg.type.SetVariable(toRef, stackOffset, false);
  6020. arg.type.isLValue = true;
  6021. arg.exprNode = node;
  6022. // Mark the argument as clean, so that MakeFunctionCall knows it
  6023. // doesn't have to make a copy of it in order to protect the value
  6024. arg.isCleanArg = true;
  6025. // Call the behaviour method
  6026. asCArray<asCExprContext *> args;
  6027. args.PushLast(&arg);
  6028. MakeFunctionCall(ctx, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
  6029. // Use the reference to the variable as the result of the expression
  6030. // Now we can mark the variable as temporary
  6031. ctx->type.SetVariable(toRef, stackOffset, true);
  6032. ctx->bc.InstrSHORT(asBC_PSF, (short)stackOffset);
  6033. }
  6034. else
  6035. {
  6036. // All casts are legal
  6037. ctx->type.Set(to);
  6038. }
  6039. }
  6040. else if( CastToObjectType(to.GetTypeInfo()) )
  6041. {
  6042. // If no opConv/opImplConv methods were found on the object, then try to find a conversion constructor on the target type
  6043. if( to.GetTypeInfo()->flags & asOBJ_REF )
  6044. funcs = CastToObjectType(to.GetTypeInfo())->beh.factories;
  6045. else
  6046. funcs = CastToObjectType(to.GetTypeInfo())->beh.constructors;
  6047. // If not explicit cast, remove any explicit conversion constructors
  6048. for (asUINT n = 0; n < funcs.GetLength(); n++)
  6049. {
  6050. asCScriptFunction *f = engine->scriptFunctions[funcs[n]];
  6051. if( f == 0 || f->parameterTypes.GetLength() != 1 || (convType != asIC_EXPLICIT_VAL_CAST && f->IsExplicit()) )
  6052. funcs.RemoveIndex(n--);
  6053. }
  6054. asCArray<asCExprContext *> args;
  6055. args.PushLast(ctx);
  6056. cost = asCC_TO_OBJECT_CONV + MatchFunctions(funcs, args, node, 0, 0, 0, false, true, false);
  6057. // Did we find a matching constructor?
  6058. if (funcs.GetLength() == 1)
  6059. {
  6060. if (generateCode)
  6061. {
  6062. // TODO: This should really reuse the code from CompileConstructCall
  6063. // Allocate the new object
  6064. asCExprValue tempObj;
  6065. asCExprContext e(engine);
  6066. bool onHeap = false;
  6067. if (to.GetTypeInfo()->flags & asOBJ_VALUE)
  6068. {
  6069. tempObj.dataType = to;
  6070. tempObj.dataType.MakeReference(false);
  6071. tempObj.stackOffset = (short)AllocateVariable(tempObj.dataType, true);
  6072. tempObj.dataType.MakeReference(true);
  6073. tempObj.isTemporary = true;
  6074. tempObj.isVariable = true;
  6075. onHeap = IsVariableOnHeap(tempObj.stackOffset);
  6076. // Push the address of the object on the stack
  6077. if (onHeap)
  6078. e.bc.InstrSHORT(asBC_VAR, tempObj.stackOffset);
  6079. }
  6080. PrepareFunctionCall(funcs[0], &e.bc, args);
  6081. MoveArgsToStack(funcs[0], &e.bc, args, false);
  6082. if (to.GetTypeInfo()->flags & asOBJ_VALUE)
  6083. {
  6084. // If the object is allocated on the stack, then call the constructor as a normal function
  6085. if (onHeap)
  6086. {
  6087. int offset = 0;
  6088. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]);
  6089. offset = descr->parameterTypes[0].GetSizeOnStackDWords();
  6090. e.bc.InstrWORD(asBC_GETREF, (asWORD)offset);
  6091. }
  6092. else
  6093. e.bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  6094. }
  6095. PerformFunctionCall(funcs[0], &e, onHeap, &args, CastToObjectType(tempObj.dataType.GetTypeInfo()));
  6096. if (to.GetTypeInfo()->flags & asOBJ_VALUE)
  6097. {
  6098. // Add tag that the object has been initialized
  6099. e.bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT);
  6100. // The constructor doesn't return anything,
  6101. // so we have to manually inform the type of
  6102. // the return value
  6103. e.type = tempObj;
  6104. if (!onHeap)
  6105. e.type.dataType.MakeReference(false);
  6106. // Push the address of the object on the stack again
  6107. e.bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  6108. }
  6109. MergeExprBytecodeAndType(ctx, &e);
  6110. }
  6111. else
  6112. {
  6113. ctx->type.Set(asCDataType::CreateType(to.GetTypeInfo(), false));
  6114. }
  6115. }
  6116. }
  6117. }
  6118. }
  6119. return cost;
  6120. }
  6121. asUINT asCCompiler::ImplicitConvObjectToObject(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode, bool allowObjectConstruct)
  6122. {
  6123. // First try a ref cast
  6124. asUINT cost = ImplicitConvObjectRef(ctx, to, node, convType, generateCode);
  6125. // If the desired type is an asOBJ_ASHANDLE then we'll assume it is allowed to implicitly
  6126. // construct the object through any of the available constructors (except those marked as explicit)
  6127. if( to.GetTypeInfo() && (to.GetTypeInfo()->flags & asOBJ_ASHANDLE) && to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() && allowObjectConstruct )
  6128. {
  6129. asCArray<int> funcs;
  6130. funcs = CastToObjectType(to.GetTypeInfo())->beh.constructors;
  6131. // Don't allow use of explicit constructors/factories in implicit conversions
  6132. if (convType == asIC_IMPLICIT_CONV)
  6133. {
  6134. for (asUINT n = 0; n < funcs.GetLength(); n++)
  6135. {
  6136. asCScriptFunction* desc = builder->GetFunctionDescription(funcs[n]);
  6137. if (desc->IsExplicit())
  6138. funcs.RemoveIndex(n--);
  6139. }
  6140. }
  6141. asCArray<asCExprContext *> args;
  6142. args.PushLast(ctx);
  6143. cost = asCC_TO_OBJECT_CONV + MatchFunctions(funcs, args, node, 0, 0, 0, false, true, false);
  6144. // Did we find a matching constructor?
  6145. if( funcs.GetLength() == 1 )
  6146. {
  6147. if( generateCode )
  6148. {
  6149. // If the ASHANDLE receives a variable type parameter, then we need to
  6150. // make sure the expression is treated as a handle and not as a value
  6151. asCScriptFunction *func = engine->scriptFunctions[funcs[0]];
  6152. if( func->parameterTypes[0].GetTokenType() == ttQuestion )
  6153. {
  6154. if( !ctx->type.isExplicitHandle )
  6155. {
  6156. asCDataType toHandle = ctx->type.dataType;
  6157. toHandle.MakeHandle(true);
  6158. toHandle.MakeReference(true);
  6159. toHandle.MakeHandleToConst(ctx->type.dataType.IsReadOnly());
  6160. ImplicitConversion(ctx, toHandle, node, asIC_IMPLICIT_CONV, true, false);
  6161. asASSERT( ctx->type.dataType.IsObjectHandle() );
  6162. }
  6163. ctx->type.isExplicitHandle = true;
  6164. }
  6165. // TODO: This should really reuse the code from CompileConstructCall
  6166. // Allocate the new object
  6167. asCExprValue tempObj;
  6168. tempObj.dataType = to;
  6169. tempObj.dataType.MakeReference(false);
  6170. tempObj.stackOffset = (short)AllocateVariable(tempObj.dataType, true);
  6171. tempObj.dataType.MakeReference(true);
  6172. tempObj.isTemporary = true;
  6173. tempObj.isVariable = true;
  6174. bool onHeap = IsVariableOnHeap(tempObj.stackOffset);
  6175. // Push the address of the object on the stack
  6176. asCExprContext e(engine);
  6177. if( onHeap )
  6178. e.bc.InstrSHORT(asBC_VAR, tempObj.stackOffset);
  6179. PrepareFunctionCall(funcs[0], &e.bc, args);
  6180. MoveArgsToStack(funcs[0], &e.bc, args, false);
  6181. // If the object is allocated on the stack, then call the constructor as a normal function
  6182. if( onHeap )
  6183. {
  6184. int offset = 0;
  6185. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]);
  6186. offset = descr->parameterTypes[0].GetSizeOnStackDWords();
  6187. e.bc.InstrWORD(asBC_GETREF, (asWORD)offset);
  6188. }
  6189. else
  6190. e.bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  6191. PerformFunctionCall(funcs[0], &e, onHeap, &args, CastToObjectType(tempObj.dataType.GetTypeInfo()));
  6192. // Add tag that the object has been initialized
  6193. e.bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT);
  6194. // The constructor doesn't return anything,
  6195. // so we have to manually inform the type of
  6196. // the return value
  6197. e.type = tempObj;
  6198. if( !onHeap )
  6199. e.type.dataType.MakeReference(false);
  6200. // Push the address of the object on the stack again
  6201. e.bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  6202. MergeExprBytecodeAndType(ctx, &e);
  6203. }
  6204. else
  6205. {
  6206. ctx->type.Set(asCDataType::CreateType(to.GetTypeInfo(), false));
  6207. }
  6208. }
  6209. }
  6210. // If the base type is still different, and we are allowed to instance
  6211. // another object then we can try an implicit value cast
  6212. if( to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() && allowObjectConstruct )
  6213. {
  6214. // Attempt implicit value cast
  6215. cost = ImplicitConvObjectValue(ctx, to, node, convType, generateCode);
  6216. }
  6217. // If we still haven't converted the base type to the correct type, then there is
  6218. // no need to continue as it is not possible to do the conversion
  6219. if( to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() )
  6220. return asCC_NO_CONV;
  6221. if( to.IsObjectHandle() )
  6222. {
  6223. // There is no extra cost in converting to a handle
  6224. // reference to handle -> handle
  6225. // reference -> handle
  6226. // object -> handle
  6227. // handle -> reference to handle
  6228. // reference -> reference to handle
  6229. // object -> reference to handle
  6230. if( (!ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReadOnly() && !to.IsHandleToConst()) ||
  6231. (ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsHandleToConst() && !to.IsHandleToConst()) )
  6232. {
  6233. // String literals can be implicitly converted to temporary local variables in order to pass them to functions expecting non-const
  6234. // TODO: NEWSTRING: Should have an engine property to warn or error on this
  6235. if (ctx->type.isConstant && ctx->type.dataType.IsEqualExceptRefAndConst(engine->stringType))
  6236. {
  6237. if (generateCode)
  6238. PrepareTemporaryVariable(node, ctx);
  6239. else
  6240. {
  6241. ctx->type.dataType.MakeReadOnly(false);
  6242. ctx->type.isConstant = false;
  6243. }
  6244. // Add the cost for the copy
  6245. cost += asCC_TO_OBJECT_CONV;
  6246. }
  6247. else if( convType != asIC_IMPLICIT_CONV )
  6248. {
  6249. asASSERT(node);
  6250. asCString str;
  6251. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  6252. Error(str, node);
  6253. }
  6254. }
  6255. if( !ctx->type.dataType.IsObjectHandle() )
  6256. {
  6257. // An object type can be directly converted to a handle of the
  6258. // same type by doing a ref copy to a new variable
  6259. if( ctx->type.dataType.SupportHandles() )
  6260. {
  6261. asCDataType dt = ctx->type.dataType;
  6262. dt.MakeHandle(true);
  6263. dt.MakeReference(false);
  6264. if( generateCode )
  6265. {
  6266. // If the expression is already a local variable, then it is not
  6267. // necessary to do a ref copy, as the ref objects on the stack are
  6268. // really handles, only the handles cannot be modified.
  6269. if( ctx->type.isVariable )
  6270. {
  6271. bool isHandleToConst = ctx->type.dataType.IsReadOnly();
  6272. ctx->type.dataType.MakeReadOnly(false);
  6273. ctx->type.dataType.MakeHandle(true);
  6274. ctx->type.dataType.MakeReadOnly(true);
  6275. ctx->type.dataType.MakeHandleToConst(isHandleToConst);
  6276. if( to.IsReference() && !ctx->type.dataType.IsReference() )
  6277. {
  6278. ctx->bc.Instr(asBC_PopPtr);
  6279. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  6280. ctx->type.dataType.MakeReference(true);
  6281. }
  6282. else if( ctx->type.dataType.IsReference() )
  6283. {
  6284. ctx->bc.Instr(asBC_RDSPtr);
  6285. ctx->type.dataType.MakeReference(false);
  6286. }
  6287. }
  6288. else
  6289. {
  6290. int offset = AllocateVariable(dt, true);
  6291. if( ctx->type.dataType.IsReference() )
  6292. ctx->bc.Instr(asBC_RDSPtr);
  6293. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  6294. if (dt.IsFuncdef())
  6295. ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  6296. else
  6297. ctx->bc.InstrPTR(asBC_REFCPY, dt.GetTypeInfo());
  6298. ctx->bc.Instr(asBC_PopPtr);
  6299. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  6300. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  6301. if( to.IsReference() )
  6302. dt.MakeReference(true);
  6303. else
  6304. ctx->bc.Instr(asBC_RDSPtr);
  6305. ctx->type.SetVariable(dt, offset, true);
  6306. }
  6307. }
  6308. else
  6309. ctx->type.dataType = dt;
  6310. // When this conversion is done the expression is no longer an lvalue
  6311. ctx->type.isLValue = false;
  6312. }
  6313. }
  6314. if( ctx->type.dataType.IsObjectHandle() )
  6315. {
  6316. // A handle to non-const can be converted to a
  6317. // handle to const, but not the other way
  6318. if( to.IsHandleToConst() )
  6319. ctx->type.dataType.MakeHandleToConst(true);
  6320. // A const handle can be converted to a non-const
  6321. // handle and vice versa as the handle is just a value
  6322. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  6323. }
  6324. if( to.IsReference() && !ctx->type.dataType.IsReference() )
  6325. {
  6326. if( generateCode )
  6327. {
  6328. asASSERT( ctx->type.dataType.IsObjectHandle() );
  6329. // If the input type is a handle, then a simple ref copy is enough
  6330. bool isExplicitHandle = ctx->type.isExplicitHandle;
  6331. ctx->type.isExplicitHandle = ctx->type.dataType.IsObjectHandle();
  6332. // If the input type is read-only we'll need to temporarily
  6333. // remove this constness, otherwise the assignment will fail
  6334. bool typeIsReadOnly = ctx->type.dataType.IsReadOnly();
  6335. ctx->type.dataType.MakeReadOnly(false);
  6336. // If the object already is a temporary variable, then the copy
  6337. // doesn't have to be made as it is already a unique object
  6338. PrepareTemporaryVariable(node, ctx);
  6339. ctx->type.dataType.MakeReadOnly(typeIsReadOnly);
  6340. ctx->type.isExplicitHandle = isExplicitHandle;
  6341. }
  6342. // A non-reference can be converted to a reference,
  6343. // by putting the value in a temporary variable
  6344. ctx->type.dataType.MakeReference(true);
  6345. // Since it is a new temporary variable it doesn't have to be const
  6346. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  6347. }
  6348. else if( !to.IsReference() && ctx->type.dataType.IsReference() )
  6349. {
  6350. Dereference(ctx, generateCode);
  6351. }
  6352. }
  6353. else // if( !to.IsObjectHandle() )
  6354. {
  6355. if( !to.IsReference() )
  6356. {
  6357. // reference to handle -> object
  6358. // handle -> object
  6359. // reference -> object
  6360. // An implicit handle can be converted to an object by adding a check for null pointer
  6361. if( ctx->type.dataType.IsObjectHandle() && !ctx->type.isExplicitHandle )
  6362. {
  6363. if( generateCode )
  6364. {
  6365. if( ctx->type.dataType.IsReference() )
  6366. {
  6367. // The pointer on the stack refers to the handle
  6368. ctx->bc.Instr(asBC_ChkRefS);
  6369. }
  6370. else
  6371. {
  6372. // The pointer on the stack refers to the object
  6373. ctx->bc.Instr(asBC_CHKREF);
  6374. }
  6375. }
  6376. ctx->type.dataType.MakeHandle(false);
  6377. }
  6378. // A const object can be converted to a non-const object through a copy
  6379. if( ctx->type.dataType.IsReadOnly() && !to.IsReadOnly() &&
  6380. allowObjectConstruct )
  6381. {
  6382. // Does the object type allow a copy to be made?
  6383. if( ctx->type.dataType.CanBeCopied() )
  6384. {
  6385. if( generateCode )
  6386. {
  6387. // Make a temporary object with the copy
  6388. PrepareTemporaryVariable(node, ctx);
  6389. }
  6390. // In case the object was already in a temporary variable, then the function
  6391. // didn't really do anything so we need to remove the constness here
  6392. ctx->type.dataType.MakeReadOnly(false);
  6393. // Add the cost for the copy
  6394. cost += asCC_TO_OBJECT_CONV;
  6395. }
  6396. }
  6397. if( ctx->type.dataType.IsReference() )
  6398. {
  6399. // This may look strange, but a value type allocated on the stack is already
  6400. // correct, so nothing should be done other than remove the mark as reference.
  6401. // For types allocated on the heap, it is necessary to dereference the pointer
  6402. // that is currently on the stack
  6403. if( IsVariableOnHeap(ctx->type.stackOffset) )
  6404. Dereference(ctx, generateCode);
  6405. else
  6406. ctx->type.dataType.MakeReference(false);
  6407. }
  6408. // A non-const object can be converted to a const object directly
  6409. if( !ctx->type.dataType.IsReadOnly() && to.IsReadOnly() )
  6410. {
  6411. ctx->type.dataType.MakeReadOnly(true);
  6412. }
  6413. }
  6414. else // if( to.IsReference() )
  6415. {
  6416. // reference to handle -> reference
  6417. // handle -> reference
  6418. // object -> reference
  6419. if( ctx->type.dataType.IsReference() )
  6420. {
  6421. if( ctx->type.isExplicitHandle && ctx->type.dataType.GetTypeInfo() && (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) )
  6422. {
  6423. // ASHANDLE objects are really value types, so explicit handle can be removed
  6424. ctx->type.isExplicitHandle = false;
  6425. ctx->type.dataType.MakeHandle(false);
  6426. }
  6427. // A reference to a handle can be converted to a reference to an object
  6428. // by first reading the address, then verifying that it is not null
  6429. if( !to.IsObjectHandle() && ctx->type.dataType.IsObjectHandle() && !ctx->type.isExplicitHandle )
  6430. {
  6431. ctx->type.dataType.MakeHandle(false);
  6432. if( generateCode )
  6433. ctx->bc.Instr(asBC_ChkRefS);
  6434. }
  6435. // A reference to a non-const can be converted to a reference to a const
  6436. if( to.IsReadOnly() )
  6437. ctx->type.dataType.MakeReadOnly(true);
  6438. else if( ctx->type.dataType.IsReadOnly() && allowObjectConstruct )
  6439. {
  6440. // A reference to a const can be converted to a reference to a
  6441. // non-const by copying the object to a temporary variable
  6442. ctx->type.dataType.MakeReadOnly(false);
  6443. if( generateCode )
  6444. {
  6445. // If the object already is a temporary variable, then the copy
  6446. // doesn't have to be made as it is already a unique object
  6447. PrepareTemporaryVariable(node, ctx);
  6448. }
  6449. // Add the cost for the copy
  6450. cost += asCC_TO_OBJECT_CONV;
  6451. }
  6452. }
  6453. else // if( !ctx->type.dataType.IsReference() )
  6454. {
  6455. // A non-reference handle can be converted to a non-handle reference by checking against null handle
  6456. if( ctx->type.dataType.IsObjectHandle() )
  6457. {
  6458. bool readOnly = false;
  6459. if( ctx->type.dataType.IsHandleToConst() )
  6460. readOnly = true;
  6461. if( generateCode )
  6462. {
  6463. if( ctx->type.isVariable )
  6464. ctx->bc.InstrSHORT(asBC_ChkNullV, ctx->type.stackOffset);
  6465. else
  6466. ctx->bc.Instr(asBC_CHKREF);
  6467. }
  6468. ctx->type.dataType.MakeHandle(false);
  6469. ctx->type.dataType.MakeReference(true);
  6470. // Make sure a handle to const isn't converted to non-const reference
  6471. if( readOnly )
  6472. ctx->type.dataType.MakeReadOnly(true);
  6473. }
  6474. else
  6475. {
  6476. // A value type allocated on the stack is differentiated
  6477. // by it not being a reference. But it can be handled as
  6478. // reference by pushing the pointer on the stack
  6479. if( (ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) &&
  6480. (ctx->type.isVariable || ctx->type.isTemporary) &&
  6481. !IsVariableOnHeap(ctx->type.stackOffset) )
  6482. {
  6483. // Actually the pointer is already pushed on the stack in
  6484. // CompileVariableAccess, so we don't need to do anything else
  6485. }
  6486. else if( generateCode )
  6487. {
  6488. // A non-reference can be converted to a reference,
  6489. // by putting the value in a temporary variable
  6490. // If the input type is read-only we'll need to temporarily
  6491. // remove this constness, otherwise the assignment will fail
  6492. bool typeIsReadOnly = ctx->type.dataType.IsReadOnly();
  6493. ctx->type.dataType.MakeReadOnly(false);
  6494. // If the object already is a temporary variable, then the copy
  6495. // doesn't have to be made as it is already a unique object
  6496. PrepareTemporaryVariable(node, ctx);
  6497. ctx->type.dataType.MakeReadOnly(typeIsReadOnly);
  6498. // Add the cost for the copy
  6499. cost += asCC_TO_OBJECT_CONV;
  6500. }
  6501. // This may look strange as the conversion was to make the expression a reference
  6502. // but a value type allocated on the stack is a reference even without the type
  6503. // being marked as such.
  6504. ctx->type.dataType.MakeReference(IsVariableOnHeap(ctx->type.stackOffset));
  6505. }
  6506. if (to.IsReadOnly())
  6507. {
  6508. // This doesn't cost anything
  6509. ctx->type.dataType.MakeReadOnly(true);
  6510. }
  6511. if (!to.IsReadOnly() && ctx->type.dataType.IsReadOnly())
  6512. {
  6513. // A const object can be converted to a non-const object through a copy
  6514. if (allowObjectConstruct || convType == asIC_EXPLICIT_VAL_CAST)
  6515. {
  6516. ctx->type.dataType.MakeReadOnly(false);
  6517. if (generateCode)
  6518. {
  6519. // Make a temporary copy of the object in order to make it non-const
  6520. PrepareTemporaryVariable(node, ctx);
  6521. }
  6522. // Add the cost for the copy
  6523. cost += asCC_TO_OBJECT_CONV;
  6524. }
  6525. // String literals can be implicitly converted to temporary local variables in order to pass them to functions expecting non-const
  6526. // TODO: NEWSTRING: Should have an engine property to warn or error on this
  6527. if (ctx->type.isConstant && ctx->type.dataType.IsEqualExceptRefAndConst(engine->stringType))
  6528. {
  6529. if (generateCode)
  6530. PrepareTemporaryVariable(node, ctx);
  6531. else
  6532. {
  6533. ctx->type.dataType.MakeReadOnly(false);
  6534. ctx->type.isConstant = false;
  6535. }
  6536. // Add the cost for the copy
  6537. cost += asCC_TO_OBJECT_CONV;
  6538. }
  6539. }
  6540. }
  6541. }
  6542. }
  6543. return cost;
  6544. }
  6545. asUINT asCCompiler::ImplicitConvPrimitiveToObject(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv isExplicit, bool generateCode, bool allowObjectConstruct)
  6546. {
  6547. asCObjectType *objType = CastToObjectType(to.GetTypeInfo());
  6548. asASSERT( objType || CastToFuncdefType(to.GetTypeInfo()) );
  6549. if( !objType )
  6550. return asCC_NO_CONV;
  6551. asCArray<int> funcs;
  6552. if (objType->flags & asOBJ_VALUE)
  6553. {
  6554. // For value types the object must have a constructor that takes a single primitive argument either by value or as input reference
  6555. for (asUINT n = 0; n < objType->beh.constructors.GetLength(); n++)
  6556. {
  6557. asCScriptFunction *func = engine->scriptFunctions[objType->beh.constructors[n]];
  6558. if (func->parameterTypes.GetLength() == 1 &&
  6559. func->parameterTypes[0].IsPrimitive() &&
  6560. !(func->inOutFlags[0] & asTM_OUTREF) &&
  6561. (isExplicit == asIC_EXPLICIT_VAL_CAST || !func->IsExplicit()) )
  6562. {
  6563. funcs.PushLast(func->id);
  6564. }
  6565. }
  6566. }
  6567. else if (objType->flags & asOBJ_REF)
  6568. {
  6569. // For ref types the object must have a factory that takes a single primitive argument either by value or as input reference
  6570. for (asUINT n = 0; n < objType->beh.factories.GetLength(); n++)
  6571. {
  6572. asCScriptFunction *func = engine->scriptFunctions[objType->beh.factories[n]];
  6573. if (func->parameterTypes.GetLength() == 1 &&
  6574. func->parameterTypes[0].IsPrimitive() &&
  6575. !(func->inOutFlags[0] & asTM_OUTREF) &&
  6576. (isExplicit == asIC_EXPLICIT_VAL_CAST || !func->IsExplicit()))
  6577. {
  6578. funcs.PushLast(func->id);
  6579. }
  6580. }
  6581. }
  6582. if( funcs.GetLength() == 0 )
  6583. return asCC_NO_CONV;
  6584. // Check if it is possible to choose a best match
  6585. asCExprContext arg(engine);
  6586. arg.type = ctx->type;
  6587. arg.exprNode = ctx->exprNode; // Use the same node for compiler messages
  6588. asCArray<asCExprContext*> args;
  6589. args.PushLast(&arg);
  6590. asUINT cost = asCC_TO_OBJECT_CONV + MatchFunctions(funcs, args, 0, 0, 0, objType, false, true, false);
  6591. if( funcs.GetLength() != 1 )
  6592. return asCC_NO_CONV;
  6593. if( !generateCode )
  6594. {
  6595. ctx->type.Set(to);
  6596. return cost;
  6597. }
  6598. // TODO: clean up: This part is similar to CompileConstructCall(). It should be put in a common function
  6599. // Clear the type of ctx, as the type is moved to the arg
  6600. ctx->type.SetDummy();
  6601. // Value types and script types are allocated through the constructor
  6602. asCExprValue tempObj;
  6603. bool onHeap = false;
  6604. if (!(objType->flags & asOBJ_REF))
  6605. {
  6606. tempObj.dataType = to;
  6607. tempObj.stackOffset = (short)AllocateVariable(to, true);
  6608. tempObj.dataType.MakeReference(true);
  6609. tempObj.isTemporary = true;
  6610. tempObj.isVariable = true;
  6611. onHeap = IsVariableOnHeap(tempObj.stackOffset);
  6612. // Push the address of the object on the stack
  6613. if (onHeap)
  6614. ctx->bc.InstrSHORT(asBC_VAR, tempObj.stackOffset);
  6615. }
  6616. PrepareFunctionCall(funcs[0], &ctx->bc, args);
  6617. MoveArgsToStack(funcs[0], &ctx->bc, args, false);
  6618. if( !(objType->flags & asOBJ_REF) )
  6619. {
  6620. // If the object is allocated on the stack, then call the constructor as a normal function
  6621. if( onHeap )
  6622. {
  6623. int offset = 0;
  6624. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]);
  6625. for( asUINT n = 0; n < args.GetLength(); n++ )
  6626. offset += descr->parameterTypes[n].GetSizeOnStackDWords();
  6627. ctx->bc.InstrWORD(asBC_GETREF, (asWORD)offset);
  6628. }
  6629. else
  6630. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  6631. PerformFunctionCall(funcs[0], ctx, onHeap, &args, CastToObjectType(tempObj.dataType.GetTypeInfo()));
  6632. // Add tag that the object has been initialized
  6633. ctx->bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT);
  6634. // The constructor doesn't return anything,
  6635. // so we have to manually inform the type of
  6636. // the return value
  6637. ctx->type = tempObj;
  6638. if( !onHeap )
  6639. ctx->type.dataType.MakeReference(false);
  6640. // Push the address of the object on the stack again
  6641. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  6642. }
  6643. else
  6644. {
  6645. // Call the factory to create the reference type
  6646. PerformFunctionCall(funcs[0], ctx, false, &args);
  6647. // Make another pass to make sure the result has the correct handle and reference settings
  6648. ImplicitConversion(ctx, to, node, isExplicit, generateCode, allowObjectConstruct);
  6649. }
  6650. return cost;
  6651. }
  6652. void asCCompiler::ImplicitConversionConstant(asCExprContext *from, const asCDataType &to, asCScriptNode *node, EImplicitConv convType)
  6653. {
  6654. asASSERT(from->type.isConstant);
  6655. // TODO: node should be the node of the value that is
  6656. // converted (not the operator that provokes the implicit
  6657. // conversion)
  6658. // If the base type is correct there is no more to do
  6659. if( to.IsEqualExceptRefAndConst(from->type.dataType) ) return;
  6660. // References cannot be constants
  6661. if( from->type.dataType.IsReference() ) return;
  6662. if( (to.IsIntegerType() && to.GetSizeInMemoryDWords() == 1 && !to.IsEnumType()) ||
  6663. (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST) )
  6664. {
  6665. if( from->type.dataType.IsFloatType() ||
  6666. from->type.dataType.IsDoubleType() ||
  6667. from->type.dataType.IsUnsignedType() ||
  6668. from->type.dataType.IsIntegerType() )
  6669. {
  6670. asCDataType targetDt;
  6671. if (to.IsEnumType())
  6672. targetDt = to;
  6673. else
  6674. targetDt = asCDataType::CreatePrimitive(ttInt, true);
  6675. // Transform the value
  6676. // Float constants can be implicitly converted to int
  6677. if( from->type.dataType.IsFloatType() )
  6678. {
  6679. float fc = from->type.GetConstantF();
  6680. int ic = int(fc);
  6681. if( float(ic) != fc )
  6682. {
  6683. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6684. }
  6685. from->type.SetConstantDW(targetDt, ic);
  6686. }
  6687. // Double constants can be implicitly converted to int
  6688. else if( from->type.dataType.IsDoubleType() )
  6689. {
  6690. double fc = from->type.GetConstantD();
  6691. int ic = int(fc);
  6692. if( double(ic) != fc )
  6693. {
  6694. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6695. }
  6696. from->type.SetConstantDW(targetDt, ic);
  6697. }
  6698. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  6699. {
  6700. // Verify that it is possible to convert to signed without getting negative
  6701. if( from->type.dataType.GetSizeInMemoryBytes() == 4 &&
  6702. int(from->type.GetConstantDW()) < 0 &&
  6703. convType != asIC_EXPLICIT_VAL_CAST &&
  6704. node != 0 )
  6705. Warning(TXT_CHANGE_SIGN, node);
  6706. // Convert to 32bit
  6707. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6708. from->type.SetConstantDW(targetDt, from->type.GetConstantB());
  6709. else if (from->type.dataType.GetSizeInMemoryBytes() == 2)
  6710. from->type.SetConstantDW(targetDt, from->type.GetConstantW());
  6711. else
  6712. from->type.dataType = targetDt;
  6713. }
  6714. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  6715. {
  6716. if (asQWORD(from->type.GetConstantQW()) >> 31)
  6717. if (convType != asIC_EXPLICIT_VAL_CAST && node) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6718. // Convert to 32bit
  6719. from->type.SetConstantDW(targetDt, int(from->type.GetConstantQW()));
  6720. }
  6721. else if (from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2)
  6722. {
  6723. if (int(from->type.GetConstantQW()) != asINT64(from->type.GetConstantQW()))
  6724. if (convType != asIC_EXPLICIT_VAL_CAST && node) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6725. // Convert to 32bit
  6726. from->type.SetConstantDW(targetDt, int(from->type.GetConstantQW()));
  6727. }
  6728. else if (from->type.dataType.IsIntegerType() &&
  6729. from->type.dataType.GetSizeInMemoryBytes() < 4)
  6730. {
  6731. // Convert to 32bit
  6732. if (from->type.dataType.GetSizeInMemoryBytes() == 1)
  6733. from->type.SetConstantDW(targetDt, (asINT8)from->type.GetConstantB());
  6734. else if (from->type.dataType.GetSizeInMemoryBytes() == 2)
  6735. from->type.SetConstantDW(targetDt, (asINT16)from->type.GetConstantW());
  6736. }
  6737. else
  6738. {
  6739. // Only int32 and enums should come here and as these are 32bit
  6740. // already nothing needs to be done except set the target type
  6741. asASSERT((from->type.dataType.GetTokenType() == ttInt ||
  6742. from->type.dataType.IsEnumType()) &&
  6743. from->type.dataType.GetSizeInMemoryBytes() == 4);
  6744. from->type.dataType = targetDt;
  6745. }
  6746. }
  6747. // Check if a downsize is necessary
  6748. if( to.IsIntegerType() &&
  6749. from->type.dataType.IsIntegerType() &&
  6750. from->type.dataType.GetSizeInMemoryBytes() > to.GetSizeInMemoryBytes() )
  6751. {
  6752. // Verify if it is possible
  6753. if( to.GetSizeInMemoryBytes() == 1 )
  6754. {
  6755. if( asINT8(from->type.GetConstantDW()) != int(from->type.GetConstantDW()) )
  6756. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6757. from->type.SetConstantB(asCDataType::CreatePrimitive(to.GetTokenType(), true), asINT8(from->type.GetConstantDW()));
  6758. }
  6759. else if( to.GetSizeInMemoryBytes() == 2 )
  6760. {
  6761. if( asINT16(from->type.GetConstantDW()) != int(from->type.GetConstantDW()) )
  6762. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6763. from->type.SetConstantW(asCDataType::CreatePrimitive(to.GetTokenType(), true), asINT16(from->type.GetConstantDW()));
  6764. }
  6765. }
  6766. }
  6767. else if( to.IsIntegerType() && to.GetSizeInMemoryDWords() == 2 )
  6768. {
  6769. // Float constants can be implicitly converted to int
  6770. if( from->type.dataType.IsFloatType() )
  6771. {
  6772. float fc = from->type.GetConstantF();
  6773. asINT64 ic = asINT64(fc);
  6774. if( float(ic) != fc )
  6775. {
  6776. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6777. }
  6778. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), ic);
  6779. }
  6780. // Double constants can be implicitly converted to int
  6781. else if( from->type.dataType.IsDoubleType() )
  6782. {
  6783. double fc = from->type.GetConstantD();
  6784. asINT64 ic = asINT64(fc);
  6785. if( double(ic) != fc )
  6786. {
  6787. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6788. }
  6789. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), ic);
  6790. }
  6791. else if( from->type.dataType.IsUnsignedType() )
  6792. {
  6793. // Convert to 64bit
  6794. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6795. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), from->type.GetConstantB());
  6796. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6797. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), from->type.GetConstantW());
  6798. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  6799. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), from->type.GetConstantDW());
  6800. else if( from->type.dataType.GetSizeInMemoryBytes() == 8 )
  6801. {
  6802. if( asINT64(from->type.GetConstantQW()) < 0 )
  6803. {
  6804. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  6805. }
  6806. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  6807. }
  6808. }
  6809. else if( from->type.dataType.IsIntegerType() )
  6810. {
  6811. // Convert to 64bit
  6812. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6813. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), (asINT8)from->type.GetConstantB());
  6814. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6815. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), (asINT16)from->type.GetConstantW());
  6816. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  6817. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), (int)from->type.GetConstantDW());
  6818. }
  6819. }
  6820. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 1 )
  6821. {
  6822. if( from->type.dataType.IsFloatType() )
  6823. {
  6824. float fc = from->type.GetConstantF();
  6825. // Some compilers set the value to 0 when converting a negative float to unsigned int.
  6826. // To maintain a consistent behaviour across compilers we convert to int first.
  6827. asUINT uic = asUINT(int(fc));
  6828. if( float(uic) != fc )
  6829. {
  6830. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6831. }
  6832. from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), uic);
  6833. // Try once more, in case of a smaller type
  6834. ImplicitConversionConstant(from, to, node, convType);
  6835. }
  6836. else if( from->type.dataType.IsDoubleType() )
  6837. {
  6838. double fc = from->type.GetConstantD();
  6839. // Some compilers set the value to 0 when converting a negative double to unsigned int.
  6840. // To maintain a consistent behaviour across compilers we convert to int first.
  6841. asUINT uic = asUINT(int(fc));
  6842. if( double(uic) != fc )
  6843. {
  6844. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6845. }
  6846. from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), uic);
  6847. // Try once more, in case of a smaller type
  6848. ImplicitConversionConstant(from, to, node, convType);
  6849. }
  6850. else if( from->type.dataType.IsIntegerType() )
  6851. {
  6852. // Verify that it is possible to convert to unsigned without loosing negative
  6853. if( (from->type.dataType.GetSizeInMemoryBytes() > 4 && asINT64(from->type.GetConstantQW()) < 0) ||
  6854. (from->type.dataType.GetSizeInMemoryBytes() == 4 && int(from->type.GetConstantDW()) < 0) ||
  6855. (from->type.dataType.GetSizeInMemoryBytes() == 2 && asINT16(from->type.GetConstantW()) < 0) ||
  6856. (from->type.dataType.GetSizeInMemoryBytes() == 1 && asINT8(from->type.GetConstantB()) < 0))
  6857. {
  6858. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  6859. }
  6860. // Check if any data is lost
  6861. if( from->type.dataType.GetSizeInMemoryBytes() > 4 && (from->type.GetConstantQW() >> 32) != 0 && (from->type.GetConstantQW() >> 32) != 0xFFFFFFFF )
  6862. {
  6863. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6864. }
  6865. // Convert to 32bit
  6866. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6867. from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), (asINT8)from->type.GetConstantB());
  6868. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6869. from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), (asINT16)from->type.GetConstantW());
  6870. else if (from->type.dataType.GetSizeInMemoryBytes() == 4 )
  6871. from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), (int)from->type.GetConstantDW());
  6872. else
  6873. from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), (int)(asINT64)from->type.GetConstantQW());
  6874. // Try once more, in case of a smaller type
  6875. ImplicitConversionConstant(from, to, node, convType);
  6876. }
  6877. else if( from->type.dataType.IsUnsignedType() &&
  6878. from->type.dataType.GetSizeInMemoryBytes() < 4 )
  6879. {
  6880. // Convert to 32bit
  6881. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6882. from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), from->type.GetConstantB());
  6883. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6884. from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), from->type.GetConstantW());
  6885. // Try once more, in case of a smaller type
  6886. ImplicitConversionConstant(from, to, node, convType);
  6887. }
  6888. else if( from->type.dataType.IsUnsignedType() &&
  6889. from->type.dataType.GetSizeInMemoryBytes() > to.GetSizeInMemoryBytes() )
  6890. {
  6891. // Verify if it is possible
  6892. if( to.GetSizeInMemoryBytes() == 1 )
  6893. {
  6894. if( (from->type.dataType.GetSizeInMemoryBytes() == 2 && asBYTE(from->type.GetConstantW()) != from->type.GetConstantW()) ||
  6895. (from->type.dataType.GetSizeInMemoryBytes() == 4 && asBYTE(from->type.GetConstantDW()) != from->type.GetConstantDW()) ||
  6896. (from->type.dataType.GetSizeInMemoryBytes() == 8 && asBYTE(from->type.GetConstantQW()) != from->type.GetConstantQW()) )
  6897. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6898. if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6899. from->type.SetConstantB(asCDataType::CreatePrimitive(to.GetTokenType(), true), asBYTE(from->type.GetConstantW()));
  6900. else if (from->type.dataType.GetSizeInMemoryBytes() == 4)
  6901. from->type.SetConstantB(asCDataType::CreatePrimitive(to.GetTokenType(), true), asBYTE(from->type.GetConstantDW()));
  6902. else if (from->type.dataType.GetSizeInMemoryBytes() == 8)
  6903. from->type.SetConstantB(asCDataType::CreatePrimitive(to.GetTokenType(), true), asBYTE(from->type.GetConstantQW()));
  6904. }
  6905. else if( to.GetSizeInMemoryBytes() == 2 )
  6906. {
  6907. if( (from->type.dataType.GetSizeInMemoryBytes() == 4 && asWORD(from->type.GetConstantDW()) != from->type.GetConstantDW()) ||
  6908. (from->type.dataType.GetSizeInMemoryBytes() == 8 && asWORD(from->type.GetConstantQW()) != from->type.GetConstantQW()) )
  6909. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6910. if (from->type.dataType.GetSizeInMemoryBytes() == 4)
  6911. from->type.SetConstantW(asCDataType::CreatePrimitive(to.GetTokenType(), true), asWORD(from->type.GetConstantDW()));
  6912. else if (from->type.dataType.GetSizeInMemoryBytes() == 8)
  6913. from->type.SetConstantW(asCDataType::CreatePrimitive(to.GetTokenType(), true), asWORD(from->type.GetConstantQW()));
  6914. }
  6915. else if (to.GetSizeInMemoryBytes() == 4)
  6916. {
  6917. if( asDWORD(from->type.GetConstantQW()) != from->type.GetConstantQW())
  6918. if (convType != asIC_EXPLICIT_VAL_CAST && node) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6919. from->type.SetConstantDW(asCDataType::CreatePrimitive(to.GetTokenType(), true), asDWORD(from->type.GetConstantQW()));
  6920. }
  6921. }
  6922. }
  6923. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 2 )
  6924. {
  6925. if( from->type.dataType.IsFloatType() )
  6926. {
  6927. float fc = from->type.GetConstantF();
  6928. // Convert first to int64 then to uint64 to avoid negative float becoming 0 on gnuc base compilers
  6929. asQWORD uic = asQWORD(asINT64(fc));
  6930. #if !defined(_MSC_VER) || _MSC_VER > 1200 // MSVC++ 6
  6931. // MSVC6 doesn't support this conversion
  6932. if( float(uic) != fc )
  6933. {
  6934. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6935. }
  6936. #endif
  6937. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), uic);
  6938. }
  6939. else if( from->type.dataType.IsDoubleType() )
  6940. {
  6941. double fc = from->type.GetConstantD();
  6942. // Convert first to int64 then to uint64 to avoid negative float becoming 0 on gnuc base compilers
  6943. asQWORD uic = asQWORD(asINT64(fc));
  6944. #if !defined(_MSC_VER) || _MSC_VER > 1200 // MSVC++ 6
  6945. // MSVC6 doesn't support this conversion
  6946. if( double(uic) != fc )
  6947. {
  6948. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6949. }
  6950. #endif
  6951. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), uic);
  6952. }
  6953. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  6954. {
  6955. // Convert to 64bit
  6956. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6957. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), (asINT64)(asINT8)from->type.GetConstantB());
  6958. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6959. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), (asINT64)(asINT16)from->type.GetConstantW());
  6960. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  6961. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), (asINT64)(int)from->type.GetConstantDW());
  6962. // Verify that it is possible to convert to unsigned without loosing negative
  6963. if( asINT64(from->type.GetConstantQW()) < 0 )
  6964. {
  6965. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  6966. }
  6967. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  6968. }
  6969. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  6970. {
  6971. // Verify that it is possible to convert to unsigned without loosing negative
  6972. if( asINT64(from->type.GetConstantQW()) < 0 )
  6973. {
  6974. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  6975. }
  6976. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  6977. }
  6978. else if( from->type.dataType.IsUnsignedType() )
  6979. {
  6980. // Convert to 64bit
  6981. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6982. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), from->type.GetConstantB());
  6983. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6984. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), from->type.GetConstantW());
  6985. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  6986. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), from->type.GetConstantDW());
  6987. }
  6988. }
  6989. else if( to.IsFloatType() )
  6990. {
  6991. if( from->type.dataType.IsDoubleType() )
  6992. {
  6993. double ic = from->type.GetConstantD();
  6994. float fc = float(ic);
  6995. from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  6996. }
  6997. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  6998. {
  6999. // Must properly convert value in case the from value is smaller
  7000. int ic;
  7001. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  7002. ic = (asINT8)from->type.GetConstantB();
  7003. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  7004. ic = (asINT16)from->type.GetConstantW();
  7005. else
  7006. ic = (int)from->type.GetConstantDW();
  7007. float fc = float(ic);
  7008. if( int(fc) != ic )
  7009. {
  7010. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  7011. }
  7012. from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  7013. }
  7014. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  7015. {
  7016. float fc = float(asINT64(from->type.GetConstantQW()));
  7017. if( asINT64(fc) != asINT64(from->type.GetConstantQW()) )
  7018. {
  7019. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  7020. }
  7021. from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  7022. }
  7023. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  7024. {
  7025. // Must properly convert value in case the from value is smaller
  7026. unsigned int uic;
  7027. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  7028. uic = from->type.GetConstantB();
  7029. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  7030. uic = from->type.GetConstantW();
  7031. else
  7032. uic = from->type.GetConstantDW();
  7033. float fc = float(uic);
  7034. if( (unsigned int)(fc) != uic )
  7035. {
  7036. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  7037. }
  7038. from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  7039. }
  7040. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  7041. {
  7042. float fc = float((asINT64)from->type.GetConstantQW());
  7043. if( asQWORD(fc) != from->type.GetConstantQW())
  7044. {
  7045. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  7046. }
  7047. from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  7048. }
  7049. }
  7050. else if( to.IsDoubleType() )
  7051. {
  7052. if( from->type.dataType.IsFloatType() )
  7053. {
  7054. float ic = from->type.GetConstantF();
  7055. double fc = double(ic);
  7056. from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  7057. }
  7058. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  7059. {
  7060. // Must properly convert value in case the from value is smaller
  7061. int ic;
  7062. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  7063. ic = (asINT8)from->type.GetConstantB();
  7064. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  7065. ic = (asINT16)from->type.GetConstantW();
  7066. else
  7067. ic = (int)from->type.GetConstantDW();
  7068. double fc = double(ic);
  7069. if( int(fc) != ic )
  7070. {
  7071. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  7072. }
  7073. from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  7074. }
  7075. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  7076. {
  7077. double fc = double(asINT64(from->type.GetConstantQW()));
  7078. if( asINT64(fc) != asINT64(from->type.GetConstantQW()) )
  7079. {
  7080. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  7081. }
  7082. from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  7083. }
  7084. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  7085. {
  7086. // Must properly convert value in case the from value is smaller
  7087. unsigned int uic;
  7088. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  7089. uic = from->type.GetConstantB();
  7090. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  7091. uic = from->type.GetConstantW();
  7092. else
  7093. uic = from->type.GetConstantDW();
  7094. double fc = double(uic);
  7095. if( (unsigned int)(fc) != uic )
  7096. {
  7097. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  7098. }
  7099. from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  7100. }
  7101. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  7102. {
  7103. double fc = double((asINT64)from->type.GetConstantQW());
  7104. if( asQWORD(fc) != from->type.GetConstantQW())
  7105. {
  7106. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  7107. }
  7108. from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  7109. }
  7110. }
  7111. }
  7112. int asCCompiler::DoAssignment(asCExprContext *ctx, asCExprContext *lctx, asCExprContext *rctx, asCScriptNode *lexpr, asCScriptNode *rexpr, eTokenType op, asCScriptNode *opNode)
  7113. {
  7114. // Don't allow any operators on expressions that take address of class method
  7115. // If methodName is set but the type is not an object, then it is a global function
  7116. if( lctx->methodName != "" || rctx->IsClassMethod() )
  7117. {
  7118. Error(TXT_INVALID_OP_ON_METHOD, opNode);
  7119. return -1;
  7120. }
  7121. // Implicit handle types should always be treated as handles in assignments
  7122. if (lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE) )
  7123. {
  7124. lctx->type.dataType.MakeHandle(true);
  7125. lctx->type.isExplicitHandle = true;
  7126. }
  7127. // Urho3D: if there is a handle type, and it does not have an overloaded assignment operator, convert to an explicit handle
  7128. // for scripting convenience. (For the Urho3D handle types, value assignment is not supported)
  7129. if (lctx->type.dataType.IsObjectHandle() && !lctx->type.dataType.IsTemplate() && !lctx->type.isExplicitHandle &&
  7130. (!lctx->type.dataType.GetBehaviour() || !lctx->type.dataType.GetBehaviour()->copy))
  7131. lctx->type.isExplicitHandle = true;
  7132. // If the left hand expression is a property accessor, then that should be used
  7133. // to do the assignment instead of the ordinary operator. The exception is when
  7134. // the property accessor is for a handle property, and the operation is a value
  7135. // assignment.
  7136. if( (lctx->property_get || lctx->property_set) &&
  7137. !(lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle) )
  7138. {
  7139. if( op != ttAssignment )
  7140. {
  7141. // Generate the code for the compound assignment, i.e. get the value, apply operator, then set the value
  7142. return ProcessPropertyGetSetAccessor(ctx, lctx, rctx, op, opNode);
  7143. }
  7144. // It is not allowed to do a handle assignment on a property
  7145. // accessor that doesn't take a handle in the set accessor.
  7146. if( lctx->property_set && lctx->type.isExplicitHandle )
  7147. {
  7148. // set_opIndex has 2 arguments, where as normal setters have only 1
  7149. asCArray<asCDataType>& parameterTypes =
  7150. builder->GetFunctionDescription(lctx->property_set)->parameterTypes;
  7151. if( !parameterTypes[parameterTypes.GetLength() - 1].IsObjectHandle() )
  7152. {
  7153. // Process the property to free the memory
  7154. ProcessPropertySetAccessor(lctx, rctx, opNode);
  7155. Error(TXT_HANDLE_ASSIGN_ON_NON_HANDLE_PROP, opNode);
  7156. return -1;
  7157. }
  7158. }
  7159. MergeExprBytecodeAndType(ctx, lctx);
  7160. return ProcessPropertySetAccessor(ctx, rctx, opNode);
  7161. }
  7162. else if( lctx->property_get && lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle )
  7163. {
  7164. // Get the handle to the object that will be used for the value assignment
  7165. if( ProcessPropertyGetAccessor(lctx, opNode) < 0 )
  7166. return -1;
  7167. }
  7168. if( lctx->type.dataType.IsPrimitive() )
  7169. {
  7170. if( !lctx->type.isLValue )
  7171. {
  7172. Error(TXT_NOT_LVALUE, lexpr);
  7173. return -1;
  7174. }
  7175. if( op != ttAssignment )
  7176. {
  7177. // Compute the operator before the assignment
  7178. asCExprValue lvalue = lctx->type;
  7179. if( lctx->type.isTemporary && !lctx->type.isVariable )
  7180. {
  7181. // The temporary variable must not be freed until the
  7182. // assignment has been performed. lvalue still holds
  7183. // the information about the temporary variable
  7184. lctx->type.isTemporary = false;
  7185. }
  7186. asCExprContext o(engine);
  7187. CompileOperator(opNode, lctx, rctx, &o);
  7188. MergeExprBytecode(rctx, &o);
  7189. rctx->type = o.type;
  7190. // Convert the rvalue to the right type and validate it
  7191. PrepareForAssignment(&lvalue.dataType, rctx, rexpr, false);
  7192. MergeExprBytecode(ctx, rctx);
  7193. lctx->type = lvalue;
  7194. // The lvalue continues the same, either it was a variable, or a reference in the register
  7195. }
  7196. else
  7197. {
  7198. // Convert the rvalue to the right type and validate it
  7199. PrepareForAssignment(&lctx->type.dataType, rctx, rexpr, false, lctx);
  7200. MergeExprBytecode(ctx, rctx);
  7201. MergeExprBytecode(ctx, lctx);
  7202. }
  7203. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  7204. PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode);
  7205. ctx->type = lctx->type;
  7206. }
  7207. else if( lctx->type.isExplicitHandle )
  7208. {
  7209. if( !lctx->type.isLValue )
  7210. {
  7211. Error(TXT_NOT_LVALUE, lexpr);
  7212. return -1;
  7213. }
  7214. // Object handles don't have any compound assignment operators
  7215. if( op != ttAssignment )
  7216. {
  7217. asCString str;
  7218. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  7219. Error(str, lexpr);
  7220. return -1;
  7221. }
  7222. if( lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) )
  7223. {
  7224. // The object is a value type but that should be treated as a handle
  7225. // Make sure the right hand value is a handle
  7226. if( !rctx->type.isExplicitHandle &&
  7227. !(rctx->type.dataType.GetTypeInfo() && (rctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE)) )
  7228. {
  7229. // Function names can be considered handles already
  7230. if( rctx->methodName == "" )
  7231. {
  7232. asCDataType dt = rctx->type.dataType;
  7233. dt.MakeHandle(true);
  7234. dt.MakeReference(false);
  7235. PrepareArgument(&dt, rctx, rexpr, true, asTM_INREF);
  7236. if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) )
  7237. {
  7238. asCString str;
  7239. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  7240. Error(str, rexpr);
  7241. return -1;
  7242. }
  7243. }
  7244. if (!rctx->type.dataType.IsObjectHandle() && !rctx->type.dataType.SupportHandles())
  7245. {
  7246. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, rexpr);
  7247. return -1;
  7248. }
  7249. // Mark the right hand expression as explicit handle even if the user didn't do it, otherwise
  7250. // the code for moving the argument to the stack may not know to correctly handle the argument type
  7251. // in case of variable parameter type.
  7252. rctx->type.isExplicitHandle = true;
  7253. }
  7254. if( CompileOverloadedDualOperator(opNode, lctx, rctx, false, ctx, true) )
  7255. {
  7256. // An overloaded assignment operator was found (or a compilation error occured)
  7257. return 0;
  7258. }
  7259. // The object must implement the opAssign method
  7260. asCString msg;
  7261. msg.Format(TXT_NO_APPROPRIATE_OPHNDLASSIGN_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  7262. Error(msg.AddressOf(), opNode);
  7263. return -1;
  7264. }
  7265. else
  7266. {
  7267. asCDataType dt = lctx->type.dataType;
  7268. dt.MakeReference(false);
  7269. PrepareArgument(&dt, rctx, rexpr, false, asTM_INREF , true);
  7270. if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) )
  7271. {
  7272. asCString str;
  7273. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  7274. Error(str, rexpr);
  7275. return -1;
  7276. }
  7277. MergeExprBytecode(ctx, rctx);
  7278. MergeExprBytecode(ctx, lctx);
  7279. if(!rctx->type.isRefSafe)
  7280. ctx->bc.InstrWORD(asBC_GETOBJREF, AS_PTR_SIZE);
  7281. PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode);
  7282. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  7283. ctx->type = lctx->type;
  7284. // After the handle assignment the original handle is left on the stack
  7285. ctx->type.dataType.MakeReference(false);
  7286. }
  7287. }
  7288. else // if( lctx->type.dataType.IsObject() )
  7289. {
  7290. // The lvalue reference may be marked as a temporary, if for example
  7291. // it was originated as a handle returned from a function. In such
  7292. // cases it must be possible to assign values to it anyway.
  7293. if( lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle )
  7294. {
  7295. // Convert the handle to a object reference
  7296. asCDataType to;
  7297. to = lctx->type.dataType;
  7298. to.MakeHandle(false);
  7299. ImplicitConversion(lctx, to, lexpr, asIC_IMPLICIT_CONV);
  7300. lctx->type.isLValue = true; // Handle may not have been an lvalue, but the dereferenced object is
  7301. }
  7302. // Check for overloaded assignment operator
  7303. if( CompileOverloadedDualOperator(opNode, lctx, rctx, false, ctx) )
  7304. {
  7305. // An overloaded assignment operator was found (or a compilation error occured)
  7306. return 0;
  7307. }
  7308. // No registered operator was found. In case the operation is a direct
  7309. // assignment and the rvalue is the same type as the lvalue, then we can
  7310. // still use the byte-for-byte copy to do the assignment
  7311. if( op != ttAssignment )
  7312. {
  7313. asCString str;
  7314. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  7315. Error(str, lexpr);
  7316. return -1;
  7317. }
  7318. // If the left hand expression is simple, i.e. without any
  7319. // function calls or allocations of memory, then we can avoid
  7320. // doing a copy of the right hand expression (done by PrepareArgument).
  7321. // Instead the reference to the value can be placed directly on the
  7322. // stack.
  7323. //
  7324. // This optimization should only be done for value types, where
  7325. // the application developer is responsible for making the
  7326. // implementation safe against unwanted destruction of the input
  7327. // reference before the time.
  7328. bool simpleExpr = (lctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) && lctx->bc.IsSimpleExpression();
  7329. // Implicitly convert the rvalue to the type of the lvalue
  7330. bool needConversion = false;
  7331. if( !lctx->type.dataType.IsEqualExceptRefAndConst(rctx->type.dataType) )
  7332. needConversion = true;
  7333. if( !simpleExpr || needConversion )
  7334. {
  7335. if( rctx->type.dataType.IsObjectHandle() && !rctx->type.isExplicitHandle &&
  7336. !lctx->type.dataType.IsObjectHandle() && rctx->type.dataType.GetTypeInfo() == lctx->type.dataType.GetTypeInfo() )
  7337. {
  7338. // Make the conversion from handle to non-handle without creating
  7339. // a copy of the object (otherwise done by PrepareArgument)
  7340. asCDataType dt = rctx->type.dataType;
  7341. dt.MakeHandle(false);
  7342. ImplicitConversion(rctx, dt, rexpr, asIC_IMPLICIT_CONV);
  7343. needConversion = false;
  7344. }
  7345. asCDataType dt = lctx->type.dataType;
  7346. dt.MakeReference(true);
  7347. // A funcdef can be accessed by ref, but only as read-only
  7348. if( dt.IsFuncdef() && !dt.IsObjectHandle() )
  7349. dt.MakeReadOnly(true);
  7350. int r = PrepareArgument(&dt, rctx, rexpr, true, 1, !needConversion);
  7351. if( r < 0 )
  7352. return -1;
  7353. if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) )
  7354. {
  7355. asCString str;
  7356. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  7357. Error(str, rexpr);
  7358. return -1;
  7359. }
  7360. }
  7361. else
  7362. {
  7363. // Process any property accessor first, before placing the final reference on the stack
  7364. if( ProcessPropertyGetAccessor(rctx, rexpr) < 0 )
  7365. return -1;
  7366. if( rctx->type.dataType.IsReference() && (!(rctx->type.isVariable || rctx->type.isTemporary) || IsVariableOnHeap(rctx->type.stackOffset)) )
  7367. rctx->bc.Instr(asBC_RDSPtr);
  7368. }
  7369. MergeExprBytecode(ctx, rctx);
  7370. MergeExprBytecode(ctx, lctx);
  7371. if( !simpleExpr || needConversion )
  7372. {
  7373. if( !rctx->type.isRefSafe && (rctx->type.isVariable || rctx->type.isTemporary) )
  7374. {
  7375. if( !IsVariableOnHeap(rctx->type.stackOffset) )
  7376. // TODO: runtime optimize: Actually the reference can be pushed on the stack directly
  7377. // as the value allocated on the stack is guaranteed to be safe.
  7378. // The bytecode optimizer should be able to determine this and optimize away the VAR + GETREF
  7379. ctx->bc.InstrWORD(asBC_GETREF, AS_PTR_SIZE);
  7380. else
  7381. ctx->bc.InstrWORD(asBC_GETOBJREF, AS_PTR_SIZE);
  7382. }
  7383. }
  7384. PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode);
  7385. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  7386. ctx->type = lctx->type;
  7387. }
  7388. return 0;
  7389. }
  7390. int asCCompiler::CompileAssignment(asCScriptNode *expr, asCExprContext *ctx)
  7391. {
  7392. asASSERT(expr->nodeType == snAssignment);
  7393. asCScriptNode *lexpr = expr->firstChild;
  7394. if( lexpr->next )
  7395. {
  7396. // Compile the two expression terms
  7397. asCExprContext lctx(engine), rctx(engine);
  7398. int rr = CompileAssignment(lexpr->next->next, &rctx);
  7399. int lr = CompileCondition(lexpr, &lctx);
  7400. if( lr >= 0 && rr >= 0 )
  7401. return DoAssignment(ctx, &lctx, &rctx, lexpr, lexpr->next->next, lexpr->next->tokenType, lexpr->next);
  7402. // Since the operands failed, the assignment was not computed
  7403. ctx->type.SetDummy();
  7404. return -1;
  7405. }
  7406. return CompileCondition(lexpr, ctx);
  7407. }
  7408. int asCCompiler::CompileCondition(asCScriptNode *expr, asCExprContext *ctx)
  7409. {
  7410. asCExprValue ctype;
  7411. // Compile the conditional expression
  7412. asCScriptNode *cexpr = expr->firstChild;
  7413. if( cexpr->next )
  7414. {
  7415. //-------------------------------
  7416. // Compile the condition
  7417. asCExprContext e(engine);
  7418. int r = CompileExpression(cexpr, &e);
  7419. if( r < 0 )
  7420. e.type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  7421. // Allow value types to be converted to bool using 'bool opImplConv()'
  7422. if( e.type.dataType.GetTypeInfo() && (e.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
  7423. ImplicitConversion(&e, asCDataType::CreatePrimitive(ttBool, false), cexpr, asIC_IMPLICIT_CONV);
  7424. if( r >= 0 && !e.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  7425. {
  7426. Error(TXT_EXPR_MUST_BE_BOOL, cexpr);
  7427. e.type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  7428. }
  7429. ctype = e.type;
  7430. if( ProcessPropertyGetAccessor(&e, cexpr) < 0)
  7431. return -1;
  7432. if( e.type.dataType.IsReference() ) ConvertToVariable(&e);
  7433. ProcessDeferredParams(&e);
  7434. //-------------------------------
  7435. // Compile the left expression
  7436. asCExprContext le(engine);
  7437. int lr = CompileAssignment(cexpr->next, &le);
  7438. // Resolve any function names already
  7439. DetermineSingleFunc(&le, cexpr->next);
  7440. //-------------------------------
  7441. // Compile the right expression
  7442. asCExprContext re(engine);
  7443. int rr = CompileAssignment(cexpr->next->next, &re);
  7444. DetermineSingleFunc(&re, cexpr->next->next);
  7445. if (lr >= 0 && rr >= 0)
  7446. {
  7447. // Don't allow any operators on expressions that take address of class method
  7448. if (le.IsClassMethod() || re.IsClassMethod())
  7449. {
  7450. Error(TXT_INVALID_OP_ON_METHOD, expr);
  7451. return -1;
  7452. }
  7453. if (ProcessPropertyGetAccessor(&le, cexpr->next) < 0)
  7454. return -1;
  7455. if (ProcessPropertyGetAccessor(&re, cexpr->next->next) < 0)
  7456. return -1;
  7457. bool isExplicitHandle = le.type.isExplicitHandle || re.type.isExplicitHandle;
  7458. // Allow an anonymous initialization list to be converted to the type in the other condition
  7459. if (le.IsAnonymousInitList() && re.type.dataType.GetBehaviour() && re.type.dataType.GetBehaviour()->listFactory)
  7460. {
  7461. asCDataType to = re.type.dataType;
  7462. to.MakeReference(false);
  7463. to.MakeReadOnly(false);
  7464. ImplicitConversion(&le, to, cexpr->next, asIC_IMPLICIT_CONV);
  7465. }
  7466. else if (re.IsAnonymousInitList() && le.type.dataType.GetBehaviour() && le.type.dataType.GetBehaviour()->listFactory)
  7467. {
  7468. asCDataType to = le.type.dataType;
  7469. to.MakeReference(false);
  7470. to.MakeReadOnly(false);
  7471. ImplicitConversion(&re, to, cexpr->next->next, asIC_IMPLICIT_CONV);
  7472. }
  7473. if (le.IsAnonymousInitList())
  7474. {
  7475. Error(TXT_CANNOT_RESOLVE_AUTO, cexpr->next);
  7476. return -1;
  7477. }
  7478. else if (re.IsAnonymousInitList())
  7479. {
  7480. Error(TXT_CANNOT_RESOLVE_AUTO, cexpr->next->next);
  7481. return -1;
  7482. }
  7483. // Try to perform an implicit cast to make the two operands of the same type
  7484. // Choose the conversion that is the least costly
  7485. if (le.type.dataType != re.type.dataType)
  7486. {
  7487. asCExprContext tmp(engine);
  7488. tmp.type = le.type;
  7489. tmp.type.dataType.MakeReference(false);
  7490. asUINT costAtoB = ImplicitConversion(&tmp, re.type.dataType, cexpr->next, asIC_IMPLICIT_CONV, false);
  7491. if (!tmp.type.dataType.IsEqualExceptRef(re.type.dataType))
  7492. costAtoB = 0xFFFFFFFF;
  7493. tmp.type = re.type;
  7494. tmp.type.dataType.MakeReference(false);
  7495. asUINT costBtoA = ImplicitConversion(&tmp, le.type.dataType, cexpr->next->next, asIC_IMPLICIT_CONV, false);
  7496. if (!tmp.type.dataType.IsEqualExceptRef(le.type.dataType))
  7497. costBtoA = 0xFFFFFFFF;
  7498. if (costAtoB < costBtoA && costAtoB != 0xFFFFFFFF)
  7499. {
  7500. Dereference(&le, true);
  7501. ImplicitConversion(&le, re.type.dataType, cexpr->next, asIC_IMPLICIT_CONV, true);
  7502. }
  7503. else if (costAtoB > costBtoA && costBtoA != 0xFFFFFFFF)
  7504. {
  7505. Dereference(&re, true);
  7506. ImplicitConversion(&re, le.type.dataType, cexpr->next->next, asIC_IMPLICIT_CONV, true);
  7507. }
  7508. // If the cost for conversion is the same in both directions we have an ambigious situation,
  7509. // which we do not resolve. In that case the script need to perform an explicit conversion
  7510. }
  7511. // Allow a 0 to be implicitly converted to the other type
  7512. if (le.type.isConstant && le.type.GetConstantData() == 0 && le.type.dataType.IsIntegerType())
  7513. {
  7514. asCDataType to = re.type.dataType;
  7515. to.MakeReference(false);
  7516. to.MakeReadOnly(true);
  7517. ImplicitConversionConstant(&le, to, cexpr->next, asIC_IMPLICIT_CONV);
  7518. }
  7519. else if( re.type.isConstant && re.type.GetConstantData() == 0 && re.type.dataType.IsIntegerType())
  7520. {
  7521. asCDataType to = le.type.dataType;
  7522. to.MakeReference(false);
  7523. to.MakeReadOnly(true);
  7524. ImplicitConversionConstant(&re, to, cexpr->next->next, asIC_IMPLICIT_CONV);
  7525. }
  7526. // Allow expression to be converted to handle if the other is handle
  7527. if (!le.type.dataType.IsObjectHandle() && re.type.dataType.IsObjectHandle() && le.type.dataType.GetTypeInfo() == re.type.dataType.GetTypeInfo() )
  7528. {
  7529. asCDataType dt = le.type.dataType;
  7530. dt.MakeHandle(true);
  7531. ImplicitConversion(&le, dt, cexpr->next, asIC_IMPLICIT_CONV);
  7532. }
  7533. if (!re.type.dataType.IsObjectHandle() && le.type.dataType.IsObjectHandle() && le.type.dataType.GetTypeInfo() == re.type.dataType.GetTypeInfo())
  7534. {
  7535. asCDataType dt = re.type.dataType;
  7536. dt.MakeHandle(true);
  7537. ImplicitConversion(&re, dt, cexpr->next->next, asIC_IMPLICIT_CONV);
  7538. }
  7539. // Allow either case to be converted to const @ if the other is const @
  7540. if( (le.type.dataType.IsHandleToConst() && !le.type.IsNullConstant()) || (re.type.dataType.IsHandleToConst() && !re.type.dataType.IsNullHandle()) )
  7541. {
  7542. le.type.dataType.MakeHandleToConst(true);
  7543. re.type.dataType.MakeHandleToConst(true);
  7544. }
  7545. // Make sure both expressions have the same type
  7546. if (!le.type.dataType.IsEqualExceptRefAndConst(re.type.dataType))
  7547. {
  7548. Error(TXT_BOTH_MUST_BE_SAME, expr);
  7549. return -1;
  7550. }
  7551. //---------------------------------
  7552. // Output the byte code
  7553. int afterLabel = nextLabel++;
  7554. int elseLabel = nextLabel++;
  7555. // If left expression is void, then we don't need to store the result
  7556. if( le.type.dataType.IsEqualExceptConst(asCDataType::CreatePrimitive(ttVoid, false)) )
  7557. {
  7558. // Put the code for the condition expression on the output
  7559. MergeExprBytecode(ctx, &e);
  7560. // Added the branch decision
  7561. ctx->type = e.type;
  7562. ConvertToVariable(ctx);
  7563. ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset);
  7564. ctx->bc.Instr(asBC_ClrHi);
  7565. ctx->bc.InstrDWORD(asBC_JZ, elseLabel);
  7566. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  7567. // Add the left expression
  7568. MergeExprBytecode(ctx, &le);
  7569. ctx->bc.InstrINT(asBC_JMP, afterLabel);
  7570. // Add the right expression
  7571. ctx->bc.Label((short)elseLabel);
  7572. MergeExprBytecode(ctx, &re);
  7573. ctx->bc.Label((short)afterLabel);
  7574. // Set the type of the result
  7575. ctx->type = le.type;
  7576. }
  7577. else if (le.type.IsNullConstant() && re.type.IsNullConstant())
  7578. {
  7579. // Special case for when both results are 'null'
  7580. // TODO: Other expressions where both results are identical literal constants can probably also be handled this way
  7581. // Put the code for the condition expression on the output
  7582. MergeExprBytecode(ctx, &e);
  7583. // Load the result into the register, but ignore the value since both paths give the same response
  7584. ctx->type = e.type;
  7585. ConvertToVariable(ctx);
  7586. ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset);
  7587. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  7588. // Return a null constant
  7589. ctx->bc.Instr(asBC_PshNull);
  7590. ctx->type.SetNullConstant();
  7591. }
  7592. else
  7593. {
  7594. // Allow "(a ? b : c) = d;" and "return (a ? b : c);" (where the latter returns the reference)
  7595. //
  7596. // Restrictions for the condition to be used as lvalue:
  7597. // 1. both b and c must be of the same type and be lvalue references
  7598. // 2. neither of the expressions can have any deferred arguments
  7599. // that would have to be cleaned up after the reference
  7600. // 3. neither expression can be temporary
  7601. //
  7602. // If either expression is local, the resulting lvalue is not valid
  7603. // for return since it is not allowed to return references to local
  7604. // variables.
  7605. //
  7606. // The reference to the local variable must be loaded into the register,
  7607. // the resulting expression must not be considered as a local variable
  7608. // with a stack offset (i.e. it will not be allowed to use asBC_VAR)
  7609. if( le.type.isLValue && re.type.isLValue &&
  7610. le.deferredParams.GetLength() == 0 && re.deferredParams.GetLength() == 0 &&
  7611. !le.type.isTemporary && !re.type.isTemporary &&
  7612. le.type.dataType == re.type.dataType )
  7613. {
  7614. // Put the code for the condition expression on the output
  7615. MergeExprBytecode(ctx, &e);
  7616. // Add the branch decision
  7617. ctx->type = e.type;
  7618. ConvertToVariable(ctx);
  7619. ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset);
  7620. ctx->bc.Instr(asBC_ClrHi);
  7621. ctx->bc.InstrDWORD(asBC_JZ, elseLabel);
  7622. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  7623. // Start of the left expression
  7624. MergeExprBytecode(ctx, &le);
  7625. if( !le.type.dataType.IsReference() && le.type.isVariable )
  7626. {
  7627. // Load the address of the variable into the register
  7628. ctx->bc.InstrSHORT(asBC_LDV, le.type.stackOffset);
  7629. }
  7630. ctx->bc.InstrINT(asBC_JMP, afterLabel);
  7631. // Start of the right expression
  7632. ctx->bc.Label((short)elseLabel);
  7633. MergeExprBytecode(ctx, &re);
  7634. if( !re.type.dataType.IsReference() && re.type.isVariable )
  7635. {
  7636. // Load the address of the variable into the register
  7637. ctx->bc.InstrSHORT(asBC_LDV, re.type.stackOffset);
  7638. }
  7639. ctx->bc.Label((short)afterLabel);
  7640. // In case the options were to objects, it is necessary to dereference the pointer on
  7641. // the stack so it will point to the actual object, instead of the variable
  7642. if( le.type.dataType.IsReference() && le.type.dataType.IsObject() && !le.type.dataType.IsObjectHandle() )
  7643. {
  7644. asASSERT( re.type.dataType.IsReference() && re.type.dataType.IsObject() && !re.type.dataType.IsObjectHandle() );
  7645. ctx->bc.Instr(asBC_RDSPtr);
  7646. }
  7647. // The result is an lvalue
  7648. ctx->type.isLValue = true;
  7649. ctx->type.dataType = le.type.dataType;
  7650. if( ctx->type.dataType.IsPrimitive() || ctx->type.dataType.IsObjectHandle() )
  7651. ctx->type.dataType.MakeReference(true);
  7652. else
  7653. ctx->type.dataType.MakeReference(false);
  7654. // It can't be a treated as a variable, since we don't know which one was used
  7655. ctx->type.isVariable = false;
  7656. ctx->type.isTemporary = false;
  7657. // Must remember if the reference was to a local variable, since it must not be allowed to be returned
  7658. ctx->type.isRefToLocal = le.type.isVariable || le.type.isRefToLocal || re.type.isVariable || re.type.isRefToLocal;
  7659. }
  7660. else
  7661. {
  7662. // Allocate temporary variable and copy the result to that one
  7663. asCExprValue temp;
  7664. temp = le.type;
  7665. temp.dataType.MakeReference(false);
  7666. temp.dataType.MakeReadOnly(false);
  7667. // Make sure the variable isn't used in any of the expressions,
  7668. // as it would be overwritten which may cause crashes or less visible bugs
  7669. int l = int(reservedVariables.GetLength());
  7670. e.bc.GetVarsUsed(reservedVariables);
  7671. le.bc.GetVarsUsed(reservedVariables);
  7672. re.bc.GetVarsUsed(reservedVariables);
  7673. int offset = AllocateVariable(temp.dataType, true, false);
  7674. reservedVariables.SetLength(l);
  7675. temp.SetVariable(temp.dataType, offset, true);
  7676. // TODO: copy: Use copy constructor if available. See PrepareTemporaryVariable()
  7677. CallDefaultConstructor(temp.dataType, offset, IsVariableOnHeap(offset), &ctx->bc, expr);
  7678. // Put the code for the condition expression on the output
  7679. MergeExprBytecode(ctx, &e);
  7680. // Add the branch decision
  7681. ctx->type = e.type;
  7682. ConvertToVariable(ctx);
  7683. ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset);
  7684. ctx->bc.Instr(asBC_ClrHi);
  7685. ctx->bc.InstrDWORD(asBC_JZ, elseLabel);
  7686. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  7687. // Assign the result of the left expression to the temporary variable
  7688. asCExprValue rtemp;
  7689. rtemp = temp;
  7690. if( rtemp.dataType.IsObjectHandle() )
  7691. rtemp.isExplicitHandle = true;
  7692. PrepareForAssignment(&rtemp.dataType, &le, cexpr->next, true);
  7693. MergeExprBytecode(ctx, &le);
  7694. if( !rtemp.dataType.IsPrimitive() )
  7695. {
  7696. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  7697. rtemp.dataType.MakeReference(IsVariableOnHeap(offset));
  7698. }
  7699. asCExprValue result;
  7700. result = rtemp;
  7701. PerformAssignment(&result, &le.type, &ctx->bc, cexpr->next);
  7702. if( !result.dataType.IsPrimitive() )
  7703. ctx->bc.Instr(asBC_PopPtr); // Pop the original value (always a pointer)
  7704. // Release the old temporary variable
  7705. ReleaseTemporaryVariable(le.type, &ctx->bc);
  7706. // Process any deferred arguments in the expressions as these must not survive until after the condition returns
  7707. ProcessDeferredParams(ctx);
  7708. ctx->bc.InstrINT(asBC_JMP, afterLabel);
  7709. // Start of the right expression
  7710. ctx->bc.Label((short)elseLabel);
  7711. // Copy the result to the same temporary variable
  7712. PrepareForAssignment(&rtemp.dataType, &re, cexpr->next, true);
  7713. MergeExprBytecode(ctx, &re);
  7714. if( !rtemp.dataType.IsPrimitive() )
  7715. {
  7716. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  7717. rtemp.dataType.MakeReference(IsVariableOnHeap(offset));
  7718. }
  7719. result = rtemp;
  7720. PerformAssignment(&result, &re.type, &ctx->bc, cexpr->next);
  7721. if( !result.dataType.IsPrimitive() )
  7722. ctx->bc.Instr(asBC_PopPtr); // Pop the original value (always a pointer)
  7723. // Release the old temporary variable
  7724. ReleaseTemporaryVariable(re.type, &ctx->bc);
  7725. // Process any deferred arguments in the expressions as these must not survive until after the condition returns
  7726. ProcessDeferredParams(ctx);
  7727. ctx->bc.Label((short)afterLabel);
  7728. // Set the temporary variable as output
  7729. ctx->type = rtemp;
  7730. ctx->type.isExplicitHandle = isExplicitHandle;
  7731. if( !ctx->type.dataType.IsPrimitive() )
  7732. {
  7733. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  7734. ctx->type.dataType.MakeReference(IsVariableOnHeap(offset));
  7735. }
  7736. // Make sure the output isn't marked as being a literal constant
  7737. ctx->type.isConstant = false;
  7738. }
  7739. }
  7740. }
  7741. else
  7742. {
  7743. ctx->type.SetDummy();
  7744. return -1;
  7745. }
  7746. }
  7747. else
  7748. return CompileExpression(cexpr, ctx);
  7749. return 0;
  7750. }
  7751. int asCCompiler::CompileExpression(asCScriptNode *expr, asCExprContext *ctx)
  7752. {
  7753. asASSERT(expr->nodeType == snExpression);
  7754. // Convert to polish post fix, i.e: a+b => ab+
  7755. asCArray<asCScriptNode *> postfix;
  7756. ConvertToPostFix(expr, postfix);
  7757. // Compile the postfix formatted expression
  7758. return CompilePostFixExpression(&postfix, ctx);
  7759. }
  7760. void asCCompiler::ConvertToPostFix(asCScriptNode *expr, asCArray<asCScriptNode *> &postfix)
  7761. {
  7762. // The algorithm that I've implemented here is similar to
  7763. // Djikstra's Shunting Yard algorithm, though I didn't know it at the time.
  7764. // ref: http://en.wikipedia.org/wiki/Shunting-yard_algorithm
  7765. // Count the nodes in order to preallocate the buffers
  7766. int count = 0;
  7767. asCScriptNode *node = expr->firstChild;
  7768. while( node )
  7769. {
  7770. count++;
  7771. node = node->next;
  7772. }
  7773. asCArray<asCScriptNode *> stackA(count);
  7774. asCArray<asCScriptNode *> &stackB = postfix;
  7775. stackB.Allocate(count, false);
  7776. node = expr->firstChild;
  7777. while( node )
  7778. {
  7779. int precedence = GetPrecedence(node);
  7780. while( stackA.GetLength() > 0 &&
  7781. precedence <= GetPrecedence(stackA[stackA.GetLength()-1]) )
  7782. stackB.PushLast(stackA.PopLast());
  7783. stackA.PushLast(node);
  7784. node = node->next;
  7785. }
  7786. while( stackA.GetLength() > 0 )
  7787. stackB.PushLast(stackA.PopLast());
  7788. }
  7789. int asCCompiler::CompilePostFixExpression(asCArray<asCScriptNode *> *postfix, asCExprContext *ctx)
  7790. {
  7791. // Shouldn't send any byte code
  7792. asASSERT(ctx->bc.GetLastInstr() == -1);
  7793. // Set the context to a dummy type to avoid further
  7794. // errors in case the expression fails to compile
  7795. ctx->type.SetDummy();
  7796. // Evaluate the operands and operators
  7797. asCArray<asCExprContext*> free;
  7798. asCArray<asCExprContext*> expr;
  7799. int ret = 0;
  7800. for( asUINT n = 0; ret == 0 && n < postfix->GetLength(); n++ )
  7801. {
  7802. asCScriptNode *node = (*postfix)[n];
  7803. if( node->nodeType == snExprTerm )
  7804. {
  7805. asCExprContext *e = free.GetLength() ? free.PopLast() : asNEW(asCExprContext)(engine);
  7806. expr.PushLast(e);
  7807. e->exprNode = node;
  7808. ret = CompileExpressionTerm(node, e);
  7809. }
  7810. else
  7811. {
  7812. asCExprContext *r = expr.PopLast();
  7813. asCExprContext *l = expr.PopLast();
  7814. // Now compile the operator
  7815. asCExprContext *e = free.GetLength() ? free.PopLast() : asNEW(asCExprContext)(engine);
  7816. ret = CompileOperator(node, l, r, e);
  7817. expr.PushLast(e);
  7818. // Free the operands
  7819. l->Clear();
  7820. free.PushLast(l);
  7821. r->Clear();
  7822. free.PushLast(r);
  7823. }
  7824. }
  7825. if( ret == 0 )
  7826. {
  7827. asASSERT(expr.GetLength() == 1);
  7828. // The final result should be moved to the output context
  7829. MergeExprBytecodeAndType(ctx, expr[0]);
  7830. }
  7831. // Clean up
  7832. for( asUINT e = 0; e < expr.GetLength(); e++ )
  7833. asDELETE(expr[e], asCExprContext);
  7834. for( asUINT f = 0; f < free.GetLength(); f++ )
  7835. asDELETE(free[f], asCExprContext);
  7836. return ret;
  7837. }
  7838. int asCCompiler::CompileAnonymousInitList(asCScriptNode *node, asCExprContext *ctx, const asCDataType &dt)
  7839. {
  7840. asASSERT(node->nodeType == snInitList);
  7841. // Do not allow constructing non-shared types in shared functions
  7842. if (outFunc->IsShared() &&
  7843. dt.GetTypeInfo() && !dt.GetTypeInfo()->IsShared())
  7844. {
  7845. asCString msg;
  7846. msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, dt.GetTypeInfo()->name.AddressOf());
  7847. Error(msg, node);
  7848. }
  7849. // If this is compiled from a default arg, then use the script code for the default arg
  7850. asCScriptCode *origCode = script;
  7851. if (ctx->origCode)
  7852. script = ctx->origCode;
  7853. // Allocate and initialize the temporary object
  7854. int offset = AllocateVariable(dt, true);
  7855. CompileInitialization(node, &ctx->bc, dt, node, offset, 0, 0);
  7856. // Push the reference to the object on the stack
  7857. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  7858. ctx->type.SetVariable(dt, offset, true);
  7859. ctx->type.isLValue = false;
  7860. // If the variable is allocated on the heap we have a reference,
  7861. // otherwise the actual object pointer is pushed on the stack.
  7862. if (IsVariableOnHeap(offset))
  7863. ctx->type.dataType.MakeReference(true);
  7864. // Clear the flag for anonymous initalization list as it is no
  7865. // longer true now that the object has been initialized.
  7866. ctx->isAnonymousInitList = false;
  7867. ctx->origCode = 0;
  7868. script = origCode;
  7869. return 0;
  7870. }
  7871. int asCCompiler::CompileExpressionTerm(asCScriptNode *node, asCExprContext *ctx)
  7872. {
  7873. // Shouldn't send any byte code
  7874. asASSERT(ctx->bc.GetLastInstr() == -1);
  7875. // Check if this is an initialization of a temp object with an initialization list
  7876. if (node->firstChild )
  7877. {
  7878. if (node->firstChild->nodeType == snDataType)
  7879. {
  7880. // Determine the type of the temporary object
  7881. asCDataType dt = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace);
  7882. return CompileAnonymousInitList(node->lastChild, ctx, dt);
  7883. }
  7884. else if (node->firstChild->nodeType == snInitList)
  7885. {
  7886. // As the type is not yet known, the init list will be compiled at a
  7887. // later time when the type can be determined from the destination
  7888. ctx->SetAnonymousInitList(node->firstChild, script);
  7889. return 0;
  7890. }
  7891. }
  7892. // Set the type as a dummy by default, in case of any compiler errors
  7893. ctx->type.SetDummy();
  7894. // Compile the value node
  7895. asCScriptNode *vnode = node->firstChild;
  7896. while( vnode->nodeType != snExprValue )
  7897. vnode = vnode->next;
  7898. asCExprContext v(engine);
  7899. int r = CompileExpressionValue(vnode, &v);
  7900. if( r < 0 )
  7901. return r;
  7902. // Compile post fix operators
  7903. asCScriptNode *pnode = vnode->next;
  7904. while( pnode )
  7905. {
  7906. r = CompileExpressionPostOp(pnode, &v);
  7907. if( r < 0 )
  7908. return r;
  7909. pnode = pnode->next;
  7910. }
  7911. // Compile pre fix operators
  7912. pnode = vnode->prev;
  7913. while( pnode )
  7914. {
  7915. r = CompileExpressionPreOp(pnode, &v);
  7916. if( r < 0 )
  7917. return r;
  7918. pnode = pnode->prev;
  7919. }
  7920. // Return the byte code and final type description
  7921. MergeExprBytecodeAndType(ctx, &v);
  7922. return 0;
  7923. }
  7924. // returns:
  7925. // SL_LOCALCONST = local constant
  7926. // SL_LOCALVAR = local variable
  7927. // SL_NOMATCH = no match
  7928. asCCompiler::SYMBOLTYPE asCCompiler::SymbolLookupLocalVar(const asCString &name, asCExprContext *outResult)
  7929. {
  7930. sVariable *v = 0;
  7931. if (variables)
  7932. v = variables->GetVariable(name.AddressOf());
  7933. if (v)
  7934. {
  7935. if (v->isPureConstant)
  7936. {
  7937. outResult->type.SetConstantData(v->type, v->constantValue);
  7938. return SL_LOCALCONST;
  7939. }
  7940. outResult->type.SetVariable(v->type, v->stackOffset, false);
  7941. return SL_LOCALVAR;
  7942. }
  7943. return SL_NOMATCH;
  7944. }
  7945. // returns:
  7946. // SL_CLASSPROPACCESS = class property accessor
  7947. // SL_CLASSPROP = class property
  7948. // SL_CLASSMETHOD = class method
  7949. // SL_CLASSTYPE = class child type
  7950. // SL_NOMATCH = no match
  7951. // SL_ERROR = error
  7952. asCCompiler::SYMBOLTYPE asCCompiler::SymbolLookupMember(const asCString &name, asCObjectType *objType, asCExprContext *outResult)
  7953. {
  7954. // See if there are any matching property accessors
  7955. asCExprContext access(engine);
  7956. access.type.Set(asCDataType::CreateType(objType, false));
  7957. access.type.dataType.MakeReference(true);
  7958. int r = 0;
  7959. // Indexed property access
  7960. asCExprContext dummyArg(engine);
  7961. r = FindPropertyAccessor(name, &access, &dummyArg, 0, 0, true);
  7962. if (r == 0)
  7963. {
  7964. // Normal property access
  7965. r = FindPropertyAccessor(name, &access, 0, 0, true);
  7966. }
  7967. if (r <= -3) return SL_ERROR;
  7968. if (r != 0)
  7969. {
  7970. // The symbol matches getters/setters (though not necessarily a compilable match)
  7971. MergeExprBytecodeAndType(outResult, &access);
  7972. outResult->type.dataType.SetTypeInfo(objType);
  7973. return SL_CLASSPROPACCESS;
  7974. }
  7975. // Look for matching properties
  7976. asCDataType dt;
  7977. dt = asCDataType::CreateType(objType, false);
  7978. asCObjectProperty *prop = builder->GetObjectProperty(dt, name.AddressOf());
  7979. if (prop)
  7980. {
  7981. outResult->type.dataType.SetTypeInfo(objType);
  7982. return SL_CLASSPROP;
  7983. }
  7984. // If it is not a property, it may still be the name of a method
  7985. asCObjectType *ot = objType;
  7986. for (asUINT n = 0; n < ot->methods.GetLength(); n++)
  7987. {
  7988. asCScriptFunction *f = engine->scriptFunctions[ot->methods[n]];
  7989. if (f->name == name &&
  7990. (builder->module->m_accessMask & f->accessMask))
  7991. {
  7992. outResult->type.dataType.SetTypeInfo(objType);
  7993. return SL_CLASSMETHOD;
  7994. }
  7995. }
  7996. // If it is not a method, then it can still be a child type
  7997. for (asUINT n = 0; n < ot->childFuncDefs.GetLength(); n++)
  7998. {
  7999. if (ot->childFuncDefs[n]->name == name)
  8000. {
  8001. outResult->type.dataType.SetTypeInfo(objType);
  8002. return SL_CLASSTYPE;
  8003. }
  8004. }
  8005. return SL_NOMATCH;
  8006. }
  8007. // The purpose of this function is to find the entity that matches the symbol name respecting the scope and visibility hierarchy
  8008. // The 'outResult' will be used to return info on what was identified, but no code will be produced by this function
  8009. // input:
  8010. // name = the name of the symbol to look for
  8011. // scope = explicit scope informed
  8012. // 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
  8013. // returns:
  8014. // SL_NOMATCH = no matching symbol
  8015. // SL_LOCALCONST = local constant
  8016. // SL_LOCALVAR = local variable
  8017. // SL_THISPTR = this pointer
  8018. // SL_CLASSPROPACCESS = class property accessor, lookupResult->dataType holds the object type in which the member was found
  8019. // SL_CLASSPROP = class property, lookupResult->dataType holds the object type in which the member was found
  8020. // SL_CLASSMETHOD = class method, lookupResult->dataType holds the object type in which the member was found
  8021. // SL_CLASSTYPE = class child type, lookupResult->dataType holds the object type in which the member was found
  8022. // SL_GLOBALPROPACCESS = global property accessor, lookupResult->symbolNamespace holds the namespace where the symbol was identified
  8023. // SL_GLOBALCONST = global constant, lookupResult->symbolNamespace holds the namespace where the symbol was identified
  8024. // SL_GLOBALVAR = global variable, lookupResult->symbolNamespace holds the namespace where the symbol was identified
  8025. // SL_GLOBALFUNC = global function, lookupResult->symbolNamespace holds the namespace where the symbol was identified
  8026. // SL_GLOBALTYPE = type, lookupResult->dataType holds the type
  8027. // SL_ENUMVAL = enum value, lookupResult->dataType holds the enum type, unless ambigious. lookupResult->symbolNamespace holds the namespace where the symbol was identified
  8028. // SL_ERROR = error
  8029. asCCompiler::SYMBOLTYPE asCCompiler::SymbolLookup(const asCString &name, const asCString &scope, asCObjectType *objType, asCExprContext *outResult)
  8030. {
  8031. asASSERT(outResult);
  8032. // It is a local variable or parameter?
  8033. // This is not accessible by default arg expressions
  8034. if (!isCompilingDefaultArg && scope == "" && !objType )
  8035. {
  8036. SYMBOLTYPE r = SymbolLookupLocalVar(name, outResult);
  8037. if (r != 0)
  8038. return r;
  8039. }
  8040. // Is it a class member?
  8041. if (scope == "" && ((objType) || (outFunc && outFunc->objectType)))
  8042. {
  8043. // 'this' is not accessible by default arg expressions
  8044. if (name == THIS_TOKEN && !objType && !isCompilingDefaultArg)
  8045. {
  8046. asCDataType dt = asCDataType::CreateType(outFunc->objectType, outFunc->IsReadOnly());
  8047. // The object pointer is located at stack position 0
  8048. outResult->type.SetVariable(dt, 0, false);
  8049. return SL_THISPTR;
  8050. }
  8051. // 'super' is not accessible by default arg expressions
  8052. if (m_isConstructor && name == SUPER_TOKEN && !objType && !isCompilingDefaultArg)
  8053. {
  8054. // If the class is derived from another class, then super can be used to call the base' class constructor
  8055. if (outFunc && outFunc->objectType->derivedFrom)
  8056. {
  8057. outResult->type.dataType.SetTypeInfo(outFunc->objectType->derivedFrom);
  8058. return SL_CLASSMETHOD;
  8059. }
  8060. }
  8061. // Look for members in the type
  8062. // class members are only accessible in default arg expressions as post op '.'
  8063. if( !isCompilingDefaultArg || (isCompilingDefaultArg && objType) )
  8064. {
  8065. SYMBOLTYPE r = SymbolLookupMember(name, objType ? objType : outFunc->objectType, outResult);
  8066. if (r != 0)
  8067. return r;
  8068. }
  8069. }
  8070. // Recursively search parent namespaces for global entities
  8071. asSNameSpace *currNamespace = DetermineNameSpace("");
  8072. while( !objType && currNamespace )
  8073. {
  8074. asCString currScope = scope;
  8075. // If the scope contains ::identifier, then use the last identifier as the class name and the rest of it as the namespace
  8076. // TODO: child funcdef: A scope can include a template type, e.g. array<ns::type>
  8077. int n = currScope.FindLast("::");
  8078. asCString typeName = n >= 0 ? currScope.SubString(n + 2) : currScope;
  8079. asCString nsName = n >= 0 ? currScope.SubString(0, n) : asCString("");
  8080. // If the scope represents a type that the current class inherits
  8081. // from then that should be used instead of going through the namespaces
  8082. if (nsName == "" && (outFunc && outFunc->objectType))
  8083. {
  8084. asCObjectType *ot = outFunc->objectType;
  8085. while (ot)
  8086. {
  8087. if (ot->name == typeName)
  8088. {
  8089. SYMBOLTYPE r = SymbolLookupMember(name, ot, outResult);
  8090. if (r != 0)
  8091. return r;
  8092. }
  8093. ot = ot->derivedFrom;
  8094. }
  8095. }
  8096. // If the scope starts with :: then search from the global scope
  8097. if (currScope.GetLength() < 2 || currScope[0] != ':')
  8098. {
  8099. if (nsName != "")
  8100. {
  8101. if (currNamespace->name != "")
  8102. nsName = currNamespace->name + "::" + nsName;
  8103. }
  8104. else
  8105. nsName = currNamespace->name;
  8106. }
  8107. else
  8108. nsName = nsName.SubString(2);
  8109. // Get the namespace for this scope
  8110. asSNameSpace *ns = engine->FindNameSpace(nsName.AddressOf());
  8111. if (ns)
  8112. {
  8113. // Is there a type with typeName in the namespace?
  8114. asCTypeInfo *scopeType = builder->GetType(typeName.AddressOf(), ns, 0);
  8115. // Check if the symbol is a member of that type
  8116. if (scopeType)
  8117. {
  8118. // Is it an object type?
  8119. if (CastToObjectType(scopeType))
  8120. {
  8121. SYMBOLTYPE r = SymbolLookupMember(name, CastToObjectType(scopeType), outResult);
  8122. if (r != 0)
  8123. return r;
  8124. }
  8125. // Is it an enum type?
  8126. if (CastToEnumType(scopeType))
  8127. {
  8128. asDWORD value = 0;
  8129. asCDataType dt;
  8130. if (builder->GetEnumValueFromType(CastToEnumType(scopeType), name.AddressOf(), dt, value))
  8131. {
  8132. // an enum value was resolved
  8133. outResult->type.SetConstantDW(dt, value);
  8134. outResult->symbolNamespace = ns;
  8135. return SL_ENUMVAL;
  8136. }
  8137. }
  8138. }
  8139. }
  8140. // Get the namespace for this scope. This may return null if the scope is an enum
  8141. nsName = currScope;
  8142. // If the scope starts with :: then search from the global scope
  8143. if (currScope.GetLength() < 2 || currScope[0] != ':')
  8144. {
  8145. if (nsName != "")
  8146. {
  8147. if (currNamespace->name != "")
  8148. nsName = currNamespace->name + "::" + nsName;
  8149. }
  8150. else
  8151. nsName = currNamespace->name;
  8152. }
  8153. else
  8154. nsName = nsName.SubString(2);
  8155. ns = engine->FindNameSpace(nsName.AddressOf());
  8156. // Is it a global property?
  8157. if (ns)
  8158. {
  8159. // See if there are any matching global property accessors
  8160. asCExprContext access(engine);
  8161. int r = 0;
  8162. // Indexed property access
  8163. asCExprContext dummyArg(engine);
  8164. r = FindPropertyAccessor(name, &access, &dummyArg, 0, ns);
  8165. if (r == 0)
  8166. {
  8167. // Normal property access
  8168. r = FindPropertyAccessor(name, &access, 0, ns);
  8169. }
  8170. if (r <= -3) return SL_ERROR;
  8171. if (r != 0)
  8172. {
  8173. // The symbol matches getters/setters (though not necessarily a compilable match)
  8174. MergeExprBytecodeAndType(outResult, &access);
  8175. outResult->symbolNamespace = ns;
  8176. return SL_GLOBALPROPACCESS;
  8177. }
  8178. // See if there is any matching global property
  8179. bool isCompiled = true;
  8180. bool isPureConstant = false;
  8181. bool isAppProp = false;
  8182. asQWORD constantValue = 0;
  8183. asCGlobalProperty *prop = builder->GetGlobalProperty(name.AddressOf(), ns, &isCompiled, &isPureConstant, &constantValue, &isAppProp);
  8184. if (prop)
  8185. {
  8186. // If the global property is a pure constant
  8187. // we can allow the compiler to optimize it. Pure
  8188. // constants are global constant variables that were
  8189. // initialized by literal constants.
  8190. if (isPureConstant)
  8191. {
  8192. outResult->type.SetConstantData(prop->type, constantValue);
  8193. outResult->symbolNamespace = ns;
  8194. return SL_GLOBALCONST;
  8195. }
  8196. else
  8197. {
  8198. outResult->type.Set(prop->type);
  8199. outResult->symbolNamespace = ns;
  8200. return SL_GLOBALVAR;
  8201. }
  8202. }
  8203. }
  8204. // Is it the name of a global function?
  8205. if (ns)
  8206. {
  8207. asCArray<int> funcs;
  8208. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  8209. if (funcs.GetLength() > 0)
  8210. {
  8211. // Defer the evaluation of which function until it is actually used
  8212. // Store the namespace and name of the function for later
  8213. outResult->type.SetUndefinedFuncHandle(engine);
  8214. outResult->methodName = ns ? ns->name + "::" + name : name;
  8215. outResult->symbolNamespace = ns;
  8216. return SL_GLOBALFUNC;
  8217. }
  8218. }
  8219. // Check for type names
  8220. if (ns)
  8221. {
  8222. asCTypeInfo *type = builder->GetType(name.AddressOf(), ns, 0);
  8223. if (type)
  8224. {
  8225. outResult->type.dataType = asCDataType::CreateType(type, false);
  8226. return SL_GLOBALTYPE;
  8227. }
  8228. }
  8229. // Is it an enum value?
  8230. if (ns && !engine->ep.requireEnumScope)
  8231. {
  8232. // Look for the enum value without explicitly informing the enum type
  8233. asDWORD value = 0;
  8234. asCDataType dt;
  8235. int e = builder->GetEnumValue(name.AddressOf(), dt, value, ns);
  8236. if (e)
  8237. {
  8238. if (e == 2)
  8239. {
  8240. // Ambiguous enum value: Save the name for resolution later.
  8241. // The ambiguity could be resolved now, but I hesitate
  8242. // to store too much information in the context.
  8243. outResult->enumValue = name.AddressOf();
  8244. // We cannot set a dummy value because it will pass through
  8245. // cleanly as an integer.
  8246. outResult->type.SetConstantDW(asCDataType::CreatePrimitive(ttIdentifier, true), 0);
  8247. outResult->symbolNamespace = ns;
  8248. return SL_ENUMVAL;
  8249. }
  8250. else
  8251. {
  8252. // an enum value was resolved
  8253. outResult->type.SetConstantDW(dt, value);
  8254. outResult->symbolNamespace = ns;
  8255. return SL_ENUMVAL;
  8256. }
  8257. }
  8258. }
  8259. // If the given scope starts with '::' then the search starts from global scope
  8260. if (scope.GetLength() >= 2 && scope[0] == ':')
  8261. break;
  8262. // Move up to parent namespace
  8263. currNamespace = engine->GetParentNameSpace(currNamespace);
  8264. }
  8265. // The name doesn't match any symbol
  8266. return SL_NOMATCH;
  8267. }
  8268. int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &scope, asCExprContext *ctx, asCScriptNode *errNode, bool isOptional, asCObjectType *objType)
  8269. {
  8270. asCExprContext lookupResult(engine);
  8271. SYMBOLTYPE symbolType = SymbolLookup(name, scope, objType, &lookupResult);
  8272. if (symbolType < 0)
  8273. {
  8274. // Give dummy value
  8275. ctx->type.SetDummy();
  8276. return -1;
  8277. }
  8278. if (symbolType == SL_NOMATCH)
  8279. {
  8280. // Give dummy value
  8281. ctx->type.SetDummy();
  8282. if (!isOptional)
  8283. {
  8284. // No matching symbol
  8285. asCString msg;
  8286. asCString smbl;
  8287. if (scope == "::")
  8288. smbl = scope;
  8289. else if (scope != "")
  8290. smbl = scope + "::";
  8291. smbl += name;
  8292. msg.Format(TXT_NO_MATCHING_SYMBOL_s, smbl.AddressOf());
  8293. Error(msg, errNode);
  8294. }
  8295. return -1;
  8296. }
  8297. // It is a local variable or parameter?
  8298. if( symbolType == SL_LOCALCONST || symbolType == SL_LOCALVAR )
  8299. {
  8300. // This is not accessible by default arg expressions
  8301. asASSERT(!isCompilingDefaultArg && scope == "" && !objType && variables);
  8302. sVariable *v = variables->GetVariable(name.AddressOf());
  8303. asASSERT(v);
  8304. if( v->isPureConstant )
  8305. ctx->type.SetConstantData(v->type, v->constantValue);
  8306. else if( v->type.IsPrimitive() )
  8307. {
  8308. if( v->type.IsReference() )
  8309. {
  8310. // Copy the reference into the register
  8311. ctx->bc.InstrSHORT(asBC_PshVPtr, (short)v->stackOffset);
  8312. ctx->bc.Instr(asBC_PopRPtr);
  8313. ctx->type.Set(v->type);
  8314. }
  8315. else
  8316. ctx->type.SetVariable(v->type, v->stackOffset, false);
  8317. // Set as lvalue unless it is a const variable
  8318. if( !v->type.IsReadOnly() )
  8319. ctx->type.isLValue = true;
  8320. }
  8321. else
  8322. {
  8323. ctx->bc.InstrSHORT(asBC_PSF, (short)v->stackOffset);
  8324. ctx->type.SetVariable(v->type, v->stackOffset, false);
  8325. // If the variable is allocated on the heap we have a reference,
  8326. // otherwise the actual object pointer is pushed on the stack.
  8327. if( v->onHeap || v->type.IsObjectHandle() ) ctx->type.dataType.MakeReference(true);
  8328. // Implicitly dereference handle parameters sent by reference
  8329. if( v->type.IsReference() && (!v->type.IsObject() || v->type.IsObjectHandle()) )
  8330. ctx->bc.Instr(asBC_RDSPtr);
  8331. // Mark the object as safe for access unless it is a handle, as the
  8332. // life time of the object is guaranteed throughout the scope.
  8333. if( !v->type.IsObjectHandle() )
  8334. ctx->type.isRefSafe = true;
  8335. // Set as lvalue unless it is a const variable
  8336. if (!v->type.IsReadOnly())
  8337. ctx->type.isLValue = true;
  8338. }
  8339. return 0;
  8340. }
  8341. // Is it a class member?
  8342. if (symbolType == SL_CLASSPROPACCESS || symbolType == SL_CLASSPROP || symbolType == SL_CLASSMETHOD || symbolType == SL_THISPTR)
  8343. {
  8344. // This is not accessible by default arg expressions
  8345. asASSERT(!isCompilingDefaultArg);
  8346. if (symbolType == SL_THISPTR)
  8347. {
  8348. asASSERT(name == THIS_TOKEN && !objType && scope == "");
  8349. asCDataType dt = asCDataType::CreateType(outFunc->objectType, outFunc->IsReadOnly());
  8350. // The object pointer is located at stack position 0
  8351. ctx->bc.InstrSHORT(asBC_PSF, 0);
  8352. ctx->type.SetVariable(dt, 0, false);
  8353. ctx->type.dataType.MakeReference(true);
  8354. ctx->type.isLValue = true;
  8355. // The 'this' handle is always considered safe (i.e. life time guaranteed)
  8356. ctx->type.isRefSafe = true;
  8357. return 0;
  8358. }
  8359. if (symbolType == SL_CLASSPROPACCESS)
  8360. {
  8361. if (scope != "")
  8362. {
  8363. // Cannot access non-static members like this
  8364. asCString msg;
  8365. msg.Format(TXT_CANNOT_ACCESS_NON_STATIC_MEMBER_s, name.AddressOf());
  8366. Error(msg, errNode);
  8367. return -1;
  8368. }
  8369. // See if there are any matching property accessors
  8370. asCExprContext access(engine);
  8371. if (objType)
  8372. access.type.Set(asCDataType::CreateType(objType, false));
  8373. else
  8374. access.type.Set(asCDataType::CreateType(outFunc->objectType, outFunc->IsReadOnly()));
  8375. access.type.dataType.MakeReference(true);
  8376. int r = 0;
  8377. if (errNode->next && errNode->next->tokenType == ttOpenBracket)
  8378. {
  8379. // This is an index access, check if there is a property accessor that takes an index arg
  8380. asCExprContext dummyArg(engine);
  8381. r = FindPropertyAccessor(name, &access, &dummyArg, errNode, 0, true);
  8382. }
  8383. if (r == 0)
  8384. {
  8385. // Normal property access
  8386. r = FindPropertyAccessor(name, &access, errNode, 0, true);
  8387. }
  8388. if (r < 0) return -1;
  8389. if (access.property_get == 0 && access.property_set == 0)
  8390. {
  8391. // Even though the symbol was identified in SymbolLookup, it doesn't match the arguments
  8392. asCString msg;
  8393. if (errNode->next && errNode->next->tokenType == ttOpenBracket)
  8394. msg.Format(TXT_PROP_ACCESS_s_DOES_NOT_EXPECT_INDEX, name.AddressOf());
  8395. else
  8396. msg.Format(TXT_PROP_ACCESS_s_EXPECTS_INDEX, name.AddressOf());
  8397. Error(msg, errNode);
  8398. return -1;
  8399. }
  8400. if (!objType)
  8401. {
  8402. // Prepare the bytecode for the member access
  8403. // This is only done when accessing through the implicit this pointer
  8404. ctx->bc.InstrSHORT(asBC_PSF, 0);
  8405. }
  8406. MergeExprBytecodeAndType(ctx, &access);
  8407. return 0;
  8408. }
  8409. if (symbolType == SL_CLASSPROP)
  8410. {
  8411. if (scope != "")
  8412. {
  8413. // Cannot access non-static members like this
  8414. asCString msg;
  8415. msg.Format(TXT_CANNOT_ACCESS_NON_STATIC_MEMBER_s, name.AddressOf());
  8416. Error(msg, errNode);
  8417. return -1;
  8418. }
  8419. asCDataType dt;
  8420. if (objType)
  8421. dt = asCDataType::CreateType(objType, false);
  8422. else
  8423. dt = asCDataType::CreateType(outFunc->objectType, false);
  8424. asCObjectProperty *prop = builder->GetObjectProperty(dt, name.AddressOf());
  8425. asASSERT(prop);
  8426. // Is the property access allowed?
  8427. if (prop->isPrivate && prop->isInherited)
  8428. {
  8429. if (engine->ep.privatePropAsProtected)
  8430. {
  8431. // The application is allowing inherited classes to access private properties of the parent
  8432. // class. This option is allowed to provide backwards compatibility with pre-2.30.0 versions
  8433. // as it was how the compiler behaved earlier.
  8434. asCString msg;
  8435. msg.Format(TXT_ACCESSING_PRIVATE_PROP_s, name.AddressOf());
  8436. Warning(msg, errNode);
  8437. }
  8438. else
  8439. {
  8440. asCString msg;
  8441. msg.Format(TXT_INHERITED_PRIVATE_PROP_ACCESS_s, name.AddressOf());
  8442. Error(msg, errNode);
  8443. }
  8444. }
  8445. if (!objType)
  8446. {
  8447. // The object pointer is located at stack position 0
  8448. // This is only done when accessing through the implicit this pointer
  8449. ctx->bc.InstrSHORT(asBC_PSF, 0);
  8450. ctx->type.SetVariable(dt, 0, false);
  8451. ctx->type.dataType.MakeReference(true);
  8452. Dereference(ctx, true);
  8453. }
  8454. // TODO: This is the same as what is in CompileExpressionPostOp
  8455. // Put the offset on the stack
  8456. ctx->bc.InstrSHORT_DW(asBC_ADDSi, (short)prop->byteOffset, engine->GetTypeIdFromDataType(dt));
  8457. if (prop->type.IsReference())
  8458. ctx->bc.Instr(asBC_RDSPtr);
  8459. // Reference to primitive must be stored in the temp register
  8460. if (prop->type.IsPrimitive())
  8461. {
  8462. // TODO: runtime optimize: The ADD offset command should store the reference in the register directly
  8463. ctx->bc.Instr(asBC_PopRPtr);
  8464. }
  8465. // Set the new type (keeping info about temp variable)
  8466. ctx->type.dataType = prop->type;
  8467. ctx->type.dataType.MakeReference(true);
  8468. ctx->type.isVariable = false;
  8469. ctx->type.isLValue = true;
  8470. if (ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle())
  8471. {
  8472. // Objects that are members are not references
  8473. ctx->type.dataType.MakeReference(false);
  8474. // Objects that are members but not handles are safe as long as the parent object is safe
  8475. if (!objType || ctx->type.isRefSafe)
  8476. ctx->type.isRefSafe = true;
  8477. }
  8478. else if (ctx->type.dataType.IsObjectHandle())
  8479. {
  8480. // Objects accessed through handles cannot be considered safe
  8481. // as the handle can be cleared at any time
  8482. ctx->type.isRefSafe = false;
  8483. }
  8484. // If the object reference is const, the property will also be const
  8485. ctx->type.dataType.MakeReadOnly(outFunc->IsReadOnly());
  8486. return 0;
  8487. }
  8488. if (symbolType == SL_CLASSMETHOD)
  8489. {
  8490. if (scope != "")
  8491. {
  8492. // Cannot access non-static members like this
  8493. asCString msg;
  8494. msg.Format(TXT_CANNOT_ACCESS_NON_STATIC_MEMBER_s, name.AddressOf());
  8495. Error(msg, errNode);
  8496. return -1;
  8497. }
  8498. #if AS_DEBUG
  8499. // If it is not a property, it may still be the name of a method which can be used to create delegates
  8500. asCObjectType *ot = outFunc->objectType;
  8501. asCScriptFunction *func = 0;
  8502. for (asUINT n = 0; n < ot->methods.GetLength(); n++)
  8503. {
  8504. asCScriptFunction *f = engine->scriptFunctions[ot->methods[n]];
  8505. if (f->name == name &&
  8506. (builder->module->m_accessMask & f->accessMask))
  8507. {
  8508. func = f;
  8509. break;
  8510. }
  8511. }
  8512. asASSERT(func);
  8513. #endif
  8514. // An object method was found. Keep the name of the method in the expression, but
  8515. // don't actually modify the bytecode at this point since it is not yet known what
  8516. // the method will be used for, or even what overloaded method should be used.
  8517. ctx->methodName = name;
  8518. // Place the object pointer on the stack, as if the expression was this.func
  8519. if (!objType)
  8520. {
  8521. // The object pointer is located at stack position 0
  8522. // This is only done when accessing through the implicit this pointer
  8523. ctx->bc.InstrSHORT(asBC_PSF, 0);
  8524. ctx->type.SetVariable(asCDataType::CreateType(outFunc->objectType, false), 0, false);
  8525. ctx->type.dataType.MakeReference(true);
  8526. Dereference(ctx, true);
  8527. }
  8528. return 0;
  8529. }
  8530. }
  8531. if (symbolType == SL_GLOBALCONST || symbolType == SL_GLOBALPROPACCESS || symbolType == SL_GLOBALVAR || symbolType == SL_GLOBALFUNC || symbolType == SL_ENUMVAL)
  8532. {
  8533. // Get the namespace from SymbolLookup
  8534. asSNameSpace *ns = lookupResult.symbolNamespace;
  8535. if (symbolType == SL_GLOBALPROPACCESS)
  8536. {
  8537. // See if there are any matching global property accessors
  8538. asCExprContext access(engine);
  8539. int r = 0;
  8540. if (errNode->next && errNode->next->tokenType == ttOpenBracket)
  8541. {
  8542. // This is an index access, check if there is a property accessor that takes an index arg
  8543. asCExprContext dummyArg(engine);
  8544. r = FindPropertyAccessor(name, &access, &dummyArg, errNode, ns);
  8545. }
  8546. if (r == 0)
  8547. {
  8548. // Normal property access
  8549. r = FindPropertyAccessor(name, &access, errNode, ns);
  8550. }
  8551. if (r < 0) return -1;
  8552. if (access.property_get == 0 && access.property_set == 0)
  8553. {
  8554. // Even though the symbol was identified in SymbolLookup, it doesn't match the arguments
  8555. asCString msg;
  8556. if (errNode->next && errNode->next->tokenType == ttOpenBracket)
  8557. msg.Format(TXT_PROP_ACCESS_s_DOES_NOT_EXPECT_INDEX, name.AddressOf());
  8558. else
  8559. msg.Format(TXT_PROP_ACCESS_s_EXPECTS_INDEX, name.AddressOf());
  8560. Error(msg, errNode);
  8561. return -1;
  8562. }
  8563. // Prepare the bytecode for the function call
  8564. MergeExprBytecodeAndType(ctx, &access);
  8565. return 0;
  8566. }
  8567. if (symbolType == SL_GLOBALCONST || symbolType == SL_GLOBALVAR)
  8568. {
  8569. bool isCompiled = true;
  8570. bool isPureConstant = false;
  8571. bool isAppProp = false;
  8572. asQWORD constantValue = 0;
  8573. asCGlobalProperty *prop = builder->GetGlobalProperty(name.AddressOf(), ns, &isCompiled, &isPureConstant, &constantValue, &isAppProp);
  8574. asASSERT(prop);
  8575. // Verify that the global property has been compiled already
  8576. if (!isCompiled)
  8577. {
  8578. asCString str;
  8579. str.Format(TXT_UNINITIALIZED_GLOBAL_VAR_s, prop->name.AddressOf());
  8580. Error(str, errNode);
  8581. return -1;
  8582. }
  8583. // If the global property is a pure constant
  8584. // we can allow the compiler to optimize it. Pure
  8585. // constants are global constant variables that were
  8586. // initialized by literal constants.
  8587. if (isPureConstant)
  8588. ctx->type.SetConstantData(prop->type, constantValue);
  8589. else
  8590. {
  8591. // A shared type must not access global vars, unless they
  8592. // too are shared, e.g. application registered vars
  8593. if (outFunc->IsShared())
  8594. {
  8595. if (!isAppProp)
  8596. {
  8597. asCString str;
  8598. str.Format(TXT_SHARED_CANNOT_ACCESS_NON_SHARED_VAR_s, prop->name.AddressOf());
  8599. Error(str, errNode);
  8600. // Allow the compilation to continue to catch other problems
  8601. }
  8602. }
  8603. ctx->type.Set(prop->type);
  8604. ctx->type.isLValue = true;
  8605. if (ctx->type.dataType.IsPrimitive())
  8606. {
  8607. // Load the address of the variable into the register
  8608. ctx->bc.InstrPTR(asBC_LDG, prop->GetAddressOfValue());
  8609. ctx->type.dataType.MakeReference(true);
  8610. }
  8611. else
  8612. {
  8613. // Push the address of the variable on the stack
  8614. ctx->bc.InstrPTR(asBC_PGA, prop->GetAddressOfValue());
  8615. // If the object is a value type or a non-handle variable to a reference type,
  8616. // then we must validate the existance as it could potentially be accessed
  8617. // before it is initialized.
  8618. // This check is not needed for application registered properties, since they
  8619. // are guaranteed to be valid by the application itself.
  8620. if (!isAppProp &&
  8621. ((ctx->type.dataType.GetTypeInfo()->flags & asOBJ_VALUE) ||
  8622. !ctx->type.dataType.IsObjectHandle()))
  8623. {
  8624. ctx->bc.Instr(asBC_ChkRefS);
  8625. }
  8626. // If the address pushed on the stack is to a value type or an object
  8627. // handle, then mark the expression as a reference. Addresses to a reference
  8628. // type aren't marked as references to get correct behaviour
  8629. if ((ctx->type.dataType.GetTypeInfo()->flags & asOBJ_VALUE) ||
  8630. ctx->type.dataType.IsObjectHandle())
  8631. {
  8632. ctx->type.dataType.MakeReference(true);
  8633. }
  8634. else
  8635. {
  8636. asASSERT((ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !ctx->type.dataType.IsObjectHandle());
  8637. // It's necessary to dereference the pointer so the pointer on the stack will point to the actual object
  8638. ctx->bc.Instr(asBC_RDSPtr);
  8639. }
  8640. }
  8641. }
  8642. return 0;
  8643. }
  8644. if (symbolType == SL_GLOBALFUNC)
  8645. {
  8646. asCArray<int> funcs;
  8647. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  8648. asASSERT(funcs.GetLength() > 0);
  8649. if (funcs.GetLength() > 0)
  8650. {
  8651. // Defer the evaluation of which function until it is actually used
  8652. // Store the namespace and name of the function for later
  8653. ctx->type.SetUndefinedFuncHandle(engine);
  8654. ctx->methodName = ns ? ns->name + "::" + name : name;
  8655. }
  8656. return 0;
  8657. }
  8658. if (symbolType == SL_ENUMVAL)
  8659. {
  8660. // The enum type and namespace must be returned from SymbolLookup
  8661. asCDataType dt = lookupResult.type.dataType;
  8662. if (!dt.IsEnumType())
  8663. {
  8664. asASSERT(!engine->ep.requireEnumScope);
  8665. // It is an ambigious enum value. The evaluation needs to be deferred for when the type is known
  8666. ctx->enumValue = name.AddressOf();
  8667. ctx->symbolNamespace = lookupResult.symbolNamespace;
  8668. // We cannot set a dummy value because it will pass through
  8669. // cleanly as an integer.
  8670. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttIdentifier, true), 0);
  8671. return 0;
  8672. }
  8673. asDWORD value = 0;
  8674. builder->GetEnumValueFromType(CastToEnumType(lookupResult.type.dataType.GetTypeInfo()), name.AddressOf(), dt, value);
  8675. // Even if the enum type is not shared, and we're compiling a shared object,
  8676. // the use of the values are still allowed, since they are treated as constants.
  8677. // an enum value was resolved
  8678. ctx->type.SetConstantDW(dt, value);
  8679. return 0;
  8680. }
  8681. }
  8682. // The result must have been identified above
  8683. if (symbolType == SL_GLOBALTYPE || symbolType == SL_CLASSTYPE)
  8684. {
  8685. // Give dummy value
  8686. ctx->type.SetDummy();
  8687. // The symbol matches a type
  8688. asCString msg;
  8689. asCString smbl;
  8690. if (scope == "::")
  8691. smbl = scope;
  8692. else if (scope != "")
  8693. smbl = scope + "::";
  8694. smbl += name;
  8695. msg.Format(TXT_EXPR_s_IS_DATA_TYPE, smbl.AddressOf());
  8696. Error(msg, errNode);
  8697. return -1;
  8698. }
  8699. // Should not come here
  8700. asASSERT(false);
  8701. return 0;
  8702. }
  8703. int asCCompiler::CompileExpressionValue(asCScriptNode *node, asCExprContext *ctx)
  8704. {
  8705. // Shouldn't receive any byte code
  8706. asASSERT(ctx->bc.GetLastInstr() == -1);
  8707. asCScriptNode *vnode = node->firstChild;
  8708. ctx->exprNode = vnode;
  8709. if( vnode->nodeType == snVariableAccess )
  8710. {
  8711. // Determine the scope resolution of the variable
  8712. asCString scope = builder->GetScopeFromNode(vnode->firstChild, script, &vnode);
  8713. // Determine the name of the variable
  8714. asASSERT(vnode->nodeType == snIdentifier );
  8715. asCString name(&script->code[vnode->tokenPos], vnode->tokenLength);
  8716. return CompileVariableAccess(name, scope, ctx, node);
  8717. }
  8718. else if( vnode->nodeType == snConstant )
  8719. {
  8720. if( vnode->tokenType == ttIntConstant )
  8721. {
  8722. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  8723. bool overflow = false;
  8724. asQWORD val = asStringScanUInt64(value.AddressOf(), 10, 0, &overflow);
  8725. // Is the number bigger than a 64bit word?
  8726. if (overflow)
  8727. {
  8728. Error(TXT_VALUE_TOO_LARGE_FOR_TYPE, vnode);
  8729. // Set the value to zero to avoid further warnings
  8730. val = 0;
  8731. }
  8732. // Do we need 64 bits?
  8733. // If the 31st bit is set we'll treat the value as a signed 64bit number to avoid
  8734. // incorrect warnings about changing signs if the value is assigned to a 64bit variable
  8735. if( val>>31 )
  8736. {
  8737. // Only if the value uses the last bit of a 64bit word do we consider the number unsigned
  8738. if( val>>63 )
  8739. ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), val);
  8740. else
  8741. ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), val);
  8742. }
  8743. else
  8744. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), asDWORD(val));
  8745. }
  8746. else if( vnode->tokenType == ttBitsConstant )
  8747. {
  8748. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  8749. // Let the function determine the radix from the prefix 0x = 16, 0d = 10, 0o = 8, or 0b = 2
  8750. bool overflow = false;
  8751. asQWORD val = asStringScanUInt64(value.AddressOf(), 0, 0, &overflow);
  8752. // Is the number bigger than a 64bit word?
  8753. if (overflow)
  8754. {
  8755. Error(TXT_VALUE_TOO_LARGE_FOR_TYPE, vnode);
  8756. // Set the value to zero to avoid further warnings
  8757. val = 0;
  8758. }
  8759. // Do we need 64 bits?
  8760. if( val>>32 )
  8761. ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), val);
  8762. else
  8763. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), asDWORD(val));
  8764. }
  8765. else if( vnode->tokenType == ttFloatConstant )
  8766. {
  8767. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  8768. // TODO: Check for overflow
  8769. size_t numScanned;
  8770. float v = float(asStringScanDouble(value.AddressOf(), &numScanned));
  8771. ctx->type.SetConstantF(asCDataType::CreatePrimitive(ttFloat, true), v);
  8772. #ifndef AS_USE_DOUBLE_AS_FLOAT
  8773. // Don't check this if we have double as float, because then the whole token would be scanned (i.e. no f suffix)
  8774. asASSERT(numScanned == vnode->tokenLength - 1);
  8775. #endif
  8776. }
  8777. else if( vnode->tokenType == ttDoubleConstant )
  8778. {
  8779. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  8780. // TODO: Check for overflow
  8781. size_t numScanned;
  8782. double v = asStringScanDouble(value.AddressOf(), &numScanned);
  8783. ctx->type.SetConstantD(asCDataType::CreatePrimitive(ttDouble, true), v);
  8784. asASSERT(numScanned == vnode->tokenLength);
  8785. }
  8786. else if( vnode->tokenType == ttTrue ||
  8787. vnode->tokenType == ttFalse )
  8788. {
  8789. #if AS_SIZEOF_BOOL == 1
  8790. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), vnode->tokenType == ttTrue ? VALUE_OF_BOOLEAN_TRUE : 0);
  8791. #else
  8792. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), vnode->tokenType == ttTrue ? VALUE_OF_BOOLEAN_TRUE : 0);
  8793. #endif
  8794. }
  8795. else if( vnode->tokenType == ttStringConstant ||
  8796. vnode->tokenType == ttMultilineStringConstant ||
  8797. vnode->tokenType == ttHeredocStringConstant )
  8798. {
  8799. asCString str;
  8800. asCScriptNode *snode = vnode->firstChild;
  8801. if( script->code[snode->tokenPos] == '\'' && engine->ep.useCharacterLiterals )
  8802. {
  8803. // Treat the single quoted string as a single character literal
  8804. str.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2);
  8805. asDWORD val = 0;
  8806. if( str.GetLength() && (asBYTE)str[0] > 127 && engine->ep.scanner == 1 )
  8807. {
  8808. // This is the start of a UTF8 encoded character. We need to decode it
  8809. val = asStringDecodeUTF8(str.AddressOf(), 0);
  8810. if( val == (asDWORD)-1 )
  8811. Error(TXT_INVALID_CHAR_LITERAL, vnode);
  8812. }
  8813. else
  8814. {
  8815. val = ProcessStringConstant(str, snode);
  8816. if( val == (asDWORD)-1 )
  8817. Error(TXT_INVALID_CHAR_LITERAL, vnode);
  8818. }
  8819. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), val);
  8820. }
  8821. else
  8822. {
  8823. // Process the string constants
  8824. while( snode )
  8825. {
  8826. asCString cat;
  8827. if( snode->tokenType == ttStringConstant )
  8828. {
  8829. cat.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2);
  8830. ProcessStringConstant(cat, snode);
  8831. }
  8832. else if( snode->tokenType == ttMultilineStringConstant )
  8833. {
  8834. if( !engine->ep.allowMultilineStrings )
  8835. Error(TXT_MULTILINE_STRINGS_NOT_ALLOWED, snode);
  8836. cat.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2);
  8837. ProcessStringConstant(cat, snode);
  8838. }
  8839. else if( snode->tokenType == ttHeredocStringConstant )
  8840. {
  8841. cat.Assign(&script->code[snode->tokenPos+3], snode->tokenLength-6);
  8842. ProcessHeredocStringConstant(cat, snode);
  8843. }
  8844. str += cat;
  8845. snode = snode->next;
  8846. }
  8847. // Call the string factory function to create a string object
  8848. if(engine->stringFactory == 0 )
  8849. {
  8850. // Error
  8851. Error(TXT_STRINGS_NOT_RECOGNIZED, vnode);
  8852. // Give dummy value
  8853. ctx->type.SetDummy();
  8854. return -1;
  8855. }
  8856. else
  8857. {
  8858. void *strPtr = const_cast<void*>(engine->stringFactory->GetStringConstant(str.AddressOf(), (asUINT)str.GetLength()));
  8859. if (strPtr == 0)
  8860. {
  8861. // TODO: A better message is needed
  8862. Error(TXT_NULL_POINTER_ACCESS, vnode);
  8863. ctx->type.SetDummy();
  8864. return -1;
  8865. }
  8866. // Keep the pointer in the list for clean up at exit
  8867. usedStringConstants.PushLast(strPtr);
  8868. // Push the pointer on the stack. The string factory already guarantees that the
  8869. // string object is valid throughout the lifetime of the script so no need to add
  8870. // reference count or make local copy.
  8871. ctx->bc.InstrPTR(asBC_PGA, strPtr);
  8872. ctx->type.Set(engine->stringType);
  8873. // Mark the string as literal constant so the compiler knows it is allowed
  8874. // to treat it differently than an ordinary constant string variable
  8875. ctx->type.isConstant = true;
  8876. // Mark the reference to the string constant as safe, so the compiler can
  8877. // avoid making unnecessary temporary copies when passing the reference to
  8878. // functions.
  8879. ctx->type.isRefSafe = true;
  8880. }
  8881. }
  8882. }
  8883. else if( vnode->tokenType == ttNull )
  8884. {
  8885. ctx->bc.Instr(asBC_PshNull);
  8886. ctx->type.SetNullConstant();
  8887. }
  8888. else
  8889. asASSERT(false);
  8890. }
  8891. else if( vnode->nodeType == snFunctionCall )
  8892. {
  8893. // Determine the scope resolution
  8894. asCString scope = builder->GetScopeFromNode(vnode->firstChild, script);
  8895. return CompileFunctionCall(vnode, ctx, 0, false, scope);
  8896. }
  8897. else if( vnode->nodeType == snConstructCall )
  8898. {
  8899. return CompileConstructCall(vnode, ctx);
  8900. }
  8901. else if( vnode->nodeType == snAssignment )
  8902. {
  8903. asCExprContext e(engine);
  8904. int r = CompileAssignment(vnode, &e);
  8905. if( r < 0 )
  8906. {
  8907. ctx->type.SetDummy();
  8908. return r;
  8909. }
  8910. MergeExprBytecodeAndType(ctx, &e);
  8911. }
  8912. else if( vnode->nodeType == snCast )
  8913. {
  8914. // Implement the cast operator
  8915. return CompileConversion(vnode, ctx);
  8916. }
  8917. else if( vnode->nodeType == snUndefined && vnode->tokenType == ttVoid )
  8918. {
  8919. // This is a void expression
  8920. ctx->SetVoidExpression();
  8921. }
  8922. else if( vnode->nodeType == snFunction )
  8923. {
  8924. // This is an anonymous function
  8925. // Defer the evaluation of the function until it is known where it
  8926. // will be used, which is where the signature will be defined
  8927. ctx->SetLambda(vnode);
  8928. }
  8929. else
  8930. asASSERT(false);
  8931. return 0;
  8932. }
  8933. asUINT asCCompiler::ProcessStringConstant(asCString &cstr, asCScriptNode *node, bool processEscapeSequences)
  8934. {
  8935. int charLiteral = -1;
  8936. // Process escape sequences
  8937. asCArray<char> str((int)cstr.GetLength());
  8938. for( asUINT n = 0; n < cstr.GetLength(); n++ )
  8939. {
  8940. #ifdef AS_DOUBLEBYTE_CHARSET
  8941. // Double-byte charset is only allowed for ASCII and not UTF16 encoded strings
  8942. if( (cstr[n] & 0x80) && engine->ep.scanner == 0 && engine->ep.stringEncoding != 1 )
  8943. {
  8944. // This is the lead character of a double byte character
  8945. // include the trail character without checking it's value.
  8946. str.PushLast(cstr[n]);
  8947. n++;
  8948. str.PushLast(cstr[n]);
  8949. continue;
  8950. }
  8951. #endif
  8952. asUINT val;
  8953. if( processEscapeSequences && cstr[n] == '\\' )
  8954. {
  8955. ++n;
  8956. if( n == cstr.GetLength() )
  8957. {
  8958. if( charLiteral == -1 ) charLiteral = 0;
  8959. return charLiteral;
  8960. }
  8961. // Hexadecimal escape sequences will allow the construction of
  8962. // invalid unicode sequences, but the string should also work as
  8963. // a bytearray so we must support this. The code for working with
  8964. // unicode text must be prepared to handle invalid unicode sequences
  8965. if( cstr[n] == 'x' || cstr[n] == 'X' )
  8966. {
  8967. ++n;
  8968. if( n == cstr.GetLength() ) break;
  8969. val = 0;
  8970. int c = engine->ep.stringEncoding == 1 ? 4 : 2;
  8971. for( ; c > 0 && n < cstr.GetLength(); c--, n++ )
  8972. {
  8973. if( cstr[n] >= '0' && cstr[n] <= '9' )
  8974. val = val*16 + cstr[n] - '0';
  8975. else if( cstr[n] >= 'a' && cstr[n] <= 'f' )
  8976. val = val*16 + cstr[n] - 'a' + 10;
  8977. else if( cstr[n] >= 'A' && cstr[n] <= 'F' )
  8978. val = val*16 + cstr[n] - 'A' + 10;
  8979. else
  8980. break;
  8981. }
  8982. // Rewind one, since the loop will increment it again
  8983. n--;
  8984. // Hexadecimal escape sequences produce exact value, even if it is not proper unicode chars
  8985. if( engine->ep.stringEncoding == 0 )
  8986. {
  8987. str.PushLast((asBYTE)val);
  8988. }
  8989. else
  8990. {
  8991. #ifndef AS_BIG_ENDIAN
  8992. str.PushLast((asBYTE)val);
  8993. str.PushLast((asBYTE)(val>>8));
  8994. #else
  8995. str.PushLast((asBYTE)(val>>8));
  8996. str.PushLast((asBYTE)val);
  8997. #endif
  8998. }
  8999. if( charLiteral == -1 ) charLiteral = val;
  9000. continue;
  9001. }
  9002. else if( cstr[n] == 'u' || cstr[n] == 'U' )
  9003. {
  9004. // \u expects 4 hex digits
  9005. // \U expects 8 hex digits
  9006. bool expect2 = cstr[n] == 'u';
  9007. int c = expect2 ? 4 : 8;
  9008. val = 0;
  9009. for( ; c > 0; c-- )
  9010. {
  9011. ++n;
  9012. if( n == cstr.GetLength() ) break;
  9013. if( cstr[n] >= '0' && cstr[n] <= '9' )
  9014. val = val*16 + cstr[n] - '0';
  9015. else if( cstr[n] >= 'a' && cstr[n] <= 'f' )
  9016. val = val*16 + cstr[n] - 'a' + 10;
  9017. else if( cstr[n] >= 'A' && cstr[n] <= 'F' )
  9018. val = val*16 + cstr[n] - 'A' + 10;
  9019. else
  9020. break;
  9021. }
  9022. if( c != 0 )
  9023. {
  9024. // Give warning about invalid code point
  9025. // TODO: Need code position for warning
  9026. asCString msg;
  9027. msg.Format(TXT_INVALID_UNICODE_FORMAT_EXPECTED_d, expect2 ? 4 : 8);
  9028. Warning(msg, node);
  9029. continue;
  9030. }
  9031. }
  9032. else
  9033. {
  9034. if( cstr[n] == '"' )
  9035. val = '"';
  9036. else if( cstr[n] == '\'' )
  9037. val = '\'';
  9038. else if( cstr[n] == 'n' )
  9039. val = '\n';
  9040. else if( cstr[n] == 'r' )
  9041. val = '\r';
  9042. else if( cstr[n] == 't' )
  9043. val = '\t';
  9044. else if( cstr[n] == '0' )
  9045. val = '\0';
  9046. else if( cstr[n] == '\\' )
  9047. val = '\\';
  9048. else
  9049. {
  9050. // Invalid escape sequence
  9051. Warning(TXT_INVALID_ESCAPE_SEQUENCE, node);
  9052. continue;
  9053. }
  9054. }
  9055. }
  9056. else
  9057. {
  9058. if( engine->ep.scanner == 1 && (cstr[n] & 0x80) )
  9059. {
  9060. unsigned int len;
  9061. val = asStringDecodeUTF8(&cstr[n], &len);
  9062. if( val == 0xFFFFFFFF )
  9063. {
  9064. // Incorrect UTF8 encoding. Use only the first byte
  9065. // TODO: Need code position for warning
  9066. Warning(TXT_INVALID_UNICODE_SEQUENCE_IN_SRC, node);
  9067. val = (unsigned char)cstr[n];
  9068. }
  9069. else
  9070. n += len-1;
  9071. }
  9072. else
  9073. val = (unsigned char)cstr[n];
  9074. }
  9075. // Add the character to the final string
  9076. char encodedValue[5];
  9077. int len;
  9078. if( engine->ep.scanner == 1 && engine->ep.stringEncoding == 0 )
  9079. {
  9080. // Convert to UTF8 encoded
  9081. len = asStringEncodeUTF8(val, encodedValue);
  9082. }
  9083. else if( engine->ep.stringEncoding == 1 )
  9084. {
  9085. // Convert to 16bit wide character string (even if the script is scanned as ASCII)
  9086. len = asStringEncodeUTF16(val, encodedValue);
  9087. }
  9088. else
  9089. {
  9090. // Do not convert ASCII characters
  9091. encodedValue[0] = (asBYTE)val;
  9092. len = 1;
  9093. }
  9094. if( len < 0 )
  9095. {
  9096. // Give warning about invalid code point
  9097. // TODO: Need code position for warning
  9098. Warning(TXT_INVALID_UNICODE_VALUE, node);
  9099. }
  9100. else
  9101. {
  9102. // Add the encoded value to the final string
  9103. str.Concatenate(encodedValue, len);
  9104. if( charLiteral == -1 ) charLiteral = val;
  9105. }
  9106. }
  9107. cstr.Assign(str.AddressOf(), str.GetLength());
  9108. return charLiteral;
  9109. }
  9110. void asCCompiler::ProcessHeredocStringConstant(asCString &str, asCScriptNode *node)
  9111. {
  9112. // Remove first line if it only contains whitespace
  9113. bool isMultiline = false;
  9114. int start;
  9115. for( start = 0; start < (int)str.GetLength(); start++ )
  9116. {
  9117. if( str[start] == '\n' )
  9118. {
  9119. isMultiline = true;
  9120. // Remove the linebreak as well
  9121. start++;
  9122. break;
  9123. }
  9124. if( str[start] != ' ' &&
  9125. str[start] != '\t' &&
  9126. str[start] != '\r' )
  9127. {
  9128. // Don't remove anything
  9129. start = 0;
  9130. break;
  9131. }
  9132. }
  9133. // Remove the line after the last line break if it only contains whitespaces
  9134. int end;
  9135. for( end = (int)str.GetLength() - 1; end >= 0; end-- )
  9136. {
  9137. if( str[end] == '\n' )
  9138. {
  9139. // Don't remove the last line break
  9140. end++;
  9141. break;
  9142. }
  9143. if( str[end] != ' ' &&
  9144. str[end] != '\t' &&
  9145. str[end] != '\r' )
  9146. {
  9147. // Don't remove anything
  9148. end = (int)str.GetLength();
  9149. break;
  9150. }
  9151. }
  9152. if( end < 0 ) end = 0;
  9153. asCString tmp;
  9154. if (end > start || engine->ep.heredocTrimMode != 2 )
  9155. {
  9156. // if heredocTrimMode == 0 the string shouldn't be trimmed
  9157. // if heredocTrimMode == 1 the string should only be trimmed if it is multiline
  9158. // if heredocTrimMode == 2 the string should always be trimmed
  9159. if (engine->ep.heredocTrimMode == 2 || (isMultiline && engine->ep.heredocTrimMode == 1))
  9160. tmp.Assign(&str[start], end - start);
  9161. else
  9162. tmp = str;
  9163. }
  9164. ProcessStringConstant(tmp, node, false);
  9165. str = tmp;
  9166. }
  9167. int asCCompiler::CompileConversion(asCScriptNode *node, asCExprContext *ctx)
  9168. {
  9169. asCExprContext expr(engine);
  9170. asCDataType to;
  9171. bool anyErrors = false;
  9172. EImplicitConv convType;
  9173. if( node->nodeType == snConstructCall || node->nodeType == snFunctionCall )
  9174. {
  9175. convType = asIC_EXPLICIT_VAL_CAST;
  9176. // Verify that there is only one argument
  9177. if( node->lastChild->firstChild == 0 ||
  9178. node->lastChild->firstChild != node->lastChild->lastChild )
  9179. {
  9180. Error(TXT_ONLY_ONE_ARGUMENT_IN_CAST, node->lastChild);
  9181. expr.type.SetDummy();
  9182. anyErrors = true;
  9183. }
  9184. else if (node->lastChild->firstChild &&
  9185. node->lastChild->firstChild->nodeType == snNamedArgument)
  9186. {
  9187. Error(TXT_INVALID_USE_OF_NAMED_ARGS, node->lastChild);
  9188. expr.type.SetDummy();
  9189. anyErrors = true;
  9190. }
  9191. else
  9192. {
  9193. // Compile the expression
  9194. int r = CompileAssignment(node->lastChild->firstChild, &expr);
  9195. if( r < 0 )
  9196. anyErrors = true;
  9197. }
  9198. // Determine the requested type
  9199. to = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace);
  9200. to.MakeReadOnly(true); // Default to const
  9201. asASSERT(to.IsPrimitive());
  9202. }
  9203. else
  9204. {
  9205. convType = asIC_EXPLICIT_REF_CAST;
  9206. // Compile the expression
  9207. int r = CompileAssignment(node->lastChild, &expr);
  9208. if( r < 0 )
  9209. anyErrors = true;
  9210. // Determine the requested type
  9211. to = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace);
  9212. // If the type support object handles, then use it
  9213. if( to.SupportHandles() )
  9214. {
  9215. to.MakeHandle(true);
  9216. if( expr.type.dataType.IsObjectConst() )
  9217. to.MakeHandleToConst(true);
  9218. }
  9219. else if( !to.IsObjectHandle() )
  9220. {
  9221. // The cast<type> operator can only be used for reference casts
  9222. Error(TXT_ILLEGAL_TARGET_TYPE_FOR_REF_CAST, node->firstChild);
  9223. anyErrors = true;
  9224. }
  9225. }
  9226. // Do not allow casting to non shared type if we're compiling a shared method
  9227. if( outFunc->IsShared() &&
  9228. to.GetTypeInfo() && !to.GetTypeInfo()->IsShared() )
  9229. {
  9230. asCString msg;
  9231. msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, to.GetTypeInfo()->name.AddressOf());
  9232. Error(msg, node);
  9233. anyErrors = true;
  9234. }
  9235. if( anyErrors )
  9236. {
  9237. // Assume that the error can be fixed and allow the compilation to continue
  9238. ctx->type.Set(to);
  9239. return -1;
  9240. }
  9241. if( ProcessPropertyGetAccessor(&expr, node) < 0 )
  9242. return -1;
  9243. // Don't allow any operators on expressions that take address of class method
  9244. if( expr.IsClassMethod() )
  9245. {
  9246. Error(TXT_INVALID_OP_ON_METHOD, node);
  9247. return -1;
  9248. }
  9249. // We don't want a reference for conversion casts
  9250. if( convType == asIC_EXPLICIT_VAL_CAST && expr.type.dataType.IsReference() )
  9251. {
  9252. if( expr.type.dataType.IsObject() )
  9253. Dereference(&expr, true);
  9254. else
  9255. ConvertToVariable(&expr);
  9256. }
  9257. ImplicitConversion(&expr, to, node, convType);
  9258. IsVariableInitialized(&expr.type, node);
  9259. // If no type conversion is really tried ignore it
  9260. if( to == expr.type.dataType )
  9261. {
  9262. // This will keep information about constant type
  9263. MergeExprBytecode(ctx, &expr);
  9264. ctx->type = expr.type;
  9265. return 0;
  9266. }
  9267. if( to.IsEqualExceptRefAndConst(expr.type.dataType) && to.IsPrimitive() )
  9268. {
  9269. MergeExprBytecode(ctx, &expr);
  9270. ctx->type = expr.type;
  9271. ctx->type.dataType.MakeReadOnly(true);
  9272. return 0;
  9273. }
  9274. // The implicit conversion already does most of the conversions permitted,
  9275. // here we'll only treat those conversions that require an explicit cast.
  9276. bool conversionOK = false;
  9277. if( !expr.type.isConstant && expr.type.dataType != asCDataType::CreatePrimitive(ttVoid, false) )
  9278. {
  9279. if( !expr.type.dataType.IsObject() )
  9280. ConvertToTempVariable(&expr);
  9281. if( to.IsObjectHandle() &&
  9282. expr.type.dataType.IsObjectHandle() &&
  9283. !(!to.IsHandleToConst() && expr.type.dataType.IsHandleToConst()) )
  9284. {
  9285. conversionOK = CompileRefCast(&expr, to, true, node);
  9286. MergeExprBytecode(ctx, &expr);
  9287. ctx->type = expr.type;
  9288. }
  9289. }
  9290. if( conversionOK )
  9291. return 0;
  9292. // Conversion not available
  9293. ctx->type.SetDummy();
  9294. asCString strTo, strFrom;
  9295. strTo = to.Format(outFunc->nameSpace);
  9296. strFrom = expr.type.dataType.Format(outFunc->nameSpace);
  9297. asCString msg;
  9298. msg.Format(TXT_NO_CONVERSION_s_TO_s, strFrom.AddressOf(), strTo.AddressOf());
  9299. Error(msg, node);
  9300. return -1;
  9301. }
  9302. void asCCompiler::AfterFunctionCall(int funcID, asCArray<asCExprContext*> &args, asCExprContext *ctx, bool deferAll)
  9303. {
  9304. // deferAll is set to true if for example the function returns a reference, since in
  9305. // this case the function might be returning a reference to one of the arguments.
  9306. asCScriptFunction *descr = builder->GetFunctionDescription(funcID);
  9307. // Parameters that are sent by reference should be assigned
  9308. // to the evaluated expression if it is an lvalue
  9309. // Evaluate the arguments from last to first
  9310. int n = (int)descr->parameterTypes.GetLength() - 1;
  9311. for( ; n >= 0; n-- )
  9312. {
  9313. // All &out arguments must be deferred, except if the argument is clean, in which case the actual reference was passed in to the function
  9314. // If deferAll is set all objects passed by reference or handle must be deferred
  9315. if( (descr->parameterTypes[n].IsReference() && (descr->inOutFlags[n] & asTM_OUTREF) && !args[n]->isCleanArg) ||
  9316. (descr->parameterTypes[n].IsObject() && deferAll && (descr->parameterTypes[n].IsReference() || descr->parameterTypes[n].IsObjectHandle())) )
  9317. {
  9318. asASSERT( !(descr->parameterTypes[n].IsReference() && (descr->inOutFlags[n] == asTM_OUTREF) && !args[n]->isCleanArg) || args[n]->origExpr );
  9319. // For &inout, only store the argument if it is for a temporary variable
  9320. if( engine->ep.allowUnsafeReferences ||
  9321. descr->inOutFlags[n] != asTM_INOUTREF || args[n]->type.isTemporary )
  9322. {
  9323. // Store the argument for later processing
  9324. asSDeferredParam outParam;
  9325. outParam.argNode = args[n]->exprNode;
  9326. outParam.argType = args[n]->type;
  9327. outParam.argInOutFlags = descr->inOutFlags[n];
  9328. outParam.origExpr = args[n]->origExpr;
  9329. ctx->deferredParams.PushLast(outParam);
  9330. }
  9331. }
  9332. else
  9333. {
  9334. // Release the temporary variable now
  9335. ReleaseTemporaryVariable(args[n]->type, &ctx->bc);
  9336. }
  9337. // Move the argument's deferred expressions over to the final expression
  9338. for( asUINT m = 0; m < args[n]->deferredParams.GetLength(); m++ )
  9339. {
  9340. ctx->deferredParams.PushLast(args[n]->deferredParams[m]);
  9341. args[n]->deferredParams[m].origExpr = 0;
  9342. }
  9343. args[n]->deferredParams.SetLength(0);
  9344. }
  9345. }
  9346. void asCCompiler::ProcessDeferredParams(asCExprContext *ctx)
  9347. {
  9348. if( isProcessingDeferredParams ) return;
  9349. isProcessingDeferredParams = true;
  9350. for( asUINT n = 0; n < ctx->deferredParams.GetLength(); n++ )
  9351. {
  9352. asSDeferredParam outParam = ctx->deferredParams[n];
  9353. if( outParam.argInOutFlags < asTM_OUTREF ) // &in, or not reference
  9354. {
  9355. // Just release the variable
  9356. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  9357. }
  9358. else if( outParam.argInOutFlags == asTM_OUTREF )
  9359. {
  9360. asCExprContext *expr = outParam.origExpr;
  9361. outParam.origExpr = 0;
  9362. if( outParam.argType.dataType.IsObjectHandle() )
  9363. {
  9364. // Implicitly convert the value to a handle
  9365. if( expr->type.dataType.IsObjectHandle() )
  9366. expr->type.isExplicitHandle = true;
  9367. }
  9368. // Verify that the expression result in a lvalue, or a property accessor
  9369. if( IsLValue(expr->type) || expr->property_get || expr->property_set )
  9370. {
  9371. asCExprContext rctx(engine);
  9372. rctx.type = outParam.argType;
  9373. if( rctx.type.dataType.IsPrimitive() )
  9374. rctx.type.dataType.MakeReference(false);
  9375. else
  9376. {
  9377. rctx.bc.InstrSHORT(asBC_PSF, outParam.argType.stackOffset);
  9378. rctx.type.dataType.MakeReference(IsVariableOnHeap(outParam.argType.stackOffset));
  9379. if( expr->type.isExplicitHandle )
  9380. rctx.type.isExplicitHandle = true;
  9381. }
  9382. asCExprContext o(engine);
  9383. DoAssignment(&o, expr, &rctx, outParam.argNode, outParam.argNode, ttAssignment, outParam.argNode);
  9384. if( !o.type.dataType.IsPrimitive() ) o.bc.Instr(asBC_PopPtr);
  9385. // The assignment may itself have resulted in a new temporary variable, e.g. if
  9386. // the opAssign returns a non-reference. We must release this temporary variable
  9387. // since it won't be used
  9388. ReleaseTemporaryVariable(o.type, &o.bc);
  9389. MergeExprBytecode(ctx, &o);
  9390. }
  9391. else
  9392. {
  9393. // We must still evaluate the expression
  9394. MergeExprBytecode(ctx, expr);
  9395. if( !expr->IsVoidExpression() && (!expr->type.isConstant || expr->type.IsNullConstant()) )
  9396. ctx->bc.Instr(asBC_PopPtr);
  9397. // Give an error, except if the argument is void, null or 0 which indicate the argument is explicitly to be ignored
  9398. if( !expr->IsVoidExpression() && !expr->type.IsNullConstant() &&
  9399. !(expr->type.isConstant && expr->type.dataType.IsPrimitive() && expr->type.GetConstantData() == 0) )
  9400. Error(TXT_ARG_NOT_LVALUE, outParam.argNode);
  9401. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  9402. }
  9403. ReleaseTemporaryVariable(expr->type, &ctx->bc);
  9404. // Delete the original expression context
  9405. asDELETE(expr, asCExprContext);
  9406. }
  9407. else // &inout
  9408. {
  9409. if( outParam.argType.isTemporary )
  9410. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  9411. else if( !outParam.argType.isVariable )
  9412. {
  9413. if( outParam.argType.dataType.IsObject() &&
  9414. ((outParam.argType.dataType.GetBehaviour()->addref &&
  9415. outParam.argType.dataType.GetBehaviour()->release) ||
  9416. (outParam.argType.dataType.GetTypeInfo()->flags & asOBJ_NOCOUNT)) )
  9417. {
  9418. // Release the object handle that was taken to guarantee the reference
  9419. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  9420. }
  9421. }
  9422. }
  9423. }
  9424. ctx->deferredParams.SetLength(0);
  9425. isProcessingDeferredParams = false;
  9426. }
  9427. int asCCompiler::CompileConstructCall(asCScriptNode *node, asCExprContext *ctx)
  9428. {
  9429. // The first node is a datatype node
  9430. asCString name;
  9431. asCExprValue tempObj;
  9432. bool onHeap = true;
  9433. asCArray<int> funcs;
  9434. bool error = false;
  9435. // It is possible that the name is really a constructor
  9436. asCDataType dt;
  9437. dt = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace, false, outFunc->objectType);
  9438. if( dt.IsPrimitive() )
  9439. {
  9440. // This is a cast to a primitive type
  9441. return CompileConversion(node, ctx);
  9442. }
  9443. if( dt.GetTypeInfo() && (dt.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE) )
  9444. {
  9445. // Types declared as implicit handle must not attempt to construct a handle
  9446. dt.MakeHandle(false);
  9447. }
  9448. // Don't accept syntax like object@(expr)
  9449. if( dt.IsObjectHandle() )
  9450. {
  9451. asCString str;
  9452. str.Format(TXT_CANT_CONSTRUCT_s_USE_REF_CAST, dt.Format(outFunc->nameSpace).AddressOf());
  9453. Error(str, node);
  9454. ctx->type.SetDummy();
  9455. return -1;
  9456. }
  9457. // Make sure the desired type can actually be instantiated
  9458. // Delegates are allowed to be created through construct calls,
  9459. // even though they cannot be instantiated as variables
  9460. if( !dt.CanBeInstantiated() && !dt.IsFuncdef() )
  9461. {
  9462. asCString str;
  9463. if( dt.IsAbstractClass() )
  9464. str.Format(TXT_ABSTRACT_CLASS_s_CANNOT_BE_INSTANTIATED, dt.Format(outFunc->nameSpace).AddressOf());
  9465. else if( dt.IsInterface() )
  9466. str.Format(TXT_INTERFACE_s_CANNOT_BE_INSTANTIATED, dt.Format(outFunc->nameSpace).AddressOf());
  9467. else
  9468. // TODO: Improve error message to explain why
  9469. str.Format(TXT_DATA_TYPE_CANT_BE_s, dt.Format(outFunc->nameSpace).AddressOf());
  9470. Error(str, node);
  9471. ctx->type.SetDummy();
  9472. return -1;
  9473. }
  9474. // Do not allow constructing non-shared types in shared functions
  9475. if( outFunc->IsShared() &&
  9476. dt.GetTypeInfo() && !dt.GetTypeInfo()->IsShared() )
  9477. {
  9478. asCString msg;
  9479. msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, dt.GetTypeInfo()->name.AddressOf());
  9480. Error(msg, node);
  9481. return -1;
  9482. }
  9483. // Compile the arguments
  9484. asCArray<asCExprContext *> args;
  9485. asCArray<asSNamedArgument> namedArgs;
  9486. asCArray<asCExprValue> temporaryVariables;
  9487. if( CompileArgumentList(node->lastChild, args, namedArgs) >= 0 )
  9488. {
  9489. // Check for a value cast behaviour
  9490. if( args.GetLength() == 1 )
  9491. {
  9492. asCExprContext conv(engine);
  9493. conv.Copy(args[0]);
  9494. asUINT cost = ImplicitConversion(&conv, dt, node->lastChild, asIC_EXPLICIT_VAL_CAST, false);
  9495. // Clean the property_arg in the temporary copy so
  9496. // it isn't deleted when conv goes out of scope
  9497. conv.property_arg = 0;
  9498. // Don't use this if the cost is 0 because it would mean that nothing
  9499. // is done and the script wants a new value to be constructed
  9500. if( conv.type.dataType.IsEqualExceptRef(dt) && cost > 0 )
  9501. {
  9502. // Make sure the result is a reference, just as if to a local variable
  9503. if( !dt.IsFuncdef() )
  9504. dt.MakeReference(true);
  9505. // Make sure any property accessor is already evaluated
  9506. if( ProcessPropertyGetAccessor(args[0], args[0]->exprNode) < 0 )
  9507. return -1;
  9508. ImplicitConversion(args[0], dt, node->lastChild, asIC_EXPLICIT_VAL_CAST);
  9509. ctx->bc.AddCode(&args[0]->bc);
  9510. ctx->type = args[0]->type;
  9511. asDELETE(args[0], asCExprContext);
  9512. return 0;
  9513. }
  9514. }
  9515. // Check for possible constructor/factory
  9516. name = dt.Format(outFunc->nameSpace);
  9517. asSTypeBehaviour *beh = dt.GetBehaviour();
  9518. if( !(dt.GetTypeInfo()->flags & asOBJ_REF) && !dt.IsFuncdef() )
  9519. {
  9520. funcs = beh->constructors;
  9521. // Value types and script types are allocated through the constructor
  9522. tempObj.dataType = dt;
  9523. tempObj.stackOffset = (short)AllocateVariable(dt, true);
  9524. tempObj.dataType.MakeReference(true);
  9525. tempObj.isTemporary = true;
  9526. tempObj.isVariable = true;
  9527. onHeap = IsVariableOnHeap(tempObj.stackOffset);
  9528. // Push the address of the object on the stack
  9529. if( onHeap )
  9530. ctx->bc.InstrSHORT(asBC_VAR, tempObj.stackOffset);
  9531. }
  9532. else if( beh )
  9533. funcs = beh->factories;
  9534. // Special case: Allow calling func(void) with a void expression.
  9535. if( args.GetLength() == 1 && args[0]->type.dataType == asCDataType::CreatePrimitive(ttVoid, false) )
  9536. {
  9537. // Evaluate the expression before the function call
  9538. MergeExprBytecode(ctx, args[0]);
  9539. asDELETE(args[0], asCExprContext);
  9540. args.SetLength(0);
  9541. }
  9542. // Special case: If this is an object constructor and there are no arguments use the default constructor.
  9543. // If none has been registered, just allocate the variable and push it on the stack.
  9544. if( args.GetLength() == 0 )
  9545. {
  9546. beh = tempObj.dataType.GetBehaviour();
  9547. if( beh && beh->construct == 0 && !(dt.GetTypeInfo()->flags & asOBJ_REF) )
  9548. {
  9549. // Call the default constructor
  9550. ctx->type = tempObj;
  9551. if( onHeap )
  9552. {
  9553. asASSERT(ctx->bc.GetLastInstr() == asBC_VAR);
  9554. ctx->bc.RemoveLastInstr();
  9555. }
  9556. CallDefaultConstructor(tempObj.dataType, tempObj.stackOffset, IsVariableOnHeap(tempObj.stackOffset), &ctx->bc, node);
  9557. // Push the reference on the stack
  9558. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  9559. return 0;
  9560. }
  9561. }
  9562. // Special case: If this is a construction of a delegate and the expression names an object method
  9563. if( dt.IsFuncdef() && args.GetLength() == 1 && args[0]->methodName != "" )
  9564. {
  9565. // TODO: delegate: It is possible that the argument returns a function pointer already, in which
  9566. // case no object delegate will be created, but instead a delegate for a function pointer
  9567. // In theory a simple cast would be good in this case, but this is a construct call so it
  9568. // is expected that a new object is created.
  9569. dt.MakeHandle(true);
  9570. ctx->type.Set(dt);
  9571. // The delegate must be able to hold on to a reference to the object
  9572. if( !args[0]->type.dataType.SupportHandles() )
  9573. {
  9574. Error(TXT_CANNOT_CREATE_DELEGATE_FOR_NOREF_TYPES, node);
  9575. error = true;
  9576. }
  9577. else
  9578. {
  9579. // Filter the available object methods to find the one that matches the func def
  9580. asCObjectType *type = CastToObjectType(args[0]->type.dataType.GetTypeInfo());
  9581. asCScriptFunction *bestMethod = 0;
  9582. for( asUINT n = 0; n < type->methods.GetLength(); n++ )
  9583. {
  9584. asCScriptFunction *func = engine->scriptFunctions[type->methods[n]];
  9585. if( func->name != args[0]->methodName )
  9586. continue;
  9587. // If the expression is for a const object, then only const methods should be accepted
  9588. if( args[0]->type.dataType.IsReadOnly() && !func->IsReadOnly() )
  9589. continue;
  9590. if( func->IsSignatureExceptNameAndObjectTypeEqual(CastToFuncdefType(dt.GetTypeInfo())->funcdef) )
  9591. {
  9592. bestMethod = func;
  9593. // If the expression is non-const the non-const overloaded method has priority
  9594. if( args[0]->type.dataType.IsReadOnly() == func->IsReadOnly() )
  9595. break;
  9596. }
  9597. }
  9598. if( bestMethod )
  9599. {
  9600. // The object pointer is already on the stack
  9601. MergeExprBytecode(ctx, args[0]);
  9602. // Push the function pointer as an additional argument
  9603. ctx->bc.InstrPTR(asBC_FuncPtr, bestMethod);
  9604. // Call the factory function for the delegate
  9605. asCArray<int> delegateFuncs;
  9606. builder->GetFunctionDescriptions(DELEGATE_FACTORY, delegateFuncs, engine->nameSpaces[0]);
  9607. asASSERT(delegateFuncs.GetLength() == 1 );
  9608. ctx->bc.Call(asBC_CALLSYS , delegateFuncs[0], 2*AS_PTR_SIZE);
  9609. // Store the returned delegate in a temporary variable
  9610. int returnOffset = AllocateVariable(dt, true, false);
  9611. dt.MakeReference(true);
  9612. ctx->type.SetVariable(dt, returnOffset, true);
  9613. ctx->bc.InstrSHORT(asBC_STOREOBJ, (short)returnOffset);
  9614. // Push a reference to the temporary variable on the stack
  9615. ctx->bc.InstrSHORT(asBC_PSF, (short)returnOffset);
  9616. // Clean up arguments
  9617. ReleaseTemporaryVariable(args[0]->type, &ctx->bc);
  9618. }
  9619. else
  9620. {
  9621. asCString msg;
  9622. msg.Format(TXT_NO_MATCHING_SIGNATURES_TO_s, CastToFuncdefType(dt.GetTypeInfo())->funcdef->GetDeclaration());
  9623. Error(msg.AddressOf(), node);
  9624. error = true;
  9625. }
  9626. }
  9627. // Clean-up arg
  9628. asDELETE(args[0], asCExprContext);
  9629. return error ? -1 : 0;
  9630. }
  9631. MatchFunctions(funcs, args, node, name.AddressOf(), &namedArgs, 0, false);
  9632. if( funcs.GetLength() != 1 )
  9633. {
  9634. // The error was reported by MatchFunctions()
  9635. error = true;
  9636. // Dummy value
  9637. ctx->type.SetDummy();
  9638. }
  9639. else
  9640. {
  9641. // TODO: Clean up: Merge this with MakeFunctionCall
  9642. // Add the default values for arguments not explicitly supplied
  9643. int r = CompileDefaultAndNamedArgs(node, args, funcs[0], CastToObjectType(dt.GetTypeInfo()), &namedArgs);
  9644. if( r == asSUCCESS )
  9645. {
  9646. asCByteCode objBC(engine);
  9647. PrepareFunctionCall(funcs[0], &ctx->bc, args);
  9648. MoveArgsToStack(funcs[0], &ctx->bc, args, false);
  9649. if( !(dt.GetTypeInfo()->flags & asOBJ_REF) )
  9650. {
  9651. // If the object is allocated on the stack, then call the constructor as a normal function
  9652. if( onHeap )
  9653. {
  9654. int offset = 0;
  9655. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]);
  9656. for( asUINT n = 0; n < args.GetLength(); n++ )
  9657. offset += descr->parameterTypes[n].GetSizeOnStackDWords();
  9658. ctx->bc.InstrWORD(asBC_GETREF, (asWORD)offset);
  9659. }
  9660. else
  9661. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  9662. PerformFunctionCall(funcs[0], ctx, onHeap, &args, CastToObjectType(tempObj.dataType.GetTypeInfo()));
  9663. // Add tag that the object has been initialized
  9664. ctx->bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT);
  9665. // The constructor doesn't return anything,
  9666. // so we have to manually inform the type of
  9667. // the return value
  9668. ctx->type = tempObj;
  9669. if( !onHeap )
  9670. ctx->type.dataType.MakeReference(false);
  9671. // Push the address of the object on the stack again
  9672. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  9673. }
  9674. else
  9675. {
  9676. // Call the factory to create the reference type
  9677. PerformFunctionCall(funcs[0], ctx, false, &args);
  9678. }
  9679. }
  9680. else
  9681. error = true;
  9682. }
  9683. }
  9684. else
  9685. {
  9686. // Failed to compile the argument list, set the result to the dummy type
  9687. ctx->type.SetDummy();
  9688. error = true;
  9689. }
  9690. // Cleanup
  9691. for( asUINT n = 0; n < args.GetLength(); n++ )
  9692. if( args[n] )
  9693. {
  9694. asDELETE(args[n], asCExprContext);
  9695. }
  9696. for( asUINT n = 0; n < namedArgs.GetLength(); n++ )
  9697. if( namedArgs[n].ctx )
  9698. {
  9699. asDELETE(namedArgs[n].ctx, asCExprContext);
  9700. }
  9701. return error ? -1 : 0;
  9702. }
  9703. int asCCompiler::CompileFunctionCall(asCScriptNode *node, asCExprContext *ctx, asCObjectType *objectType, bool objIsConst, const asCString &scope)
  9704. {
  9705. asCExprValue tempObj;
  9706. asCArray<int> funcs;
  9707. int localVar = -1;
  9708. bool initializeMembers = false;
  9709. asCExprContext funcExpr(engine);
  9710. asCScriptNode *nm = node->lastChild->prev;
  9711. asCString name(&script->code[nm->tokenPos], nm->tokenLength);
  9712. // Find the matching entities
  9713. // If objectType is set then this is a post op expression and we shouldn't look for local variables
  9714. asCExprContext lookupResult(engine);
  9715. SYMBOLTYPE symbolType = SymbolLookup(name, scope, objectType, &lookupResult);
  9716. if (symbolType < 0)
  9717. return -1;
  9718. if (symbolType == SL_NOMATCH)
  9719. {
  9720. // No matching symbol
  9721. asCString msg;
  9722. asCString smbl;
  9723. if (scope == "::")
  9724. smbl = scope;
  9725. else if (scope != "")
  9726. smbl = scope + "::";
  9727. smbl += name;
  9728. msg.Format(TXT_NO_MATCHING_SYMBOL_s, smbl.AddressOf());
  9729. Error(msg, node);
  9730. return -1;
  9731. }
  9732. // Is the symbol matching a variable/property?
  9733. if (symbolType == SL_LOCALCONST || symbolType == SL_LOCALVAR ||
  9734. symbolType == SL_THISPTR || symbolType == SL_CLASSPROPACCESS || symbolType == SL_CLASSPROP ||
  9735. symbolType == SL_GLOBALPROPACCESS || symbolType == SL_GLOBALCONST || symbolType == SL_GLOBALVAR || symbolType == SL_ENUMVAL)
  9736. {
  9737. // Variables/properties can be used as functions if they have the opCall
  9738. // Compile the variable
  9739. // TODO: Take advantage of the known symbol, so it doesn't have to be looked up again
  9740. localVar = CompileVariableAccess(name, scope, &funcExpr, node, false, objectType);
  9741. if( localVar < 0 )
  9742. return -1;
  9743. if (funcExpr.type.dataType.IsFuncdef())
  9744. {
  9745. funcs.PushLast(CastToFuncdefType(funcExpr.type.dataType.GetTypeInfo())->funcdef->id);
  9746. }
  9747. else if (funcExpr.type.dataType.IsObject())
  9748. {
  9749. // Keep information about temporary variables as deferred expression so it can be properly cleaned up after the call
  9750. if (ctx->type.isTemporary)
  9751. {
  9752. asASSERT(objectType);
  9753. asSDeferredParam deferred;
  9754. deferred.origExpr = 0;
  9755. deferred.argInOutFlags = asTM_INREF;
  9756. deferred.argNode = 0;
  9757. deferred.argType.SetVariable(ctx->type.dataType, ctx->type.stackOffset, true);
  9758. ctx->deferredParams.PushLast(deferred);
  9759. }
  9760. if (funcExpr.property_get == 0)
  9761. Dereference(ctx, true);
  9762. // Add the bytecode for accessing the object on which opCall will be called
  9763. if (ctx->type.dataType.IsObject())
  9764. {
  9765. // Make sure the ProcessPropertyGetAccess knows whether or not to
  9766. // dereference the original object before calling the get accessor
  9767. funcExpr.property_ref = ctx->type.dataType.IsReference();
  9768. }
  9769. MergeExprBytecodeAndType(ctx, &funcExpr);
  9770. if( ProcessPropertyGetAccessor(ctx, node) < 0 )
  9771. return -1;
  9772. Dereference(ctx, true);
  9773. objectType = CastToObjectType(funcExpr.type.dataType.GetTypeInfo());
  9774. // Get the opCall methods from the object type
  9775. if (funcExpr.type.dataType.IsObjectHandle())
  9776. objIsConst = funcExpr.type.dataType.IsHandleToConst();
  9777. else
  9778. objIsConst = funcExpr.type.dataType.IsReadOnly();
  9779. builder->GetObjectMethodDescriptions("opCall", CastToObjectType(funcExpr.type.dataType.GetTypeInfo()), funcs, objIsConst);
  9780. }
  9781. else
  9782. {
  9783. // The variable is not a function or object with opCall
  9784. asCString msg;
  9785. msg.Format(TXT_NOT_A_FUNC_s_IS_TYPE_s, name.AddressOf(), lookupResult.type.dataType.Format(outFunc->nameSpace).AddressOf());
  9786. Error(msg, node);
  9787. return -1;
  9788. }
  9789. }
  9790. // Is the symbol matching a class method?
  9791. if (symbolType == SL_CLASSMETHOD)
  9792. {
  9793. // If we're compiling a constructor and the name of the function is super then
  9794. // the constructor of the base class is being called.
  9795. // super cannot be prefixed with a scope operator
  9796. if (scope == "" && m_isConstructor && name == SUPER_TOKEN)
  9797. {
  9798. // If the class is not derived from anyone else, calling super should give an error
  9799. if (outFunc && outFunc->objectType->derivedFrom)
  9800. funcs = outFunc->objectType->derivedFrom->beh.constructors;
  9801. // Must not allow calling base class' constructor multiple times
  9802. if (continueLabels.GetLength() > 0)
  9803. {
  9804. // If a continue label is set we are in a loop
  9805. Error(TXT_CANNOT_CALL_CONSTRUCTOR_IN_LOOPS, node);
  9806. }
  9807. else if (breakLabels.GetLength() > 0)
  9808. {
  9809. // TODO: inheritance: Should eventually allow constructors in switch statements
  9810. // If a break label is set we are either in a loop or a switch statements
  9811. Error(TXT_CANNOT_CALL_CONSTRUCTOR_IN_SWITCH, node);
  9812. }
  9813. else if (m_isConstructorCalled)
  9814. {
  9815. Error(TXT_CANNOT_CALL_CONSTRUCTOR_TWICE, node);
  9816. }
  9817. m_isConstructorCalled = true;
  9818. // We need to initialize the class members, but only after all the deferred arguments have been completed
  9819. initializeMembers = true;
  9820. }
  9821. else
  9822. {
  9823. // The scope can be used to specify the base class
  9824. builder->GetObjectMethodDescriptions(name.AddressOf(), CastToObjectType(lookupResult.type.dataType.GetTypeInfo()), funcs, objIsConst, scope, node, script);
  9825. }
  9826. // If a class method is being called implicitly, then add the this pointer for the call
  9827. if (funcs.GetLength() && !objectType && outFunc->objectType)
  9828. {
  9829. // Verify that the identified function is actually part of the class hierarchy
  9830. if (!outFunc->objectType->DerivesFrom(lookupResult.type.dataType.GetTypeInfo()))
  9831. {
  9832. asCString msg;
  9833. asCString mthd;
  9834. if (scope == "")
  9835. mthd = name;
  9836. else if (scope == "::")
  9837. mthd = scope + name;
  9838. else
  9839. mthd = scope + "::" + name;
  9840. msg.Format(TXT_METHOD_s_NOT_PART_OF_OBJECT_s, mthd.AddressOf(), outFunc->objectType->name.AddressOf());
  9841. Error(msg, node);
  9842. return -1;
  9843. }
  9844. objectType = outFunc->objectType;
  9845. asCDataType dt = asCDataType::CreateType(objectType, false);
  9846. // The object pointer is located at stack position 0
  9847. ctx->bc.InstrSHORT(asBC_PSF, 0);
  9848. ctx->type.SetVariable(dt, 0, false);
  9849. ctx->type.dataType.MakeReference(true);
  9850. Dereference(ctx, true);
  9851. }
  9852. else if (funcs.GetLength() && !objectType && !outFunc->objectType)
  9853. {
  9854. // Cannot call class methods directly without the object
  9855. asCString msg;
  9856. msg.Format(TXT_CANNOT_ACCESS_NON_STATIC_MEMBER_s, name.AddressOf());
  9857. Error(msg, node);
  9858. return -1;
  9859. }
  9860. }
  9861. // Is it a global function?
  9862. if (symbolType == SL_GLOBALFUNC)
  9863. {
  9864. // The symbol lookup identified the namespace to use
  9865. int n = lookupResult.methodName.FindLast("::");
  9866. asSNameSpace *ns = engine->FindNameSpace(lookupResult.methodName.SubString(0, n).AddressOf());
  9867. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  9868. }
  9869. // Is it a type?
  9870. if (symbolType == SL_CLASSTYPE || symbolType == SL_GLOBALTYPE)
  9871. {
  9872. bool isValid = false;
  9873. asCDataType dt = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace, false, outFunc->objectType, false, &isValid);
  9874. if (isValid)
  9875. return CompileConstructCall(node, ctx);
  9876. }
  9877. // Compile the arguments
  9878. asCArray<asCExprContext *> args;
  9879. asCArray<asSNamedArgument> namedArgs;
  9880. bool isOK = true;
  9881. if( CompileArgumentList(node->lastChild, args, namedArgs) >= 0 )
  9882. {
  9883. // Special case: Allow calling func(void) with an expression that evaluates to no datatype, but isn't exactly 'void'
  9884. if( args.GetLength() == 1 && args[0]->type.IsVoid() && !args[0]->IsVoidExpression() )
  9885. {
  9886. // Evaluate the expression before the function call
  9887. MergeExprBytecode(ctx, args[0]);
  9888. asDELETE(args[0], asCExprContext);
  9889. args.SetLength(0);
  9890. }
  9891. MatchFunctions(funcs, args, node, name.AddressOf(), &namedArgs, objectType, objIsConst, false, true, scope);
  9892. if( funcs.GetLength() != 1 )
  9893. {
  9894. // The error was reported by MatchFunctions()
  9895. // Dummy value
  9896. ctx->type.SetDummy();
  9897. isOK = false;
  9898. }
  9899. else
  9900. {
  9901. // Add the default values for arguments not explicitly supplied
  9902. int r = CompileDefaultAndNamedArgs(node, args, funcs[0], objectType, &namedArgs);
  9903. // TODO: funcdef: Do we have to make sure the handle is stored in a temporary variable, or
  9904. // is it enough to make sure it is in a local variable?
  9905. // For function pointer we must guarantee that the function is safe, i.e.
  9906. // by first storing the function pointer in a local variable (if it isn't already in one)
  9907. if( r == asSUCCESS )
  9908. {
  9909. asCScriptFunction *func = builder->GetFunctionDescription(funcs[0]);
  9910. if( func->funcType == asFUNC_FUNCDEF )
  9911. {
  9912. if( objectType && funcExpr.property_get <= 0 )
  9913. {
  9914. // Dereference the object pointer to access the member
  9915. Dereference(ctx, true);
  9916. }
  9917. if( funcExpr.property_get > 0 )
  9918. {
  9919. if( ProcessPropertyGetAccessor(&funcExpr, node) < 0 )
  9920. return -1;
  9921. Dereference(&funcExpr, true);
  9922. }
  9923. else
  9924. {
  9925. Dereference(&funcExpr, true);
  9926. ConvertToVariable(&funcExpr);
  9927. }
  9928. // The actual function should be called as if a global function
  9929. objectType = 0;
  9930. // The function call will be made directly from the local variable so the function pointer shouldn't be on the stack
  9931. funcExpr.bc.Instr(asBC_PopPtr);
  9932. asCExprValue tmp = ctx->type;
  9933. MergeExprBytecodeAndType(ctx, &funcExpr);
  9934. ReleaseTemporaryVariable(tmp, &ctx->bc);
  9935. }
  9936. r = MakeFunctionCall(ctx, funcs[0], objectType, args, node, false, 0, funcExpr.type.stackOffset);
  9937. if( r < 0 )
  9938. {
  9939. ctx->type.SetDummy();
  9940. isOK = false;
  9941. }
  9942. }
  9943. else
  9944. isOK = false;
  9945. }
  9946. }
  9947. else
  9948. {
  9949. // Failed to compile the argument list, set the dummy type and continue compilation
  9950. ctx->type.SetDummy();
  9951. isOK = false;
  9952. }
  9953. // Cleanup
  9954. for( asUINT n = 0; n < args.GetLength(); n++ )
  9955. if( args[n] )
  9956. {
  9957. asDELETE(args[n], asCExprContext);
  9958. }
  9959. for( asUINT n = 0; n < namedArgs.GetLength(); n++ )
  9960. if( namedArgs[n].ctx )
  9961. {
  9962. asDELETE(namedArgs[n].ctx, asCExprContext);
  9963. }
  9964. if( initializeMembers )
  9965. {
  9966. asASSERT( m_isConstructor );
  9967. // Need to initialize members here, as they may use the properties of the base class
  9968. // If there are multiple paths that call super(), then there will also be multiple
  9969. // locations with initializations of the members. It is not possible to consolidate
  9970. // these in one place, as the expressions for the initialization are evaluated where
  9971. // they are compiled, which means that they may access different variables depending
  9972. // on the scope where super() is called.
  9973. // Members that don't have an explicit initialization expression will be initialized
  9974. // beginning of the constructor as they are guaranteed not to use at the any
  9975. // members of the base class.
  9976. CompileMemberInitialization(&ctx->bc, false);
  9977. }
  9978. return isOK ? 0 : -1;
  9979. }
  9980. asSNameSpace *asCCompiler::DetermineNameSpace(const asCString &scope)
  9981. {
  9982. asSNameSpace *ns;
  9983. if( scope == "" )
  9984. {
  9985. // When compiling default argument expression the correct namespace is stored in the outFunc even for objects
  9986. if( outFunc->nameSpace->name != "" || isCompilingDefaultArg )
  9987. ns = outFunc->nameSpace;
  9988. else if( outFunc->objectType && outFunc->objectType->nameSpace->name != "" )
  9989. ns = outFunc->objectType->nameSpace;
  9990. else
  9991. ns = engine->nameSpaces[0];
  9992. }
  9993. else if( scope == "::" )
  9994. ns = engine->nameSpaces[0];
  9995. else
  9996. ns = engine->FindNameSpace(scope.AddressOf());
  9997. return ns;
  9998. }
  9999. int asCCompiler::CompileExpressionPreOp(asCScriptNode *node, asCExprContext *ctx)
  10000. {
  10001. int op = node->tokenType;
  10002. // Don't allow any prefix operators except handle on expressions that take address of class method
  10003. if( ctx->IsClassMethod() && op != ttHandle )
  10004. {
  10005. Error(TXT_INVALID_OP_ON_METHOD, node);
  10006. return -1;
  10007. }
  10008. // Don't allow any operators on void expressions
  10009. if( ctx->IsVoidExpression() )
  10010. {
  10011. Error(TXT_VOID_CANT_BE_OPERAND, node);
  10012. return -1;
  10013. }
  10014. IsVariableInitialized(&ctx->type, node);
  10015. if( op == ttHandle )
  10016. {
  10017. if( ctx->methodName != "" )
  10018. {
  10019. // Don't allow taking the handle of a handle
  10020. if( ctx->type.isExplicitHandle )
  10021. {
  10022. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node);
  10023. return -1;
  10024. }
  10025. }
  10026. else
  10027. {
  10028. // Don't allow taking handle of a handle, i.e. @@
  10029. if( ctx->type.isExplicitHandle )
  10030. {
  10031. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node);
  10032. return -1;
  10033. }
  10034. // @null is allowed even though it is implicit
  10035. if( !ctx->type.IsNullConstant() )
  10036. {
  10037. // Verify that the type allow its handle to be taken
  10038. if( !ctx->type.dataType.SupportHandles() && !ctx->type.dataType.IsObjectHandle() )
  10039. {
  10040. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node);
  10041. return -1;
  10042. }
  10043. // Objects that are not local variables are not references
  10044. // Objects allocated on the stack are also not marked as references
  10045. if( !ctx->type.dataType.IsReference() &&
  10046. !((ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) && !ctx->type.isVariable) &&
  10047. !(ctx->type.isVariable && !IsVariableOnHeap(ctx->type.stackOffset)) )
  10048. {
  10049. Error(TXT_NOT_VALID_REFERENCE, node);
  10050. return -1;
  10051. }
  10052. // Convert the expression to a handle
  10053. if( !ctx->type.dataType.IsObjectHandle() && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) )
  10054. {
  10055. asCDataType to = ctx->type.dataType;
  10056. to.MakeHandle(true);
  10057. to.MakeReference(true);
  10058. to.MakeHandleToConst(ctx->type.dataType.IsReadOnly());
  10059. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV, true, false);
  10060. asASSERT( ctx->type.dataType.IsObjectHandle() );
  10061. }
  10062. else if( ctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE )
  10063. {
  10064. // For the ASHANDLE type we'll simply set the expression as a handle
  10065. ctx->type.dataType.MakeHandle(true);
  10066. }
  10067. }
  10068. }
  10069. // Mark the expression as an explicit handle to avoid implicit conversions to non-handle expressions
  10070. ctx->type.isExplicitHandle = true;
  10071. }
  10072. else if( (op == ttMinus || op == ttPlus || op == ttBitNot || op == ttInc || op == ttDec) && ctx->type.dataType.IsObject() )
  10073. {
  10074. // Look for the appropriate method
  10075. // There is no overloadable operator for unary plus
  10076. const char *opName = 0;
  10077. switch( op )
  10078. {
  10079. case ttMinus: opName = "opNeg"; break;
  10080. case ttBitNot: opName = "opCom"; break;
  10081. case ttInc: opName = "opPreInc"; break;
  10082. case ttDec: opName = "opPreDec"; break;
  10083. }
  10084. if( opName )
  10085. {
  10086. // TODO: Should convert this to something similar to CompileOverloadedDualOperator2
  10087. if( ProcessPropertyGetAccessor(ctx, node) < 0 )
  10088. return -1;
  10089. // 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
  10090. // Find the correct method
  10091. bool isConst = ctx->type.dataType.IsObjectConst();
  10092. asCArray<int> funcs;
  10093. asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  10094. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  10095. {
  10096. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  10097. if( func->name == opName &&
  10098. func->parameterTypes.GetLength() == 0 &&
  10099. (!isConst || func->IsReadOnly()) )
  10100. {
  10101. funcs.PushLast(func->id);
  10102. }
  10103. }
  10104. // Did we find the method?
  10105. if( funcs.GetLength() == 1 )
  10106. {
  10107. asCArray<asCExprContext *> args;
  10108. return MakeFunctionCall(ctx, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
  10109. }
  10110. else if( funcs.GetLength() == 0 )
  10111. {
  10112. asCString str;
  10113. str = asCString(opName) + "()";
  10114. if( isConst )
  10115. str += " const";
  10116. str.Format(TXT_FUNCTION_s_NOT_FOUND, str.AddressOf());
  10117. Error(str, node);
  10118. ctx->type.SetDummy();
  10119. return -1;
  10120. }
  10121. else if( funcs.GetLength() > 1 )
  10122. {
  10123. Error(TXT_MORE_THAN_ONE_MATCHING_OP, node);
  10124. PrintMatchingFuncs(funcs, node);
  10125. ctx->type.SetDummy();
  10126. return -1;
  10127. }
  10128. }
  10129. else if( op == ttPlus )
  10130. {
  10131. Error(TXT_ILLEGAL_OPERATION, node);
  10132. ctx->type.SetDummy();
  10133. return -1;
  10134. }
  10135. }
  10136. else if( op == ttPlus || op == ttMinus )
  10137. {
  10138. // This is only for primitives. Objects are treated in the above block
  10139. // Make sure the type is a math type
  10140. if( !(ctx->type.dataType.IsIntegerType() ||
  10141. ctx->type.dataType.IsUnsignedType() ||
  10142. ctx->type.dataType.IsFloatType() ||
  10143. ctx->type.dataType.IsDoubleType() ) )
  10144. {
  10145. Error(TXT_ILLEGAL_OPERATION, node);
  10146. return -1;
  10147. }
  10148. if( ProcessPropertyGetAccessor(ctx, node) < 0 )
  10149. return -1;
  10150. asCDataType to = ctx->type.dataType;
  10151. if( ctx->type.dataType.IsUnsignedType() )
  10152. {
  10153. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  10154. to = asCDataType::CreatePrimitive(ttInt8, false);
  10155. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  10156. to = asCDataType::CreatePrimitive(ttInt16, false);
  10157. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 )
  10158. to = asCDataType::CreatePrimitive(ttInt, false);
  10159. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 8 )
  10160. to = asCDataType::CreatePrimitive(ttInt64, false);
  10161. else
  10162. {
  10163. Error(TXT_INVALID_TYPE, node);
  10164. return -1;
  10165. }
  10166. }
  10167. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  10168. // Use an explicit conversion in case of constants to avoid unnecessary warning about change of sign
  10169. ImplicitConversion(ctx, to, node, ctx->type.isConstant ? asIC_EXPLICIT_VAL_CAST : asIC_IMPLICIT_CONV);
  10170. if( !ctx->type.isConstant )
  10171. {
  10172. ConvertToTempVariable(ctx);
  10173. asASSERT(!ctx->type.isLValue);
  10174. if( op == ttMinus )
  10175. {
  10176. if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  10177. ctx->bc.InstrSHORT(asBC_NEGi, ctx->type.stackOffset);
  10178. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  10179. ctx->bc.InstrSHORT(asBC_NEGi64, ctx->type.stackOffset);
  10180. else if( ctx->type.dataType.IsFloatType() )
  10181. ctx->bc.InstrSHORT(asBC_NEGf, ctx->type.stackOffset);
  10182. else if( ctx->type.dataType.IsDoubleType() )
  10183. ctx->bc.InstrSHORT(asBC_NEGd, ctx->type.stackOffset);
  10184. else
  10185. {
  10186. Error(TXT_ILLEGAL_OPERATION, node);
  10187. return -1;
  10188. }
  10189. return 0;
  10190. }
  10191. }
  10192. else
  10193. {
  10194. if( op == ttMinus )
  10195. {
  10196. if (ctx->type.dataType.IsIntegerType())
  10197. {
  10198. if (ctx->type.dataType.GetSizeInMemoryBytes() == 4)
  10199. ctx->type.SetConstantDW(-(int)ctx->type.GetConstantDW());
  10200. else if (ctx->type.dataType.GetSizeInMemoryBytes() == 2)
  10201. ctx->type.SetConstantW(-(asINT16)ctx->type.GetConstantW());
  10202. else if (ctx->type.dataType.GetSizeInMemoryBytes() == 1)
  10203. ctx->type.SetConstantB(-(asINT8)ctx->type.GetConstantB());
  10204. else if (ctx->type.dataType.GetSizeInMemoryBytes() == 8)
  10205. ctx->type.SetConstantQW(-(asINT64)ctx->type.GetConstantQW());
  10206. }
  10207. else if( ctx->type.dataType.IsFloatType() )
  10208. ctx->type.SetConstantF(-ctx->type.GetConstantF());
  10209. else if( ctx->type.dataType.IsDoubleType() )
  10210. ctx->type.SetConstantD(-ctx->type.GetConstantD());
  10211. else
  10212. {
  10213. Error(TXT_ILLEGAL_OPERATION, node);
  10214. return -1;
  10215. }
  10216. return 0;
  10217. }
  10218. }
  10219. }
  10220. else if( op == ttNot )
  10221. {
  10222. // Allow value types to be converted to bool using 'bool opImplConv()'
  10223. if( ctx->type.dataType.GetTypeInfo() && (ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
  10224. ImplicitConversion(ctx, asCDataType::CreatePrimitive(ttBool, false), node, asIC_IMPLICIT_CONV);
  10225. if( ctx->type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  10226. {
  10227. if( ctx->type.isConstant )
  10228. {
  10229. #if AS_SIZEOF_BOOL == 1
  10230. ctx->type.SetConstantB(ctx->type.GetConstantB() == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  10231. #else
  10232. ctx->type.SetConstantDW(ctx->type.GetConstantDW() == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  10233. #endif
  10234. return 0;
  10235. }
  10236. if( ProcessPropertyGetAccessor(ctx, node) < 0 )
  10237. return -1;
  10238. ConvertToTempVariable(ctx);
  10239. asASSERT(!ctx->type.isLValue);
  10240. ctx->bc.InstrSHORT(asBC_NOT, ctx->type.stackOffset);
  10241. }
  10242. else
  10243. {
  10244. Error(TXT_ILLEGAL_OPERATION, node);
  10245. return -1;
  10246. }
  10247. }
  10248. else if( op == ttBitNot )
  10249. {
  10250. if( ProcessPropertyGetAccessor(ctx, node) < 0 )
  10251. return -1;
  10252. asCDataType to = ctx->type.dataType;
  10253. if( ctx->type.dataType.IsIntegerType() )
  10254. {
  10255. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  10256. to = asCDataType::CreatePrimitive(ttUInt8, false);
  10257. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  10258. to = asCDataType::CreatePrimitive(ttUInt16, false);
  10259. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 )
  10260. to = asCDataType::CreatePrimitive(ttUInt, false);
  10261. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 8 )
  10262. to = asCDataType::CreatePrimitive(ttUInt64, false);
  10263. else
  10264. {
  10265. Error(TXT_INVALID_TYPE, node);
  10266. return -1;
  10267. }
  10268. }
  10269. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  10270. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV);
  10271. if( ctx->type.dataType.IsUnsignedType() )
  10272. {
  10273. if( ctx->type.isConstant )
  10274. {
  10275. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  10276. ctx->type.SetConstantB(~ctx->type.GetConstantB());
  10277. else if (ctx->type.dataType.GetSizeInMemoryBytes() == 2)
  10278. ctx->type.SetConstantW(~ctx->type.GetConstantW());
  10279. else if (ctx->type.dataType.GetSizeInMemoryBytes() == 4)
  10280. ctx->type.SetConstantDW(~ctx->type.GetConstantDW());
  10281. else
  10282. ctx->type.SetConstantQW(~ctx->type.GetConstantQW());
  10283. return 0;
  10284. }
  10285. ConvertToTempVariable(ctx);
  10286. asASSERT(!ctx->type.isLValue);
  10287. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  10288. ctx->bc.InstrSHORT(asBC_BNOT, ctx->type.stackOffset);
  10289. else
  10290. ctx->bc.InstrSHORT(asBC_BNOT64, ctx->type.stackOffset);
  10291. }
  10292. else
  10293. {
  10294. Error(TXT_ILLEGAL_OPERATION, node);
  10295. return -1;
  10296. }
  10297. }
  10298. else if( op == ttInc || op == ttDec )
  10299. {
  10300. // Need a reference to the primitive that will be updated
  10301. // The result of this expression is the same reference as before
  10302. // Make sure the reference isn't a temporary variable
  10303. if( ctx->type.isTemporary )
  10304. {
  10305. Error(TXT_REF_IS_TEMP, node);
  10306. return -1;
  10307. }
  10308. if( ctx->type.dataType.IsReadOnly() )
  10309. {
  10310. Error(TXT_REF_IS_READ_ONLY, node);
  10311. return -1;
  10312. }
  10313. if( ctx->property_get || ctx->property_set )
  10314. {
  10315. Error(TXT_INVALID_REF_PROP_ACCESS, node);
  10316. return -1;
  10317. }
  10318. if( !ctx->type.isLValue )
  10319. {
  10320. Error(TXT_NOT_LVALUE, node);
  10321. return -1;
  10322. }
  10323. if( ctx->type.isVariable && !ctx->type.dataType.IsReference() )
  10324. ConvertToReference(ctx);
  10325. else if( !ctx->type.dataType.IsReference() )
  10326. {
  10327. Error(TXT_NOT_VALID_REFERENCE, node);
  10328. return -1;
  10329. }
  10330. if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt64, false)) ||
  10331. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt64, false)) )
  10332. {
  10333. if( op == ttInc )
  10334. ctx->bc.Instr(asBC_INCi64);
  10335. else
  10336. ctx->bc.Instr(asBC_DECi64);
  10337. }
  10338. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt, false)) ||
  10339. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt, false)) )
  10340. {
  10341. if( op == ttInc )
  10342. ctx->bc.Instr(asBC_INCi);
  10343. else
  10344. ctx->bc.Instr(asBC_DECi);
  10345. }
  10346. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt16, false)) ||
  10347. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt16, false)) )
  10348. {
  10349. if( op == ttInc )
  10350. ctx->bc.Instr(asBC_INCi16);
  10351. else
  10352. ctx->bc.Instr(asBC_DECi16);
  10353. }
  10354. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt8, false)) ||
  10355. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt8, false)) )
  10356. {
  10357. if( op == ttInc )
  10358. ctx->bc.Instr(asBC_INCi8);
  10359. else
  10360. ctx->bc.Instr(asBC_DECi8);
  10361. }
  10362. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttFloat, false)) )
  10363. {
  10364. if( op == ttInc )
  10365. ctx->bc.Instr(asBC_INCf);
  10366. else
  10367. ctx->bc.Instr(asBC_DECf);
  10368. }
  10369. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttDouble, false)) )
  10370. {
  10371. if( op == ttInc )
  10372. ctx->bc.Instr(asBC_INCd);
  10373. else
  10374. ctx->bc.Instr(asBC_DECd);
  10375. }
  10376. else
  10377. {
  10378. Error(TXT_ILLEGAL_OPERATION, node);
  10379. return -1;
  10380. }
  10381. }
  10382. else
  10383. {
  10384. // Unknown operator
  10385. asASSERT(false);
  10386. return -1;
  10387. }
  10388. return 0;
  10389. }
  10390. void asCCompiler::ConvertToReference(asCExprContext *ctx)
  10391. {
  10392. if( ctx->type.isVariable && !ctx->type.dataType.IsReference() )
  10393. {
  10394. ctx->bc.InstrSHORT(asBC_LDV, ctx->type.stackOffset);
  10395. ctx->type.dataType.MakeReference(true);
  10396. ctx->type.SetVariable(ctx->type.dataType, ctx->type.stackOffset, ctx->type.isTemporary);
  10397. }
  10398. }
  10399. int asCCompiler::FindPropertyAccessor(const asCString &name, asCExprContext *ctx, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess)
  10400. {
  10401. return FindPropertyAccessor(name, ctx, 0, node, ns, isThisAccess);
  10402. }
  10403. // Returns:
  10404. // 1 = a valid match was found
  10405. // 0 = no matching symbols (or feature disabled)
  10406. // -1 = ambiguous getters or setters, i.e. multiple methods match symbol name and signature
  10407. // -2 = mismatching type for getter and setter
  10408. // -3 = processing error, e.g. out of memory
  10409. int asCCompiler::FindPropertyAccessor(const asCString &name, asCExprContext *ctx, asCExprContext *arg, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess)
  10410. {
  10411. // TODO: With asEP_PROPERTY_ACCESSOR_MODE == 3 this method doesn't need to validate the
  10412. // getter/setter as it is done at the time of declaration. Should deprecate the other options
  10413. if( engine->ep.propertyAccessorMode == 0 )
  10414. {
  10415. // Property accessors have been disabled by the application
  10416. return 0;
  10417. }
  10418. int getId = 0, setId = 0;
  10419. asCString getName = "get_" + name;
  10420. asCString setName = "set_" + name;
  10421. asCArray<int> multipleGetFuncs, multipleSetFuncs;
  10422. if( ctx->type.dataType.IsObject() )
  10423. {
  10424. asASSERT( ns == 0 );
  10425. // Don't look for property accessors in script classes if the script
  10426. // property accessors have been disabled by the application
  10427. if( !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) ||
  10428. engine->ep.propertyAccessorMode >= 2 )
  10429. {
  10430. // Check if the object has any methods with the corresponding accessor name(s)
  10431. asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  10432. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  10433. {
  10434. asCScriptFunction *f = engine->scriptFunctions[ot->methods[n]];
  10435. if( engine->ep.propertyAccessorMode == 3 && !f->IsProperty() )
  10436. continue;
  10437. // TODO: The type of the parameter should match the argument (unless the arg is a dummy)
  10438. if( f->name == getName && (int)f->parameterTypes.GetLength() == (arg?1:0) )
  10439. {
  10440. if( getId == 0 )
  10441. getId = ot->methods[n];
  10442. else
  10443. {
  10444. if( multipleGetFuncs.GetLength() == 0 )
  10445. multipleGetFuncs.PushLast(getId);
  10446. multipleGetFuncs.PushLast(ot->methods[n]);
  10447. }
  10448. }
  10449. // TODO: getset: If the parameter is a reference, it must not be an out reference. Should we allow inout ref?
  10450. if( f->name == setName && (int)f->parameterTypes.GetLength() == (arg?2:1) )
  10451. {
  10452. if( setId == 0 )
  10453. setId = ot->methods[n];
  10454. else
  10455. {
  10456. if( multipleSetFuncs.GetLength() == 0 )
  10457. multipleSetFuncs.PushLast(setId);
  10458. multipleSetFuncs.PushLast(ot->methods[n]);
  10459. }
  10460. }
  10461. }
  10462. }
  10463. }
  10464. else
  10465. {
  10466. asASSERT( ns != 0 );
  10467. // Look for appropriate global functions.
  10468. asCArray<int> funcs;
  10469. asUINT n;
  10470. builder->GetFunctionDescriptions(getName.AddressOf(), funcs, ns);
  10471. for( n = 0; n < funcs.GetLength(); n++ )
  10472. {
  10473. asCScriptFunction *f = builder->GetFunctionDescription(funcs[n]);
  10474. if( engine->ep.propertyAccessorMode == 3 && !f->IsProperty() )
  10475. continue;
  10476. // Ignore script functions, if the application has disabled script defined property accessors
  10477. if( engine->ep.propertyAccessorMode == 1 && f->funcType == asFUNC_SCRIPT )
  10478. continue;
  10479. // TODO: The type of the parameter should match the argument (unless the arg is a dummy)
  10480. if( (int)f->parameterTypes.GetLength() == (arg?1:0) )
  10481. {
  10482. if( getId == 0 )
  10483. getId = funcs[n];
  10484. else
  10485. {
  10486. if( multipleGetFuncs.GetLength() == 0 )
  10487. multipleGetFuncs.PushLast(getId);
  10488. multipleGetFuncs.PushLast(funcs[n]);
  10489. }
  10490. }
  10491. }
  10492. funcs.SetLength(0);
  10493. builder->GetFunctionDescriptions(setName.AddressOf(), funcs, ns);
  10494. for( n = 0; n < funcs.GetLength(); n++ )
  10495. {
  10496. asCScriptFunction *f = builder->GetFunctionDescription(funcs[n]);
  10497. if( engine->ep.propertyAccessorMode == 3 && !f->IsProperty() )
  10498. continue;
  10499. // Ignore script functions, if the application has disabled script defined property accessors
  10500. if( engine->ep.propertyAccessorMode == 1 && f->funcType == asFUNC_SCRIPT )
  10501. continue;
  10502. // TODO: getset: If the parameter is a reference, it must not be an out reference. Should we allow inout ref?
  10503. if( (int)f->parameterTypes.GetLength() == (arg?2:1) )
  10504. {
  10505. if( setId == 0 )
  10506. setId = funcs[n];
  10507. else
  10508. {
  10509. if( multipleSetFuncs.GetLength() == 0 )
  10510. multipleSetFuncs.PushLast(setId);
  10511. multipleSetFuncs.PushLast(funcs[n]);
  10512. }
  10513. }
  10514. }
  10515. }
  10516. bool isConst = ctx->type.dataType.IsObjectConst();
  10517. // Check for multiple matches
  10518. if( multipleGetFuncs.GetLength() > 0 )
  10519. {
  10520. // Filter the list by constness
  10521. FilterConst(multipleGetFuncs, !isConst);
  10522. if( multipleGetFuncs.GetLength() > 1 )
  10523. {
  10524. if (node)
  10525. {
  10526. asCString str;
  10527. str.Format(TXT_MULTIPLE_PROP_GET_ACCESSOR_FOR_s, name.AddressOf());
  10528. Error(str, node);
  10529. PrintMatchingFuncs(multipleGetFuncs, node);
  10530. }
  10531. return -1;
  10532. }
  10533. else
  10534. {
  10535. // The id may have changed
  10536. getId = multipleGetFuncs[0];
  10537. }
  10538. }
  10539. if( multipleSetFuncs.GetLength() > 0 )
  10540. {
  10541. // Filter the list by constness
  10542. FilterConst(multipleSetFuncs, !isConst);
  10543. if( multipleSetFuncs.GetLength() > 1 )
  10544. {
  10545. if (node)
  10546. {
  10547. asCString str;
  10548. str.Format(TXT_MULTIPLE_PROP_SET_ACCESSOR_FOR_s, name.AddressOf());
  10549. Error(str, node);
  10550. PrintMatchingFuncs(multipleSetFuncs, node);
  10551. }
  10552. return -1;
  10553. }
  10554. else
  10555. {
  10556. // The id may have changed
  10557. setId = multipleSetFuncs[0];
  10558. }
  10559. }
  10560. // Check for type compatibility between get and set accessor
  10561. if( getId && setId )
  10562. {
  10563. asCScriptFunction *getFunc = builder->GetFunctionDescription(getId);
  10564. asCScriptFunction *setFunc = builder->GetFunctionDescription(setId);
  10565. // It is permitted for a getter to return a handle and the setter to take a reference
  10566. int idx = (arg?1:0);
  10567. if( !getFunc->returnType.IsEqualExceptRefAndConst(setFunc->parameterTypes[idx]) &&
  10568. !((getFunc->returnType.IsObjectHandle() && !setFunc->parameterTypes[idx].IsObjectHandle()) &&
  10569. (getFunc->returnType.GetTypeInfo() == setFunc->parameterTypes[idx].GetTypeInfo())) )
  10570. {
  10571. if (node)
  10572. {
  10573. asCString str;
  10574. str.Format(TXT_GET_SET_ACCESSOR_TYPE_MISMATCH_FOR_s, name.AddressOf());
  10575. Error(str, node);
  10576. asCArray<int> funcs;
  10577. funcs.PushLast(getId);
  10578. funcs.PushLast(setId);
  10579. PrintMatchingFuncs(funcs, node);
  10580. }
  10581. return -2;
  10582. }
  10583. }
  10584. // Check if we are within one of the accessors
  10585. int realGetId = getId;
  10586. int realSetId = setId;
  10587. if( outFunc->objectType && isThisAccess )
  10588. {
  10589. // The property accessors would be virtual functions, so we need to find the real implementation
  10590. asCScriptFunction *getFunc = getId ? builder->GetFunctionDescription(getId) : 0;
  10591. if( getFunc &&
  10592. getFunc->funcType == asFUNC_VIRTUAL &&
  10593. outFunc->objectType->DerivesFrom(getFunc->objectType) )
  10594. realGetId = outFunc->objectType->virtualFunctionTable[getFunc->vfTableIdx]->id;
  10595. asCScriptFunction *setFunc = setId ? builder->GetFunctionDescription(setId) : 0;
  10596. if( setFunc &&
  10597. setFunc->funcType == asFUNC_VIRTUAL &&
  10598. outFunc->objectType->DerivesFrom(setFunc->objectType) )
  10599. realSetId = outFunc->objectType->virtualFunctionTable[setFunc->vfTableIdx]->id;
  10600. }
  10601. // Avoid recursive call by not treating this as a property accessor call.
  10602. // This will also allow having the real property with the same name as the accessors.
  10603. if( (isThisAccess || outFunc->objectType == 0) &&
  10604. ((realGetId && realGetId == outFunc->id) ||
  10605. (realSetId && realSetId == outFunc->id)) )
  10606. {
  10607. getId = 0;
  10608. setId = 0;
  10609. }
  10610. if( getId || setId )
  10611. {
  10612. // Property accessors were found, but we don't know which is to be used yet, so
  10613. // we just prepare the bytecode for the method call, and then store the function ids
  10614. // so that the right one can be used when we get there.
  10615. ctx->property_get = getId;
  10616. ctx->property_set = setId;
  10617. bool isRefSafe = ctx->type.isRefSafe;
  10618. if( ctx->type.dataType.IsObject() )
  10619. {
  10620. // If the object is read-only then we need to remember that
  10621. if( (!ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReadOnly()) ||
  10622. (ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsHandleToConst()) )
  10623. ctx->property_const = true;
  10624. else
  10625. ctx->property_const = false;
  10626. // If the object is a handle then we need to remember that
  10627. ctx->property_handle = ctx->type.dataType.IsObjectHandle();
  10628. ctx->property_ref = ctx->type.dataType.IsReference();
  10629. }
  10630. // The setter's parameter type is used as the property type,
  10631. // unless only the getter is available
  10632. asCDataType dt;
  10633. if( setId )
  10634. dt = builder->GetFunctionDescription(setId)->parameterTypes[(arg?1:0)];
  10635. else
  10636. dt = builder->GetFunctionDescription(getId)->returnType;
  10637. // Just change the type, the context must still maintain information
  10638. // about previous variable offset and the indicator of temporary variable.
  10639. int offset = ctx->type.stackOffset;
  10640. bool isTemp = ctx->type.isTemporary;
  10641. ctx->type.Set(dt);
  10642. ctx->type.stackOffset = (short)offset;
  10643. ctx->type.isTemporary = isTemp;
  10644. ctx->exprNode = node;
  10645. // Remember if the object is safe, so the invocation of the property
  10646. // accessor doesn't needlessly make a safe copy of the handle
  10647. ctx->type.isRefSafe = isRefSafe;
  10648. // Store the argument for later use
  10649. if( arg )
  10650. {
  10651. ctx->property_arg = asNEW(asCExprContext)(engine);
  10652. if( ctx->property_arg == 0 )
  10653. {
  10654. // Out of memory
  10655. return -3;
  10656. }
  10657. MergeExprBytecodeAndType(ctx->property_arg, arg);
  10658. }
  10659. return 1;
  10660. }
  10661. // No accessor was found
  10662. return 0;
  10663. }
  10664. int asCCompiler::ProcessPropertySetAccessor(asCExprContext *ctx, asCExprContext *arg, asCScriptNode *node)
  10665. {
  10666. // TODO: A lot of this code is similar to ProcessPropertyGetAccessor. Can we unify them?
  10667. if( !ctx->property_set )
  10668. {
  10669. Error(TXT_PROPERTY_HAS_NO_SET_ACCESSOR, node);
  10670. return -1;
  10671. }
  10672. asCScriptFunction *func = builder->GetFunctionDescription(ctx->property_set);
  10673. // Make sure the arg match the property
  10674. asCArray<int> funcs;
  10675. funcs.PushLast(ctx->property_set);
  10676. asCArray<asCExprContext *> args;
  10677. if( ctx->property_arg )
  10678. args.PushLast(ctx->property_arg);
  10679. args.PushLast(arg);
  10680. MatchFunctions(funcs, args, node, func->GetName(), 0, func->objectType, ctx->property_const);
  10681. if( funcs.GetLength() == 0 )
  10682. {
  10683. // MatchFunctions already reported the error
  10684. if( ctx->property_arg )
  10685. {
  10686. asDELETE(ctx->property_arg, asCExprContext);
  10687. ctx->property_arg = 0;
  10688. }
  10689. return -1;
  10690. }
  10691. if( func->objectType )
  10692. {
  10693. // Setup the context with the original type so the method call gets built correctly
  10694. ctx->type.dataType = asCDataType::CreateType(func->objectType, ctx->property_const);
  10695. if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
  10696. if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
  10697. // Don't allow the call if the object is read-only and the property accessor is not const
  10698. if( ctx->property_const && !func->IsReadOnly() )
  10699. {
  10700. Error(TXT_NON_CONST_METHOD_ON_CONST_OBJ, node);
  10701. asCArray<int> funcCandidates;
  10702. funcCandidates.PushLast(ctx->property_set);
  10703. PrintMatchingFuncs(funcCandidates, node);
  10704. }
  10705. }
  10706. // Call the accessor
  10707. int r = MakeFunctionCall(ctx, ctx->property_set, func->objectType, args, node);
  10708. ctx->property_get = 0;
  10709. ctx->property_set = 0;
  10710. if( ctx->property_arg )
  10711. {
  10712. asDELETE(ctx->property_arg, asCExprContext);
  10713. ctx->property_arg = 0;
  10714. }
  10715. return r;
  10716. }
  10717. int asCCompiler::ProcessPropertyGetSetAccessor(asCExprContext *ctx, asCExprContext *lctx, asCExprContext *rctx, eTokenType op, asCScriptNode *errNode)
  10718. {
  10719. // TODO: Perhaps it might be interesting to allow the definition of compound setters for better
  10720. // performance, e.g. set_add_prop, set_mul_prop, etc. With these it would also be possible
  10721. // to support value types, since it would be a single call
  10722. // Compound assignment for indexed property accessors is not supported yet
  10723. if( lctx->property_arg != 0 )
  10724. {
  10725. // Process the property to free the memory
  10726. ProcessPropertySetAccessor(lctx, rctx, errNode);
  10727. Error(TXT_COMPOUND_ASGN_WITH_IDX_PROP, errNode);
  10728. return -1;
  10729. }
  10730. // Compound assignments require both get and set accessors
  10731. if( lctx->property_set == 0 || lctx->property_get == 0 )
  10732. {
  10733. // Process the property to free the memory
  10734. ProcessPropertySetAccessor(lctx, rctx, errNode);
  10735. Error(TXT_COMPOUND_ASGN_REQUIRE_GET_SET, errNode);
  10736. return -1;
  10737. }
  10738. // Property accessors on value types (or scoped references types) are not supported since
  10739. // it is not possible to guarantee that the object will stay alive between the two calls
  10740. asCScriptFunction *func = engine->scriptFunctions[lctx->property_set];
  10741. if( func->objectType && (func->objectType->flags & (asOBJ_VALUE | asOBJ_SCOPED)) )
  10742. {
  10743. // Process the property to free the memory
  10744. ProcessPropertySetAccessor(lctx, rctx, errNode);
  10745. Error(TXT_COMPOUND_ASGN_ON_VALUE_TYPE, errNode);
  10746. return -1;
  10747. }
  10748. // Translate the compound assignment to the corresponding dual operator
  10749. switch( op )
  10750. {
  10751. case ttAddAssign: op = ttPlus; break;
  10752. case ttSubAssign: op = ttMinus; break;
  10753. case ttMulAssign: op = ttStar; break;
  10754. case ttDivAssign: op = ttSlash; break;
  10755. case ttModAssign: op = ttPercent; break;
  10756. case ttPowAssign: op = ttStarStar; break;
  10757. case ttAndAssign: op = ttAmp; break;
  10758. case ttOrAssign: op = ttBitOr; break;
  10759. case ttXorAssign: op = ttBitXor; break;
  10760. case ttShiftLeftAssign: op = ttBitShiftLeft; break;
  10761. case ttShiftRightAAssign: op = ttBitShiftRightArith; break;
  10762. case ttShiftRightLAssign: op = ttBitShiftRight; break;
  10763. default: op = ttUnrecognizedToken; break;
  10764. }
  10765. if( op == ttUnrecognizedToken )
  10766. {
  10767. // Shouldn't happen
  10768. asASSERT(false);
  10769. // Process the property to free the memory
  10770. ProcessPropertySetAccessor(lctx, rctx, errNode);
  10771. return -1;
  10772. }
  10773. asCExprContext before(engine);
  10774. if( func->objectType && (func->objectType->flags & (asOBJ_REF|asOBJ_SCOPED)) == asOBJ_REF )
  10775. {
  10776. // Keep a reference to the object in a local variable
  10777. before.bc.AddCode(&lctx->bc);
  10778. asUINT len = reservedVariables.GetLength();
  10779. rctx->bc.GetVarsUsed(reservedVariables);
  10780. before.bc.GetVarsUsed(reservedVariables);
  10781. asCDataType dt = asCDataType::CreateObjectHandle(func->objectType, false);
  10782. int offset = AllocateVariable(dt, true);
  10783. reservedVariables.SetLength(len);
  10784. before.type.SetVariable(dt, offset, true);
  10785. if( lctx->property_ref )
  10786. before.bc.Instr(asBC_RDSPtr);
  10787. before.bc.InstrSHORT(asBC_PSF, (short)offset);
  10788. before.bc.InstrPTR(asBC_REFCPY, func->objectType);
  10789. before.bc.Instr(asBC_PopPtr);
  10790. if( lctx->type.isTemporary )
  10791. {
  10792. // Add the release of the temporary variable as a deferred expression
  10793. asSDeferredParam deferred;
  10794. deferred.origExpr = 0;
  10795. deferred.argInOutFlags = asTM_INREF;
  10796. deferred.argNode = 0;
  10797. deferred.argType.SetVariable(ctx->type.dataType, lctx->type.stackOffset, true);
  10798. before.deferredParams.PushLast(deferred);
  10799. }
  10800. // Update the left expression to use the local variable
  10801. lctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  10802. lctx->type.stackOffset = (short)offset;
  10803. lctx->property_ref = true;
  10804. // Don't release the temporary variable too early
  10805. lctx->type.isTemporary = false;
  10806. ctx->bc.AddCode(&before.bc);
  10807. }
  10808. // Keep the original information on the property
  10809. asCExprContext llctx(engine);
  10810. llctx.type = lctx->type;
  10811. llctx.property_arg = lctx->property_arg;
  10812. llctx.property_const = lctx->property_const;
  10813. llctx.property_get = lctx->property_get;
  10814. llctx.property_handle = lctx->property_handle;
  10815. llctx.property_ref = lctx->property_ref;
  10816. llctx.property_set = lctx->property_set;
  10817. // Compile the dual operator using the get accessor
  10818. CompileOperator(errNode, lctx, rctx, ctx, op, false);
  10819. // If we made a local variable to hold the reference it must be reused
  10820. if( before.type.stackOffset )
  10821. llctx.bc.InstrSHORT(asBC_PSF, before.type.stackOffset);
  10822. // Compile the assignment using the set accessor
  10823. ProcessPropertySetAccessor(&llctx, ctx, errNode);
  10824. MergeExprBytecodeAndType(ctx, &llctx);
  10825. if( before.type.stackOffset )
  10826. ReleaseTemporaryVariable(before.type.stackOffset, &ctx->bc);
  10827. asASSERT( ctx->deferredParams.GetLength() == 0 );
  10828. ctx->deferredParams = before.deferredParams;
  10829. ProcessDeferredParams(ctx);
  10830. return 0;
  10831. }
  10832. int asCCompiler::ProcessPropertyGetAccessor(asCExprContext *ctx, asCScriptNode *node)
  10833. {
  10834. // If no property accessor has been prepared then don't do anything
  10835. if( !ctx->property_get && !ctx->property_set )
  10836. return 0;
  10837. if( !ctx->property_get )
  10838. {
  10839. // Raise error on missing accessor
  10840. Error(TXT_PROPERTY_HAS_NO_GET_ACCESSOR, node);
  10841. return -1;
  10842. }
  10843. asCExprValue objType = ctx->type;
  10844. asCScriptFunction *func = builder->GetFunctionDescription(ctx->property_get);
  10845. // Make sure the arg match the property
  10846. asCArray<int> funcs;
  10847. funcs.PushLast(ctx->property_get);
  10848. asCArray<asCExprContext *> args;
  10849. if( ctx->property_arg )
  10850. args.PushLast(ctx->property_arg);
  10851. MatchFunctions(funcs, args, node, func->GetName(), 0, func->objectType, ctx->property_const);
  10852. if( funcs.GetLength() == 0 )
  10853. {
  10854. // MatchFunctions already reported the error
  10855. if( ctx->property_arg )
  10856. {
  10857. asDELETE(ctx->property_arg, asCExprContext);
  10858. ctx->property_arg = 0;
  10859. }
  10860. return -1;
  10861. }
  10862. if( func->objectType )
  10863. {
  10864. // Setup the context with the original type so the method call gets built correctly
  10865. ctx->type.dataType = asCDataType::CreateType(func->objectType, ctx->property_const);
  10866. if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
  10867. if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
  10868. // Don't allow the call if the object is read-only and the property accessor is not const
  10869. if( ctx->property_const && !func->IsReadOnly() )
  10870. {
  10871. Error(TXT_NON_CONST_METHOD_ON_CONST_OBJ, node);
  10872. asCArray<int> funcCandidates;
  10873. funcCandidates.PushLast(ctx->property_get);
  10874. PrintMatchingFuncs(funcCandidates, node);
  10875. return -1;
  10876. }
  10877. }
  10878. // The explicit handle flag must be remembered
  10879. bool isExplicitHandle = ctx->type.isExplicitHandle;
  10880. // Call the accessor
  10881. int r = MakeFunctionCall(ctx, ctx->property_get, func->objectType, args, node);
  10882. if( isExplicitHandle )
  10883. ctx->type.isExplicitHandle = true;
  10884. // Clear the property get/set ids
  10885. ctx->property_get = 0;
  10886. ctx->property_set = 0;
  10887. if( ctx->property_arg )
  10888. {
  10889. asDELETE(ctx->property_arg, asCExprContext);
  10890. ctx->property_arg = 0;
  10891. }
  10892. return r;
  10893. }
  10894. int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asCExprContext *ctx)
  10895. {
  10896. // Don't allow any postfix operators on expressions that take address of class method
  10897. if( ctx->IsClassMethod() )
  10898. {
  10899. Error(TXT_INVALID_OP_ON_METHOD, node);
  10900. return -1;
  10901. }
  10902. // Don't allow any operators on void expressions
  10903. if( ctx->IsVoidExpression() )
  10904. {
  10905. Error(TXT_VOID_CANT_BE_OPERAND, node);
  10906. return -1;
  10907. }
  10908. // Check if the variable is initialized (if it indeed is a variable)
  10909. IsVariableInitialized(&ctx->type, node);
  10910. int op = node->tokenType;
  10911. if( (op == ttInc || op == ttDec) && ctx->type.dataType.IsObject() )
  10912. {
  10913. const char *opName = 0;
  10914. switch( op )
  10915. {
  10916. case ttInc: opName = "opPostInc"; break;
  10917. case ttDec: opName = "opPostDec"; break;
  10918. }
  10919. if( opName )
  10920. {
  10921. // TODO: Should convert this to something similar to CompileOverloadedDualOperator2
  10922. if( ProcessPropertyGetAccessor(ctx, node) < 0 )
  10923. return -1;
  10924. // 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
  10925. // Find the correct method
  10926. bool isConst = ctx->type.dataType.IsObjectConst();
  10927. asCArray<int> funcs;
  10928. asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  10929. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  10930. {
  10931. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  10932. if( func->name == opName &&
  10933. func->parameterTypes.GetLength() == 0 &&
  10934. (!isConst || func->IsReadOnly()) )
  10935. {
  10936. funcs.PushLast(func->id);
  10937. }
  10938. }
  10939. // Did we find the method?
  10940. if( funcs.GetLength() == 1 )
  10941. {
  10942. asCArray<asCExprContext *> args;
  10943. return MakeFunctionCall(ctx, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
  10944. }
  10945. else if( funcs.GetLength() == 0 )
  10946. {
  10947. asCString str;
  10948. str = asCString(opName) + "()";
  10949. if( isConst )
  10950. str += " const";
  10951. str.Format(TXT_FUNCTION_s_NOT_FOUND, str.AddressOf());
  10952. Error(str, node);
  10953. ctx->type.SetDummy();
  10954. return -1;
  10955. }
  10956. else if( funcs.GetLength() > 1 )
  10957. {
  10958. Error(TXT_MORE_THAN_ONE_MATCHING_OP, node);
  10959. PrintMatchingFuncs(funcs, node);
  10960. ctx->type.SetDummy();
  10961. return -1;
  10962. }
  10963. }
  10964. }
  10965. else if( op == ttInc || op == ttDec )
  10966. {
  10967. // Make sure the reference isn't a temporary variable
  10968. if( ctx->type.isTemporary )
  10969. {
  10970. Error(TXT_REF_IS_TEMP, node);
  10971. return -1;
  10972. }
  10973. if( ctx->type.dataType.IsReadOnly() )
  10974. {
  10975. Error(TXT_REF_IS_READ_ONLY, node);
  10976. return -1;
  10977. }
  10978. if( ctx->property_get || ctx->property_set )
  10979. {
  10980. Error(TXT_INVALID_REF_PROP_ACCESS, node);
  10981. return -1;
  10982. }
  10983. if( !ctx->type.isLValue )
  10984. {
  10985. Error(TXT_NOT_LVALUE, node);
  10986. return -1;
  10987. }
  10988. if( ctx->type.isVariable && !ctx->type.dataType.IsReference() )
  10989. ConvertToReference(ctx);
  10990. else if( !ctx->type.dataType.IsReference() )
  10991. {
  10992. Error(TXT_NOT_VALID_REFERENCE, node);
  10993. return -1;
  10994. }
  10995. // Copy the value to a temp before changing it
  10996. ConvertToTempVariable(ctx);
  10997. asASSERT(!ctx->type.isLValue);
  10998. // Increment the value pointed to by the reference still in the register
  10999. asEBCInstr iInc = asBC_INCi, iDec = asBC_DECi;
  11000. if( ctx->type.dataType.IsDoubleType() )
  11001. {
  11002. iInc = asBC_INCd;
  11003. iDec = asBC_DECd;
  11004. }
  11005. else if( ctx->type.dataType.IsFloatType() )
  11006. {
  11007. iInc = asBC_INCf;
  11008. iDec = asBC_DECf;
  11009. }
  11010. else if( ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType() )
  11011. {
  11012. if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt16, false)) ||
  11013. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt16, false)) )
  11014. {
  11015. iInc = asBC_INCi16;
  11016. iDec = asBC_DECi16;
  11017. }
  11018. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt8, false)) ||
  11019. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt8, false)) )
  11020. {
  11021. iInc = asBC_INCi8;
  11022. iDec = asBC_DECi8;
  11023. }
  11024. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt64, false)) ||
  11025. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt64, false)) )
  11026. {
  11027. iInc = asBC_INCi64;
  11028. iDec = asBC_DECi64;
  11029. }
  11030. }
  11031. else
  11032. {
  11033. Error(TXT_ILLEGAL_OPERATION, node);
  11034. return -1;
  11035. }
  11036. if( op == ttInc ) ctx->bc.Instr(iInc); else ctx->bc.Instr(iDec);
  11037. }
  11038. else if( op == ttDot )
  11039. {
  11040. if( node->firstChild->nodeType == snIdentifier )
  11041. {
  11042. if( ProcessPropertyGetAccessor(ctx, node) < 0 )
  11043. return -1;
  11044. // Get the property name
  11045. asCString name(&script->code[node->firstChild->tokenPos], node->firstChild->tokenLength);
  11046. if( ctx->type.dataType.IsObject() )
  11047. {
  11048. // We need to look for get/set property accessors.
  11049. // If found, the context stores information on the get/set accessors
  11050. // until it is known which is to be used.
  11051. int r = 0;
  11052. if( node->next && node->next->tokenType == ttOpenBracket )
  11053. {
  11054. // The property accessor should take an index arg
  11055. asCExprContext dummyArg(engine);
  11056. r = FindPropertyAccessor(name, ctx, &dummyArg, node, 0);
  11057. }
  11058. if( r == 0 )
  11059. r = FindPropertyAccessor(name, ctx, node, 0);
  11060. if( r != 0 )
  11061. return r;
  11062. if( !ctx->type.dataType.IsPrimitive() )
  11063. Dereference(ctx, true);
  11064. if( ctx->type.dataType.IsObjectHandle() )
  11065. {
  11066. // Convert the handle to a normal object
  11067. asCDataType dt = ctx->type.dataType;
  11068. dt.MakeHandle(false);
  11069. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV);
  11070. // The handle may not have been an lvalue, but the dereferenced object is
  11071. ctx->type.isLValue = true;
  11072. }
  11073. bool isConst = ctx->type.dataType.IsObjectConst();
  11074. asCObjectProperty *prop = builder->GetObjectProperty(ctx->type.dataType, name.AddressOf());
  11075. if( prop )
  11076. {
  11077. // Is the property access allowed?
  11078. if( (prop->isPrivate || prop->isProtected) && (!outFunc || outFunc->objectType != ctx->type.dataType.GetTypeInfo()) )
  11079. {
  11080. asCString msg;
  11081. if( prop->isPrivate )
  11082. msg.Format(TXT_PRIVATE_PROP_ACCESS_s, name.AddressOf());
  11083. else
  11084. msg.Format(TXT_PROTECTED_PROP_ACCESS_s, name.AddressOf());
  11085. Error(msg, node);
  11086. }
  11087. // Adjust the pointer for composite member
  11088. // 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
  11089. if( prop->compositeOffset || prop->isCompositeIndirect )
  11090. ctx->bc.InstrSHORT_DW(asBC_ADDSi, (short)prop->compositeOffset, engine->GetTypeIdFromDataType(asCDataType::CreateType(ctx->type.dataType.GetTypeInfo(), false)));
  11091. if (prop->isCompositeIndirect)
  11092. ctx->bc.Instr(asBC_RDSPtr);
  11093. // Put the offset on the stack
  11094. // This must always be done even if the offset is 0 so the type info is stored
  11095. ctx->bc.InstrSHORT_DW(asBC_ADDSi, (short)prop->byteOffset, engine->GetTypeIdFromDataType(asCDataType::CreateType(ctx->type.dataType.GetTypeInfo(), false)));
  11096. if( prop->type.IsReference() )
  11097. ctx->bc.Instr(asBC_RDSPtr);
  11098. // Reference to primitive must be stored in the temp register
  11099. if( prop->type.IsPrimitive() )
  11100. {
  11101. ctx->bc.Instr(asBC_PopRPtr);
  11102. }
  11103. // Keep information about temporary variables as deferred expression
  11104. if( ctx->type.isTemporary )
  11105. {
  11106. // Add the release of this reference, as a deferred expression
  11107. asSDeferredParam deferred;
  11108. deferred.origExpr = 0;
  11109. deferred.argInOutFlags = asTM_INREF;
  11110. deferred.argNode = 0;
  11111. deferred.argType.SetVariable(ctx->type.dataType, ctx->type.stackOffset, true);
  11112. ctx->deferredParams.PushLast(deferred);
  11113. }
  11114. // Set the new type and make sure it is not treated as a variable anymore
  11115. ctx->type.dataType = prop->type;
  11116. ctx->type.dataType.MakeReference(true);
  11117. ctx->type.isVariable = false;
  11118. ctx->type.isTemporary = false;
  11119. if( (ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) && !ctx->type.dataType.IsObjectHandle() )
  11120. {
  11121. // Objects that are members are not references
  11122. ctx->type.dataType.MakeReference(false);
  11123. // The object is safe (life time guaranteed) if the parent object is also safe
  11124. }
  11125. else if (ctx->type.dataType.IsObjectHandle())
  11126. {
  11127. // A object accessed through a handle cannot be considered safe,
  11128. // as it can be cleared at any time
  11129. ctx->type.isRefSafe = false;
  11130. }
  11131. ctx->type.dataType.MakeReadOnly(isConst ? true : prop->type.IsReadOnly());
  11132. }
  11133. else
  11134. {
  11135. // If the name is not a property, the compiler must check if the name matches
  11136. // a method, which can be used for constructing delegates
  11137. asIScriptFunction *func = 0;
  11138. asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  11139. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  11140. {
  11141. if( engine->scriptFunctions[ot->methods[n]]->name == name )
  11142. {
  11143. func = engine->scriptFunctions[ot->methods[n]];
  11144. break;
  11145. }
  11146. }
  11147. if( func )
  11148. {
  11149. // An object method was found. Keep the name of the method in the expression, but
  11150. // don't actually modify the bytecode at this point since it is not yet known what
  11151. // the method will be used for, or even what overloaded method should be used.
  11152. ctx->methodName = name;
  11153. }
  11154. else
  11155. {
  11156. asCString str;
  11157. str.Format(TXT_s_NOT_MEMBER_OF_s, name.AddressOf(), ctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  11158. Error(str, node);
  11159. return -1;
  11160. }
  11161. }
  11162. }
  11163. else
  11164. {
  11165. asCString str;
  11166. str.Format(TXT_s_NOT_MEMBER_OF_s, name.AddressOf(), ctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  11167. Error(str, node);
  11168. return -1;
  11169. }
  11170. }
  11171. else
  11172. {
  11173. // Make sure it is an object we are accessing
  11174. if( !ctx->type.dataType.IsObject() )
  11175. {
  11176. asCString str;
  11177. str.Format(TXT_ILLEGAL_OPERATION_ON_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  11178. Error(str, node);
  11179. return -1;
  11180. }
  11181. // Process the get property accessor
  11182. if( ProcessPropertyGetAccessor(ctx, node) < 0 )
  11183. return -1;
  11184. // Compile function call
  11185. int r = CompileFunctionCall(node->firstChild, ctx, CastToObjectType(ctx->type.dataType.GetTypeInfo()), ctx->type.dataType.IsObjectConst());
  11186. if( r < 0 ) return r;
  11187. }
  11188. }
  11189. else if( op == ttOpenBracket )
  11190. {
  11191. // If the property access takes an index arg and the argument hasn't been evaluated yet,
  11192. // then we should use that instead of processing it now. If the argument has already been
  11193. // evaluated, then we should process the property accessor as a get access now as the new
  11194. // index operator is on the result of that accessor.
  11195. asCString propertyName;
  11196. asSNameSpace *ns = 0;
  11197. if( ((ctx->property_get && builder->GetFunctionDescription(ctx->property_get)->GetParamCount() == 1) ||
  11198. (ctx->property_set && builder->GetFunctionDescription(ctx->property_set)->GetParamCount() == 2)) &&
  11199. (ctx->property_arg && ctx->property_arg->type.dataType.GetTokenType() == ttUnrecognizedToken) )
  11200. {
  11201. // Determine the name of the property accessor
  11202. asCScriptFunction *func = 0;
  11203. if( ctx->property_get )
  11204. func = builder->GetFunctionDescription(ctx->property_get);
  11205. else
  11206. func = builder->GetFunctionDescription(ctx->property_set);
  11207. propertyName = func->GetName();
  11208. propertyName = propertyName.SubString(4);
  11209. // Set the original type of the expression so we can re-evaluate the property accessor
  11210. if( func->objectType )
  11211. {
  11212. ctx->type.dataType = asCDataType::CreateType(func->objectType, ctx->property_const);
  11213. if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
  11214. if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
  11215. }
  11216. else
  11217. {
  11218. // Store the namespace where the function is declared
  11219. // so the same function can be found later
  11220. ctx->type.SetDummy();
  11221. ns = func->nameSpace;
  11222. }
  11223. ctx->property_get = ctx->property_set = 0;
  11224. if( ctx->property_arg )
  11225. {
  11226. asDELETE(ctx->property_arg, asCExprContext);
  11227. ctx->property_arg = 0;
  11228. }
  11229. }
  11230. else
  11231. {
  11232. if( !ctx->type.dataType.IsObject() )
  11233. {
  11234. asCString str;
  11235. str.Format(TXT_OBJECT_DOESNT_SUPPORT_INDEX_OP, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  11236. Error(str, node);
  11237. return -1;
  11238. }
  11239. if( ProcessPropertyGetAccessor(ctx, node) < 0 )
  11240. return -1;
  11241. }
  11242. // Compile the expression
  11243. bool isOK = true;
  11244. asCArray<asCExprContext *> args;
  11245. asCArray<asSNamedArgument> namedArgs;
  11246. asASSERT( node->firstChild->nodeType == snArgList );
  11247. if( CompileArgumentList(node->firstChild, args, namedArgs) >= 0 )
  11248. {
  11249. // Check for the existence of the opIndex method
  11250. bool lookForProperty = true;
  11251. if( propertyName == "" )
  11252. {
  11253. bool isConst = ctx->type.dataType.IsObjectConst();
  11254. asCObjectType *objectType = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  11255. asCArray<int> funcs;
  11256. builder->GetObjectMethodDescriptions("opIndex", objectType, funcs, isConst);
  11257. if( funcs.GetLength() > 0 )
  11258. {
  11259. // Since there are opIndex methods, the compiler should not look for get/set_opIndex accessors
  11260. lookForProperty = false;
  11261. // Determine which of opIndex methods that match
  11262. MatchFunctions(funcs, args, node, "opIndex", 0, objectType, isConst);
  11263. if( funcs.GetLength() != 1 )
  11264. {
  11265. // The error has already been reported by MatchFunctions
  11266. isOK = false;
  11267. }
  11268. else
  11269. {
  11270. // Add the default values for arguments not explicitly supplied
  11271. int r = CompileDefaultAndNamedArgs(node, args, funcs[0], objectType);
  11272. if( r < 0 )
  11273. isOK = false;
  11274. else if( MakeFunctionCall(ctx, funcs[0], objectType, args, node, false, 0, ctx->type.stackOffset) < 0 )
  11275. isOK = false;
  11276. }
  11277. }
  11278. }
  11279. if( lookForProperty && isOK )
  11280. {
  11281. if( args.GetLength() != 1 )
  11282. {
  11283. // TODO: opIndex: Implement support for multiple index arguments in set_opIndex too
  11284. Error(TXT_PROP_ACCESS_WITH_INDEX_ONE_ARG, node);
  11285. isOK = false;
  11286. }
  11287. else
  11288. {
  11289. Dereference(ctx, true);
  11290. asCExprContext lctx(engine);
  11291. MergeExprBytecodeAndType(&lctx, ctx);
  11292. // Check for accessors methods for the opIndex, either as get/set_opIndex or as get/set with the property name
  11293. int r = FindPropertyAccessor(propertyName == "" ? "opIndex" : propertyName.AddressOf(), &lctx, args[0], node, ns);
  11294. if (r == 0)
  11295. {
  11296. asCString str;
  11297. str.Format(TXT_OBJECT_DOESNT_SUPPORT_INDEX_OP, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  11298. Error(str, node);
  11299. isOK = false;
  11300. }
  11301. else if (r < 0)
  11302. isOK = false;
  11303. if (isOK)
  11304. MergeExprBytecodeAndType(ctx, &lctx);
  11305. }
  11306. }
  11307. }
  11308. else
  11309. isOK = false;
  11310. // Cleanup
  11311. for( asUINT n = 0; n < args.GetLength(); n++ )
  11312. if( args[n] )
  11313. {
  11314. asDELETE(args[n], asCExprContext);
  11315. }
  11316. if( !isOK )
  11317. return -1;
  11318. }
  11319. else if( op == ttOpenParanthesis )
  11320. {
  11321. // TODO: Most of this is already done by CompileFunctionCall(). Can we share the code?
  11322. // Make sure the expression is a funcdef or an object that may have opCall methods
  11323. if( !ctx->type.dataType.GetTypeInfo() || (!ctx->type.dataType.IsFuncdef() && !ctx->type.dataType.IsObject()) )
  11324. {
  11325. Error(TXT_EXPR_DOESNT_EVAL_TO_FUNC, node);
  11326. return -1;
  11327. }
  11328. // Compile arguments
  11329. bool isOK = true;
  11330. asCArray<asCExprContext *> args;
  11331. asCArray<asSNamedArgument> namedArgs;
  11332. if( CompileArgumentList(node->lastChild, args, namedArgs) >= 0 )
  11333. {
  11334. // Match arguments with the funcdef
  11335. asCArray<int> funcs;
  11336. if( ctx->type.dataType.IsFuncdef() )
  11337. {
  11338. funcs.PushLast(CastToFuncdefType(ctx->type.dataType.GetTypeInfo())->funcdef->id);
  11339. MatchFunctions(funcs, args, node, ctx->type.dataType.GetTypeInfo()->name.AddressOf(), &namedArgs);
  11340. }
  11341. else
  11342. {
  11343. bool isConst = ctx->type.dataType.IsObjectConst();
  11344. builder->GetObjectMethodDescriptions("opCall", CastToObjectType(ctx->type.dataType.GetTypeInfo()), funcs, isConst);
  11345. MatchFunctions(funcs, args, node, "opCall", &namedArgs, CastToObjectType(ctx->type.dataType.GetTypeInfo()), isConst);
  11346. }
  11347. if( funcs.GetLength() != 1 )
  11348. {
  11349. // The error was reported by MatchFunctions()
  11350. // Dummy value
  11351. ctx->type.SetDummy();
  11352. }
  11353. else
  11354. {
  11355. // Add the default values for arguments not explicitly supplied
  11356. int r = CompileDefaultAndNamedArgs(node, args, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), &namedArgs);
  11357. // TODO: funcdef: Do we have to make sure the handle is stored in a temporary variable, or
  11358. // is it enough to make sure it is in a local variable?
  11359. // For function pointer we must guarantee that the function is safe, i.e.
  11360. // by first storing the function pointer in a local variable (if it isn't already in one)
  11361. if( r == asSUCCESS )
  11362. {
  11363. Dereference(ctx, true);
  11364. if( ctx->type.dataType.IsFuncdef() )
  11365. {
  11366. if( !ctx->type.isVariable )
  11367. ConvertToVariable(ctx);
  11368. // Remove the reference from the stack as the asBC_CALLPTR instruction takes the variable as argument
  11369. ctx->bc.Instr(asBC_PopPtr);
  11370. }
  11371. r = MakeFunctionCall(ctx, funcs[0], ctx->type.dataType.IsFuncdef() ? 0 : CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node, false, 0, ctx->type.stackOffset);
  11372. if( r < 0 )
  11373. isOK = false;
  11374. }
  11375. else
  11376. isOK = false;
  11377. }
  11378. }
  11379. else
  11380. ctx->type.SetDummy();
  11381. // Cleanup
  11382. for( asUINT n = 0; n < args.GetLength(); n++ )
  11383. if( args[n] )
  11384. {
  11385. asDELETE(args[n], asCExprContext);
  11386. }
  11387. for( asUINT n = 0; n < namedArgs.GetLength(); n++ )
  11388. if( namedArgs[n].ctx )
  11389. {
  11390. asDELETE(namedArgs[n].ctx, asCExprContext);
  11391. }
  11392. if( !isOK )
  11393. return -1;
  11394. }
  11395. return 0;
  11396. }
  11397. int asCCompiler::GetPrecedence(asCScriptNode *op)
  11398. {
  11399. // x ** y
  11400. // x * y, x / y, x % y
  11401. // x + y, x - y
  11402. // x <= y, x < y, x >= y, x > y
  11403. // x = =y, x != y, x xor y, x is y, x !is y
  11404. // x and y
  11405. // x or y
  11406. // The following are not used in this function,
  11407. // but should have lower precedence than the above
  11408. // x ? y : z
  11409. // x = y
  11410. // The expression term have the highest precedence
  11411. if( op->nodeType == snExprTerm )
  11412. return 1;
  11413. // Evaluate operators by token
  11414. int tokenType = op->tokenType;
  11415. if( tokenType == ttStarStar )
  11416. return 0;
  11417. if( tokenType == ttStar || tokenType == ttSlash || tokenType == ttPercent )
  11418. return -1;
  11419. if( tokenType == ttPlus || tokenType == ttMinus )
  11420. return -2;
  11421. if( tokenType == ttBitShiftLeft ||
  11422. tokenType == ttBitShiftRight ||
  11423. tokenType == ttBitShiftRightArith )
  11424. return -3;
  11425. if( tokenType == ttAmp )
  11426. return -4;
  11427. if( tokenType == ttBitXor )
  11428. return -5;
  11429. if( tokenType == ttBitOr )
  11430. return -6;
  11431. if( tokenType == ttLessThanOrEqual ||
  11432. tokenType == ttLessThan ||
  11433. tokenType == ttGreaterThanOrEqual ||
  11434. tokenType == ttGreaterThan )
  11435. return -7;
  11436. if( tokenType == ttEqual || tokenType == ttNotEqual || tokenType == ttXor || tokenType == ttIs || tokenType == ttNotIs )
  11437. return -8;
  11438. if( tokenType == ttAnd )
  11439. return -9;
  11440. if( tokenType == ttOr )
  11441. return -10;
  11442. // Unknown operator
  11443. asASSERT(false);
  11444. return 0;
  11445. }
  11446. asUINT asCCompiler::MatchArgument(asCArray<int> &funcs, asCArray<asSOverloadCandidate> &matches, const asCExprContext *argExpr, int paramNum, bool allowObjectConstruct)
  11447. {
  11448. matches.SetLength(0);
  11449. for( asUINT n = 0; n < funcs.GetLength(); n++ )
  11450. {
  11451. asCScriptFunction *desc = builder->GetFunctionDescription(funcs[n]);
  11452. // Does the function have arguments enough?
  11453. if( (int)desc->parameterTypes.GetLength() <= paramNum )
  11454. continue;
  11455. int cost = MatchArgument(desc, argExpr, paramNum, allowObjectConstruct);
  11456. if( cost != -1 )
  11457. matches.PushLast(asSOverloadCandidate(funcs[n], asUINT(cost)));
  11458. }
  11459. return (asUINT)matches.GetLength();
  11460. }
  11461. int asCCompiler::MatchArgument(asCScriptFunction *desc, const asCExprContext *argExpr, int paramNum, bool allowObjectConstruct)
  11462. {
  11463. // void expressions can match any out parameter, but nothing else
  11464. if( argExpr->IsVoidExpression() )
  11465. {
  11466. if( desc->inOutFlags[paramNum] == asTM_OUTREF )
  11467. return 0;
  11468. return -1;
  11469. }
  11470. // Anonymous init lists can only match parameters that can be initialized with a list
  11471. if (argExpr->IsAnonymousInitList())
  11472. {
  11473. if( (desc->parameterTypes[paramNum].IsReference() && (desc->inOutFlags[paramNum] & asTM_INREF) == 0) ||
  11474. desc->parameterTypes[paramNum].GetBehaviour() == 0 ||
  11475. desc->parameterTypes[paramNum].GetBehaviour()->listFactory == 0 )
  11476. {
  11477. return -1;
  11478. }
  11479. return 0;
  11480. }
  11481. // Can we make the match by implicit conversion?
  11482. asCExprContext ti(engine);
  11483. ti.type = argExpr->type;
  11484. ti.methodName = argExpr->methodName;
  11485. ti.enumValue = argExpr->enumValue;
  11486. ti.exprNode = argExpr->exprNode;
  11487. if( argExpr->type.dataType.IsPrimitive() )
  11488. ti.type.dataType.MakeReference(false);
  11489. // Don't allow the implicit conversion to make a copy in case the argument is expecting a reference to the true value
  11490. if (desc->parameterTypes[paramNum].IsReference() && desc->inOutFlags[paramNum] == asTM_INOUTREF)
  11491. allowObjectConstruct = false;
  11492. int cost = ImplicitConversion(&ti, desc->parameterTypes[paramNum], 0, asIC_IMPLICIT_CONV, false, allowObjectConstruct);
  11493. // If the function parameter is an inout-reference then it must not be possible to call the
  11494. // function with an incorrect argument type, even though the type can normally be converted.
  11495. if( desc->parameterTypes[paramNum].IsReference() &&
  11496. desc->inOutFlags[paramNum] == asTM_INOUTREF &&
  11497. desc->parameterTypes[paramNum].GetTokenType() != ttQuestion )
  11498. {
  11499. // Observe, that the below checks are only necessary for when unsafe references have been
  11500. // enabled by the application. Without this the &inout reference form wouldn't be allowed
  11501. // for these value types.
  11502. // Don't allow a primitive to be converted to a reference of another primitive type
  11503. if( desc->parameterTypes[paramNum].IsPrimitive() &&
  11504. desc->parameterTypes[paramNum].GetTokenType() != argExpr->type.dataType.GetTokenType() )
  11505. {
  11506. asASSERT( engine->ep.allowUnsafeReferences );
  11507. return -1;
  11508. }
  11509. // Don't allow an enum to be converted to a reference of another enum type
  11510. if( desc->parameterTypes[paramNum].IsEnumType() &&
  11511. desc->parameterTypes[paramNum].GetTypeInfo() != argExpr->type.dataType.GetTypeInfo() )
  11512. {
  11513. asASSERT( engine->ep.allowUnsafeReferences );
  11514. return -1;
  11515. }
  11516. // Don't allow a non-handle expression to be converted to a reference to a handle
  11517. if( desc->parameterTypes[paramNum].IsObjectHandle() &&
  11518. !argExpr->type.dataType.IsObjectHandle() )
  11519. {
  11520. asASSERT( engine->ep.allowUnsafeReferences );
  11521. return -1;
  11522. }
  11523. // Don't allow a value type to be converted
  11524. if( (desc->parameterTypes[paramNum].GetTypeInfo() && (desc->parameterTypes[paramNum].GetTypeInfo()->GetFlags() & asOBJ_VALUE)) &&
  11525. (desc->parameterTypes[paramNum].GetTypeInfo() != argExpr->type.dataType.GetTypeInfo()) )
  11526. {
  11527. asASSERT( engine->ep.allowUnsafeReferences );
  11528. return -1;
  11529. }
  11530. }
  11531. // How well does the argument match the function parameter?
  11532. if( desc->parameterTypes[paramNum].IsEqualExceptRef(ti.type.dataType) )
  11533. return cost;
  11534. // No match is available
  11535. return -1;
  11536. }
  11537. int asCCompiler::PrepareArgument2(asCExprContext *ctx, asCExprContext *arg, asCDataType *paramType, bool isFunction, int refType, bool isMakingCopy)
  11538. {
  11539. // Reference parameters whose value won't be used don't evaluate the expression
  11540. // Clean arguments (i.e. default value) will be passed in directly as there is nothing to protect
  11541. if( paramType->IsReference() && !(refType & asTM_INREF) && !arg->isCleanArg )
  11542. {
  11543. // Store the original bytecode so that it can be reused when processing the deferred output parameter
  11544. asCExprContext *orig = asNEW(asCExprContext)(engine);
  11545. if( orig == 0 )
  11546. {
  11547. // Out of memory
  11548. return -1;
  11549. }
  11550. MergeExprBytecodeAndType(orig, arg);
  11551. arg->origExpr = orig;
  11552. }
  11553. int r = PrepareArgument(paramType, arg, arg->exprNode, isFunction, refType, isMakingCopy);
  11554. if (r < 0)
  11555. return r;
  11556. // arg still holds the original expression for output parameters
  11557. ctx->bc.AddCode(&arg->bc);
  11558. return 0;
  11559. }
  11560. bool asCCompiler::CompileOverloadedDualOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, bool leftToRight, asCExprContext *ctx, bool isHandle, eTokenType token)
  11561. {
  11562. DetermineSingleFunc(lctx, node);
  11563. DetermineSingleFunc(rctx, node);
  11564. ctx->exprNode = node;
  11565. // What type of operator is it?
  11566. if( token == ttUnrecognizedToken )
  11567. token = node->tokenType;
  11568. if( token == ttUnrecognizedToken )
  11569. {
  11570. // This happens when the compiler is inferring an assignment
  11571. // operation from another action, for example in preparing a value
  11572. // as a function argument
  11573. token = ttAssignment;
  11574. }
  11575. // boolean operators are not overloadable
  11576. if( token == ttAnd ||
  11577. token == ttOr ||
  11578. token == ttXor )
  11579. return false;
  11580. // Dual operators can also be implemented as class methods
  11581. if( token == ttEqual ||
  11582. token == ttNotEqual )
  11583. {
  11584. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  11585. // Find the matching opEquals method
  11586. int r = CompileOverloadedDualOperator2(node, "opEquals", lctx, rctx, leftToRight, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  11587. if( r == 0 )
  11588. {
  11589. // Try again by switching the order of the operands
  11590. r = CompileOverloadedDualOperator2(node, "opEquals", rctx, lctx, !leftToRight, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  11591. }
  11592. if( r == 1 )
  11593. {
  11594. if( token == ttNotEqual )
  11595. ctx->bc.InstrSHORT(asBC_NOT, ctx->type.stackOffset);
  11596. // Success, don't continue
  11597. return true;
  11598. }
  11599. else if( r < 0 )
  11600. {
  11601. // Compiler error, don't continue
  11602. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  11603. return true;
  11604. }
  11605. }
  11606. if( token == ttEqual ||
  11607. token == ttNotEqual ||
  11608. token == ttLessThan ||
  11609. token == ttLessThanOrEqual ||
  11610. token == ttGreaterThan ||
  11611. token == ttGreaterThanOrEqual )
  11612. {
  11613. bool swappedOrder = false;
  11614. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  11615. // Find the matching opCmp method
  11616. int r = CompileOverloadedDualOperator2(node, "opCmp", lctx, rctx, leftToRight, ctx, true, asCDataType::CreatePrimitive(ttInt, false));
  11617. if( r == 0 )
  11618. {
  11619. // Try again by switching the order of the operands
  11620. swappedOrder = true;
  11621. r = CompileOverloadedDualOperator2(node, "opCmp", rctx, lctx, !leftToRight, ctx, true, asCDataType::CreatePrimitive(ttInt, false));
  11622. }
  11623. if( r == 1 )
  11624. {
  11625. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  11626. int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, false), true);
  11627. ctx->bc.InstrW_DW(asBC_CMPIi, ctx->type.stackOffset, 0);
  11628. if( token == ttEqual )
  11629. ctx->bc.Instr(asBC_TZ);
  11630. else if( token == ttNotEqual )
  11631. ctx->bc.Instr(asBC_TNZ);
  11632. else if( (token == ttLessThan && !swappedOrder) ||
  11633. (token == ttGreaterThan && swappedOrder) )
  11634. ctx->bc.Instr(asBC_TS);
  11635. else if( (token == ttLessThanOrEqual && !swappedOrder) ||
  11636. (token == ttGreaterThanOrEqual && swappedOrder) )
  11637. ctx->bc.Instr(asBC_TNP);
  11638. else if( (token == ttGreaterThan && !swappedOrder) ||
  11639. (token == ttLessThan && swappedOrder) )
  11640. ctx->bc.Instr(asBC_TP);
  11641. else if( (token == ttGreaterThanOrEqual && !swappedOrder) ||
  11642. (token == ttLessThanOrEqual && swappedOrder) )
  11643. ctx->bc.Instr(asBC_TNS);
  11644. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  11645. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, false), a, true);
  11646. // Success, don't continue
  11647. return true;
  11648. }
  11649. else if( r < 0 )
  11650. {
  11651. // Compiler error, don't continue
  11652. #if AS_SIZEOF_BOOL == 1
  11653. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  11654. #else
  11655. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  11656. #endif
  11657. return true;
  11658. }
  11659. }
  11660. // The rest of the operators are not commutative, and doesn't require specific return type
  11661. const char *op = 0, *op_r = 0;
  11662. switch( int(token) ) // convert to int to avoid warning in gnuc that not all values are tested
  11663. {
  11664. case ttPlus: op = "opAdd"; op_r = "opAdd_r"; break;
  11665. case ttMinus: op = "opSub"; op_r = "opSub_r"; break;
  11666. case ttStar: op = "opMul"; op_r = "opMul_r"; break;
  11667. case ttSlash: op = "opDiv"; op_r = "opDiv_r"; break;
  11668. case ttPercent: op = "opMod"; op_r = "opMod_r"; break;
  11669. case ttStarStar: op = "opPow"; op_r = "opPow_r"; break;
  11670. case ttBitOr: op = "opOr"; op_r = "opOr_r"; break;
  11671. case ttAmp: op = "opAnd"; op_r = "opAnd_r"; break;
  11672. case ttBitXor: op = "opXor"; op_r = "opXor_r"; break;
  11673. case ttBitShiftLeft: op = "opShl"; op_r = "opShl_r"; break;
  11674. case ttBitShiftRight: op = "opShr"; op_r = "opShr_r"; break;
  11675. case ttBitShiftRightArith: op = "opUShr"; op_r = "opUShr_r"; break;
  11676. }
  11677. // TODO: Might be interesting to support a concatenation operator, e.g. ~
  11678. if( op && op_r )
  11679. {
  11680. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  11681. // Find the matching operator method
  11682. int r = CompileOverloadedDualOperator2(node, op, lctx, rctx, leftToRight, ctx);
  11683. if( r == 0 )
  11684. {
  11685. // Try again by switching the order of the operands, and using the reversed operator
  11686. r = CompileOverloadedDualOperator2(node, op_r, rctx, lctx, !leftToRight, ctx);
  11687. }
  11688. if( r == 1 )
  11689. {
  11690. // Success, don't continue
  11691. return true;
  11692. }
  11693. else if( r < 0 )
  11694. {
  11695. // Compiler error, don't continue
  11696. ctx->type.SetDummy();
  11697. return true;
  11698. }
  11699. }
  11700. // Assignment operators
  11701. op = 0;
  11702. if( isHandle )
  11703. {
  11704. // Only asOBJ_ASHANDLE types can get here
  11705. asASSERT( lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) );
  11706. asASSERT( token == ttAssignment );
  11707. if( token == ttAssignment )
  11708. op = "opHndlAssign";
  11709. }
  11710. else
  11711. {
  11712. switch( int(token) ) // convert to int to avoid warning in gnuc that not all values are tested
  11713. {
  11714. case ttAssignment: op = "opAssign"; break;
  11715. case ttAddAssign: op = "opAddAssign"; break;
  11716. case ttSubAssign: op = "opSubAssign"; break;
  11717. case ttMulAssign: op = "opMulAssign"; break;
  11718. case ttDivAssign: op = "opDivAssign"; break;
  11719. case ttModAssign: op = "opModAssign"; break;
  11720. case ttPowAssign: op = "opPowAssign"; break;
  11721. case ttOrAssign: op = "opOrAssign"; break;
  11722. case ttAndAssign: op = "opAndAssign"; break;
  11723. case ttXorAssign: op = "opXorAssign"; break;
  11724. case ttShiftLeftAssign: op = "opShlAssign"; break;
  11725. case ttShiftRightLAssign: op = "opShrAssign"; break;
  11726. case ttShiftRightAAssign: op = "opUShrAssign"; break;
  11727. }
  11728. }
  11729. if( op )
  11730. {
  11731. if( builder->engine->ep.disallowValueAssignForRefType &&
  11732. lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !(lctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCOPED) )
  11733. {
  11734. if( token == ttAssignment )
  11735. Error(TXT_DISALLOW_ASSIGN_ON_REF_TYPE, node);
  11736. else
  11737. Error(TXT_DISALLOW_COMPOUND_ASSIGN_ON_REF_TYPE, node);
  11738. // Set a dummy output
  11739. ctx->type.Set(lctx->type.dataType);
  11740. return true;
  11741. }
  11742. // TODO: Shouldn't accept const lvalue with the assignment operators
  11743. // Find the matching operator method
  11744. int r = CompileOverloadedDualOperator2(node, op, lctx, rctx, false, ctx);
  11745. if( r == 1 )
  11746. {
  11747. // Success, don't continue
  11748. return true;
  11749. }
  11750. else if( r < 0 )
  11751. {
  11752. // Compiler error, don't continue
  11753. ctx->type.SetDummy();
  11754. return true;
  11755. }
  11756. }
  11757. // No suitable operator was found
  11758. return false;
  11759. }
  11760. // Returns negative on compile error
  11761. // zero on no matching operator
  11762. // one on matching operator
  11763. int asCCompiler::CompileOverloadedDualOperator2(asCScriptNode *node, const char *methodName, asCExprContext *lctx, asCExprContext *rctx, bool leftToRight, asCExprContext *ctx, bool specificReturn, const asCDataType &returnType)
  11764. {
  11765. // Find the matching method
  11766. if( lctx->type.dataType.IsObject() &&
  11767. (!lctx->type.isExplicitHandle ||
  11768. lctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) &&
  11769. !lctx->type.IsNullConstant() )
  11770. {
  11771. asUINT n;
  11772. // Is the left value a const?
  11773. bool isConst = lctx->type.dataType.IsObjectConst();
  11774. asCArray<int> funcs;
  11775. asCObjectType *ot = CastToObjectType(lctx->type.dataType.GetTypeInfo());
  11776. asASSERT(ot);
  11777. for( n = 0; ot && n < ot->methods.GetLength(); n++ )
  11778. {
  11779. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  11780. asASSERT( func );
  11781. if( func && func->name == methodName &&
  11782. (!specificReturn || func->returnType == returnType) &&
  11783. func->parameterTypes.GetLength() == 1 &&
  11784. (!isConst || func->IsReadOnly()) )
  11785. {
  11786. // Make sure the method is accessible by the module
  11787. if( builder->module->m_accessMask & func->accessMask )
  11788. {
  11789. funcs.PushLast(func->id);
  11790. }
  11791. }
  11792. }
  11793. // Which is the best matching function?
  11794. asCArray<asSOverloadCandidate> tempFuncs;
  11795. MatchArgument(funcs, tempFuncs, rctx, 0);
  11796. // Find the lowest cost operator(s)
  11797. asCArray<int> ops;
  11798. asUINT bestCost = asUINT(-1);
  11799. for( n = 0; n < tempFuncs.GetLength(); ++n )
  11800. {
  11801. asUINT cost = tempFuncs[n].cost;
  11802. if( cost < bestCost )
  11803. {
  11804. ops.SetLength(0);
  11805. bestCost = cost;
  11806. }
  11807. if( cost == bestCost )
  11808. ops.PushLast(tempFuncs[n].funcId);
  11809. }
  11810. // If the object is not const, then we need to prioritize non-const methods
  11811. if( !isConst )
  11812. FilterConst(ops);
  11813. // Did we find an operator?
  11814. if( ops.GetLength() == 1 )
  11815. {
  11816. // Reserve the variables used in the right expression so the new temporary
  11817. // variable allocated for the left operand isn't accidentally overwritten.
  11818. int l = int(reservedVariables.GetLength());
  11819. rctx->bc.GetVarsUsed(reservedVariables);
  11820. // Process the lctx expression as get accessor
  11821. if( ProcessPropertyGetAccessor(lctx, node) < 0 )
  11822. return -1;
  11823. reservedVariables.SetLength(l);
  11824. asCExprContext tmpCtx(engine);
  11825. if (leftToRight)
  11826. {
  11827. // Make sure lctx is in fact a variable. If it is a reference there is no
  11828. // guarantee that the reference will stay alive throughout the evaluation of rctx
  11829. if (!lctx->type.isVariable)
  11830. {
  11831. // Reserve the variables used in the right expression so the new temporary
  11832. // variable allocated for the left operand isn't accidentally overwritten.
  11833. l = int(reservedVariables.GetLength());
  11834. rctx->bc.GetVarsUsed(reservedVariables);
  11835. if (engine->ep.allowUnsafeReferences && lctx->type.dataType.IsObject() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_VALUE))
  11836. {
  11837. // If the application allows unsafe references, then it is not necessary to
  11838. // make a copy of the object, just store the reference as a local variable
  11839. // Allocate a temporary variable as reference to the type
  11840. asCDataType dt = lctx->type.dataType;
  11841. dt.MakeReference(true);
  11842. int offset = AllocateVariable(dt, true, false, true);
  11843. Dereference(lctx, true);
  11844. // Copy the pointer to the temporary variable
  11845. lctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  11846. if (lctx->type.dataType.IsFuncdef())
  11847. lctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  11848. else
  11849. lctx->bc.InstrPTR(asBC_REFCPY, lctx->type.dataType.GetTypeInfo());
  11850. lctx->type.SetVariable(dt, offset, true);
  11851. }
  11852. else
  11853. {
  11854. if (lctx->type.dataType.SupportHandles())
  11855. lctx->type.dataType.MakeHandle(true);
  11856. PrepareTemporaryVariable(node, lctx);
  11857. }
  11858. reservedVariables.SetLength(l);
  11859. }
  11860. // Move the bytecode for the left operand to a temporary context
  11861. // so we can later make sure this is computed first
  11862. tmpCtx.bc.AddCode(&lctx->bc);
  11863. tmpCtx.bc.Instr(asBC_PopPtr);
  11864. // Add bytecode to push the object pointer computed in the left operand on the stack as the this pointer
  11865. // This will be placed after rctx by MakeFunctionCall below
  11866. lctx->bc.InstrWORD(asBC_PSF, lctx->type.stackOffset);
  11867. // Implicitly dereference handle parameters sent by reference
  11868. sVariable *v = variables->GetVariableByOffset(lctx->type.stackOffset);
  11869. if (v && v->type.IsReference() && (!v->type.IsObject() || v->type.IsObjectHandle()))
  11870. lctx->bc.Instr(asBC_RDSPtr);
  11871. }
  11872. else
  11873. {
  11874. // Make sure the rvalue doesn't have deferred temporary variables that are also used in the lvalue,
  11875. // since that would cause the VM to overwrite the variable while executing the bytecode for the lvalue.
  11876. asCArray<int> usedVars;
  11877. lctx->bc.GetVarsUsed(usedVars);
  11878. asUINT oldReservedVars = reservedVariables.GetLength();
  11879. for (n = 0; n < rctx->deferredParams.GetLength(); n++)
  11880. {
  11881. if (rctx->deferredParams[n].argType.isTemporary &&
  11882. usedVars.Exists(rctx->deferredParams[n].argType.stackOffset))
  11883. {
  11884. if (reservedVariables.GetLength() == oldReservedVars)
  11885. reservedVariables.Concatenate(usedVars);
  11886. // Allocate a new variable for the deferred argument
  11887. int offset = AllocateVariableNotIn(rctx->deferredParams[n].argType.dataType, true, false, rctx);
  11888. int oldVar = rctx->deferredParams[n].argType.stackOffset;
  11889. rctx->deferredParams[n].argType.stackOffset = short(offset);
  11890. rctx->bc.ExchangeVar(oldVar, offset);
  11891. ReleaseTemporaryVariable(oldVar, 0);
  11892. }
  11893. }
  11894. reservedVariables.SetLength(oldReservedVars);
  11895. }
  11896. // Merge the bytecode so that it forms lvalue.methodName(rvalue)
  11897. asCArray<asCExprContext *> args;
  11898. args.PushLast(rctx);
  11899. MergeExprBytecode(ctx, lctx);
  11900. ctx->type = lctx->type;
  11901. if( MakeFunctionCall(ctx, ops[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node) < 0 )
  11902. return -1;
  11903. // Rearrange the bytecode so the left argument is computed first
  11904. if (leftToRight)
  11905. {
  11906. tmpCtx.bc.AddCode(&ctx->bc);
  11907. ctx->bc.AddCode(&tmpCtx.bc);
  11908. }
  11909. // Found matching operator
  11910. return 1;
  11911. }
  11912. else if( ops.GetLength() > 1 )
  11913. {
  11914. Error(TXT_MORE_THAN_ONE_MATCHING_OP, node);
  11915. PrintMatchingFuncs(ops, node);
  11916. ctx->type.SetDummy();
  11917. // Compiler error
  11918. return -1;
  11919. }
  11920. }
  11921. // No matching operator
  11922. return 0;
  11923. }
  11924. int asCCompiler::MakeFunctionCall(asCExprContext *ctx, int funcId, asCObjectType *objectType, asCArray<asCExprContext*> &args, asCScriptNode *node, bool useVariable, int stackOffset, int funcPtrVar)
  11925. {
  11926. if( objectType )
  11927. Dereference(ctx, true);
  11928. // Store the expression node for error reporting
  11929. if( ctx->exprNode == 0 )
  11930. ctx->exprNode = node;
  11931. asCByteCode objBC(engine);
  11932. objBC.AddCode(&ctx->bc);
  11933. int r = PrepareFunctionCall(funcId, &ctx->bc, args);
  11934. if (r < 0)
  11935. return r;
  11936. // Verify if any of the args variable offsets are used in the other code.
  11937. // If they are exchange the offset for a new one
  11938. asUINT n;
  11939. for( n = 0; n < args.GetLength(); n++ )
  11940. {
  11941. if( args[n]->type.isTemporary && objBC.IsVarUsed(args[n]->type.stackOffset) )
  11942. {
  11943. // Release the current temporary variable
  11944. ReleaseTemporaryVariable(args[n]->type, 0);
  11945. asCDataType dt = args[n]->type.dataType;
  11946. dt.MakeReference(false);
  11947. int l = int(reservedVariables.GetLength());
  11948. objBC.GetVarsUsed(reservedVariables);
  11949. ctx->bc.GetVarsUsed(reservedVariables);
  11950. int newOffset = AllocateVariable(dt, true, IsVariableOnHeap(args[n]->type.stackOffset));
  11951. reservedVariables.SetLength(l);
  11952. asASSERT( IsVariableOnHeap(args[n]->type.stackOffset) == IsVariableOnHeap(newOffset) );
  11953. ctx->bc.ExchangeVar(args[n]->type.stackOffset, newOffset);
  11954. args[n]->type.stackOffset = (short)newOffset;
  11955. args[n]->type.isTemporary = true;
  11956. args[n]->type.isVariable = true;
  11957. }
  11958. }
  11959. // If the function will return a value type on the stack, then we must allocate space
  11960. // for that here and push the address on the stack as a hidden argument to the function
  11961. asCScriptFunction *func = builder->GetFunctionDescription(funcId);
  11962. if( func->DoesReturnOnStack() )
  11963. {
  11964. asASSERT(!useVariable);
  11965. useVariable = true;
  11966. stackOffset = AllocateVariable(func->returnType, true);
  11967. ctx->bc.InstrSHORT(asBC_PSF, short(stackOffset));
  11968. }
  11969. ctx->bc.AddCode(&objBC);
  11970. MoveArgsToStack(funcId, &ctx->bc, args, objectType ? true : false);
  11971. PerformFunctionCall(funcId, ctx, false, &args, 0, useVariable, stackOffset, funcPtrVar);
  11972. return 0;
  11973. }
  11974. int asCCompiler::CompileOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType op, bool leftToRight)
  11975. {
  11976. // Don't allow any operators on expressions that take address of class method, but allow it on global functions
  11977. if( (lctx->IsClassMethod()) || (rctx->IsClassMethod()) )
  11978. {
  11979. Error(TXT_INVALID_OP_ON_METHOD, node);
  11980. return -1;
  11981. }
  11982. // Don't allow any operators on void expressions
  11983. if( lctx->IsVoidExpression() || rctx->IsVoidExpression() )
  11984. {
  11985. Error(TXT_VOID_CANT_BE_OPERAND, node);
  11986. return -1;
  11987. }
  11988. if( op == ttUnrecognizedToken )
  11989. op = node->tokenType;
  11990. IsVariableInitialized(&lctx->type, node);
  11991. IsVariableInitialized(&rctx->type, node);
  11992. if( lctx->type.isExplicitHandle || rctx->type.isExplicitHandle ||
  11993. lctx->type.IsNullConstant() || rctx->type.IsNullConstant() ||
  11994. op == ttIs || op == ttNotIs )
  11995. {
  11996. CompileOperatorOnHandles(node, lctx, rctx, ctx, op);
  11997. return 0;
  11998. }
  11999. else
  12000. {
  12001. // Compile an overloaded operator for the two operands
  12002. if( CompileOverloadedDualOperator(node, lctx, rctx, leftToRight, ctx, false, op) )
  12003. return 0;
  12004. // If both operands are objects, then we shouldn't continue
  12005. if( lctx->type.dataType.IsObject() && rctx->type.dataType.IsObject() )
  12006. {
  12007. asCString str;
  12008. 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());
  12009. Error(str, node);
  12010. ctx->type.SetDummy();
  12011. return -1;
  12012. }
  12013. // Process the property get accessors (if any)
  12014. if( ProcessPropertyGetAccessor(lctx, node) < 0 )
  12015. return -1;
  12016. if( ProcessPropertyGetAccessor(rctx, node) < 0 )
  12017. return -1;
  12018. // Make sure we have two variables or constants
  12019. if( lctx->type.dataType.IsReference() ) ConvertToVariableNotIn(lctx, rctx);
  12020. if( rctx->type.dataType.IsReference() ) ConvertToVariableNotIn(rctx, lctx);
  12021. // Make sure lctx doesn't end up with a variable used in rctx
  12022. if( lctx->type.isTemporary && rctx->bc.IsVarUsed(lctx->type.stackOffset) )
  12023. {
  12024. int offset = AllocateVariableNotIn(lctx->type.dataType, true, false, rctx);
  12025. rctx->bc.ExchangeVar(lctx->type.stackOffset, offset);
  12026. ReleaseTemporaryVariable(offset, 0);
  12027. }
  12028. // Math operators
  12029. // + - * / % ** += -= *= /= %= **=
  12030. if( op == ttPlus || op == ttAddAssign ||
  12031. op == ttMinus || op == ttSubAssign ||
  12032. op == ttStar || op == ttMulAssign ||
  12033. op == ttSlash || op == ttDivAssign ||
  12034. op == ttPercent || op == ttModAssign ||
  12035. op == ttStarStar || op == ttPowAssign )
  12036. {
  12037. CompileMathOperator(node, lctx, rctx, ctx, op);
  12038. return 0;
  12039. }
  12040. // Bitwise operators
  12041. // << >> >>> & | ^ <<= >>= >>>= &= |= ^=
  12042. if( op == ttAmp || op == ttAndAssign ||
  12043. op == ttBitOr || op == ttOrAssign ||
  12044. op == ttBitXor || op == ttXorAssign ||
  12045. op == ttBitShiftLeft || op == ttShiftLeftAssign ||
  12046. op == ttBitShiftRight || op == ttShiftRightLAssign ||
  12047. op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  12048. {
  12049. CompileBitwiseOperator(node, lctx, rctx, ctx, op);
  12050. return 0;
  12051. }
  12052. // Comparison operators
  12053. // == != < > <= >=
  12054. if( op == ttEqual || op == ttNotEqual ||
  12055. op == ttLessThan || op == ttLessThanOrEqual ||
  12056. op == ttGreaterThan || op == ttGreaterThanOrEqual )
  12057. {
  12058. CompileComparisonOperator(node, lctx, rctx, ctx, op);
  12059. return 0;
  12060. }
  12061. // Boolean operators
  12062. // && || ^^
  12063. if( op == ttAnd || op == ttOr || op == ttXor )
  12064. {
  12065. CompileBooleanOperator(node, lctx, rctx, ctx, op);
  12066. return 0;
  12067. }
  12068. }
  12069. asASSERT(false);
  12070. return -1;
  12071. }
  12072. void asCCompiler::ConvertToTempVariableNotIn(asCExprContext *ctx, asCExprContext *exclude)
  12073. {
  12074. int l = int(reservedVariables.GetLength());
  12075. if( exclude ) exclude->bc.GetVarsUsed(reservedVariables);
  12076. ConvertToTempVariable(ctx);
  12077. reservedVariables.SetLength(l);
  12078. }
  12079. void asCCompiler::ConvertToTempVariable(asCExprContext *ctx)
  12080. {
  12081. // This is only used for primitive types and null handles
  12082. asASSERT( ctx->type.dataType.IsPrimitive() || ctx->type.dataType.IsNullHandle() );
  12083. ConvertToVariable(ctx);
  12084. if( !ctx->type.isTemporary )
  12085. {
  12086. if( ctx->type.dataType.IsPrimitive() )
  12087. {
  12088. // Copy the variable to a temporary variable
  12089. int offset = AllocateVariable(ctx->type.dataType, true);
  12090. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  12091. ctx->bc.InstrW_W(asBC_CpyVtoV4, offset, ctx->type.stackOffset);
  12092. else
  12093. ctx->bc.InstrW_W(asBC_CpyVtoV8, offset, ctx->type.stackOffset);
  12094. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  12095. }
  12096. else
  12097. {
  12098. // We should never get here
  12099. asASSERT(false);
  12100. }
  12101. }
  12102. }
  12103. void asCCompiler::ConvertToVariable(asCExprContext *ctx)
  12104. {
  12105. // We should never get here while the context is still an unprocessed property accessor
  12106. asASSERT(ctx->property_get == 0 && ctx->property_set == 0);
  12107. int offset;
  12108. if( !ctx->type.isVariable &&
  12109. (ctx->type.dataType.IsObjectHandle() ||
  12110. (ctx->type.dataType.IsObject() && ctx->type.dataType.SupportHandles())) )
  12111. {
  12112. offset = AllocateVariable(ctx->type.dataType, true);
  12113. if( ctx->type.IsNullConstant() )
  12114. {
  12115. if( ctx->bc.GetLastInstr() == asBC_PshNull )
  12116. ctx->bc.Instr(asBC_PopPtr); // Pop the null constant pushed onto the stack
  12117. ctx->bc.InstrSHORT(asBC_ClrVPtr, (short)offset);
  12118. }
  12119. else
  12120. {
  12121. Dereference(ctx, true);
  12122. // Copy the object handle to a variable
  12123. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  12124. if( ctx->type.dataType.IsFuncdef() )
  12125. ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  12126. else
  12127. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo());
  12128. ctx->bc.Instr(asBC_PopPtr);
  12129. }
  12130. // As this is an object the reference must be placed on the stack
  12131. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  12132. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  12133. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  12134. ctx->type.dataType.MakeHandle(true);
  12135. ctx->type.dataType.MakeReference(true);
  12136. }
  12137. else if( (!ctx->type.isVariable || ctx->type.dataType.IsReference()) &&
  12138. ctx->type.dataType.IsPrimitive() )
  12139. {
  12140. if( ctx->type.isConstant )
  12141. {
  12142. offset = AllocateVariable(ctx->type.dataType, true);
  12143. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  12144. ctx->bc.InstrSHORT_B(asBC_SetV1, (short)offset, ctx->type.GetConstantB());
  12145. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  12146. ctx->bc.InstrSHORT_W(asBC_SetV2, (short)offset, ctx->type.GetConstantW());
  12147. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 )
  12148. ctx->bc.InstrSHORT_DW(asBC_SetV4, (short)offset, ctx->type.GetConstantDW());
  12149. else
  12150. ctx->bc.InstrSHORT_QW(asBC_SetV8, (short)offset, ctx->type.GetConstantQW());
  12151. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  12152. return;
  12153. }
  12154. else
  12155. {
  12156. asASSERT(ctx->type.dataType.IsPrimitive());
  12157. asASSERT(ctx->type.dataType.IsReference());
  12158. ctx->type.dataType.MakeReference(false);
  12159. offset = AllocateVariable(ctx->type.dataType, true);
  12160. // Read the value from the address in the register directly into the variable
  12161. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  12162. ctx->bc.InstrSHORT(asBC_RDR1, (short)offset);
  12163. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  12164. ctx->bc.InstrSHORT(asBC_RDR2, (short)offset);
  12165. else if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  12166. ctx->bc.InstrSHORT(asBC_RDR4, (short)offset);
  12167. else
  12168. ctx->bc.InstrSHORT(asBC_RDR8, (short)offset);
  12169. }
  12170. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  12171. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  12172. }
  12173. }
  12174. void asCCompiler::ConvertToVariableNotIn(asCExprContext *ctx, asCExprContext *exclude)
  12175. {
  12176. int l = int(reservedVariables.GetLength());
  12177. if( exclude ) exclude->bc.GetVarsUsed(reservedVariables);
  12178. ConvertToVariable(ctx);
  12179. reservedVariables.SetLength(l);
  12180. }
  12181. void asCCompiler::ImplicitConvObjectToBestMathType(asCExprContext *ctx, asCScriptNode *node)
  12182. {
  12183. asCArray<int> funcs;
  12184. asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  12185. if( ot )
  12186. {
  12187. for( unsigned int n = 0; n < ot->methods.GetLength(); n++ )
  12188. {
  12189. // Consider only implicit casts
  12190. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  12191. if( func->name == "opImplConv" &&
  12192. func->returnType.IsPrimitive() &&
  12193. func->parameterTypes.GetLength() == 0 )
  12194. funcs.PushLast(ot->methods[n]);
  12195. }
  12196. // Use the one with the highest precision
  12197. const eTokenType match[10] = {ttDouble, ttFloat, ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8};
  12198. while( funcs.GetLength() > 1 )
  12199. {
  12200. eTokenType returnType = builder->GetFunctionDescription(funcs[0])->returnType.GetTokenType();
  12201. int value1 = 11, value2 = 11;
  12202. for( asUINT i = 0; i < 10; i++ )
  12203. {
  12204. if( returnType == match[i] )
  12205. {
  12206. value1 = i;
  12207. break;
  12208. }
  12209. }
  12210. for( asUINT n = 1; n < funcs.GetLength(); n++ )
  12211. {
  12212. returnType = builder->GetFunctionDescription(funcs[n])->returnType.GetTokenType();
  12213. for( asUINT i = 0; i < 10; i++ )
  12214. {
  12215. if( returnType == match[i] )
  12216. {
  12217. value2 = i;
  12218. break;
  12219. }
  12220. }
  12221. if( value2 >= value1 )
  12222. {
  12223. // Remove this and continue searching
  12224. funcs.RemoveIndexUnordered(n--);
  12225. }
  12226. else
  12227. {
  12228. // Remove the first, and start over
  12229. funcs.RemoveIndexUnordered(0);
  12230. break;
  12231. }
  12232. }
  12233. }
  12234. // Do the conversion
  12235. if( funcs.GetLength() )
  12236. ImplicitConvObjectToPrimitive(ctx, builder->GetFunctionDescription(funcs[0])->returnType, node, asIC_IMPLICIT_CONV);
  12237. }
  12238. }
  12239. void asCCompiler::CompileMathOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType op)
  12240. {
  12241. // TODO: If a constant is only using 32bits, then a 32bit operation is preferred
  12242. // TODO: clean up: This initial part is identical to CompileComparisonOperator. Make a common function out of it
  12243. // If either operand is a non-primitive then use the primitive type
  12244. if( !lctx->type.dataType.IsPrimitive() )
  12245. {
  12246. int l = int(reservedVariables.GetLength());
  12247. rctx->bc.GetVarsUsed(reservedVariables);
  12248. ImplicitConvObjectToBestMathType(lctx, node);
  12249. reservedVariables.SetLength(l);
  12250. }
  12251. if( !rctx->type.dataType.IsPrimitive() )
  12252. {
  12253. int l = int(reservedVariables.GetLength());
  12254. lctx->bc.GetVarsUsed(reservedVariables);
  12255. ImplicitConvObjectToBestMathType(rctx, node);
  12256. reservedVariables.SetLength(l);
  12257. }
  12258. // Both types must now be primitives. Implicitly convert them so they match
  12259. asCDataType to;
  12260. if( lctx->type.dataType.IsDoubleType() || rctx->type.dataType.IsDoubleType() )
  12261. to.SetTokenType(ttDouble);
  12262. else if( lctx->type.dataType.IsFloatType() || rctx->type.dataType.IsFloatType() )
  12263. to.SetTokenType(ttFloat);
  12264. else if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 || rctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  12265. {
  12266. // Convert to int64 if both are signed or if one is non-constant and signed
  12267. if( (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) ||
  12268. (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) )
  12269. to.SetTokenType(ttInt64);
  12270. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  12271. to.SetTokenType(ttUInt64);
  12272. else
  12273. to.SetTokenType(ttInt64);
  12274. }
  12275. else
  12276. {
  12277. // Convert to int32 if both are signed or if one is non-constant and signed
  12278. if( (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) ||
  12279. (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) )
  12280. to.SetTokenType(ttInt);
  12281. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  12282. to.SetTokenType(ttUInt);
  12283. else
  12284. to.SetTokenType(ttInt);
  12285. }
  12286. // If doing an operation with double constant and float variable, the constant should be converted to float
  12287. if( (lctx->type.isConstant && lctx->type.dataType.IsDoubleType() && !rctx->type.isConstant && rctx->type.dataType.IsFloatType()) ||
  12288. (rctx->type.isConstant && rctx->type.dataType.IsDoubleType() && !lctx->type.isConstant && lctx->type.dataType.IsFloatType()) )
  12289. to.SetTokenType(ttFloat);
  12290. if( op == ttUnrecognizedToken )
  12291. op = node->tokenType;
  12292. // If integer division is disabled, convert to floating-point
  12293. if( engine->ep.disableIntegerDivision &&
  12294. (op == ttSlash || op == ttDivAssign) &&
  12295. (to.IsIntegerType() || to.IsUnsignedType()) )
  12296. {
  12297. // Use double to avoid losing precision when dividing with 32bit ints
  12298. // For 64bit ints there is unfortunately no greater type so with those
  12299. // there is still a risk of loosing precision
  12300. to.SetTokenType(ttDouble);
  12301. }
  12302. // Do the actual conversion
  12303. int l = int(reservedVariables.GetLength());
  12304. rctx->bc.GetVarsUsed(reservedVariables);
  12305. lctx->bc.GetVarsUsed(reservedVariables);
  12306. if( lctx->type.dataType.IsReference() )
  12307. ConvertToVariable(lctx);
  12308. if( rctx->type.dataType.IsReference() )
  12309. ConvertToVariable(rctx);
  12310. if( to.IsPrimitive() )
  12311. {
  12312. // ttStarStar allows an integer, right-hand operand and a double
  12313. // left-hand operand.
  12314. if( (op == ttStarStar || op == ttPowAssign) &&
  12315. lctx->type.dataType.IsDoubleType() &&
  12316. (rctx->type.dataType.IsIntegerType() ||
  12317. rctx->type.dataType.IsUnsignedType()) )
  12318. {
  12319. to.SetTokenType(ttInt);
  12320. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true);
  12321. to.SetTokenType(ttDouble);
  12322. }
  12323. else
  12324. {
  12325. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true);
  12326. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true);
  12327. }
  12328. }
  12329. reservedVariables.SetLength(l);
  12330. // Verify that the conversion was successful
  12331. if( !lctx->type.dataType.IsIntegerType() &&
  12332. !lctx->type.dataType.IsUnsignedType() &&
  12333. !lctx->type.dataType.IsFloatType() &&
  12334. !lctx->type.dataType.IsDoubleType() )
  12335. {
  12336. asCString str;
  12337. str.Format(TXT_NO_CONVERSION_s_TO_MATH_TYPE, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  12338. Error(str, node);
  12339. ctx->type.SetDummy();
  12340. return;
  12341. }
  12342. if( !rctx->type.dataType.IsIntegerType() &&
  12343. !rctx->type.dataType.IsUnsignedType() &&
  12344. !rctx->type.dataType.IsFloatType() &&
  12345. !rctx->type.dataType.IsDoubleType() )
  12346. {
  12347. asCString str;
  12348. str.Format(TXT_NO_CONVERSION_s_TO_MATH_TYPE, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  12349. Error(str, node);
  12350. ctx->type.SetDummy();
  12351. return;
  12352. }
  12353. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  12354. // Verify if we are dividing with a constant zero
  12355. if( rctx->type.isConstant &&
  12356. (op == ttSlash || op == ttDivAssign ||
  12357. op == ttPercent || op == ttModAssign) &&
  12358. ((rctx->type.dataType.GetSizeInMemoryBytes() == 4 && rctx->type.GetConstantDW() == 0) ||
  12359. (rctx->type.dataType.GetSizeInMemoryBytes() == 8 && rctx->type.GetConstantQW() == 0) ||
  12360. (rctx->type.dataType.GetSizeInMemoryBytes() == 1 && rctx->type.GetConstantB() == 0) ||
  12361. (rctx->type.dataType.GetSizeInMemoryBytes() == 2 && rctx->type.GetConstantW() == 0)) )
  12362. {
  12363. Error(TXT_DIVIDE_BY_ZERO, node);
  12364. }
  12365. if( !isConstant )
  12366. {
  12367. ConvertToVariableNotIn(lctx, rctx);
  12368. ConvertToVariableNotIn(rctx, lctx);
  12369. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  12370. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  12371. if( op == ttAddAssign || op == ttSubAssign ||
  12372. op == ttMulAssign || op == ttDivAssign ||
  12373. op == ttModAssign || op == ttPowAssign )
  12374. {
  12375. // Merge the operands in the different order so that they are evaluated correctly
  12376. MergeExprBytecode(ctx, rctx);
  12377. MergeExprBytecode(ctx, lctx);
  12378. // We must not process the deferred parameters yet, as
  12379. // it may overwrite the lvalue kept in the register
  12380. }
  12381. else
  12382. {
  12383. MergeExprBytecode(ctx, lctx);
  12384. MergeExprBytecode(ctx, rctx);
  12385. ProcessDeferredParams(ctx);
  12386. }
  12387. asEBCInstr instruction = asBC_ADDi;
  12388. if( lctx->type.dataType.IsIntegerType() ||
  12389. lctx->type.dataType.IsUnsignedType() )
  12390. {
  12391. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  12392. {
  12393. if( op == ttPlus || op == ttAddAssign )
  12394. instruction = asBC_ADDi;
  12395. else if( op == ttMinus || op == ttSubAssign )
  12396. instruction = asBC_SUBi;
  12397. else if( op == ttStar || op == ttMulAssign )
  12398. instruction = asBC_MULi;
  12399. else if( op == ttSlash || op == ttDivAssign )
  12400. {
  12401. if( lctx->type.dataType.IsIntegerType() )
  12402. instruction = asBC_DIVi;
  12403. else
  12404. instruction = asBC_DIVu;
  12405. }
  12406. else if( op == ttPercent || op == ttModAssign )
  12407. {
  12408. if( lctx->type.dataType.IsIntegerType() )
  12409. instruction = asBC_MODi;
  12410. else
  12411. instruction = asBC_MODu;
  12412. }
  12413. else if( op == ttStarStar || op == ttPowAssign )
  12414. {
  12415. if( lctx->type.dataType.IsIntegerType() )
  12416. instruction = asBC_POWi;
  12417. else
  12418. instruction = asBC_POWu;
  12419. }
  12420. }
  12421. else
  12422. {
  12423. if( op == ttPlus || op == ttAddAssign )
  12424. instruction = asBC_ADDi64;
  12425. else if( op == ttMinus || op == ttSubAssign )
  12426. instruction = asBC_SUBi64;
  12427. else if( op == ttStar || op == ttMulAssign )
  12428. instruction = asBC_MULi64;
  12429. else if( op == ttSlash || op == ttDivAssign )
  12430. {
  12431. if( lctx->type.dataType.IsIntegerType() )
  12432. instruction = asBC_DIVi64;
  12433. else
  12434. instruction = asBC_DIVu64;
  12435. }
  12436. else if( op == ttPercent || op == ttModAssign )
  12437. {
  12438. if( lctx->type.dataType.IsIntegerType() )
  12439. instruction = asBC_MODi64;
  12440. else
  12441. instruction = asBC_MODu64;
  12442. }
  12443. else if( op == ttStarStar || op == ttPowAssign )
  12444. {
  12445. if( lctx->type.dataType.IsIntegerType() )
  12446. instruction = asBC_POWi64;
  12447. else
  12448. instruction = asBC_POWu64;
  12449. }
  12450. }
  12451. }
  12452. else if( lctx->type.dataType.IsFloatType() )
  12453. {
  12454. if( op == ttPlus || op == ttAddAssign )
  12455. instruction = asBC_ADDf;
  12456. else if( op == ttMinus || op == ttSubAssign )
  12457. instruction = asBC_SUBf;
  12458. else if( op == ttStar || op == ttMulAssign )
  12459. instruction = asBC_MULf;
  12460. else if( op == ttSlash || op == ttDivAssign )
  12461. instruction = asBC_DIVf;
  12462. else if( op == ttPercent || op == ttModAssign )
  12463. instruction = asBC_MODf;
  12464. else if( op == ttStarStar || op == ttPowAssign )
  12465. instruction = asBC_POWf;
  12466. }
  12467. else if( lctx->type.dataType.IsDoubleType() )
  12468. {
  12469. if( rctx->type.dataType.IsIntegerType() )
  12470. {
  12471. asASSERT(rctx->type.dataType.GetSizeInMemoryDWords() == 1);
  12472. if( op == ttStarStar || op == ttPowAssign )
  12473. instruction = asBC_POWdi;
  12474. else
  12475. asASSERT(false); // Should not be possible
  12476. }
  12477. else
  12478. {
  12479. if( op == ttPlus || op == ttAddAssign )
  12480. instruction = asBC_ADDd;
  12481. else if( op == ttMinus || op == ttSubAssign )
  12482. instruction = asBC_SUBd;
  12483. else if( op == ttStar || op == ttMulAssign )
  12484. instruction = asBC_MULd;
  12485. else if( op == ttSlash || op == ttDivAssign )
  12486. instruction = asBC_DIVd;
  12487. else if( op == ttPercent || op == ttModAssign )
  12488. instruction = asBC_MODd;
  12489. else if( op == ttStarStar || op == ttPowAssign )
  12490. instruction = asBC_POWd;
  12491. }
  12492. }
  12493. else
  12494. {
  12495. // Shouldn't be possible
  12496. asASSERT(false);
  12497. }
  12498. // Do the operation
  12499. int a = AllocateVariable(lctx->type.dataType, true);
  12500. int b = lctx->type.stackOffset;
  12501. int c = rctx->type.stackOffset;
  12502. ctx->bc.InstrW_W_W(instruction, a, b, c);
  12503. ctx->type.SetVariable(lctx->type.dataType, a, true);
  12504. }
  12505. else
  12506. {
  12507. // Both values are constants
  12508. if( lctx->type.dataType.IsIntegerType() ||
  12509. lctx->type.dataType.IsUnsignedType() )
  12510. {
  12511. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  12512. {
  12513. int v = 0;
  12514. if( op == ttPlus )
  12515. v = int(lctx->type.GetConstantDW()) + int(rctx->type.GetConstantDW());
  12516. else if( op == ttMinus )
  12517. v = int(lctx->type.GetConstantDW()) - int(rctx->type.GetConstantDW());
  12518. else if( op == ttStar )
  12519. v = int(lctx->type.GetConstantDW()) * int(rctx->type.GetConstantDW());
  12520. else if( op == ttSlash )
  12521. {
  12522. // TODO: Should probably report an error, rather than silently convert the value to 0
  12523. if( rctx->type.GetConstantDW() == 0 || (int(rctx->type.GetConstantDW()) == -1 && lctx->type.GetConstantDW() == 0x80000000) )
  12524. v = 0;
  12525. else
  12526. if( lctx->type.dataType.IsIntegerType() )
  12527. v = int(lctx->type.GetConstantDW()) / int(rctx->type.GetConstantDW());
  12528. else
  12529. v = lctx->type.GetConstantDW() / rctx->type.GetConstantDW();
  12530. }
  12531. else if( op == ttPercent )
  12532. {
  12533. // TODO: Should probably report an error, rather than silently convert the value to 0
  12534. if( rctx->type.GetConstantDW() == 0 || (int(rctx->type.GetConstantDW()) == -1 && lctx->type.GetConstantDW() == 0x80000000) )
  12535. v = 0;
  12536. else
  12537. if( lctx->type.dataType.IsIntegerType() )
  12538. v = int(lctx->type.GetConstantDW()) % int(rctx->type.GetConstantDW());
  12539. else
  12540. v = lctx->type.GetConstantDW() % rctx->type.GetConstantDW();
  12541. }
  12542. else if( op == ttStarStar )
  12543. {
  12544. bool isOverflow;
  12545. if( lctx->type.dataType.IsIntegerType() )
  12546. v = as_powi(int(lctx->type.GetConstantDW()), int(rctx->type.GetConstantDW()), isOverflow);
  12547. else
  12548. v = as_powu(lctx->type.GetConstantDW(), rctx->type.GetConstantDW(), isOverflow);
  12549. if( isOverflow )
  12550. Error(TXT_POW_OVERFLOW, node);
  12551. }
  12552. ctx->type.SetConstantDW(lctx->type.dataType, v);
  12553. // If the right value is greater than the left value in a minus operation, then we need to convert the type to int
  12554. if( lctx->type.dataType.GetTokenType() == ttUInt && op == ttMinus && lctx->type.GetConstantDW() < rctx->type.GetConstantDW())
  12555. ctx->type.dataType.SetTokenType(ttInt);
  12556. }
  12557. else
  12558. {
  12559. asQWORD v = 0;
  12560. if( op == ttPlus )
  12561. v = asINT64(lctx->type.GetConstantQW()) + asINT64(rctx->type.GetConstantQW());
  12562. else if( op == ttMinus )
  12563. v = asINT64(lctx->type.GetConstantQW()) - asINT64(rctx->type.GetConstantQW());
  12564. else if( op == ttStar )
  12565. v = asINT64(lctx->type.GetConstantQW()) * asINT64(rctx->type.GetConstantQW());
  12566. else if( op == ttSlash )
  12567. {
  12568. // TODO: Should probably report an error, rather than silently convert the value to 0
  12569. if( rctx->type.GetConstantQW() == 0 || (rctx->type.GetConstantQW() == asQWORD(-1) && lctx->type.GetConstantQW() == (asQWORD(1)<<63)) )
  12570. v = 0;
  12571. else
  12572. if( lctx->type.dataType.IsIntegerType() )
  12573. v = asINT64(lctx->type.GetConstantQW()) / asINT64(rctx->type.GetConstantQW());
  12574. else
  12575. v = lctx->type.GetConstantQW() / rctx->type.GetConstantQW();
  12576. }
  12577. else if( op == ttPercent )
  12578. {
  12579. // TODO: Should probably report an error, rather than silently convert the value to 0
  12580. if( rctx->type.GetConstantQW() == 0 || (rctx->type.GetConstantQW() == asQWORD(-1) && lctx->type.GetConstantQW() == (asQWORD(1)<<63)) )
  12581. v = 0;
  12582. else
  12583. if( lctx->type.dataType.IsIntegerType() )
  12584. v = asINT64(lctx->type.GetConstantQW()) % asINT64(rctx->type.GetConstantQW());
  12585. else
  12586. v = lctx->type.GetConstantQW() % rctx->type.GetConstantQW();
  12587. }
  12588. else if( op == ttStarStar )
  12589. {
  12590. bool isOverflow;
  12591. if( lctx->type.dataType.IsIntegerType() )
  12592. v = as_powi64(asINT64(lctx->type.GetConstantQW()), asINT64(rctx->type.GetConstantQW()), isOverflow);
  12593. else
  12594. v = as_powu64(lctx->type.GetConstantQW(), rctx->type.GetConstantQW(), isOverflow);
  12595. if( isOverflow )
  12596. Error(TXT_POW_OVERFLOW, node);
  12597. }
  12598. ctx->type.SetConstantQW(lctx->type.dataType, v);
  12599. // If the right value is greater than the left value in a minus operation, then we need to convert the type to int
  12600. if( lctx->type.dataType.GetTokenType() == ttUInt64 && op == ttMinus && lctx->type.GetConstantQW() < rctx->type.GetConstantQW())
  12601. ctx->type.dataType.SetTokenType(ttInt64);
  12602. }
  12603. }
  12604. else if( lctx->type.dataType.IsFloatType() )
  12605. {
  12606. float v = 0.0f;
  12607. if( op == ttPlus )
  12608. v = lctx->type.GetConstantF() + rctx->type.GetConstantF();
  12609. else if( op == ttMinus )
  12610. v = lctx->type.GetConstantF() - rctx->type.GetConstantF();
  12611. else if( op == ttStar )
  12612. v = lctx->type.GetConstantF() * rctx->type.GetConstantF();
  12613. else if( op == ttSlash )
  12614. {
  12615. if( rctx->type.GetConstantF() == 0 )
  12616. v = 0;
  12617. else
  12618. v = lctx->type.GetConstantF() / rctx->type.GetConstantF();
  12619. }
  12620. else if( op == ttPercent )
  12621. {
  12622. if( rctx->type.GetConstantF() == 0 )
  12623. v = 0;
  12624. else
  12625. v = fmodf(lctx->type.GetConstantF(), rctx->type.GetConstantF());
  12626. }
  12627. else if( op == ttStarStar )
  12628. {
  12629. v = powf(lctx->type.GetConstantF(), rctx->type.GetConstantF());
  12630. if( v == HUGE_VAL )
  12631. Error(TXT_POW_OVERFLOW, node);
  12632. }
  12633. ctx->type.SetConstantF(lctx->type.dataType, v);
  12634. }
  12635. else if( lctx->type.dataType.IsDoubleType() )
  12636. {
  12637. double v = 0.0;
  12638. if( rctx->type.dataType.IsIntegerType() )
  12639. {
  12640. asASSERT(rctx->type.dataType.GetSizeInMemoryDWords() == 1);
  12641. if( op == ttStarStar || op == ttPowAssign )
  12642. {
  12643. v = pow(lctx->type.GetConstantD(), int(rctx->type.GetConstantDW()));
  12644. if( v == HUGE_VAL )
  12645. Error(TXT_POW_OVERFLOW, node);
  12646. }
  12647. else
  12648. asASSERT(false); // Should not be possible
  12649. }
  12650. else
  12651. {
  12652. if( op == ttPlus )
  12653. v = lctx->type.GetConstantD() + rctx->type.GetConstantD();
  12654. else if( op == ttMinus )
  12655. v = lctx->type.GetConstantD() - rctx->type.GetConstantD();
  12656. else if( op == ttStar )
  12657. v = lctx->type.GetConstantD() * rctx->type.GetConstantD();
  12658. else if( op == ttSlash )
  12659. {
  12660. if( rctx->type.GetConstantD() == 0 )
  12661. v = 0;
  12662. else
  12663. v = lctx->type.GetConstantD() / rctx->type.GetConstantD();
  12664. }
  12665. else if( op == ttPercent )
  12666. {
  12667. if( rctx->type.GetConstantD() == 0 )
  12668. v = 0;
  12669. else
  12670. v = fmod(lctx->type.GetConstantD(), rctx->type.GetConstantD());
  12671. }
  12672. else if( op == ttStarStar )
  12673. {
  12674. v = pow(lctx->type.GetConstantD(), rctx->type.GetConstantD());
  12675. if( v == HUGE_VAL )
  12676. Error(TXT_POW_OVERFLOW, node);
  12677. }
  12678. }
  12679. ctx->type.SetConstantD(lctx->type.dataType, v);
  12680. }
  12681. else
  12682. {
  12683. // Shouldn't be possible
  12684. asASSERT(false);
  12685. }
  12686. }
  12687. }
  12688. void asCCompiler::CompileBitwiseOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType op)
  12689. {
  12690. // TODO: If a constant is only using 32bits, then a 32bit operation is preferred
  12691. if( op == ttUnrecognizedToken )
  12692. op = node->tokenType;
  12693. if( op == ttAmp || op == ttAndAssign ||
  12694. op == ttBitOr || op == ttOrAssign ||
  12695. op == ttBitXor || op == ttXorAssign )
  12696. {
  12697. // Also do not permit float/double to be implicitly converted to integer in this case
  12698. // as the user may think the result is a bitwise operation on the float value but it's not
  12699. if (lctx->type.dataType.IsFloatType() || lctx->type.dataType.IsDoubleType())
  12700. {
  12701. asCString str;
  12702. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  12703. Error(str, node);
  12704. // Set an integer value and allow the compiler to continue
  12705. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), 0);
  12706. return;
  12707. }
  12708. if (rctx->type.dataType.IsFloatType() || rctx->type.dataType.IsDoubleType())
  12709. {
  12710. asCString str;
  12711. str.Format(TXT_ILLEGAL_OPERATION_ON_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  12712. Error(str, node);
  12713. // Set an integer value and allow the compiler to continue
  12714. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), 0);
  12715. return;
  12716. }
  12717. // Convert left hand operand to integer if it's not already one
  12718. asCDataType to;
  12719. if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 ||
  12720. rctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  12721. to.SetTokenType(ttInt64);
  12722. else
  12723. to.SetTokenType(ttInt);
  12724. // Do the actual conversion (keep sign/unsigned if possible)
  12725. int l = int(reservedVariables.GetLength());
  12726. rctx->bc.GetVarsUsed(reservedVariables);
  12727. if( lctx->type.dataType.IsUnsignedType() )
  12728. to.SetTokenType( to.GetSizeOnStackDWords() == 1 ? ttUInt : ttUInt64 );
  12729. else
  12730. to.SetTokenType( to.GetSizeOnStackDWords() == 1 ? ttInt : ttInt64 );
  12731. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true);
  12732. reservedVariables.SetLength(l);
  12733. // Verify that the conversion was successful
  12734. if( lctx->type.dataType != to )
  12735. {
  12736. asCString str;
  12737. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  12738. Error(str, node);
  12739. }
  12740. // Convert right hand operand to same size as left hand
  12741. l = int(reservedVariables.GetLength());
  12742. lctx->bc.GetVarsUsed(reservedVariables);
  12743. if( rctx->type.dataType.IsUnsignedType() )
  12744. to.SetTokenType( to.GetSizeOnStackDWords() == 1 ? ttUInt : ttUInt64 );
  12745. else
  12746. to.SetTokenType( to.GetSizeOnStackDWords() == 1 ? ttInt : ttInt64 );
  12747. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true);
  12748. reservedVariables.SetLength(l);
  12749. if( rctx->type.dataType != to )
  12750. {
  12751. asCString str;
  12752. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  12753. Error(str, node);
  12754. }
  12755. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  12756. if( !isConstant )
  12757. {
  12758. ConvertToVariableNotIn(lctx, rctx);
  12759. ConvertToVariableNotIn(rctx, lctx);
  12760. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  12761. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  12762. if( op == ttAndAssign || op == ttOrAssign || op == ttXorAssign )
  12763. {
  12764. // Compound assignments execute the right hand value first
  12765. MergeExprBytecode(ctx, rctx);
  12766. MergeExprBytecode(ctx, lctx);
  12767. }
  12768. else
  12769. {
  12770. MergeExprBytecode(ctx, lctx);
  12771. MergeExprBytecode(ctx, rctx);
  12772. }
  12773. ProcessDeferredParams(ctx);
  12774. asEBCInstr instruction = asBC_BAND;
  12775. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  12776. {
  12777. if( op == ttAmp || op == ttAndAssign )
  12778. instruction = asBC_BAND;
  12779. else if( op == ttBitOr || op == ttOrAssign )
  12780. instruction = asBC_BOR;
  12781. else if( op == ttBitXor || op == ttXorAssign )
  12782. instruction = asBC_BXOR;
  12783. }
  12784. else
  12785. {
  12786. if( op == ttAmp || op == ttAndAssign )
  12787. instruction = asBC_BAND64;
  12788. else if( op == ttBitOr || op == ttOrAssign )
  12789. instruction = asBC_BOR64;
  12790. else if( op == ttBitXor || op == ttXorAssign )
  12791. instruction = asBC_BXOR64;
  12792. }
  12793. // Do the operation
  12794. int a = AllocateVariable(lctx->type.dataType, true);
  12795. int b = lctx->type.stackOffset;
  12796. int c = rctx->type.stackOffset;
  12797. ctx->bc.InstrW_W_W(instruction, a, b, c);
  12798. ctx->type.SetVariable(lctx->type.dataType, a, true);
  12799. }
  12800. else
  12801. {
  12802. if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  12803. {
  12804. asQWORD v = 0;
  12805. if( op == ttAmp )
  12806. v = lctx->type.GetConstantQW() & rctx->type.GetConstantQW();
  12807. else if( op == ttBitOr )
  12808. v = lctx->type.GetConstantQW() | rctx->type.GetConstantQW();
  12809. else if( op == ttBitXor )
  12810. v = lctx->type.GetConstantQW() ^ rctx->type.GetConstantQW();
  12811. // Remember the result
  12812. ctx->type.SetConstantQW(lctx->type.dataType, v);
  12813. }
  12814. else
  12815. {
  12816. asDWORD v = 0;
  12817. if( op == ttAmp )
  12818. v = lctx->type.GetConstantDW() & rctx->type.GetConstantDW();
  12819. else if( op == ttBitOr )
  12820. v = lctx->type.GetConstantDW() | rctx->type.GetConstantDW();
  12821. else if( op == ttBitXor )
  12822. v = lctx->type.GetConstantDW() ^ rctx->type.GetConstantDW();
  12823. // Remember the result
  12824. ctx->type.SetConstantDW(lctx->type.dataType, v);
  12825. }
  12826. }
  12827. }
  12828. else if( op == ttBitShiftLeft || op == ttShiftLeftAssign ||
  12829. op == ttBitShiftRight || op == ttShiftRightLAssign ||
  12830. op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  12831. {
  12832. // Don't permit object to primitive conversion, since we don't know which integer type is the correct one
  12833. // Also do not permit float/double to be implicitly converted to integer in this case
  12834. if( lctx->type.dataType.IsObject() || lctx->type.dataType.IsFloatType() || lctx->type.dataType.IsDoubleType() )
  12835. {
  12836. asCString str;
  12837. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  12838. Error(str, node);
  12839. // Set an integer value and allow the compiler to continue
  12840. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), 0);
  12841. return;
  12842. }
  12843. // Convert left hand operand to integer if it's not already one
  12844. asCDataType to = lctx->type.dataType;
  12845. if( lctx->type.dataType.IsUnsignedType() &&
  12846. lctx->type.dataType.GetSizeInMemoryBytes() < 4 )
  12847. {
  12848. // Upgrade to 32bit
  12849. to = asCDataType::CreatePrimitive(ttUInt, false);
  12850. }
  12851. else if( !lctx->type.dataType.IsUnsignedType() )
  12852. {
  12853. if (lctx->type.dataType.GetSizeInMemoryDWords() == 2)
  12854. to = asCDataType::CreatePrimitive(ttInt64, false);
  12855. else
  12856. to = asCDataType::CreatePrimitive(ttInt, false);
  12857. }
  12858. // Do the actual conversion
  12859. int l = int(reservedVariables.GetLength());
  12860. rctx->bc.GetVarsUsed(reservedVariables);
  12861. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true);
  12862. reservedVariables.SetLength(l);
  12863. // Verify that the conversion was successful
  12864. if( lctx->type.dataType != to )
  12865. {
  12866. asCString str;
  12867. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  12868. Error(str, node);
  12869. }
  12870. // Right operand must be 32bit uint
  12871. l = int(reservedVariables.GetLength());
  12872. lctx->bc.GetVarsUsed(reservedVariables);
  12873. ImplicitConversion(rctx, asCDataType::CreatePrimitive(ttUInt, true), node, asIC_IMPLICIT_CONV, true);
  12874. reservedVariables.SetLength(l);
  12875. if( !rctx->type.dataType.IsUnsignedType() )
  12876. {
  12877. asCString str;
  12878. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), "uint");
  12879. Error(str, node);
  12880. }
  12881. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  12882. if( !isConstant )
  12883. {
  12884. ConvertToVariableNotIn(lctx, rctx);
  12885. ConvertToVariableNotIn(rctx, lctx);
  12886. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  12887. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  12888. if( op == ttShiftLeftAssign || op == ttShiftRightLAssign || op == ttShiftRightAAssign )
  12889. {
  12890. // Compound assignments execute the right hand value first
  12891. MergeExprBytecode(ctx, rctx);
  12892. MergeExprBytecode(ctx, lctx);
  12893. }
  12894. else
  12895. {
  12896. MergeExprBytecode(ctx, lctx);
  12897. MergeExprBytecode(ctx, rctx);
  12898. }
  12899. ProcessDeferredParams(ctx);
  12900. asEBCInstr instruction = asBC_BSLL;
  12901. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  12902. {
  12903. if( op == ttBitShiftLeft || op == ttShiftLeftAssign )
  12904. instruction = asBC_BSLL;
  12905. else if( op == ttBitShiftRight || op == ttShiftRightLAssign )
  12906. instruction = asBC_BSRL;
  12907. else if( op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  12908. instruction = asBC_BSRA;
  12909. }
  12910. else
  12911. {
  12912. if( op == ttBitShiftLeft || op == ttShiftLeftAssign )
  12913. instruction = asBC_BSLL64;
  12914. else if( op == ttBitShiftRight || op == ttShiftRightLAssign )
  12915. instruction = asBC_BSRL64;
  12916. else if( op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  12917. instruction = asBC_BSRA64;
  12918. }
  12919. // Do the operation
  12920. int a = AllocateVariable(lctx->type.dataType, true);
  12921. int b = lctx->type.stackOffset;
  12922. int c = rctx->type.stackOffset;
  12923. ctx->bc.InstrW_W_W(instruction, a, b, c);
  12924. ctx->type.SetVariable(lctx->type.dataType, a, true);
  12925. }
  12926. else
  12927. {
  12928. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  12929. {
  12930. asDWORD v = 0;
  12931. if( op == ttBitShiftLeft )
  12932. v = lctx->type.GetConstantDW() << rctx->type.GetConstantDW();
  12933. else if( op == ttBitShiftRight )
  12934. v = lctx->type.GetConstantDW() >> rctx->type.GetConstantDW();
  12935. else if( op == ttBitShiftRightArith )
  12936. v = int(lctx->type.GetConstantDW()) >> rctx->type.GetConstantDW();
  12937. ctx->type.SetConstantDW(lctx->type.dataType, v);
  12938. }
  12939. else
  12940. {
  12941. asQWORD v = 0;
  12942. if( op == ttBitShiftLeft )
  12943. v = lctx->type.GetConstantQW() << rctx->type.GetConstantDW();
  12944. else if( op == ttBitShiftRight )
  12945. v = lctx->type.GetConstantQW() >> rctx->type.GetConstantDW();
  12946. else if( op == ttBitShiftRightArith )
  12947. v = asINT64(lctx->type.GetConstantQW()) >> rctx->type.GetConstantDW();
  12948. ctx->type.SetConstantQW(lctx->type.dataType, v);
  12949. }
  12950. }
  12951. }
  12952. }
  12953. void asCCompiler::CompileComparisonOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType op)
  12954. {
  12955. // Both operands must be of the same type
  12956. // If either operand is a non-primitive then first convert them to the best number type
  12957. if( !lctx->type.dataType.IsPrimitive() )
  12958. {
  12959. int l = int(reservedVariables.GetLength());
  12960. rctx->bc.GetVarsUsed(reservedVariables);
  12961. ImplicitConvObjectToBestMathType(lctx, node);
  12962. reservedVariables.SetLength(l);
  12963. }
  12964. if( !rctx->type.dataType.IsPrimitive() )
  12965. {
  12966. int l = int(reservedVariables.GetLength());
  12967. lctx->bc.GetVarsUsed(reservedVariables);
  12968. ImplicitConvObjectToBestMathType(rctx, node);
  12969. reservedVariables.SetLength(l);
  12970. }
  12971. // Implicitly convert the operands to matching types
  12972. asCDataType to;
  12973. if( lctx->type.dataType.IsDoubleType() || rctx->type.dataType.IsDoubleType() )
  12974. to.SetTokenType(ttDouble);
  12975. else if( lctx->type.dataType.IsFloatType() || rctx->type.dataType.IsFloatType() )
  12976. to.SetTokenType(ttFloat);
  12977. else if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 || rctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  12978. {
  12979. // Convert to int64 if both are signed or if one is non-constant and signed
  12980. if( (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) ||
  12981. (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) )
  12982. to.SetTokenType(ttInt64);
  12983. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  12984. to.SetTokenType(ttUInt64);
  12985. else
  12986. to.SetTokenType(ttInt64);
  12987. }
  12988. else
  12989. {
  12990. // Convert to int32 if both are signed or if one is non-constant and signed
  12991. if( (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) ||
  12992. (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) )
  12993. to.SetTokenType(ttInt);
  12994. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  12995. to.SetTokenType(ttUInt);
  12996. else if( lctx->type.dataType.IsBooleanType() || rctx->type.dataType.IsBooleanType() )
  12997. to.SetTokenType(ttBool);
  12998. else
  12999. to.SetTokenType(ttInt);
  13000. }
  13001. // If doing an operation with double constant and float variable, the constant should be converted to float
  13002. if( (lctx->type.isConstant && lctx->type.dataType.IsDoubleType() && !rctx->type.isConstant && rctx->type.dataType.IsFloatType()) ||
  13003. (rctx->type.isConstant && rctx->type.dataType.IsDoubleType() && !lctx->type.isConstant && lctx->type.dataType.IsFloatType()) )
  13004. to.SetTokenType(ttFloat);
  13005. asASSERT( to.GetTokenType() != ttUnrecognizedToken );
  13006. // Do we have a mismatch between the sign of the operand?
  13007. bool signMismatch = false;
  13008. for( int n = 0; !signMismatch && n < 2; n++ )
  13009. {
  13010. asCExprContext *opCtx = n ? rctx : lctx;
  13011. if( opCtx->type.dataType.IsUnsignedType() != to.IsUnsignedType() )
  13012. {
  13013. // We have a mismatch, unless the value is a literal constant and the conversion won't affect its value
  13014. signMismatch = true;
  13015. if( opCtx->type.isConstant )
  13016. {
  13017. if( opCtx->type.dataType.GetTokenType() == ttUInt64 || opCtx->type.dataType.GetTokenType() == ttInt64 )
  13018. {
  13019. if( !(opCtx->type.GetConstantQW() & (asQWORD(1)<<63)) )
  13020. signMismatch = false;
  13021. }
  13022. else if(opCtx->type.dataType.GetTokenType() == ttUInt || opCtx->type.dataType.GetTokenType() == ttInt || opCtx->type.dataType.IsEnumType() )
  13023. {
  13024. if( !(opCtx->type.GetConstantDW() & (1<<31)) )
  13025. signMismatch = false;
  13026. }
  13027. else if (opCtx->type.dataType.GetTokenType() == ttUInt16 || opCtx->type.dataType.GetTokenType() == ttInt16)
  13028. {
  13029. if (!(opCtx->type.GetConstantW() & (1 << 15)))
  13030. signMismatch = false;
  13031. }
  13032. else if (opCtx->type.dataType.GetTokenType() == ttUInt8 || opCtx->type.dataType.GetTokenType() == ttInt8)
  13033. {
  13034. if (!(opCtx->type.GetConstantB() & (1 << 7)))
  13035. signMismatch = false;
  13036. }
  13037. // It's not necessary to check for floats or double, because if
  13038. // it was then the types for the conversion will never be unsigned
  13039. }
  13040. }
  13041. }
  13042. // Check for signed/unsigned mismatch
  13043. if( signMismatch )
  13044. Warning(TXT_SIGNED_UNSIGNED_MISMATCH, node);
  13045. // Attempt to resolve ambiguous enumerations
  13046. if( lctx->type.dataType.IsEnumType() && rctx->enumValue != "" )
  13047. ImplicitConversion(rctx, lctx->type.dataType, node, asIC_IMPLICIT_CONV);
  13048. else if( rctx->type.dataType.IsEnumType() && lctx->enumValue != "" )
  13049. ImplicitConversion(lctx, rctx->type.dataType, node, asIC_IMPLICIT_CONV);
  13050. // Do the actual conversion
  13051. int l = int(reservedVariables.GetLength());
  13052. rctx->bc.GetVarsUsed(reservedVariables);
  13053. if( lctx->type.dataType.IsReference() )
  13054. ConvertToVariable(lctx);
  13055. if( rctx->type.dataType.IsReference() )
  13056. ConvertToVariable(rctx);
  13057. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV);
  13058. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV);
  13059. reservedVariables.SetLength(l);
  13060. // Verify that the conversion was successful
  13061. bool ok = true;
  13062. if( !lctx->type.dataType.IsEqualExceptConst(to) )
  13063. {
  13064. asCString str;
  13065. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  13066. Error(str, node);
  13067. ok = false;
  13068. }
  13069. if( !rctx->type.dataType.IsEqualExceptConst(to) )
  13070. {
  13071. asCString str;
  13072. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  13073. Error(str, node);
  13074. ok = false;
  13075. }
  13076. if( !ok )
  13077. {
  13078. // It wasn't possible to get two valid operands, so we just return
  13079. // a boolean result and let the compiler continue.
  13080. #if AS_SIZEOF_BOOL == 1
  13081. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  13082. #else
  13083. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  13084. #endif
  13085. return;
  13086. }
  13087. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  13088. if( op == ttUnrecognizedToken )
  13089. op = node->tokenType;
  13090. if( !isConstant )
  13091. {
  13092. if( to.IsBooleanType() )
  13093. {
  13094. if( op == ttEqual || op == ttNotEqual )
  13095. {
  13096. // Must convert to temporary variable, because we are changing the value before comparison
  13097. ConvertToTempVariableNotIn(lctx, rctx);
  13098. ConvertToTempVariableNotIn(rctx, lctx);
  13099. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  13100. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  13101. // Make sure they are equal if not false
  13102. lctx->bc.InstrWORD(asBC_NOT, lctx->type.stackOffset);
  13103. rctx->bc.InstrWORD(asBC_NOT, rctx->type.stackOffset);
  13104. MergeExprBytecode(ctx, lctx);
  13105. MergeExprBytecode(ctx, rctx);
  13106. ProcessDeferredParams(ctx);
  13107. int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, true), true);
  13108. int b = lctx->type.stackOffset;
  13109. int c = rctx->type.stackOffset;
  13110. if( op == ttEqual )
  13111. {
  13112. ctx->bc.InstrW_W(asBC_CMPi,b,c);
  13113. ctx->bc.Instr(asBC_TZ);
  13114. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  13115. }
  13116. else if( op == ttNotEqual )
  13117. {
  13118. ctx->bc.InstrW_W(asBC_CMPi,b,c);
  13119. ctx->bc.Instr(asBC_TNZ);
  13120. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  13121. }
  13122. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  13123. }
  13124. else
  13125. {
  13126. // TODO: Use TXT_ILLEGAL_OPERATION_ON
  13127. Error(TXT_ILLEGAL_OPERATION, node);
  13128. #if AS_SIZEOF_BOOL == 1
  13129. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), 0);
  13130. #else
  13131. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), 0);
  13132. #endif
  13133. }
  13134. }
  13135. else
  13136. {
  13137. ConvertToVariableNotIn(lctx, rctx);
  13138. ConvertToVariableNotIn(rctx, lctx);
  13139. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  13140. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  13141. MergeExprBytecode(ctx, lctx);
  13142. MergeExprBytecode(ctx, rctx);
  13143. ProcessDeferredParams(ctx);
  13144. asEBCInstr iCmp = asBC_CMPi, iT = asBC_TZ;
  13145. if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  13146. iCmp = asBC_CMPi;
  13147. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  13148. iCmp = asBC_CMPu;
  13149. else if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  13150. iCmp = asBC_CMPi64;
  13151. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  13152. iCmp = asBC_CMPu64;
  13153. else if( lctx->type.dataType.IsFloatType() )
  13154. iCmp = asBC_CMPf;
  13155. else if( lctx->type.dataType.IsDoubleType() )
  13156. iCmp = asBC_CMPd;
  13157. else
  13158. asASSERT(false);
  13159. if( op == ttEqual )
  13160. iT = asBC_TZ;
  13161. else if( op == ttNotEqual )
  13162. iT = asBC_TNZ;
  13163. else if( op == ttLessThan )
  13164. iT = asBC_TS;
  13165. else if( op == ttLessThanOrEqual )
  13166. iT = asBC_TNP;
  13167. else if( op == ttGreaterThan )
  13168. iT = asBC_TP;
  13169. else if( op == ttGreaterThanOrEqual )
  13170. iT = asBC_TNS;
  13171. int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, true), true);
  13172. int b = lctx->type.stackOffset;
  13173. int c = rctx->type.stackOffset;
  13174. ctx->bc.InstrW_W(iCmp, b, c);
  13175. ctx->bc.Instr(iT);
  13176. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  13177. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  13178. }
  13179. }
  13180. else
  13181. {
  13182. if( to.IsBooleanType() )
  13183. {
  13184. if( op == ttEqual || op == ttNotEqual )
  13185. {
  13186. asDWORD lv, rv;
  13187. #if AS_SIZEOF_BOOL == 1
  13188. lv = lctx->type.GetConstantB();
  13189. rv = rctx->type.GetConstantB();
  13190. #else
  13191. lv = lctx->type.GetConstantDW();
  13192. rv = rctx->type.GetConstantDW();
  13193. #endif
  13194. // Make sure they are equal if not false
  13195. if (lv != 0) lv = VALUE_OF_BOOLEAN_TRUE;
  13196. if (rv != 0) rv = VALUE_OF_BOOLEAN_TRUE;
  13197. asDWORD v = 0;
  13198. if (op == ttEqual)
  13199. v = (lv == rv) ? VALUE_OF_BOOLEAN_TRUE : 0;
  13200. else if (op == ttNotEqual)
  13201. v = (lv != rv) ? VALUE_OF_BOOLEAN_TRUE : 0;
  13202. #if AS_SIZEOF_BOOL == 1
  13203. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), (asBYTE)v);
  13204. #else
  13205. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), v);
  13206. #endif
  13207. }
  13208. else
  13209. {
  13210. // TODO: Use TXT_ILLEGAL_OPERATION_ON
  13211. Error(TXT_ILLEGAL_OPERATION, node);
  13212. }
  13213. }
  13214. else
  13215. {
  13216. int i = 0;
  13217. if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  13218. {
  13219. int v = int(lctx->type.GetConstantDW()) - int(rctx->type.GetConstantDW());
  13220. if( v < 0 ) i = -1;
  13221. if( v > 0 ) i = 1;
  13222. }
  13223. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  13224. {
  13225. asDWORD v1 = lctx->type.GetConstantDW();
  13226. asDWORD v2 = rctx->type.GetConstantDW();
  13227. if( v1 < v2 ) i = -1;
  13228. if( v1 > v2 ) i = 1;
  13229. }
  13230. else if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  13231. {
  13232. asINT64 v = asINT64(lctx->type.GetConstantQW()) - asINT64(rctx->type.GetConstantQW());
  13233. if( v < 0 ) i = -1;
  13234. if( v > 0 ) i = 1;
  13235. }
  13236. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  13237. {
  13238. asQWORD v1 = lctx->type.GetConstantQW();
  13239. asQWORD v2 = rctx->type.GetConstantQW();
  13240. if( v1 < v2 ) i = -1;
  13241. if( v1 > v2 ) i = 1;
  13242. }
  13243. else if( lctx->type.dataType.IsFloatType() )
  13244. {
  13245. float v = lctx->type.GetConstantF() - rctx->type.GetConstantF();
  13246. if( v < 0 ) i = -1;
  13247. if( v > 0 ) i = 1;
  13248. }
  13249. else if( lctx->type.dataType.IsDoubleType() )
  13250. {
  13251. double v = lctx->type.GetConstantD() - rctx->type.GetConstantD();
  13252. if( v < 0 ) i = -1;
  13253. if( v > 0 ) i = 1;
  13254. }
  13255. if( op == ttEqual )
  13256. i = (i == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  13257. else if( op == ttNotEqual )
  13258. i = (i != 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  13259. else if( op == ttLessThan )
  13260. i = (i < 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  13261. else if( op == ttLessThanOrEqual )
  13262. i = (i <= 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  13263. else if( op == ttGreaterThan )
  13264. i = (i > 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  13265. else if( op == ttGreaterThanOrEqual )
  13266. i = (i >= 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  13267. #if AS_SIZEOF_BOOL == 1
  13268. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), (asBYTE)i);
  13269. #else
  13270. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), i);
  13271. #endif
  13272. }
  13273. }
  13274. }
  13275. void asCCompiler::PushVariableOnStack(asCExprContext *ctx, bool asReference)
  13276. {
  13277. // Put the result on the stack
  13278. if( asReference )
  13279. {
  13280. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  13281. ctx->type.dataType.MakeReference(true);
  13282. }
  13283. else
  13284. {
  13285. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  13286. ctx->bc.InstrSHORT(asBC_PshV4, ctx->type.stackOffset);
  13287. else
  13288. ctx->bc.InstrSHORT(asBC_PshV8, ctx->type.stackOffset);
  13289. }
  13290. }
  13291. void asCCompiler::CompileBooleanOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType op)
  13292. {
  13293. // Both operands must be booleans
  13294. asCDataType to;
  13295. to.SetTokenType(ttBool);
  13296. // Do the actual conversion
  13297. int l = int(reservedVariables.GetLength());
  13298. rctx->bc.GetVarsUsed(reservedVariables);
  13299. lctx->bc.GetVarsUsed(reservedVariables);
  13300. // Allow value types to be converted to bool using 'bool opImplConv()'
  13301. if( lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
  13302. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV);
  13303. if( rctx->type.dataType.GetTypeInfo() && (rctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
  13304. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV);
  13305. reservedVariables.SetLength(l);
  13306. // Verify that the conversion was successful
  13307. if( !lctx->type.dataType.IsBooleanType() )
  13308. {
  13309. asCString str;
  13310. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), "bool");
  13311. Error(str, node);
  13312. // Force the conversion to allow compilation to proceed
  13313. lctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  13314. }
  13315. if( !rctx->type.dataType.IsBooleanType() )
  13316. {
  13317. asCString str;
  13318. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), "bool");
  13319. Error(str, node);
  13320. // Force the conversion to allow compilation to proceed
  13321. rctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  13322. }
  13323. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  13324. ctx->type.Set(asCDataType::CreatePrimitive(ttBool, true));
  13325. // What kind of operator is it?
  13326. if( op == ttUnrecognizedToken )
  13327. op = node->tokenType;
  13328. if( op == ttXor )
  13329. {
  13330. if( !isConstant )
  13331. {
  13332. // Must convert to temporary variable, because we are changing the value before comparison
  13333. ConvertToTempVariableNotIn(lctx, rctx);
  13334. ConvertToTempVariableNotIn(rctx, lctx);
  13335. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  13336. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  13337. // Make sure they are equal if not false
  13338. lctx->bc.InstrWORD(asBC_NOT, lctx->type.stackOffset);
  13339. rctx->bc.InstrWORD(asBC_NOT, rctx->type.stackOffset);
  13340. MergeExprBytecode(ctx, lctx);
  13341. MergeExprBytecode(ctx, rctx);
  13342. ProcessDeferredParams(ctx);
  13343. int a = AllocateVariable(ctx->type.dataType, true);
  13344. int b = lctx->type.stackOffset;
  13345. int c = rctx->type.stackOffset;
  13346. ctx->bc.InstrW_W_W(asBC_BXOR,a,b,c);
  13347. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  13348. }
  13349. else
  13350. {
  13351. // Make sure they are equal if not false
  13352. #if AS_SIZEOF_BOOL == 1
  13353. if( lctx->type.GetConstantB() != 0 ) lctx->type.SetConstantB(VALUE_OF_BOOLEAN_TRUE);
  13354. if( rctx->type.GetConstantB() != 0 ) rctx->type.SetConstantB(VALUE_OF_BOOLEAN_TRUE);
  13355. asBYTE v = 0;
  13356. v = lctx->type.GetConstantB() - rctx->type.GetConstantB();
  13357. if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  13358. ctx->type.isConstant = true;
  13359. ctx->type.SetConstantB(v);
  13360. #else
  13361. if( lctx->type.GetConstantDW() != 0 ) lctx->type.SetConstantDW(VALUE_OF_BOOLEAN_TRUE);
  13362. if( rctx->type.GetConstantDW() != 0 ) rctx->type.SetConstantDW(VALUE_OF_BOOLEAN_TRUE);
  13363. asDWORD v = 0;
  13364. v = lctx->type.GetConstantDW() - rctx->type.GetConstantDW();
  13365. if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  13366. ctx->type.isConstant = true;
  13367. ctx->type.SetConstantDW(v);
  13368. #endif
  13369. }
  13370. }
  13371. else if( op == ttAnd ||
  13372. op == ttOr )
  13373. {
  13374. if( !isConstant )
  13375. {
  13376. // If or-operator and first value is 1 the second value shouldn't be calculated
  13377. // if and-operator and first value is 0 the second value shouldn't be calculated
  13378. ConvertToVariable(lctx);
  13379. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  13380. MergeExprBytecode(ctx, lctx);
  13381. int offset = AllocateVariable(asCDataType::CreatePrimitive(ttBool, false), true);
  13382. int label1 = nextLabel++;
  13383. int label2 = nextLabel++;
  13384. ctx->bc.InstrSHORT(asBC_CpyVtoR4, lctx->type.stackOffset);
  13385. ctx->bc.Instr(asBC_ClrHi);
  13386. if( op == ttAnd )
  13387. {
  13388. ctx->bc.InstrDWORD(asBC_JNZ, label1);
  13389. ctx->bc.InstrW_DW(asBC_SetV4, (asWORD)offset, 0);
  13390. ctx->bc.InstrINT(asBC_JMP, label2);
  13391. }
  13392. else if( op == ttOr )
  13393. {
  13394. ctx->bc.InstrDWORD(asBC_JZ, label1);
  13395. #if AS_SIZEOF_BOOL == 1
  13396. ctx->bc.InstrSHORT_B(asBC_SetV1, (short)offset, VALUE_OF_BOOLEAN_TRUE);
  13397. #else
  13398. ctx->bc.InstrSHORT_DW(asBC_SetV4, (short)offset, VALUE_OF_BOOLEAN_TRUE);
  13399. #endif
  13400. ctx->bc.InstrINT(asBC_JMP, label2);
  13401. }
  13402. ctx->bc.Label((short)label1);
  13403. ConvertToVariable(rctx);
  13404. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  13405. rctx->bc.InstrW_W(asBC_CpyVtoV4, offset, rctx->type.stackOffset);
  13406. MergeExprBytecode(ctx, rctx);
  13407. ctx->bc.Label((short)label2);
  13408. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, false), offset, true);
  13409. }
  13410. else
  13411. {
  13412. #if AS_SIZEOF_BOOL == 1
  13413. asBYTE v = 0;
  13414. if( op == ttAnd )
  13415. v = lctx->type.GetConstantB() && rctx->type.GetConstantB();
  13416. else if( op == ttOr )
  13417. v = lctx->type.GetConstantB() || rctx->type.GetConstantB();
  13418. // Remember the result
  13419. ctx->type.isConstant = true;
  13420. ctx->type.SetConstantB(v);
  13421. #else
  13422. asDWORD v = 0;
  13423. if( op == ttAnd )
  13424. v = lctx->type.GetConstantDW() && rctx->type.GetConstantDW();
  13425. else if( op == ttOr )
  13426. v = lctx->type.GetConstantDW() || rctx->type.GetConstantDW();
  13427. // Remember the result
  13428. ctx->type.isConstant = true;
  13429. ctx->type.SetConstantDW(v);
  13430. #endif
  13431. }
  13432. }
  13433. }
  13434. void asCCompiler::CompileOperatorOnHandles(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType opToken)
  13435. {
  13436. // Process the property accessor as get
  13437. if( ProcessPropertyGetAccessor(lctx, node) < 0 )
  13438. return;
  13439. if( ProcessPropertyGetAccessor(rctx, node) < 0 )
  13440. return;
  13441. DetermineSingleFunc(lctx, node);
  13442. DetermineSingleFunc(rctx, node);
  13443. // Make sure lctx doesn't end up with a variable used in rctx
  13444. if( lctx->type.isTemporary && rctx->bc.IsVarUsed(lctx->type.stackOffset) )
  13445. {
  13446. asCArray<int> vars;
  13447. rctx->bc.GetVarsUsed(vars);
  13448. int offset = AllocateVariable(lctx->type.dataType, true);
  13449. rctx->bc.ExchangeVar(lctx->type.stackOffset, offset);
  13450. ReleaseTemporaryVariable(offset, 0);
  13451. }
  13452. if( opToken == ttUnrecognizedToken )
  13453. opToken = node->tokenType;
  13454. // Warn if not both operands are explicit handles or null handles
  13455. if( (opToken == ttEqual || opToken == ttNotEqual) &&
  13456. ((!(lctx->type.isExplicitHandle || lctx->type.IsNullConstant()) && !(lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE))) ||
  13457. (!(rctx->type.isExplicitHandle || rctx->type.IsNullConstant()) && !(rctx->type.dataType.GetTypeInfo() && (rctx->type.dataType.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE)))) )
  13458. {
  13459. Warning(TXT_HANDLE_COMPARISON, node);
  13460. }
  13461. // If one of the operands is a value type used as handle, we should look for the opEquals method
  13462. if( ((lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE)) ||
  13463. (rctx->type.dataType.GetTypeInfo() && (rctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE))) &&
  13464. (opToken == ttEqual || opToken == ttIs ||
  13465. opToken == ttNotEqual || opToken == ttNotIs) )
  13466. {
  13467. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  13468. // Find the matching opEquals method
  13469. int r = CompileOverloadedDualOperator2(node, "opEquals", lctx, rctx, true, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  13470. if( r == 0 )
  13471. {
  13472. // Try again by switching the order of the operands
  13473. r = CompileOverloadedDualOperator2(node, "opEquals", rctx, lctx, false, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  13474. }
  13475. if( r == 1 )
  13476. {
  13477. if( opToken == ttNotEqual || opToken == ttNotIs )
  13478. ctx->bc.InstrSHORT(asBC_NOT, ctx->type.stackOffset);
  13479. // Success, don't continue
  13480. return;
  13481. }
  13482. else if( r == 0 )
  13483. {
  13484. // Couldn't find opEquals method
  13485. Error(TXT_NO_APPROPRIATE_OPEQUALS, node);
  13486. }
  13487. // Compiler error, don't continue
  13488. #if AS_SIZEOF_BOOL == 1
  13489. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  13490. #else
  13491. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  13492. #endif
  13493. return;
  13494. }
  13495. // Implicitly convert null to the other type
  13496. asCDataType to;
  13497. if( lctx->type.IsNullConstant() )
  13498. to = rctx->type.dataType;
  13499. else if( rctx->type.IsNullConstant() )
  13500. to = lctx->type.dataType;
  13501. else
  13502. {
  13503. // Find a common base type
  13504. asCExprContext tmp(engine);
  13505. tmp.type = rctx->type;
  13506. ImplicitConversion(&tmp, lctx->type.dataType, 0, asIC_IMPLICIT_CONV, false);
  13507. if( tmp.type.dataType.GetTypeInfo() == lctx->type.dataType.GetTypeInfo() )
  13508. to = lctx->type.dataType;
  13509. else
  13510. to = rctx->type.dataType;
  13511. // Assume handle-to-const as it is not possible to convert handle-to-const to handle-to-non-const
  13512. to.MakeHandleToConst(true);
  13513. }
  13514. // Need to pop the value if it is a null constant
  13515. if( lctx->type.IsNullConstant() )
  13516. lctx->bc.Instr(asBC_PopPtr);
  13517. if( rctx->type.IsNullConstant() )
  13518. rctx->bc.Instr(asBC_PopPtr);
  13519. // Convert both sides to explicit handles
  13520. to.MakeHandle(true);
  13521. to.MakeReference(false);
  13522. if( !to.IsObjectHandle() )
  13523. {
  13524. // Compiler error, don't continue
  13525. Error(TXT_OPERANDS_MUST_BE_HANDLES, node);
  13526. #if AS_SIZEOF_BOOL == 1
  13527. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  13528. #else
  13529. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  13530. #endif
  13531. return;
  13532. }
  13533. // Do the conversion
  13534. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV);
  13535. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV);
  13536. // Both operands must be of the same type
  13537. // Verify that the conversion was successful
  13538. if( !lctx->type.dataType.IsEqualExceptConst(to) )
  13539. {
  13540. asCString str;
  13541. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  13542. Error(str, node);
  13543. }
  13544. if( !rctx->type.dataType.IsEqualExceptConst(to) )
  13545. {
  13546. asCString str;
  13547. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  13548. Error(str, node);
  13549. }
  13550. // Make sure it really is handles that are being compared
  13551. if( !lctx->type.dataType.IsObjectHandle() )
  13552. {
  13553. Error(TXT_OPERANDS_MUST_BE_HANDLES, node);
  13554. }
  13555. ctx->type.Set(asCDataType::CreatePrimitive(ttBool, true));
  13556. if( opToken == ttEqual || opToken == ttNotEqual || opToken == ttIs || opToken == ttNotIs )
  13557. {
  13558. // Make sure handles received as parameters by reference are copied to a local variable before the
  13559. // asBC_CmpPtr, so we don't end up comparing the reference to the handle instead of the handle itself
  13560. if( lctx->type.isVariable && !lctx->type.isTemporary && lctx->type.stackOffset <= 0 )
  13561. lctx->type.isVariable = false;
  13562. if( rctx->type.isVariable && !rctx->type.isTemporary && rctx->type.stackOffset <= 0 )
  13563. rctx->type.isVariable = false;
  13564. // TODO: runtime optimize: don't do REFCPY if not necessary
  13565. ConvertToVariableNotIn(lctx, rctx);
  13566. ConvertToVariable(rctx);
  13567. // Pop the pointers from the stack as they will not be used
  13568. lctx->bc.Instr(asBC_PopPtr);
  13569. rctx->bc.Instr(asBC_PopPtr);
  13570. MergeExprBytecode(ctx, lctx);
  13571. MergeExprBytecode(ctx, rctx);
  13572. int a = AllocateVariable(ctx->type.dataType, true);
  13573. int b = lctx->type.stackOffset;
  13574. int c = rctx->type.stackOffset;
  13575. ctx->bc.InstrW_W(asBC_CmpPtr, b, c);
  13576. if( opToken == ttEqual || opToken == ttIs )
  13577. ctx->bc.Instr(asBC_TZ);
  13578. else if( opToken == ttNotEqual || opToken == ttNotIs )
  13579. ctx->bc.Instr(asBC_TNZ);
  13580. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  13581. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  13582. ReleaseTemporaryVariable(lctx->type, &ctx->bc);
  13583. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  13584. ProcessDeferredParams(ctx);
  13585. }
  13586. else
  13587. {
  13588. // TODO: Use TXT_ILLEGAL_OPERATION_ON
  13589. Error(TXT_ILLEGAL_OPERATION, node);
  13590. }
  13591. }
  13592. void asCCompiler::PerformFunctionCall(int funcId, asCExprContext *ctx, bool isConstructor, asCArray<asCExprContext*> *args, asCObjectType *objType, bool useVariable, int varOffset, int funcPtrVar)
  13593. {
  13594. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  13595. // A shared object may not call non-shared functions
  13596. if( outFunc->IsShared() && !descr->IsShared() )
  13597. {
  13598. asCString msg;
  13599. msg.Format(TXT_SHARED_CANNOT_CALL_NON_SHARED_FUNC_s, descr->GetDeclarationStr().AddressOf());
  13600. Error(msg, ctx->exprNode);
  13601. }
  13602. // Check if the function is private or protected
  13603. if (descr->IsPrivate())
  13604. {
  13605. asCObjectType *type = descr->objectType;
  13606. if (type == 0 && descr->traits.GetTrait(asTRAIT_CONSTRUCTOR))
  13607. type = CastToObjectType(descr->returnType.GetTypeInfo());
  13608. asASSERT(type);
  13609. if( (type != outFunc->GetObjectType()) )
  13610. {
  13611. asCString msg;
  13612. msg.Format(TXT_PRIVATE_METHOD_CALL_s, descr->GetDeclarationStr().AddressOf());
  13613. Error(msg, ctx->exprNode);
  13614. }
  13615. }
  13616. else if (descr->IsProtected())
  13617. {
  13618. asCObjectType *type = descr->objectType;
  13619. if (type == 0 && descr->traits.GetTrait(asTRAIT_CONSTRUCTOR))
  13620. type = CastToObjectType(descr->returnType.GetTypeInfo());
  13621. asASSERT(type);
  13622. if (!(type == outFunc->objectType || (outFunc->objectType && outFunc->objectType->DerivesFrom(type))))
  13623. {
  13624. asCString msg;
  13625. msg.Format(TXT_PROTECTED_METHOD_CALL_s, descr->GetDeclarationStr().AddressOf());
  13626. Error(msg, ctx->exprNode);
  13627. }
  13628. }
  13629. int argSize = descr->GetSpaceNeededForArguments();
  13630. // If we're calling a class method we must make sure the object is guaranteed to stay
  13631. // alive throughout the call by holding on to a reference in a local variable. This must
  13632. // be done for any methods that return references, and any calls on script objects.
  13633. // Application registered objects are assumed to know to keep themselves alive even
  13634. // if the method doesn't return a reference.
  13635. if( !ctx->type.isRefSafe &&
  13636. descr->objectType &&
  13637. (ctx->type.dataType.IsObjectHandle() || ctx->type.dataType.SupportHandles()) &&
  13638. (descr->returnType.IsReference() || (ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_SCRIPT_OBJECT)) &&
  13639. !(ctx->type.isVariable || ctx->type.isTemporary) &&
  13640. !(ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_SCOPED) &&
  13641. !(ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_ASHANDLE) )
  13642. {
  13643. // TODO: runtime optimize: Avoid this for global variables, by storing a reference to the global variable once in a
  13644. // local variable and then refer to the same for each call. An alias for the global variable
  13645. // should be stored in the variable scope so that the compiler can find it. For loops and
  13646. // scopes that will always be executed, i.e. non-if scopes the alias should be stored in the
  13647. // higher scope to increase the probability of re-use.
  13648. int tempRef = AllocateVariable(ctx->type.dataType, true);
  13649. ctx->bc.InstrSHORT(asBC_PSF, (short)tempRef);
  13650. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo());
  13651. // Add the release of this reference as a deferred expression
  13652. asSDeferredParam deferred;
  13653. deferred.origExpr = 0;
  13654. deferred.argInOutFlags = asTM_INREF;
  13655. deferred.argNode = 0;
  13656. deferred.argType.SetVariable(ctx->type.dataType, tempRef, true);
  13657. ctx->deferredParams.PushLast(deferred);
  13658. // Forget the current type
  13659. ctx->type.SetDummy();
  13660. }
  13661. // Check if there is a need to add a hidden pointer for when the function returns an object by value
  13662. if( descr->DoesReturnOnStack() && !useVariable )
  13663. {
  13664. useVariable = true;
  13665. varOffset = AllocateVariable(descr->returnType, true);
  13666. // Push the pointer to the pre-allocated space for the return value
  13667. ctx->bc.InstrSHORT(asBC_PSF, short(varOffset));
  13668. if( descr->objectType )
  13669. {
  13670. // The object pointer is already on the stack, but should be the top
  13671. // one, so we need to swap the pointers in order to get the correct
  13672. ctx->bc.Instr(asBC_SwapPtr);
  13673. }
  13674. }
  13675. if( isConstructor )
  13676. {
  13677. // Sometimes the value types are allocated on the heap,
  13678. // which is when this way of constructing them is used.
  13679. asASSERT(useVariable == false);
  13680. if( (objType->flags & asOBJ_TEMPLATE) )
  13681. {
  13682. asASSERT( descr->funcType == asFUNC_SCRIPT );
  13683. // Find the id of the real constructor and not the generated stub
  13684. asUINT id = 0;
  13685. asDWORD *bc = descr->scriptData->byteCode.AddressOf();
  13686. while( bc )
  13687. {
  13688. if( (*(asBYTE*)bc) == asBC_CALLSYS )
  13689. {
  13690. id = asBC_INTARG(bc);
  13691. break;
  13692. }
  13693. bc += asBCTypeSize[asBCInfo[*(asBYTE*)bc].type];
  13694. }
  13695. asASSERT( id );
  13696. ctx->bc.InstrPTR(asBC_OBJTYPE, objType);
  13697. ctx->bc.Alloc(asBC_ALLOC, objType, id, argSize + AS_PTR_SIZE + AS_PTR_SIZE);
  13698. }
  13699. else
  13700. ctx->bc.Alloc(asBC_ALLOC, objType, descr->id, argSize+AS_PTR_SIZE);
  13701. // The instruction has already moved the returned object to the variable
  13702. ctx->type.Set(asCDataType::CreatePrimitive(ttVoid, false));
  13703. ctx->type.isLValue = false;
  13704. // Clean up arguments
  13705. if( args )
  13706. AfterFunctionCall(funcId, *args, ctx, false);
  13707. ProcessDeferredParams(ctx);
  13708. return;
  13709. }
  13710. else
  13711. {
  13712. if( descr->objectType )
  13713. argSize += AS_PTR_SIZE;
  13714. // If the function returns an object by value the address of the location
  13715. // where the value should be stored is passed as an argument too
  13716. if( descr->DoesReturnOnStack() )
  13717. argSize += AS_PTR_SIZE;
  13718. // TODO: runtime optimize: If it is known that a class method cannot be overridden the call
  13719. // should be made with asBC_CALL as it is faster. Examples where this
  13720. // is known is for example finalled methods where the class doesn't derive
  13721. // from any other, or even non-finalled methods but where it is known
  13722. // at compile time the true type of the object. The first should be
  13723. // quite easy to determine, but the latter will be quite complex and possibly
  13724. // not worth it.
  13725. if( descr->funcType == asFUNC_IMPORTED )
  13726. ctx->bc.Call(asBC_CALLBND , descr->id, argSize);
  13727. // TODO: Maybe we need two different byte codes
  13728. else if( descr->funcType == asFUNC_INTERFACE || descr->funcType == asFUNC_VIRTUAL )
  13729. ctx->bc.Call(asBC_CALLINTF, descr->id, argSize);
  13730. else if( descr->funcType == asFUNC_SCRIPT )
  13731. ctx->bc.Call(asBC_CALL , descr->id, argSize);
  13732. else if( descr->funcType == asFUNC_SYSTEM )
  13733. {
  13734. // Check if we can use the faster asBC_Thiscall1 instruction, i.e. one of
  13735. // type &obj::func(int)
  13736. // type &obj::func(uint)
  13737. if( descr->GetObjectType() && descr->returnType.IsReference() &&
  13738. descr->parameterTypes.GetLength() == 1 &&
  13739. (descr->parameterTypes[0].IsIntegerType() || descr->parameterTypes[0].IsUnsignedType()) &&
  13740. descr->parameterTypes[0].GetSizeInMemoryBytes() == 4 &&
  13741. !descr->parameterTypes[0].IsReference() )
  13742. ctx->bc.Call(asBC_Thiscall1, descr->id, argSize);
  13743. else
  13744. ctx->bc.Call(asBC_CALLSYS , descr->id, argSize);
  13745. }
  13746. else if( descr->funcType == asFUNC_FUNCDEF )
  13747. ctx->bc.CallPtr(asBC_CallPtr, funcPtrVar, argSize);
  13748. }
  13749. if( (descr->returnType.IsObject() || descr->returnType.IsFuncdef()) && !descr->returnType.IsReference() )
  13750. {
  13751. int returnOffset = 0;
  13752. asCExprValue tmpExpr = ctx->type;
  13753. if( descr->DoesReturnOnStack() )
  13754. {
  13755. asASSERT( useVariable );
  13756. // The variable was allocated before the function was called
  13757. returnOffset = varOffset;
  13758. ctx->type.SetVariable(descr->returnType, returnOffset, true);
  13759. // The variable was initialized by the function, so we need to mark it as initialized here
  13760. ctx->bc.ObjInfo(varOffset, asOBJ_INIT);
  13761. }
  13762. else
  13763. {
  13764. if( useVariable )
  13765. {
  13766. // Use the given variable
  13767. returnOffset = varOffset;
  13768. ctx->type.SetVariable(descr->returnType, returnOffset, false);
  13769. }
  13770. else
  13771. {
  13772. // Allocate a temporary variable for the returned object
  13773. // The returned object will actually be allocated on the heap, so
  13774. // we must force the allocation of the variable to do the same
  13775. returnOffset = AllocateVariable(descr->returnType, true, !descr->returnType.IsObjectHandle());
  13776. ctx->type.SetVariable(descr->returnType, returnOffset, true);
  13777. }
  13778. // Move the pointer from the object register to the temporary variable
  13779. ctx->bc.InstrSHORT(asBC_STOREOBJ, (short)returnOffset);
  13780. }
  13781. ReleaseTemporaryVariable(tmpExpr, &ctx->bc);
  13782. ctx->type.dataType.MakeReference(IsVariableOnHeap(returnOffset));
  13783. ctx->type.isLValue = false; // It is a reference, but not an lvalue
  13784. // Clean up arguments
  13785. if( args )
  13786. AfterFunctionCall(funcId, *args, ctx, false);
  13787. ProcessDeferredParams(ctx);
  13788. ctx->bc.InstrSHORT(asBC_PSF, (short)returnOffset);
  13789. }
  13790. else if( descr->returnType.IsReference() )
  13791. {
  13792. asASSERT(useVariable == false);
  13793. // We cannot clean up the arguments yet, because the
  13794. // reference might be pointing to one of them.
  13795. if( args )
  13796. AfterFunctionCall(funcId, *args, ctx, true);
  13797. // Do not process the output parameters yet, because it
  13798. // might invalidate the returned reference
  13799. // If the context holds a variable that needs cleanup
  13800. // store it as a deferred parameter so it will be cleaned up
  13801. // afterwards.
  13802. if( ctx->type.isTemporary )
  13803. {
  13804. asSDeferredParam defer;
  13805. defer.argNode = 0;
  13806. defer.argType = ctx->type;
  13807. defer.argInOutFlags = asTM_INOUTREF;
  13808. defer.origExpr = 0;
  13809. ctx->deferredParams.PushLast(defer);
  13810. }
  13811. ctx->type.Set(descr->returnType);
  13812. if( !descr->returnType.IsPrimitive() )
  13813. {
  13814. ctx->bc.Instr(asBC_PshRPtr);
  13815. if( descr->returnType.IsObject() &&
  13816. !descr->returnType.IsObjectHandle() )
  13817. {
  13818. // We are getting the pointer to the object
  13819. // not a pointer to a object variable
  13820. ctx->type.dataType.MakeReference(false);
  13821. }
  13822. }
  13823. // A returned reference can be used as lvalue
  13824. ctx->type.isLValue = true;
  13825. }
  13826. else
  13827. {
  13828. asCExprValue tmpExpr = ctx->type;
  13829. if( descr->returnType.GetSizeInMemoryBytes() )
  13830. {
  13831. int offset;
  13832. if (useVariable)
  13833. offset = varOffset;
  13834. else
  13835. {
  13836. // Allocate a temporary variable to hold the value, but make sure
  13837. // the temporary variable isn't used in any of the deferred arguments
  13838. int l = int(reservedVariables.GetLength());
  13839. for (asUINT n = 0; args && n < args->GetLength(); n++)
  13840. {
  13841. asCExprContext *expr = (*args)[n]->origExpr;
  13842. if (expr)
  13843. expr->bc.GetVarsUsed(reservedVariables);
  13844. }
  13845. offset = AllocateVariable(descr->returnType, true);
  13846. reservedVariables.SetLength(l);
  13847. }
  13848. ctx->type.SetVariable(descr->returnType, offset, true);
  13849. // Move the value from the return register to the variable
  13850. if( descr->returnType.GetSizeOnStackDWords() == 1 )
  13851. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)offset);
  13852. else if( descr->returnType.GetSizeOnStackDWords() == 2 )
  13853. ctx->bc.InstrSHORT(asBC_CpyRtoV8, (short)offset);
  13854. }
  13855. else
  13856. ctx->type.Set(descr->returnType);
  13857. ReleaseTemporaryVariable(tmpExpr, &ctx->bc);
  13858. ctx->type.isLValue = false;
  13859. // Clean up arguments
  13860. if( args )
  13861. AfterFunctionCall(funcId, *args, ctx, false);
  13862. ProcessDeferredParams(ctx);
  13863. }
  13864. }
  13865. // This only merges the bytecode, but doesn't modify the type of the final context
  13866. void asCCompiler::MergeExprBytecode(asCExprContext *before, asCExprContext *after)
  13867. {
  13868. before->bc.AddCode(&after->bc);
  13869. for( asUINT n = 0; n < after->deferredParams.GetLength(); n++ )
  13870. {
  13871. before->deferredParams.PushLast(after->deferredParams[n]);
  13872. after->deferredParams[n].origExpr = 0;
  13873. }
  13874. after->deferredParams.SetLength(0);
  13875. }
  13876. // This merges both bytecode and the type of the final context
  13877. void asCCompiler::MergeExprBytecodeAndType(asCExprContext *before, asCExprContext *after)
  13878. {
  13879. MergeExprBytecode(before, after);
  13880. before->Merge(after);
  13881. }
  13882. void asCCompiler::FilterConst(asCArray<int> &funcs, bool removeConst)
  13883. {
  13884. if( funcs.GetLength() == 0 ) return;
  13885. // This is only done for object methods
  13886. asCScriptFunction *desc = builder->GetFunctionDescription(funcs[0]);
  13887. if( !desc || desc->objectType == 0 ) return;
  13888. // Check if there are any non-const matches
  13889. asUINT n;
  13890. bool foundNonConst = false;
  13891. for( n = 0; n < funcs.GetLength(); n++ )
  13892. {
  13893. desc = builder->GetFunctionDescription(funcs[n]);
  13894. if( desc && desc->IsReadOnly() != removeConst )
  13895. {
  13896. foundNonConst = true;
  13897. break;
  13898. }
  13899. }
  13900. if( foundNonConst )
  13901. {
  13902. // Remove all const methods
  13903. for( n = 0; n < funcs.GetLength(); n++ )
  13904. {
  13905. desc = builder->GetFunctionDescription(funcs[n]);
  13906. if( desc && desc->IsReadOnly() == removeConst )
  13907. {
  13908. if( n == funcs.GetLength() - 1 )
  13909. funcs.PopLast();
  13910. else
  13911. funcs[n] = funcs.PopLast();
  13912. n--;
  13913. }
  13914. }
  13915. }
  13916. }
  13917. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  13918. asCExprValue::asCExprValue()
  13919. {
  13920. isTemporary = false;
  13921. stackOffset = 0;
  13922. isConstant = false;
  13923. isVariable = false;
  13924. isExplicitHandle = false;
  13925. qwordValue = 0;
  13926. isLValue = false;
  13927. isRefToLocal = false;
  13928. isRefSafe = false;
  13929. }
  13930. void asCExprValue::Set(const asCDataType &dt)
  13931. {
  13932. dataType = dt;
  13933. isTemporary = false;
  13934. stackOffset = 0;
  13935. isConstant = false;
  13936. isVariable = false;
  13937. isExplicitHandle = false;
  13938. qwordValue = 0;
  13939. isLValue = false;
  13940. isRefToLocal = false;
  13941. isRefSafe = false;
  13942. }
  13943. void asCExprValue::SetVariable(const asCDataType &in_dt, int in_stackOffset, bool in_isTemporary)
  13944. {
  13945. Set(in_dt);
  13946. this->isVariable = true;
  13947. this->isTemporary = in_isTemporary;
  13948. this->stackOffset = (short)in_stackOffset;
  13949. }
  13950. void asCExprValue::SetConstantQW(const asCDataType &dt, asQWORD value)
  13951. {
  13952. Set(dt);
  13953. isConstant = true;
  13954. SetConstantQW(value);
  13955. }
  13956. void asCExprValue::SetConstantDW(const asCDataType &dt, asDWORD value)
  13957. {
  13958. Set(dt);
  13959. isConstant = true;
  13960. SetConstantDW(value);
  13961. }
  13962. void asCExprValue::SetConstantB(const asCDataType &dt, asBYTE value)
  13963. {
  13964. Set(dt);
  13965. isConstant = true;
  13966. SetConstantB(value);
  13967. }
  13968. void asCExprValue::SetConstantW(const asCDataType &dt, asWORD value)
  13969. {
  13970. Set(dt);
  13971. isConstant = true;
  13972. SetConstantW(value);
  13973. }
  13974. void asCExprValue::SetConstantF(const asCDataType &dt, float value)
  13975. {
  13976. Set(dt);
  13977. isConstant = true;
  13978. SetConstantF(value);
  13979. }
  13980. void asCExprValue::SetConstantD(const asCDataType &dt, double value)
  13981. {
  13982. Set(dt);
  13983. isConstant = true;
  13984. SetConstantD(value);
  13985. }
  13986. void asCExprValue::SetConstantQW(asQWORD value)
  13987. {
  13988. asASSERT(dataType.GetSizeInMemoryBytes() == 8);
  13989. qwordValue = value;
  13990. }
  13991. void asCExprValue::SetConstantDW(asDWORD value)
  13992. {
  13993. asASSERT(dataType.GetSizeInMemoryBytes() == 4);
  13994. dwordValue = value;
  13995. }
  13996. void asCExprValue::SetConstantW(asWORD value)
  13997. {
  13998. asASSERT(dataType.GetSizeInMemoryBytes() == 2);
  13999. wordValue = value;
  14000. }
  14001. void asCExprValue::SetConstantB(asBYTE value)
  14002. {
  14003. asASSERT(dataType.GetSizeInMemoryBytes() == 1);
  14004. byteValue = value;
  14005. }
  14006. void asCExprValue::SetConstantF(float value)
  14007. {
  14008. asASSERT(dataType.GetSizeInMemoryBytes() == 4);
  14009. floatValue = value;
  14010. }
  14011. void asCExprValue::SetConstantD(double value)
  14012. {
  14013. asASSERT(dataType.GetSizeInMemoryBytes() == 8);
  14014. doubleValue = value;
  14015. }
  14016. asQWORD asCExprValue::GetConstantQW()
  14017. {
  14018. asASSERT(dataType.GetSizeInMemoryBytes() == 8);
  14019. return qwordValue;
  14020. }
  14021. asDWORD asCExprValue::GetConstantDW()
  14022. {
  14023. asASSERT(dataType.GetSizeInMemoryBytes() == 4);
  14024. return dwordValue;
  14025. }
  14026. asWORD asCExprValue::GetConstantW()
  14027. {
  14028. asASSERT(dataType.GetSizeInMemoryBytes() == 2);
  14029. return wordValue;
  14030. }
  14031. asBYTE asCExprValue::GetConstantB()
  14032. {
  14033. asASSERT(dataType.GetSizeInMemoryBytes() == 1);
  14034. return byteValue;
  14035. }
  14036. float asCExprValue::GetConstantF()
  14037. {
  14038. asASSERT(dataType.GetSizeInMemoryBytes() == 4);
  14039. return floatValue;
  14040. }
  14041. double asCExprValue::GetConstantD()
  14042. {
  14043. asASSERT(dataType.GetSizeInMemoryBytes() == 8);
  14044. return doubleValue;
  14045. }
  14046. void asCExprValue::SetConstantData(const asCDataType &dt, asQWORD qw)
  14047. {
  14048. Set(dt);
  14049. isConstant = true;
  14050. // This code is necessary to guarantee that the code
  14051. // works on both big endian and little endian CPUs.
  14052. if (dataType.GetSizeInMemoryBytes() == 1)
  14053. byteValue = (asBYTE)qw;
  14054. if (dataType.GetSizeInMemoryBytes() == 2)
  14055. wordValue = (asWORD)qw;
  14056. if (dataType.GetSizeInMemoryBytes() == 4)
  14057. dwordValue = (asDWORD)qw;
  14058. else
  14059. qwordValue = qw;
  14060. }
  14061. asQWORD asCExprValue::GetConstantData()
  14062. {
  14063. asQWORD qw = 0;
  14064. // This code is necessary to guarantee that the code
  14065. // works on both big endian and little endian CPUs.
  14066. if (dataType.GetSizeInMemoryBytes() == 1)
  14067. qw = byteValue;
  14068. if (dataType.GetSizeInMemoryBytes() == 2)
  14069. qw = wordValue;
  14070. if (dataType.GetSizeInMemoryBytes() == 4)
  14071. qw = dwordValue;
  14072. else
  14073. qw = qwordValue;
  14074. return qw;
  14075. }
  14076. void asCExprValue::SetUndefinedFuncHandle(asCScriptEngine *engine)
  14077. {
  14078. // This is used for when the expression evaluates to a
  14079. // function, but it is not yet known exactly which. The
  14080. // owner expression will hold the name of the function
  14081. // to determine the exact function when the signature is
  14082. // known.
  14083. Set(asCDataType::CreateObjectHandle(&engine->functionBehaviours, true));
  14084. isConstant = true;
  14085. isExplicitHandle = false;
  14086. qwordValue = 1; // Set to a different value than 0 to differentiate from null constant
  14087. isLValue = false;
  14088. }
  14089. bool asCExprValue::IsUndefinedFuncHandle() const
  14090. {
  14091. if (isConstant == false) return false;
  14092. if (qwordValue == 0) return false;
  14093. if (isLValue) return false;
  14094. if (dataType.GetTypeInfo() == 0) return false;
  14095. if (dataType.GetTypeInfo()->name != "$func") return false;
  14096. if (dataType.IsFuncdef()) return false;
  14097. return true;
  14098. }
  14099. void asCExprValue::SetNullConstant()
  14100. {
  14101. Set(asCDataType::CreateNullHandle());
  14102. isConstant = true;
  14103. isExplicitHandle = false;
  14104. qwordValue = 0;
  14105. isLValue = false;
  14106. }
  14107. bool asCExprValue::IsNullConstant() const
  14108. {
  14109. // We can't check the actual object type, because the null constant may have been cast to another type
  14110. if (isConstant && dataType.IsObjectHandle() && qwordValue == 0)
  14111. return true;
  14112. return false;
  14113. }
  14114. void asCExprValue::SetVoid()
  14115. {
  14116. Set(asCDataType::CreatePrimitive(ttVoid, false));
  14117. isLValue = false;
  14118. isConstant = true;
  14119. }
  14120. bool asCExprValue::IsVoid() const
  14121. {
  14122. if (dataType.GetTokenType() == ttVoid)
  14123. return true;
  14124. return false;
  14125. }
  14126. void asCExprValue::SetDummy()
  14127. {
  14128. SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), 0);
  14129. }
  14130. ////////////////////////////////////////////////////////////////////////////////////////////////
  14131. asCExprContext::asCExprContext(asCScriptEngine *engine) : bc(engine)
  14132. {
  14133. property_arg = 0;
  14134. Clear();
  14135. }
  14136. asCExprContext::~asCExprContext()
  14137. {
  14138. if (property_arg)
  14139. asDELETE(property_arg, asCExprContext);
  14140. }
  14141. void asCExprContext::Clear()
  14142. {
  14143. bc.ClearAll();
  14144. type.Set(asCDataType());
  14145. deferredParams.SetLength(0);
  14146. if (property_arg)
  14147. asDELETE(property_arg, asCExprContext);
  14148. property_arg = 0;
  14149. exprNode = 0;
  14150. origExpr = 0;
  14151. property_get = 0;
  14152. property_set = 0;
  14153. property_const = false;
  14154. property_handle = false;
  14155. property_ref = false;
  14156. methodName = "";
  14157. enumValue = "";
  14158. symbolNamespace = 0;
  14159. isVoidExpression = false;
  14160. isCleanArg = false;
  14161. isAnonymousInitList = false;
  14162. origCode = 0;
  14163. }
  14164. bool asCExprContext::IsClassMethod() const
  14165. {
  14166. if (type.dataType.GetTypeInfo() == 0) return false;
  14167. if (methodName == "") return false;
  14168. if (type.dataType.GetTypeInfo() == &type.dataType.GetTypeInfo()->engine->functionBehaviours) return false;
  14169. if (isAnonymousInitList) return false;
  14170. return true;
  14171. }
  14172. bool asCExprContext::IsGlobalFunc() const
  14173. {
  14174. if (type.dataType.GetTypeInfo() == 0) return false;
  14175. if (methodName == "") return false;
  14176. if (type.dataType.GetTypeInfo() != &type.dataType.GetTypeInfo()->engine->functionBehaviours) return false;
  14177. if (isAnonymousInitList) return false;
  14178. return true;
  14179. }
  14180. void asCExprContext::SetLambda(asCScriptNode *funcDecl)
  14181. {
  14182. asASSERT(funcDecl && funcDecl->nodeType == snFunction);
  14183. asASSERT(bc.GetLastInstr() == -1);
  14184. Clear();
  14185. type.SetUndefinedFuncHandle(bc.GetEngine());
  14186. exprNode = funcDecl;
  14187. }
  14188. bool asCExprContext::IsLambda() const
  14189. {
  14190. if (type.IsUndefinedFuncHandle() && exprNode && exprNode->nodeType == snFunction)
  14191. return true;
  14192. return false;
  14193. }
  14194. void asCExprContext::SetVoidExpression()
  14195. {
  14196. Clear();
  14197. type.SetVoid();
  14198. isVoidExpression = true;
  14199. }
  14200. bool asCExprContext::IsVoidExpression() const
  14201. {
  14202. if (isVoidExpression && type.IsVoid() && exprNode == 0)
  14203. return true;
  14204. return false;
  14205. }
  14206. void asCExprContext::SetAnonymousInitList(asCScriptNode *initList, asCScriptCode *script)
  14207. {
  14208. Clear();
  14209. exprNode = initList;
  14210. origCode = script;
  14211. isAnonymousInitList = true;
  14212. }
  14213. bool asCExprContext::IsAnonymousInitList() const
  14214. {
  14215. if (isAnonymousInitList && exprNode && exprNode->nodeType == snInitList)
  14216. return true;
  14217. return false;
  14218. }
  14219. void asCExprContext::Copy(asCExprContext *other)
  14220. {
  14221. type = other->type;
  14222. property_get = other->property_get;
  14223. property_set = other->property_set;
  14224. property_const = other->property_const;
  14225. property_handle = other->property_handle;
  14226. property_ref = other->property_ref;
  14227. property_arg = other->property_arg;
  14228. exprNode = other->exprNode;
  14229. methodName = other->methodName;
  14230. enumValue = other->enumValue;
  14231. isVoidExpression = other->isVoidExpression;
  14232. isCleanArg = other->isCleanArg;
  14233. isAnonymousInitList = other->isAnonymousInitList;
  14234. origCode = other->origCode;
  14235. // Do not copy the origExpr member
  14236. }
  14237. void asCExprContext::Merge(asCExprContext *after)
  14238. {
  14239. // Overwrite properties with the expression that comes after
  14240. Copy(after);
  14241. // Clean the properties in 'after' that have now moved into
  14242. // this structure so they are not cleaned up accidentally
  14243. after->property_arg = 0;
  14244. }
  14245. END_AS_NAMESPACE
  14246. #endif // AS_NO_COMPILER