as_compiler.cpp 475 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871987298739874987598769877987898799880988198829883988498859886988798889889989098919892989398949895989698979898989999009901990299039904990599069907990899099910991199129913991499159916991799189919992099219922992399249925992699279928992999309931993299339934993599369937993899399940994199429943994499459946994799489949995099519952995399549955995699579958995999609961996299639964996599669967996899699970997199729973997499759976997799789979998099819982998399849985998699879988998999909991999299939994999599969997999899991000010001100021000310004100051000610007100081000910010100111001210013100141001510016100171001810019100201002110022100231002410025100261002710028100291003010031100321003310034100351003610037100381003910040100411004210043100441004510046100471004810049100501005110052100531005410055100561005710058100591006010061100621006310064100651006610067100681006910070100711007210073100741007510076100771007810079100801008110082100831008410085100861008710088100891009010091100921009310094100951009610097100981009910100101011010210103101041010510106101071010810109101101011110112101131011410115101161011710118101191012010121101221012310124101251012610127101281012910130101311013210133101341013510136101371013810139101401014110142101431014410145101461014710148101491015010151101521015310154101551015610157101581015910160101611016210163101641016510166101671016810169101701017110172101731017410175101761017710178101791018010181101821018310184101851018610187101881018910190101911019210193101941019510196101971019810199102001020110202102031020410205102061020710208102091021010211102121021310214102151021610217102181021910220102211022210223102241022510226102271022810229102301023110232102331023410235102361023710238102391024010241102421024310244102451024610247102481024910250102511025210253102541025510256102571025810259102601026110262102631026410265102661026710268102691027010271102721027310274102751027610277102781027910280102811028210283102841028510286102871028810289102901029110292102931029410295102961029710298102991030010301103021030310304103051030610307103081030910310103111031210313103141031510316103171031810319103201032110322103231032410325103261032710328103291033010331103321033310334103351033610337103381033910340103411034210343103441034510346103471034810349103501035110352103531035410355103561035710358103591036010361103621036310364103651036610367103681036910370103711037210373103741037510376103771037810379103801038110382103831038410385103861038710388103891039010391103921039310394103951039610397103981039910400104011040210403104041040510406104071040810409104101041110412104131041410415104161041710418104191042010421104221042310424104251042610427104281042910430104311043210433104341043510436104371043810439104401044110442104431044410445104461044710448104491045010451104521045310454104551045610457104581045910460104611046210463104641046510466104671046810469104701047110472104731047410475104761047710478104791048010481104821048310484104851048610487104881048910490104911049210493104941049510496104971049810499105001050110502105031050410505105061050710508105091051010511105121051310514105151051610517105181051910520105211052210523105241052510526105271052810529105301053110532105331053410535105361053710538105391054010541105421054310544105451054610547105481054910550105511055210553105541055510556105571055810559105601056110562105631056410565105661056710568105691057010571105721057310574105751057610577105781057910580105811058210583105841058510586105871058810589105901059110592105931059410595105961059710598105991060010601106021060310604106051060610607106081060910610106111061210613106141061510616106171061810619106201062110622106231062410625106261062710628106291063010631106321063310634106351063610637106381063910640106411064210643106441064510646106471064810649106501065110652106531065410655106561065710658106591066010661106621066310664106651066610667106681066910670106711067210673106741067510676106771067810679106801068110682106831068410685106861068710688106891069010691106921069310694106951069610697106981069910700107011070210703107041070510706107071070810709107101071110712107131071410715107161071710718107191072010721107221072310724107251072610727107281072910730107311073210733107341073510736107371073810739107401074110742107431074410745107461074710748107491075010751107521075310754107551075610757107581075910760107611076210763107641076510766107671076810769107701077110772107731077410775107761077710778107791078010781107821078310784107851078610787107881078910790107911079210793107941079510796107971079810799108001080110802108031080410805108061080710808108091081010811108121081310814108151081610817108181081910820108211082210823108241082510826108271082810829108301083110832108331083410835108361083710838108391084010841108421084310844108451084610847108481084910850108511085210853108541085510856108571085810859108601086110862108631086410865108661086710868108691087010871108721087310874108751087610877108781087910880108811088210883108841088510886108871088810889108901089110892108931089410895108961089710898108991090010901109021090310904109051090610907109081090910910109111091210913109141091510916109171091810919109201092110922109231092410925109261092710928109291093010931109321093310934109351093610937109381093910940109411094210943109441094510946109471094810949109501095110952109531095410955109561095710958109591096010961109621096310964109651096610967109681096910970109711097210973109741097510976109771097810979109801098110982109831098410985109861098710988109891099010991109921099310994109951099610997109981099911000110011100211003110041100511006110071100811009110101101111012110131101411015110161101711018110191102011021110221102311024110251102611027110281102911030110311103211033110341103511036110371103811039110401104111042110431104411045110461104711048110491105011051110521105311054110551105611057110581105911060110611106211063110641106511066110671106811069110701107111072110731107411075110761107711078110791108011081110821108311084110851108611087110881108911090110911109211093110941109511096110971109811099111001110111102111031110411105111061110711108111091111011111111121111311114111151111611117111181111911120111211112211123111241112511126111271112811129111301113111132111331113411135111361113711138111391114011141111421114311144111451114611147111481114911150111511115211153111541115511156111571115811159111601116111162111631116411165111661116711168111691117011171111721117311174111751117611177111781117911180111811118211183111841118511186111871118811189111901119111192111931119411195111961119711198111991120011201112021120311204112051120611207112081120911210112111121211213112141121511216112171121811219112201122111222112231122411225112261122711228112291123011231112321123311234112351123611237112381123911240112411124211243112441124511246112471124811249112501125111252112531125411255112561125711258112591126011261112621126311264112651126611267112681126911270112711127211273112741127511276112771127811279112801128111282112831128411285112861128711288112891129011291112921129311294112951129611297112981129911300113011130211303113041130511306113071130811309113101131111312113131131411315113161131711318113191132011321113221132311324113251132611327113281132911330113311133211333113341133511336113371133811339113401134111342113431134411345113461134711348113491135011351113521135311354113551135611357113581135911360113611136211363113641136511366113671136811369113701137111372113731137411375113761137711378113791138011381113821138311384113851138611387113881138911390113911139211393113941139511396113971139811399114001140111402114031140411405114061140711408114091141011411114121141311414114151141611417114181141911420114211142211423114241142511426114271142811429114301143111432114331143411435114361143711438114391144011441114421144311444114451144611447114481144911450114511145211453114541145511456114571145811459114601146111462114631146411465114661146711468114691147011471114721147311474114751147611477114781147911480114811148211483114841148511486114871148811489114901149111492114931149411495114961149711498114991150011501115021150311504115051150611507115081150911510115111151211513115141151511516115171151811519115201152111522115231152411525115261152711528115291153011531115321153311534115351153611537115381153911540115411154211543115441154511546115471154811549115501155111552115531155411555115561155711558115591156011561115621156311564115651156611567115681156911570115711157211573115741157511576115771157811579115801158111582115831158411585115861158711588115891159011591115921159311594115951159611597115981159911600116011160211603116041160511606116071160811609116101161111612116131161411615116161161711618116191162011621116221162311624116251162611627116281162911630116311163211633116341163511636116371163811639116401164111642116431164411645116461164711648116491165011651116521165311654116551165611657116581165911660116611166211663116641166511666116671166811669116701167111672116731167411675116761167711678116791168011681116821168311684116851168611687116881168911690116911169211693116941169511696116971169811699117001170111702117031170411705117061170711708117091171011711117121171311714117151171611717117181171911720117211172211723117241172511726117271172811729117301173111732117331173411735117361173711738117391174011741117421174311744117451174611747117481174911750117511175211753117541175511756117571175811759117601176111762117631176411765117661176711768117691177011771117721177311774117751177611777117781177911780117811178211783117841178511786117871178811789117901179111792117931179411795117961179711798117991180011801118021180311804118051180611807118081180911810118111181211813118141181511816118171181811819118201182111822118231182411825118261182711828118291183011831118321183311834118351183611837118381183911840118411184211843118441184511846118471184811849118501185111852118531185411855118561185711858118591186011861118621186311864118651186611867118681186911870118711187211873118741187511876118771187811879118801188111882118831188411885118861188711888118891189011891118921189311894118951189611897118981189911900119011190211903119041190511906119071190811909119101191111912119131191411915119161191711918119191192011921119221192311924119251192611927119281192911930119311193211933119341193511936119371193811939119401194111942119431194411945119461194711948119491195011951119521195311954119551195611957119581195911960119611196211963119641196511966119671196811969119701197111972119731197411975119761197711978119791198011981119821198311984119851198611987119881198911990119911199211993119941199511996119971199811999120001200112002120031200412005120061200712008120091201012011120121201312014120151201612017120181201912020120211202212023120241202512026120271202812029120301203112032120331203412035120361203712038120391204012041120421204312044120451204612047120481204912050120511205212053120541205512056120571205812059120601206112062120631206412065120661206712068120691207012071120721207312074120751207612077120781207912080120811208212083120841208512086120871208812089120901209112092120931209412095120961209712098120991210012101121021210312104121051210612107121081210912110121111211212113121141211512116121171211812119121201212112122121231212412125121261212712128121291213012131121321213312134121351213612137121381213912140121411214212143121441214512146121471214812149121501215112152121531215412155121561215712158121591216012161121621216312164121651216612167121681216912170121711217212173121741217512176121771217812179121801218112182121831218412185121861218712188121891219012191121921219312194121951219612197121981219912200122011220212203122041220512206122071220812209122101221112212122131221412215122161221712218122191222012221122221222312224122251222612227122281222912230122311223212233122341223512236122371223812239122401224112242122431224412245122461224712248122491225012251122521225312254122551225612257122581225912260122611226212263122641226512266122671226812269122701227112272122731227412275122761227712278122791228012281122821228312284122851228612287122881228912290122911229212293122941229512296122971229812299123001230112302123031230412305123061230712308123091231012311123121231312314123151231612317123181231912320123211232212323123241232512326123271232812329123301233112332123331233412335123361233712338123391234012341123421234312344123451234612347123481234912350123511235212353123541235512356123571235812359123601236112362123631236412365123661236712368123691237012371123721237312374123751237612377123781237912380123811238212383123841238512386123871238812389123901239112392123931239412395123961239712398123991240012401124021240312404124051240612407124081240912410124111241212413124141241512416124171241812419124201242112422124231242412425124261242712428124291243012431124321243312434124351243612437124381243912440124411244212443124441244512446124471244812449124501245112452124531245412455124561245712458124591246012461124621246312464124651246612467124681246912470124711247212473124741247512476124771247812479124801248112482124831248412485124861248712488124891249012491124921249312494124951249612497124981249912500125011250212503125041250512506125071250812509125101251112512125131251412515125161251712518125191252012521125221252312524125251252612527125281252912530125311253212533125341253512536125371253812539125401254112542125431254412545125461254712548125491255012551125521255312554125551255612557125581255912560125611256212563125641256512566125671256812569125701257112572125731257412575125761257712578125791258012581125821258312584125851258612587125881258912590125911259212593125941259512596125971259812599126001260112602126031260412605126061260712608126091261012611126121261312614126151261612617126181261912620126211262212623126241262512626126271262812629126301263112632126331263412635126361263712638126391264012641126421264312644126451264612647126481264912650126511265212653126541265512656126571265812659126601266112662126631266412665126661266712668126691267012671126721267312674126751267612677126781267912680126811268212683126841268512686126871268812689126901269112692126931269412695126961269712698126991270012701127021270312704127051270612707127081270912710127111271212713127141271512716127171271812719127201272112722127231272412725127261272712728127291273012731127321273312734127351273612737127381273912740127411274212743127441274512746127471274812749127501275112752127531275412755127561275712758127591276012761127621276312764127651276612767127681276912770127711277212773127741277512776127771277812779127801278112782127831278412785127861278712788127891279012791127921279312794127951279612797127981279912800128011280212803128041280512806128071280812809128101281112812128131281412815128161281712818128191282012821128221282312824128251282612827128281282912830128311283212833128341283512836128371283812839128401284112842128431284412845128461284712848128491285012851128521285312854128551285612857128581285912860128611286212863128641286512866128671286812869128701287112872128731287412875128761287712878128791288012881128821288312884128851288612887128881288912890128911289212893128941289512896128971289812899129001290112902129031290412905129061290712908129091291012911129121291312914129151291612917129181291912920129211292212923129241292512926129271292812929129301293112932129331293412935129361293712938129391294012941129421294312944129451294612947129481294912950129511295212953129541295512956129571295812959129601296112962129631296412965129661296712968129691297012971129721297312974129751297612977129781297912980129811298212983129841298512986129871298812989129901299112992129931299412995129961299712998129991300013001130021300313004130051300613007130081300913010130111301213013130141301513016130171301813019130201302113022130231302413025130261302713028130291303013031130321303313034130351303613037130381303913040130411304213043130441304513046130471304813049130501305113052130531305413055130561305713058130591306013061130621306313064130651306613067130681306913070130711307213073130741307513076130771307813079130801308113082130831308413085130861308713088130891309013091130921309313094130951309613097130981309913100131011310213103131041310513106131071310813109131101311113112131131311413115131161311713118131191312013121131221312313124131251312613127131281312913130131311313213133131341313513136131371313813139131401314113142131431314413145131461314713148131491315013151131521315313154131551315613157131581315913160131611316213163131641316513166131671316813169131701317113172131731317413175131761317713178131791318013181131821318313184131851318613187131881318913190131911319213193131941319513196131971319813199132001320113202132031320413205132061320713208132091321013211132121321313214132151321613217132181321913220132211322213223132241322513226132271322813229132301323113232132331323413235132361323713238132391324013241132421324313244132451324613247132481324913250132511325213253132541325513256132571325813259132601326113262132631326413265132661326713268132691327013271132721327313274132751327613277132781327913280132811328213283132841328513286132871328813289132901329113292132931329413295132961329713298132991330013301133021330313304133051330613307133081330913310133111331213313133141331513316133171331813319133201332113322133231332413325133261332713328133291333013331133321333313334133351333613337133381333913340133411334213343133441334513346133471334813349133501335113352133531335413355133561335713358133591336013361133621336313364133651336613367133681336913370133711337213373133741337513376133771337813379133801338113382133831338413385133861338713388133891339013391133921339313394133951339613397133981339913400134011340213403134041340513406134071340813409134101341113412134131341413415134161341713418134191342013421134221342313424134251342613427134281342913430134311343213433134341343513436134371343813439134401344113442134431344413445134461344713448134491345013451134521345313454134551345613457134581345913460134611346213463134641346513466134671346813469134701347113472134731347413475134761347713478134791348013481134821348313484134851348613487134881348913490134911349213493134941349513496134971349813499135001350113502135031350413505135061350713508135091351013511135121351313514135151351613517135181351913520135211352213523135241352513526135271352813529135301353113532135331353413535135361353713538135391354013541135421354313544135451354613547135481354913550135511355213553135541355513556135571355813559135601356113562135631356413565135661356713568135691357013571135721357313574135751357613577135781357913580135811358213583135841358513586135871358813589135901359113592135931359413595135961359713598135991360013601136021360313604136051360613607136081360913610136111361213613136141361513616136171361813619136201362113622136231362413625136261362713628136291363013631136321363313634136351363613637136381363913640136411364213643136441364513646136471364813649136501365113652136531365413655136561365713658136591366013661136621366313664136651366613667136681366913670136711367213673136741367513676136771367813679136801368113682136831368413685136861368713688136891369013691136921369313694136951369613697136981369913700137011370213703137041370513706137071370813709137101371113712137131371413715137161371713718137191372013721137221372313724137251372613727137281372913730137311373213733137341373513736137371373813739137401374113742137431374413745137461374713748137491375013751137521375313754137551375613757137581375913760137611376213763137641376513766137671376813769137701377113772137731377413775137761377713778137791378013781137821378313784137851378613787137881378913790137911379213793137941379513796137971379813799138001380113802138031380413805138061380713808138091381013811138121381313814138151381613817138181381913820138211382213823138241382513826138271382813829138301383113832138331383413835138361383713838138391384013841138421384313844138451384613847138481384913850138511385213853138541385513856138571385813859138601386113862138631386413865138661386713868138691387013871138721387313874138751387613877138781387913880138811388213883138841388513886138871388813889138901389113892138931389413895138961389713898138991390013901139021390313904139051390613907139081390913910139111391213913139141391513916139171391813919139201392113922139231392413925139261392713928139291393013931139321393313934139351393613937139381393913940139411394213943139441394513946139471394813949139501395113952139531395413955139561395713958139591396013961139621396313964139651396613967139681396913970139711397213973139741397513976139771397813979139801398113982139831398413985139861398713988139891399013991139921399313994139951399613997139981399914000140011400214003140041400514006140071400814009140101401114012140131401414015140161401714018140191402014021140221402314024140251402614027140281402914030140311403214033140341403514036140371403814039140401404114042140431404414045140461404714048140491405014051140521405314054140551405614057140581405914060140611406214063140641406514066140671406814069140701407114072140731407414075140761407714078140791408014081140821408314084140851408614087140881408914090140911409214093140941409514096140971409814099141001410114102141031410414105141061410714108141091411014111141121411314114141151411614117141181411914120141211412214123141241412514126141271412814129141301413114132141331413414135141361413714138141391414014141141421414314144141451414614147141481414914150141511415214153141541415514156141571415814159141601416114162141631416414165141661416714168141691417014171141721417314174141751417614177141781417914180141811418214183141841418514186141871418814189141901419114192141931419414195141961419714198141991420014201142021420314204142051420614207142081420914210142111421214213142141421514216142171421814219142201422114222142231422414225142261422714228142291423014231142321423314234142351423614237142381423914240142411424214243142441424514246142471424814249142501425114252142531425414255142561425714258142591426014261142621426314264142651426614267142681426914270142711427214273142741427514276142771427814279142801428114282142831428414285142861428714288142891429014291142921429314294142951429614297142981429914300143011430214303143041430514306143071430814309143101431114312143131431414315143161431714318143191432014321143221432314324143251432614327143281432914330143311433214333143341433514336143371433814339143401434114342143431434414345143461434714348143491435014351143521435314354143551435614357143581435914360143611436214363143641436514366143671436814369143701437114372143731437414375143761437714378143791438014381143821438314384143851438614387143881438914390143911439214393143941439514396143971439814399144001440114402144031440414405144061440714408144091441014411144121441314414144151441614417144181441914420144211442214423144241442514426144271442814429144301443114432144331443414435144361443714438144391444014441144421444314444144451444614447144481444914450144511445214453144541445514456144571445814459144601446114462144631446414465144661446714468144691447014471144721447314474144751447614477144781447914480144811448214483144841448514486144871448814489144901449114492144931449414495144961449714498144991450014501145021450314504145051450614507145081450914510145111451214513145141451514516145171451814519145201452114522145231452414525145261452714528145291453014531145321453314534145351453614537145381453914540145411454214543145441454514546145471454814549145501455114552145531455414555145561455714558145591456014561145621456314564145651456614567145681456914570145711457214573145741457514576145771457814579145801458114582145831458414585145861458714588145891459014591145921459314594145951459614597145981459914600146011460214603146041460514606146071460814609146101461114612146131461414615146161461714618146191462014621146221462314624146251462614627146281462914630146311463214633146341463514636146371463814639146401464114642146431464414645146461464714648146491465014651146521465314654146551465614657146581465914660146611466214663146641466514666146671466814669146701467114672146731467414675146761467714678146791468014681146821468314684146851468614687146881468914690146911469214693146941469514696146971469814699147001470114702147031470414705147061470714708147091471014711147121471314714147151471614717147181471914720147211472214723147241472514726147271472814729147301473114732147331473414735147361473714738147391474014741147421474314744147451474614747147481474914750147511475214753147541475514756147571475814759147601476114762147631476414765147661476714768147691477014771147721477314774147751477614777147781477914780147811478214783147841478514786147871478814789147901479114792147931479414795147961479714798147991480014801148021480314804148051480614807148081480914810148111481214813148141481514816148171481814819148201482114822148231482414825148261482714828148291483014831148321483314834148351483614837148381483914840148411484214843148441484514846148471484814849148501485114852148531485414855148561485714858148591486014861148621486314864148651486614867148681486914870148711487214873148741487514876148771487814879148801488114882148831488414885148861488714888148891489014891148921489314894148951489614897148981489914900149011490214903149041490514906149071490814909149101491114912149131491414915149161491714918149191492014921149221492314924149251492614927149281492914930149311493214933149341493514936149371493814939149401494114942149431494414945149461494714948149491495014951149521495314954149551495614957149581495914960149611496214963149641496514966149671496814969149701497114972149731497414975149761497714978149791498014981149821498314984149851498614987149881498914990149911499214993149941499514996149971499814999150001500115002150031500415005150061500715008150091501015011150121501315014150151501615017150181501915020150211502215023150241502515026150271502815029150301503115032150331503415035150361503715038150391504015041150421504315044150451504615047150481504915050150511505215053150541505515056150571505815059150601506115062150631506415065150661506715068150691507015071150721507315074150751507615077150781507915080150811508215083150841508515086150871508815089150901509115092150931509415095150961509715098150991510015101151021510315104151051510615107151081510915110151111511215113151141511515116151171511815119151201512115122151231512415125151261512715128151291513015131151321513315134151351513615137151381513915140151411514215143151441514515146151471514815149151501515115152151531515415155151561515715158151591516015161151621516315164151651516615167151681516915170151711517215173151741517515176151771517815179151801518115182151831518415185151861518715188151891519015191151921519315194151951519615197151981519915200152011520215203152041520515206152071520815209152101521115212152131521415215152161521715218152191522015221152221522315224152251522615227152281522915230152311523215233152341523515236152371523815239152401524115242152431524415245152461524715248152491525015251152521525315254152551525615257152581525915260152611526215263152641526515266152671526815269152701527115272152731527415275152761527715278152791528015281152821528315284152851528615287152881528915290152911529215293152941529515296152971529815299
  1. /*
  2. AngelCode Scripting Library
  3. Copyright (c) 2003-2017 Andreas Jonsson
  4. This software is provided 'as-is', without any express or implied
  5. warranty. In no event will the authors be held liable for any
  6. damages arising from the use of this software.
  7. Permission is granted to anyone to use this software for any
  8. purpose, including commercial applications, and to alter it and
  9. redistribute it freely, subject to the following restrictions:
  10. 1. The origin of this software must not be misrepresented; you
  11. must not claim that you wrote the original software. If you use
  12. this software in a product, an acknowledgment in the product
  13. documentation would be appreciated but is not required.
  14. 2. Altered source versions must be plainly marked as such, and
  15. must not be misrepresented as being the original software.
  16. 3. This notice may not be removed or altered from any source
  17. distribution.
  18. The original version of this library can be located at:
  19. http://www.angelcode.com/angelscript/
  20. Andreas Jonsson
  21. [email protected]
  22. */
  23. // Modified by Lasse Oorni for Urho3D
  24. //
  25. // as_compiler.cpp
  26. //
  27. // The class that does the actual compilation of the functions
  28. //
  29. #include <math.h> // fmodf() pow()
  30. #include "as_config.h"
  31. #ifndef AS_NO_COMPILER
  32. #include "as_compiler.h"
  33. #include "as_tokendef.h"
  34. #include "as_tokenizer.h"
  35. #include "as_string_util.h"
  36. #include "as_texts.h"
  37. #include "as_parser.h"
  38. #include "as_debug.h"
  39. #include "as_context.h" // as_powi()
  40. BEGIN_AS_NAMESPACE
  41. //
  42. // The calling convention rules for script functions:
  43. // - If a class method returns a reference, the caller must guarantee the object pointer stays alive until the function returns, and the reference is no longer going to be used
  44. // - If a class method doesn't return a reference, it must guarantee by itself that the this pointer stays alive during the function call. If no outside access is made, then the function is guaranteed to stay alive and nothing needs to be done
  45. // - The object pointer is always passed as the first argument, position 0
  46. // - If the function returns a value type the caller must reserve the memory for this and pass the pointer as the first argument after the object pointer
  47. //
  48. // TODO: I must correct the interpretation of a reference to objects in the compiler.
  49. // A reference should mean that a pointer to the object is on the stack.
  50. // No expression should end up as non-references to objects, as the actual object is
  51. // never put on the stack.
  52. // Local variables are declared as non-references, but the expression should be a reference to the variable.
  53. // Function parameters of called functions can also be non-references, but in that case it means the
  54. // object will be passed by value (currently on the heap, which will be moved to the application stack).
  55. //
  56. // The compiler shouldn't use the asCDataType::IsReference. The datatype should always be stored as non-references.
  57. // Instead the compiler should keep track of references in TypeInfo, where it should also state how the reference
  58. // is currently stored, i.e. in variable, in register, on stack, etc.
  59. asCCompiler::asCCompiler(asCScriptEngine *engine) : byteCode(engine)
  60. {
  61. builder = 0;
  62. script = 0;
  63. variables = 0;
  64. isProcessingDeferredParams = false;
  65. isCompilingDefaultArg = false;
  66. noCodeOutput = 0;
  67. }
  68. asCCompiler::~asCCompiler()
  69. {
  70. while( variables )
  71. {
  72. asCVariableScope *var = variables;
  73. variables = variables->parent;
  74. asDELETE(var,asCVariableScope);
  75. }
  76. }
  77. void asCCompiler::Reset(asCBuilder *in_builder, asCScriptCode *in_script, asCScriptFunction *in_outFunc)
  78. {
  79. this->builder = in_builder;
  80. this->engine = in_builder->engine;
  81. this->script = in_script;
  82. this->outFunc = in_outFunc;
  83. hasCompileErrors = false;
  84. m_isConstructor = false;
  85. m_isConstructorCalled = false;
  86. m_classDecl = 0;
  87. m_globalVar = 0;
  88. nextLabel = 0;
  89. breakLabels.SetLength(0);
  90. continueLabels.SetLength(0);
  91. numLambdas = 0;
  92. byteCode.ClearAll();
  93. }
  94. int asCCompiler::CompileDefaultConstructor(asCBuilder *in_builder, asCScriptCode *in_script, asCScriptNode *in_node, asCScriptFunction *in_outFunc, sClassDeclaration *in_classDecl)
  95. {
  96. Reset(in_builder, in_script, in_outFunc);
  97. m_classDecl = in_classDecl;
  98. // Insert a JitEntry at the start of the function for JIT compilers
  99. byteCode.InstrPTR(asBC_JitEntry, 0);
  100. // Add a variable scope that might be needed to declare dummy variables
  101. // in case the member initialization refers to undefined symbols.
  102. AddVariableScope();
  103. // Initialize the class members that have no explicit expression first. This will allow the
  104. // base class' constructor to access these members without worry they will be uninitialized.
  105. // This can happen if the base class' constructor calls a method that is overridden by the derived class
  106. CompileMemberInitialization(&byteCode, true);
  107. // If the class is derived from another, then the base class' default constructor must be called
  108. if( outFunc->objectType->derivedFrom )
  109. {
  110. // Make sure the base class really has a default constructor
  111. if( outFunc->objectType->derivedFrom->beh.construct == 0 )
  112. Error(TEXT_BASE_DOESNT_HAVE_DEF_CONSTR, in_node);
  113. // Call the base class' default constructor
  114. byteCode.InstrSHORT(asBC_PSF, 0);
  115. byteCode.Instr(asBC_RDSPtr);
  116. byteCode.Call(asBC_CALL, outFunc->objectType->derivedFrom->beh.construct, AS_PTR_SIZE);
  117. }
  118. // Initialize the class members that explicit expressions afterwards. This allow the expressions
  119. // to access the base class members without worry they will be uninitialized
  120. CompileMemberInitialization(&byteCode, false);
  121. byteCode.OptimizeLocally(tempVariableOffsets);
  122. // If there are compile errors, there is no reason to build the final code
  123. if( hasCompileErrors )
  124. return -1;
  125. // Pop the object pointer from the stack
  126. byteCode.Ret(AS_PTR_SIZE);
  127. // Count total variable size
  128. int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1;
  129. outFunc->scriptData->variableSpace = varSize;
  130. FinalizeFunction();
  131. #ifdef AS_DEBUG
  132. // DEBUG: output byte code
  133. byteCode.DebugOutput(("__" + outFunc->objectType->name + "_" + outFunc->name + "__defconstr.txt").AddressOf(), in_outFunc);
  134. #endif
  135. return 0;
  136. }
  137. int asCCompiler::CompileFactory(asCBuilder *in_builder, asCScriptCode *in_script, asCScriptFunction *in_outFunc)
  138. {
  139. Reset(in_builder, in_script, in_outFunc);
  140. // Insert a JitEntry at the start of the function for JIT compilers
  141. byteCode.InstrPTR(asBC_JitEntry, 0);
  142. // Find the corresponding constructor
  143. asCDataType dt = asCDataType::CreateType(outFunc->returnType.GetTypeInfo(), false);
  144. int constructor = 0;
  145. for( unsigned int n = 0; n < dt.GetBehaviour()->factories.GetLength(); n++ )
  146. {
  147. if( dt.GetBehaviour()->factories[n] == outFunc->id )
  148. {
  149. constructor = dt.GetBehaviour()->constructors[n];
  150. break;
  151. }
  152. }
  153. // Allocate the class and instantiate it with the constructor
  154. int varOffset = AllocateVariable(dt, true);
  155. outFunc->scriptData->variableSpace = AS_PTR_SIZE;
  156. byteCode.InstrSHORT(asBC_PSF, (short)varOffset);
  157. // Copy all arguments to the top of the stack
  158. // TODO: runtime optimize: Might be interesting to have a specific instruction for copying all arguments
  159. int offset = (int)outFunc->GetSpaceNeededForArguments();
  160. for( int a = int(outFunc->parameterTypes.GetLength()) - 1; a >= 0; a-- )
  161. {
  162. if( !outFunc->parameterTypes[a].IsPrimitive() ||
  163. outFunc->parameterTypes[a].IsReference() )
  164. {
  165. offset -= AS_PTR_SIZE;
  166. byteCode.InstrSHORT(asBC_PshVPtr, short(-offset));
  167. }
  168. else
  169. {
  170. if( outFunc->parameterTypes[a].GetSizeOnStackDWords() == 2 )
  171. {
  172. offset -= 2;
  173. byteCode.InstrSHORT(asBC_PshV8, short(-offset));
  174. }
  175. else
  176. {
  177. offset -= 1;
  178. byteCode.InstrSHORT(asBC_PshV4, short(-offset));
  179. }
  180. }
  181. }
  182. int argDwords = (int)outFunc->GetSpaceNeededForArguments();
  183. byteCode.Alloc(asBC_ALLOC, dt.GetTypeInfo(), constructor, argDwords + AS_PTR_SIZE);
  184. // Return a handle to the newly created object
  185. byteCode.InstrSHORT(asBC_LOADOBJ, (short)varOffset);
  186. byteCode.Ret(argDwords);
  187. FinalizeFunction();
  188. // Tell the virtual machine not to clean up parameters on exception
  189. outFunc->dontCleanUpOnException = true;
  190. /*
  191. #ifdef AS_DEBUG
  192. // DEBUG: output byte code
  193. asCString args;
  194. args.Format("%d", outFunc->parameterTypes.GetLength());
  195. byteCode.DebugOutput(("__" + outFunc->name + "__factory" + args + ".txt").AddressOf(), engine);
  196. #endif
  197. */
  198. return 0;
  199. }
  200. void asCCompiler::FinalizeFunction()
  201. {
  202. TimeIt("asCCompiler::FinalizeFunction");
  203. asASSERT( outFunc->scriptData );
  204. asUINT n;
  205. // Finalize the bytecode
  206. byteCode.Finalize(tempVariableOffsets);
  207. byteCode.ExtractObjectVariableInfo(outFunc);
  208. // Compile the list of object variables for the exception handler
  209. // Start with the variables allocated on the heap, and then the ones allocated on the stack
  210. for( n = 0; n < variableAllocations.GetLength(); n++ )
  211. {
  212. if( (variableAllocations[n].IsObject() || variableAllocations[n].IsFuncdef()) && !variableAllocations[n].IsReference() )
  213. {
  214. if( variableIsOnHeap[n] )
  215. {
  216. outFunc->scriptData->objVariableTypes.PushLast(variableAllocations[n].GetTypeInfo());
  217. outFunc->scriptData->objVariablePos.PushLast(GetVariableOffset(n));
  218. }
  219. }
  220. }
  221. outFunc->scriptData->objVariablesOnHeap = asUINT(outFunc->scriptData->objVariablePos.GetLength());
  222. for( n = 0; n < variableAllocations.GetLength(); n++ )
  223. {
  224. if( (variableAllocations[n].IsObject() || variableAllocations[n].IsFuncdef()) && !variableAllocations[n].IsReference() )
  225. {
  226. if( !variableIsOnHeap[n] )
  227. {
  228. outFunc->scriptData->objVariableTypes.PushLast(variableAllocations[n].GetTypeInfo());
  229. outFunc->scriptData->objVariablePos.PushLast(GetVariableOffset(n));
  230. }
  231. }
  232. }
  233. // Copy byte code to the function
  234. asASSERT( outFunc->scriptData->byteCode.GetLength() == 0 );
  235. outFunc->scriptData->byteCode.SetLength(byteCode.GetSize());
  236. byteCode.Output(outFunc->scriptData->byteCode.AddressOf());
  237. outFunc->AddReferences();
  238. outFunc->scriptData->stackNeeded = byteCode.largestStackUsed + outFunc->scriptData->variableSpace;
  239. outFunc->scriptData->lineNumbers = byteCode.lineNumbers;
  240. // Extract the script section indexes too if there are any entries that are different from the function's script section
  241. int lastIdx = outFunc->scriptData->scriptSectionIdx;
  242. for( n = 0; n < byteCode.sectionIdxs.GetLength(); n++ )
  243. {
  244. if( byteCode.sectionIdxs[n] != lastIdx )
  245. {
  246. lastIdx = byteCode.sectionIdxs[n];
  247. outFunc->scriptData->sectionIdxs.PushLast(byteCode.lineNumbers[n*2]);
  248. outFunc->scriptData->sectionIdxs.PushLast(lastIdx);
  249. }
  250. }
  251. }
  252. // internal
  253. int asCCompiler::SetupParametersAndReturnVariable(asCArray<asCString> &parameterNames, asCScriptNode *func)
  254. {
  255. int stackPos = 0;
  256. if( outFunc->objectType )
  257. stackPos = -AS_PTR_SIZE; // The first parameter is the pointer to the object
  258. // Add the first variable scope, which the parameters and
  259. // variables declared in the outermost statement block is
  260. // part of.
  261. AddVariableScope();
  262. bool isDestructor = false;
  263. asCDataType returnType;
  264. // Examine return type
  265. returnType = outFunc->returnType;
  266. // Check if this is a constructor or destructor
  267. if( returnType.GetTokenType() == ttVoid && outFunc->objectType )
  268. {
  269. if( outFunc->name[0] == '~' )
  270. isDestructor = true;
  271. else if( outFunc->objectType->name == outFunc->name )
  272. m_isConstructor = true;
  273. }
  274. // Is the return type allowed?
  275. if( returnType != asCDataType::CreatePrimitive(ttVoid, false) &&
  276. !returnType.CanBeInstantiated() )
  277. {
  278. // TODO: Hasn't this been validated by the builder already?
  279. asCString str;
  280. str.Format(TXT_RETURN_CANT_BE_s, returnType.Format(outFunc->nameSpace).AddressOf());
  281. Error(str, func);
  282. }
  283. // If the return type is a value type returned by value the address of the
  284. // location where the value will be stored is pushed on the stack before
  285. // the arguments
  286. if( !(isDestructor || m_isConstructor) && outFunc->DoesReturnOnStack() )
  287. stackPos -= AS_PTR_SIZE;
  288. asCVariableScope vs(0);
  289. // Declare parameters
  290. asUINT n;
  291. for( n = 0; n < parameterNames.GetLength(); n++ )
  292. {
  293. // Get the parameter type
  294. asCDataType &type = outFunc->parameterTypes[n];
  295. asETypeModifiers inoutFlag = n < outFunc->inOutFlags.GetLength() ? outFunc->inOutFlags[n] : asTM_NONE;
  296. // Is the data type allowed?
  297. // TODO: Hasn't this been validated by the builder already?
  298. if( (type.IsReference() && inoutFlag != asTM_INOUTREF && !type.CanBeInstantiated()) ||
  299. (!type.IsReference() && !type.CanBeInstantiated()) )
  300. {
  301. asCString parm = type.Format(outFunc->nameSpace);
  302. if( inoutFlag == asTM_INREF )
  303. parm += "in";
  304. else if( inoutFlag == asTM_OUTREF )
  305. parm += "out";
  306. asCString str;
  307. str.Format(TXT_PARAMETER_CANT_BE_s, parm.AddressOf());
  308. Error(str, func);
  309. }
  310. // If the parameter has a name then declare it as variable
  311. if( parameterNames[n] != "" )
  312. {
  313. asCString &name = parameterNames[n];
  314. if( vs.DeclareVariable(name.AddressOf(), type, stackPos, true) < 0 )
  315. {
  316. // TODO: It might be an out-of-memory too
  317. Error(TXT_PARAMETER_ALREADY_DECLARED, func);
  318. }
  319. // Add marker for variable declaration
  320. byteCode.VarDecl((int)outFunc->scriptData->variables.GetLength());
  321. outFunc->AddVariable(name, type, stackPos);
  322. }
  323. else
  324. vs.DeclareVariable("", type, stackPos, true);
  325. // Move to next parameter
  326. stackPos -= type.GetSizeOnStackDWords();
  327. }
  328. for( n = asUINT(vs.variables.GetLength()); n-- > 0; )
  329. variables->DeclareVariable(vs.variables[n]->name.AddressOf(), vs.variables[n]->type, vs.variables[n]->stackOffset, vs.variables[n]->onHeap);
  330. variables->DeclareVariable("return", returnType, stackPos, true);
  331. return stackPos;
  332. }
  333. void asCCompiler::CompileMemberInitialization(asCByteCode *bc, bool onlyDefaults)
  334. {
  335. asASSERT( m_classDecl );
  336. // Initialize each member in the order they were declared
  337. for( asUINT n = 0; n < outFunc->objectType->properties.GetLength(); n++ )
  338. {
  339. asCObjectProperty *prop = outFunc->objectType->properties[n];
  340. // Check if the property has an initialization expression
  341. asCScriptNode *declNode = 0;
  342. asCScriptNode *initNode = 0;
  343. asCScriptCode *initScript = 0;
  344. for( asUINT m = 0; m < m_classDecl->propInits.GetLength(); m++ )
  345. {
  346. if( m_classDecl->propInits[m].name == prop->name )
  347. {
  348. declNode = m_classDecl->propInits[m].declNode;
  349. initNode = m_classDecl->propInits[m].initNode;
  350. initScript = m_classDecl->propInits[m].file;
  351. break;
  352. }
  353. }
  354. // If declNode is null, the property was inherited in which case
  355. // it was already initialized by the base class' constructor
  356. if( declNode )
  357. {
  358. if( initNode )
  359. {
  360. if( onlyDefaults )
  361. continue;
  362. #ifdef AS_NO_MEMBER_INIT
  363. // Give an error as the initialization in the declaration has been disabled
  364. asCScriptCode *origScript = script;
  365. script = initScript;
  366. Error("Initialization of members in declaration is not supported", initNode);
  367. script = origScript;
  368. // Clear the initialization node
  369. initNode = 0;
  370. initScript = script;
  371. #else
  372. // Re-parse the initialization expression as the parser now knows the types, which it didn't earlier
  373. asCParser parser(builder);
  374. int r = parser.ParseVarInit(initScript, initNode);
  375. if( r < 0 )
  376. continue;
  377. initNode = parser.GetScriptNode();
  378. #endif
  379. }
  380. else
  381. {
  382. if( !onlyDefaults )
  383. continue;
  384. }
  385. #ifdef AS_NO_MEMBER_INIT
  386. // The initialization will be done in the asCScriptObject constructor, so
  387. // here we should just validate that the member has a default constructor
  388. if( prop->type.IsObject() &&
  389. !prop->type.IsObjectHandle() &&
  390. (((prop->type.GetTypeInfo()->flags & asOBJ_REF) &&
  391. prop->type.GetBehaviour()->factory == 0) ||
  392. ((prop->type.GetTypeInfo()->flags & asOBJ_VALUE) &&
  393. prop->type.GetBehaviour()->construct == 0 &&
  394. !(prop->type.GetTypeInfo()->flags & asOBJ_POD))) )
  395. {
  396. // Class has no default factory/constructor.
  397. asCString str;
  398. // TODO: funcdef: asCDataType should have a GetTypeName()
  399. if( prop->type.GetFuncDef() )
  400. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, prop->type.GetFuncDef()->GetName());
  401. else
  402. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, prop->type.GetTypeInfo()->GetName());
  403. Error(str, declNode);
  404. }
  405. #else
  406. // Temporarily set the script that is being compiled to where the member initialization is declared.
  407. // The script can be different when including mixin classes from a different script section
  408. asCScriptCode *origScript = script;
  409. script = initScript;
  410. // Add a line instruction with the position of the declaration
  411. LineInstr(bc, declNode->tokenPos);
  412. // Compile the initialization
  413. asQWORD constantValue;
  414. asCByteCode bcInit(engine);
  415. CompileInitialization(initNode, &bcInit, prop->type, declNode, prop->byteOffset, &constantValue, 2);
  416. bcInit.OptimizeLocally(tempVariableOffsets);
  417. bc->AddCode(&bcInit);
  418. script = origScript;
  419. #endif
  420. }
  421. }
  422. }
  423. // Entry
  424. int asCCompiler::CompileFunction(asCBuilder *in_builder, asCScriptCode *in_script, asCArray<asCString> &in_parameterNames, asCScriptNode *in_func, asCScriptFunction *in_outFunc, sClassDeclaration *in_classDecl)
  425. {
  426. TimeIt("asCCompiler::CompileFunction");
  427. Reset(in_builder, in_script, in_outFunc);
  428. int buildErrors = builder->numErrors;
  429. int stackPos = SetupParametersAndReturnVariable(in_parameterNames, in_func);
  430. //--------------------------------------------
  431. // Compile the statement block
  432. if( m_isConstructor )
  433. m_classDecl = in_classDecl;
  434. // We need to parse the statement block now
  435. asCScriptNode *blockBegin;
  436. // If the function signature was implicit, e.g. virtual property accessor or
  437. // lambda function, then the received node already is the statement block
  438. if( in_func->nodeType != snStatementBlock )
  439. blockBegin = in_func->lastChild;
  440. else
  441. blockBegin = in_func;
  442. // TODO: memory: We can parse the statement block one statement at a time, thus save even more memory
  443. // 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
  444. asCParser parser(builder);
  445. int r = parser.ParseStatementBlock(script, blockBegin);
  446. if( r < 0 ) return -1;
  447. asCScriptNode *block = parser.GetScriptNode();
  448. // Reserve a label for the cleanup code
  449. nextLabel++;
  450. bool hasReturn;
  451. asCByteCode bc(engine);
  452. LineInstr(&bc, blockBegin->tokenPos);
  453. CompileStatementBlock(block, false, &hasReturn, &bc);
  454. LineInstr(&bc, blockBegin->tokenPos + blockBegin->tokenLength);
  455. // Make sure there is a return in all paths (if not return type is void)
  456. // Don't bother with this check if there are compiler errors, e.g. Unreachable code
  457. if( !hasCompileErrors && outFunc->returnType != asCDataType::CreatePrimitive(ttVoid, false) )
  458. {
  459. if( hasReturn == false )
  460. Error(TXT_NOT_ALL_PATHS_RETURN, blockBegin);
  461. }
  462. //------------------------------------------------
  463. // Concatenate the bytecode
  464. // Insert a JitEntry at the start of the function for JIT compilers
  465. byteCode.InstrPTR(asBC_JitEntry, 0);
  466. if( outFunc->objectType )
  467. {
  468. if( m_isConstructor )
  469. {
  470. if( outFunc->objectType->derivedFrom )
  471. {
  472. // Call the base class' default constructor unless called manually in the code
  473. if( !m_isConstructorCalled )
  474. {
  475. if( outFunc->objectType->derivedFrom->beh.construct )
  476. {
  477. // Initialize members without explicit expression first
  478. CompileMemberInitialization(&byteCode, true);
  479. // Call base class' constructor
  480. asCByteCode tmpBC(engine);
  481. tmpBC.InstrSHORT(asBC_PSF, 0);
  482. tmpBC.Instr(asBC_RDSPtr);
  483. tmpBC.Call(asBC_CALL, outFunc->objectType->derivedFrom->beh.construct, AS_PTR_SIZE);
  484. tmpBC.OptimizeLocally(tempVariableOffsets);
  485. byteCode.AddCode(&tmpBC);
  486. // Add the initialization of the members with explicit expressions
  487. CompileMemberInitialization(&byteCode, false);
  488. }
  489. else
  490. Error(TEXT_BASE_DOESNT_HAVE_DEF_CONSTR, blockBegin);
  491. }
  492. else
  493. {
  494. // Only initialize members that don't have an explicit expression
  495. // The members that are explicitly initialized will be initialized after the call to base class' constructor
  496. CompileMemberInitialization(&byteCode, true);
  497. }
  498. }
  499. else
  500. {
  501. // Add the initialization of the members
  502. CompileMemberInitialization(&byteCode, true);
  503. CompileMemberInitialization(&byteCode, false);
  504. }
  505. }
  506. }
  507. // Add the code for the statement block
  508. byteCode.AddCode(&bc);
  509. // Count total variable size
  510. int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1;
  511. outFunc->scriptData->variableSpace = varSize;
  512. // Deallocate all local variables
  513. int n;
  514. for( n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  515. {
  516. sVariable *v = variables->variables[n];
  517. if( v->stackOffset > 0 )
  518. {
  519. // Call variables destructors
  520. if( v->name != "return" && v->name != "return address" )
  521. CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode);
  522. DeallocateVariable(v->stackOffset);
  523. }
  524. }
  525. // This is the label that return statements jump to
  526. // in order to exit the function
  527. byteCode.Label(0);
  528. // Call destructors for function parameters
  529. for( n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  530. {
  531. sVariable *v = variables->variables[n];
  532. if( v->stackOffset <= 0 )
  533. {
  534. // Call variable destructors here, for variables not yet destroyed
  535. if( v->name != "return" && v->name != "return address" )
  536. CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode);
  537. }
  538. // Do not deallocate parameters
  539. }
  540. // Check if the number of labels in the functions isn't too many to be handled
  541. if( nextLabel >= (1<<15) )
  542. Error(TXT_TOO_MANY_JUMP_LABELS, in_func);
  543. // If there are compile errors, there is no reason to build the final code
  544. if( hasCompileErrors || builder->numErrors != buildErrors )
  545. return -1;
  546. // At this point there should be no variables allocated
  547. asASSERT(variableAllocations.GetLength() == freeVariables.GetLength());
  548. // Remove the variable scope
  549. RemoveVariableScope();
  550. byteCode.Ret(-stackPos);
  551. FinalizeFunction();
  552. #ifdef AS_DEBUG
  553. // DEBUG: output byte code
  554. if( outFunc->objectType )
  555. byteCode.DebugOutput(("__" + outFunc->objectType->name + "_" + outFunc->name + ".txt").AddressOf(), in_outFunc);
  556. else
  557. byteCode.DebugOutput(("__" + outFunc->name + ".txt").AddressOf(), in_outFunc);
  558. #endif
  559. return 0;
  560. }
  561. int asCCompiler::CallCopyConstructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asCExprContext *arg, asCScriptNode *node, bool isGlobalVar, bool derefDest)
  562. {
  563. if( !type.IsObject() )
  564. return 0;
  565. // CallCopyConstructor should not be called for object handles.
  566. asASSERT( !type.IsObjectHandle() );
  567. asCArray<asCExprContext*> args;
  568. args.PushLast(arg);
  569. // The reference parameter must be pushed on the stack
  570. asASSERT( arg->type.dataType.GetTypeInfo() == type.GetTypeInfo() );
  571. // Since we're calling the copy constructor, we have to trust the function to not do
  572. // anything stupid otherwise we will just enter a loop, as we try to make temporary
  573. // copies of the argument in order to guarantee safety.
  574. if( type.GetTypeInfo()->flags & asOBJ_REF )
  575. {
  576. asCExprContext ctx(engine);
  577. int func = 0;
  578. asSTypeBehaviour *beh = type.GetBehaviour();
  579. if( beh ) func = beh->copyfactory;
  580. if( func > 0 )
  581. {
  582. if( !isGlobalVar )
  583. {
  584. // Call factory and store the handle in the given variable
  585. PerformFunctionCall(func, &ctx, false, &args, CastToObjectType(type.GetTypeInfo()), true, offset);
  586. // Pop the reference left by the function call
  587. ctx.bc.Instr(asBC_PopPtr);
  588. }
  589. else
  590. {
  591. // Call factory
  592. PerformFunctionCall(func, &ctx, false, &args, CastToObjectType(type.GetTypeInfo()));
  593. // Store the returned handle in the global variable
  594. ctx.bc.Instr(asBC_RDSPtr);
  595. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  596. ctx.bc.InstrPTR(asBC_REFCPY, type.GetTypeInfo());
  597. ctx.bc.Instr(asBC_PopPtr);
  598. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  599. }
  600. bc->AddCode(&ctx.bc);
  601. return 0;
  602. }
  603. }
  604. else
  605. {
  606. asSTypeBehaviour *beh = type.GetBehaviour();
  607. int func = beh ? beh->copyconstruct : 0;
  608. if( func > 0 )
  609. {
  610. // Push the address where the object will be stored on the stack, before the argument
  611. // TODO: When the context is serializable this probably has to be changed, since this
  612. // pointer can remain on the stack while the context is suspended. There is no
  613. // risk the pointer becomes invalid though, there is just no easy way to serialize it.
  614. asCByteCode tmp(engine);
  615. if( isGlobalVar )
  616. tmp.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  617. else if( isObjectOnHeap )
  618. tmp.InstrSHORT(asBC_PSF, (short)offset);
  619. tmp.AddCode(bc);
  620. bc->AddCode(&tmp);
  621. // When the object is allocated on the stack the object pointer
  622. // must be pushed on the stack after the arguments
  623. if( !isObjectOnHeap )
  624. {
  625. asASSERT( !isGlobalVar );
  626. bc->InstrSHORT(asBC_PSF, (short)offset);
  627. if( derefDest )
  628. {
  629. // The variable is a reference to the real location, so we need to dereference it
  630. bc->Instr(asBC_RDSPtr);
  631. }
  632. }
  633. asCExprContext ctx(engine);
  634. PerformFunctionCall(func, &ctx, isObjectOnHeap, &args, CastToObjectType(type.GetTypeInfo()));
  635. bc->AddCode(&ctx.bc);
  636. // TODO: value on stack: This probably needs to be done in PerformFunctionCall
  637. // Mark the object as initialized
  638. if( !isObjectOnHeap )
  639. bc->ObjInfo(offset, asOBJ_INIT);
  640. return 0;
  641. }
  642. }
  643. // Class has no copy constructor/factory.
  644. asCString str;
  645. str.Format(TXT_NO_COPY_CONSTRUCTOR_FOR_s, type.GetTypeInfo()->GetName());
  646. Error(str, node);
  647. return -1;
  648. }
  649. int asCCompiler::CallDefaultConstructor(const asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asCScriptNode *node, int isVarGlobOrMem, bool derefDest)
  650. {
  651. if( !type.IsObject() || type.IsObjectHandle() )
  652. return 0;
  653. if( type.GetTypeInfo()->flags & asOBJ_REF )
  654. {
  655. asCExprContext ctx(engine);
  656. ctx.exprNode = node;
  657. int func = 0;
  658. asSTypeBehaviour *beh = type.GetBehaviour();
  659. if( beh )
  660. {
  661. func = beh->factory;
  662. // If no trivial default factory is found, look for a factory where all params have default args
  663. if( func == 0 )
  664. {
  665. for( asUINT n = 0; n < beh->factories.GetLength(); n++ )
  666. {
  667. asCScriptFunction *f = engine->scriptFunctions[beh->factories[n]];
  668. if( f->defaultArgs.GetLength() == f->parameterTypes.GetLength() &&
  669. f->defaultArgs[0] != 0 )
  670. {
  671. func = beh->factories[n];
  672. break;
  673. }
  674. }
  675. }
  676. }
  677. if( func > 0 )
  678. {
  679. asCArray<asCExprContext *> args;
  680. asCScriptFunction *f = engine->scriptFunctions[func];
  681. if( f->parameterTypes.GetLength() )
  682. {
  683. // Add the default values for arguments not explicitly supplied
  684. CompileDefaultAndNamedArgs(node, args, func, CastToObjectType(type.GetTypeInfo()));
  685. PrepareFunctionCall(func, &ctx.bc, args);
  686. MoveArgsToStack(func, &ctx.bc, args, false);
  687. }
  688. if( isVarGlobOrMem == 0 )
  689. {
  690. // Call factory and store the handle in the given variable
  691. PerformFunctionCall(func, &ctx, false, &args, CastToObjectType(type.GetTypeInfo()), true, offset);
  692. // Pop the reference left by the function call
  693. ctx.bc.Instr(asBC_PopPtr);
  694. }
  695. else
  696. {
  697. // Call factory
  698. PerformFunctionCall(func, &ctx, false, &args, CastToObjectType(type.GetTypeInfo()));
  699. // TODO: runtime optimize: Should have a way of storing the object pointer directly to the destination
  700. // instead of first storing it in a local variable and then copying it to the
  701. // destination.
  702. if( !(type.GetTypeInfo()->flags & asOBJ_SCOPED) )
  703. {
  704. // Only dereference the variable if not a scoped type
  705. ctx.bc.Instr(asBC_RDSPtr);
  706. }
  707. if( isVarGlobOrMem == 1 )
  708. {
  709. // Store the returned handle in the global variable
  710. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  711. }
  712. else
  713. {
  714. // Store the returned handle in the class member
  715. ctx.bc.InstrSHORT(asBC_PSF, 0);
  716. ctx.bc.Instr(asBC_RDSPtr);
  717. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  718. }
  719. if( type.GetTypeInfo()->flags & asOBJ_SCOPED )
  720. {
  721. // For scoped typed we must move the reference from the local
  722. // variable rather than copy it as there is no AddRef behaviour
  723. ctx.bc.InstrSHORT_DW(asBC_COPY, AS_PTR_SIZE, asTYPEID_OBJHANDLE | engine->GetTypeIdFromDataType(type));
  724. // Clear the local variable so the reference isn't released
  725. ctx.bc.InstrSHORT(asBC_ClrVPtr, ctx.type.stackOffset);
  726. }
  727. else
  728. {
  729. if( type.IsFuncdef() )
  730. ctx.bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  731. else
  732. ctx.bc.InstrPTR(asBC_REFCPY, type.GetTypeInfo());
  733. }
  734. ctx.bc.Instr(asBC_PopPtr);
  735. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  736. }
  737. bc->AddCode(&ctx.bc);
  738. // Cleanup
  739. for( asUINT n = 0; n < args.GetLength(); n++ )
  740. if( args[n] )
  741. {
  742. asDELETE(args[n], asCExprContext);
  743. }
  744. return 0;
  745. }
  746. }
  747. else
  748. {
  749. asCExprContext ctx(engine);
  750. ctx.exprNode = node;
  751. asSTypeBehaviour *beh = type.GetBehaviour();
  752. int func = 0;
  753. if( beh )
  754. {
  755. func = beh->construct;
  756. // If no trivial default constructor is found, look for a constructor where all params have default args
  757. if( func == 0 )
  758. {
  759. for( asUINT n = 0; n < beh->constructors.GetLength(); n++ )
  760. {
  761. asCScriptFunction *f = engine->scriptFunctions[beh->constructors[n]];
  762. if( f->defaultArgs.GetLength() == f->parameterTypes.GetLength() &&
  763. f->defaultArgs[0] != 0 )
  764. {
  765. func = beh->constructors[n];
  766. break;
  767. }
  768. }
  769. }
  770. }
  771. // Allocate and initialize with the default constructor
  772. if( func != 0 || (type.GetTypeInfo()->flags & asOBJ_POD) )
  773. {
  774. asCArray<asCExprContext *> args;
  775. asCScriptFunction *f = engine->scriptFunctions[func];
  776. if( f && f->parameterTypes.GetLength() )
  777. {
  778. // Add the default values for arguments not explicitly supplied
  779. CompileDefaultAndNamedArgs(node, args, func, CastToObjectType(type.GetTypeInfo()));
  780. PrepareFunctionCall(func, &ctx.bc, args);
  781. MoveArgsToStack(func, &ctx.bc, args, false);
  782. }
  783. if( !isObjectOnHeap )
  784. {
  785. if( isVarGlobOrMem == 0 )
  786. {
  787. // There is nothing to do if there is no function,
  788. // as the memory is already allocated on the stack
  789. if( func )
  790. {
  791. // Call the constructor as a normal function
  792. bc->InstrSHORT(asBC_PSF, (short)offset);
  793. if( derefDest )
  794. bc->Instr(asBC_RDSPtr);
  795. asCExprContext ctxCall(engine);
  796. PerformFunctionCall(func, &ctxCall, false, 0, CastToObjectType(type.GetTypeInfo()));
  797. bc->AddCode(&ctxCall.bc);
  798. // TODO: value on stack: This probably needs to be done in PerformFunctionCall
  799. // Mark the object as initialized
  800. bc->ObjInfo(offset, asOBJ_INIT);
  801. }
  802. }
  803. else if( isVarGlobOrMem == 2 )
  804. {
  805. // Only POD types can be allocated inline in script classes
  806. asASSERT( type.GetTypeInfo()->flags & asOBJ_POD );
  807. if( func )
  808. {
  809. // Call the constructor as a normal function
  810. bc->InstrSHORT(asBC_PSF, 0);
  811. bc->Instr(asBC_RDSPtr);
  812. bc->InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  813. asCExprContext ctxCall(engine);
  814. PerformFunctionCall(func, &ctxCall, false, 0, CastToObjectType(type.GetTypeInfo()));
  815. bc->AddCode(&ctxCall.bc);
  816. }
  817. }
  818. else
  819. {
  820. asASSERT( false );
  821. }
  822. }
  823. else
  824. {
  825. if( isVarGlobOrMem == 0 )
  826. bc->InstrSHORT(asBC_PSF, (short)offset);
  827. else if( isVarGlobOrMem == 1 )
  828. bc->InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  829. else
  830. {
  831. bc->InstrSHORT(asBC_PSF, 0);
  832. bc->Instr(asBC_RDSPtr);
  833. bc->InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  834. }
  835. if( (type.GetTypeInfo()->flags & asOBJ_TEMPLATE) )
  836. {
  837. asCScriptFunction *descr = engine->scriptFunctions[func];
  838. asASSERT( descr->funcType == asFUNC_SCRIPT );
  839. // Find the id of the real constructor and not the generated stub
  840. asUINT id = 0;
  841. asDWORD *funcBc = descr->scriptData->byteCode.AddressOf();
  842. while( funcBc )
  843. {
  844. if( (*(asBYTE*)funcBc) == asBC_CALLSYS )
  845. {
  846. id = asBC_INTARG(funcBc);
  847. break;
  848. }
  849. funcBc += asBCTypeSize[asBCInfo[*(asBYTE*)funcBc].type];
  850. }
  851. asASSERT( id );
  852. bc->InstrPTR(asBC_OBJTYPE, type.GetTypeInfo());
  853. bc->Alloc(asBC_ALLOC, type.GetTypeInfo(), id, AS_PTR_SIZE + AS_PTR_SIZE);
  854. }
  855. else
  856. bc->Alloc(asBC_ALLOC, type.GetTypeInfo(), func, AS_PTR_SIZE);
  857. }
  858. // Cleanup
  859. for( asUINT n = 0; n < args.GetLength(); n++ )
  860. if( args[n] )
  861. {
  862. asDELETE(args[n], asCExprContext);
  863. }
  864. return 0;
  865. }
  866. }
  867. // Class has no default factory/constructor.
  868. asCString str;
  869. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, type.GetTypeInfo()->GetName());
  870. Error(str, node);
  871. return -1;
  872. }
  873. void asCCompiler::CallDestructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc)
  874. {
  875. if( !type.IsReference() )
  876. {
  877. // Call destructor for the data type
  878. if( type.IsObject() || type.IsFuncdef() )
  879. {
  880. // The null pointer doesn't need to be destroyed
  881. if( type.IsNullHandle() )
  882. return;
  883. // Nothing is done for list pattern types, as this is taken care of by the CompileInitList method
  884. if( type.GetTypeInfo()->flags & asOBJ_LIST_PATTERN )
  885. return;
  886. if( isObjectOnHeap || type.IsObjectHandle() )
  887. {
  888. // Free the memory
  889. if (type.IsFuncdef())
  890. bc->InstrW_PTR(asBC_FREE, (short)offset, &engine->functionBehaviours);
  891. else
  892. bc->InstrW_PTR(asBC_FREE, (short)offset, type.GetTypeInfo());
  893. }
  894. else
  895. {
  896. asASSERT( type.GetTypeInfo()->GetFlags() & asOBJ_VALUE );
  897. if( type.GetBehaviour()->destruct )
  898. {
  899. // Call the destructor as a regular function
  900. asCExprContext ctx(engine);
  901. ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
  902. PerformFunctionCall(type.GetBehaviour()->destruct, &ctx);
  903. ctx.bc.OptimizeLocally(tempVariableOffsets);
  904. bc->AddCode(&ctx.bc);
  905. }
  906. // TODO: Value on stack: This probably needs to be done in PerformFunctionCall
  907. // Mark the object as destroyed
  908. bc->ObjInfo(offset, asOBJ_UNINIT);
  909. }
  910. }
  911. }
  912. }
  913. void asCCompiler::LineInstr(asCByteCode *bc, size_t pos)
  914. {
  915. int r, c;
  916. script->ConvertPosToRowCol(pos, &r, &c);
  917. bc->Line(r, c, script->idx);
  918. }
  919. void asCCompiler::CompileStatementBlock(asCScriptNode *block, bool ownVariableScope, bool *hasReturn, asCByteCode *bc)
  920. {
  921. *hasReturn = false;
  922. bool isFinished = false;
  923. bool hasUnreachableCode = false;
  924. bool hasReturnBefore = false;
  925. if( ownVariableScope )
  926. {
  927. bc->Block(true);
  928. AddVariableScope();
  929. }
  930. asCScriptNode *node = block->firstChild;
  931. while( node )
  932. {
  933. #ifdef AS_DEBUG
  934. // Keep the current line in a variable so it will be easier
  935. // to determine where in a script an assert is occurring.
  936. int currentLine = 0;
  937. script->ConvertPosToRowCol(node->tokenPos, &currentLine, 0);
  938. #endif
  939. if( !hasUnreachableCode && (*hasReturn || isFinished) )
  940. {
  941. // Empty statements don't count
  942. if( node->nodeType != snExpressionStatement || node->firstChild )
  943. {
  944. hasUnreachableCode = true;
  945. Warning(TXT_UNREACHABLE_CODE, node);
  946. }
  947. if( *hasReturn )
  948. hasReturnBefore = true;
  949. }
  950. if( node->nodeType == snBreak || node->nodeType == snContinue )
  951. isFinished = true;
  952. asCByteCode statement(engine);
  953. if( node->nodeType == snDeclaration )
  954. CompileDeclaration(node, &statement);
  955. else
  956. CompileStatement(node, hasReturn, &statement);
  957. // Ignore missing returns in unreachable code paths
  958. if( !(*hasReturn) && hasReturnBefore )
  959. *hasReturn = true;
  960. LineInstr(bc, node->tokenPos);
  961. bc->AddCode(&statement);
  962. if( !hasCompileErrors )
  963. {
  964. asASSERT( tempVariables.GetLength() == 0 );
  965. asASSERT( reservedVariables.GetLength() == 0 );
  966. }
  967. node = node->next;
  968. }
  969. if( ownVariableScope )
  970. {
  971. // Deallocate variables in this block, in reverse order
  972. for( int n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  973. {
  974. sVariable *v = variables->variables[n];
  975. // Call variable destructors here, for variables not yet destroyed
  976. // If the block is terminated with a break, continue, or
  977. // return the variables are already destroyed
  978. if( !isFinished && !*hasReturn )
  979. CallDestructor(v->type, v->stackOffset, v->onHeap, bc);
  980. // Don't deallocate function parameters
  981. if( v->stackOffset > 0 )
  982. DeallocateVariable(v->stackOffset);
  983. }
  984. RemoveVariableScope();
  985. bc->Block(false);
  986. }
  987. }
  988. // Entry
  989. int asCCompiler::CompileGlobalVariable(asCBuilder *in_builder, asCScriptCode *in_script, asCScriptNode *in_node, sGlobalVariableDescription *in_gvar, asCScriptFunction *in_outFunc)
  990. {
  991. Reset(in_builder, in_script, in_outFunc);
  992. m_globalVar = in_gvar;
  993. // Add a variable scope (even though variables can't be declared)
  994. AddVariableScope();
  995. in_gvar->isPureConstant = false;
  996. // Parse the initialization nodes
  997. asCParser parser(builder);
  998. if (in_node)
  999. {
  1000. int r = parser.ParseVarInit(in_script, in_node);
  1001. if (r < 0)
  1002. return r;
  1003. in_node = parser.GetScriptNode();
  1004. }
  1005. asCExprContext compiledCtx(engine);
  1006. bool preCompiled = false;
  1007. if (in_gvar->datatype.IsAuto())
  1008. {
  1009. preCompiled = CompileAutoType(in_gvar->datatype, compiledCtx, in_node, in_gvar->declaredAtNode);
  1010. if (!preCompiled)
  1011. {
  1012. // If it wasn't possible to determine the type from the expression then there
  1013. // is no need to continue with the initialization. The error was already reported
  1014. // in CompileAutoType.
  1015. return -1;
  1016. }
  1017. }
  1018. if( in_gvar->property == 0 )
  1019. {
  1020. in_gvar->property = builder->module->AllocateGlobalProperty(in_gvar->name.AddressOf(), in_gvar->datatype, in_gvar->ns);
  1021. in_gvar->index = in_gvar->property->id;
  1022. }
  1023. // Compile the expression
  1024. asCExprContext ctx(engine);
  1025. asQWORD constantValue = 0;
  1026. if( CompileInitialization(in_node, &ctx.bc, in_gvar->datatype, in_gvar->declaredAtNode, in_gvar->index, &constantValue, 1, preCompiled ? &compiledCtx : 0) )
  1027. {
  1028. // Should the variable be marked as pure constant?
  1029. if( in_gvar->datatype.IsPrimitive() && in_gvar->datatype.IsReadOnly() )
  1030. {
  1031. in_gvar->isPureConstant = true;
  1032. in_gvar->constantValue = constantValue;
  1033. }
  1034. }
  1035. // Concatenate the bytecode
  1036. int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1;
  1037. // Add information on the line number for the global variable
  1038. size_t pos = 0;
  1039. if( in_gvar->declaredAtNode )
  1040. pos = in_gvar->declaredAtNode->tokenPos;
  1041. else if( in_gvar->initializationNode )
  1042. pos = in_gvar->initializationNode->tokenPos;
  1043. LineInstr(&byteCode, pos);
  1044. // Reserve space for all local variables
  1045. outFunc->scriptData->variableSpace = varSize;
  1046. ctx.bc.OptimizeLocally(tempVariableOffsets);
  1047. byteCode.AddCode(&ctx.bc);
  1048. // Deallocate variables in this block, in reverse order
  1049. for( int n = (int)variables->variables.GetLength() - 1; n >= 0; --n )
  1050. {
  1051. sVariable *v = variables->variables[n];
  1052. // Call variable destructors here, for variables not yet destroyed
  1053. CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode);
  1054. DeallocateVariable(v->stackOffset);
  1055. }
  1056. if( hasCompileErrors ) return -1;
  1057. // At this point there should be no variables allocated
  1058. asASSERT(variableAllocations.GetLength() == freeVariables.GetLength());
  1059. // Remove the variable scope again
  1060. RemoveVariableScope();
  1061. byteCode.Ret(0);
  1062. FinalizeFunction();
  1063. #ifdef AS_DEBUG
  1064. // DEBUG: output byte code
  1065. byteCode.DebugOutput(("___init_" + in_gvar->name + ".txt").AddressOf(), outFunc);
  1066. #endif
  1067. return 0;
  1068. }
  1069. void asCCompiler::DetermineSingleFunc(asCExprContext *ctx, asCScriptNode *node)
  1070. {
  1071. // Don't do anything if this is not a deferred global function
  1072. if( !ctx->IsGlobalFunc() )
  1073. return;
  1074. // Determine the namespace
  1075. asSNameSpace *ns = 0;
  1076. asCString name = "";
  1077. int pos = ctx->methodName.FindLast("::");
  1078. if( pos >= 0 )
  1079. {
  1080. asCString nsName = ctx->methodName.SubString(0, pos+2);
  1081. // Cut off the ::
  1082. if( nsName.GetLength() > 2 )
  1083. nsName.SetLength(nsName.GetLength()-2);
  1084. ns = DetermineNameSpace(nsName);
  1085. name = ctx->methodName.SubString(pos+2);
  1086. }
  1087. else
  1088. {
  1089. DetermineNameSpace("");
  1090. name = ctx->methodName;
  1091. }
  1092. asCArray<int> funcs;
  1093. if( ns )
  1094. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  1095. // CompileVariableAccess should guarantee that at least one function is exists
  1096. asASSERT( funcs.GetLength() > 0 );
  1097. if( funcs.GetLength() > 1 )
  1098. {
  1099. asCString str;
  1100. str.Format(TXT_MULTIPLE_MATCHING_SIGNATURES_TO_s, ctx->methodName.AddressOf());
  1101. Error(str, node);
  1102. // Fall through so the compiler can continue as if only one function was matching
  1103. }
  1104. // A shared object may not access global functions unless they too are shared (e.g. registered functions)
  1105. if( !builder->GetFunctionDescription(funcs[0])->IsShared() &&
  1106. outFunc->IsShared() )
  1107. {
  1108. asCString msg;
  1109. msg.Format(TXT_SHARED_CANNOT_CALL_NON_SHARED_FUNC_s, builder->GetFunctionDescription(funcs[0])->GetDeclaration());
  1110. Error(msg, node);
  1111. // Fall through so the compiler can continue anyway
  1112. }
  1113. // Push the function pointer on the stack
  1114. ctx->bc.InstrPTR(asBC_FuncPtr, builder->GetFunctionDescription(funcs[0]));
  1115. ctx->type.Set(asCDataType::CreateType(engine->FindMatchingFuncdef(builder->GetFunctionDescription(funcs[0]), builder->module), false));
  1116. ctx->type.dataType.MakeHandle(true);
  1117. ctx->type.isExplicitHandle = true;
  1118. ctx->methodName = "";
  1119. }
  1120. void asCCompiler::CompileInitAsCopy(asCDataType &dt, int offset, asCByteCode *bc, asCExprContext *arg, asCScriptNode *node, bool derefDestination)
  1121. {
  1122. bool isObjectOnHeap = derefDestination ? false : IsVariableOnHeap(offset);
  1123. // Use copy constructor if available.
  1124. if(CastToObjectType(dt.GetTypeInfo()) && CastToObjectType(dt.GetTypeInfo())->beh.copyconstruct )
  1125. {
  1126. PrepareForAssignment(&dt, arg, node, true);
  1127. int r = CallCopyConstructor(dt, offset, isObjectOnHeap, bc, arg, node, 0, derefDestination);
  1128. if( r < 0 && tempVariables.Exists(offset) )
  1129. Error(TXT_FAILED_TO_CREATE_TEMP_OBJ, node);
  1130. }
  1131. else
  1132. {
  1133. // TODO: Need to reserve variables, as the default constructor may need
  1134. // to allocate temporary variables to compute default args
  1135. // Allocate and construct the temporary object before whatever is already in the bytecode
  1136. asCByteCode tmpBC(engine);
  1137. int r = CallDefaultConstructor(dt, offset, isObjectOnHeap, &tmpBC, node, 0, derefDestination);
  1138. if( r < 0 )
  1139. {
  1140. if( tempVariables.Exists(offset) )
  1141. Error(TXT_FAILED_TO_CREATE_TEMP_OBJ, node);
  1142. return;
  1143. }
  1144. tmpBC.AddCode(bc);
  1145. bc->AddCode(&tmpBC);
  1146. // Assign the evaluated expression to the temporary variable
  1147. PrepareForAssignment(&dt, arg, node, true);
  1148. bc->AddCode(&arg->bc);
  1149. // Call the opAssign method to assign the value to the temporary object
  1150. dt.MakeReference(isObjectOnHeap);
  1151. asCExprValue type;
  1152. type.Set(dt);
  1153. type.isTemporary = true;
  1154. type.stackOffset = (short)offset;
  1155. if( dt.IsObjectHandle() )
  1156. type.isExplicitHandle = true;
  1157. bc->InstrSHORT(asBC_PSF, (short)offset);
  1158. if( derefDestination )
  1159. bc->Instr(asBC_RDSPtr);
  1160. r = PerformAssignment(&type, &arg->type, bc, node);
  1161. if( r < 0 )
  1162. {
  1163. if( tempVariables.Exists(offset) )
  1164. Error(TXT_FAILED_TO_CREATE_TEMP_OBJ, node);
  1165. return;
  1166. }
  1167. // Pop the reference that was pushed on the stack if the result is an object
  1168. if( type.dataType.IsObject() || type.dataType.IsFuncdef() )
  1169. bc->Instr(asBC_PopPtr);
  1170. // If the assignment operator returned an object by value it will
  1171. // be in a temporary variable which we need to destroy now
  1172. if( type.isTemporary && type.stackOffset != (short)offset )
  1173. ReleaseTemporaryVariable(type.stackOffset, bc);
  1174. // Release the original value too in case it is a temporary
  1175. ReleaseTemporaryVariable(arg->type, bc);
  1176. }
  1177. }
  1178. int asCCompiler::PrepareArgument(asCDataType *paramType, asCExprContext *ctx, asCScriptNode *node, bool isFunction, int refType, bool isMakingCopy)
  1179. {
  1180. asCDataType param = *paramType;
  1181. if( paramType->GetTokenType() == ttQuestion )
  1182. {
  1183. // The function is expecting a var type. If the argument is a function name, we must now decide which function it is
  1184. DetermineSingleFunc(ctx, node);
  1185. // Since the function is expecting a var type ?, then we don't want to convert the argument to anything else
  1186. param = ctx->type.dataType;
  1187. param.MakeHandle(ctx->type.isExplicitHandle || ctx->type.IsNullConstant());
  1188. // Treat the void expression like a null handle when working with var types
  1189. if( ctx->IsVoidExpression() )
  1190. param = asCDataType::CreateNullHandle();
  1191. // If value assign is disabled for reference types, then make
  1192. // sure to always pass the handle to ? parameters
  1193. if( builder->engine->ep.disallowValueAssignForRefType &&
  1194. ctx->type.dataType.GetTypeInfo() && (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCOPED) )
  1195. {
  1196. param.MakeHandle(true);
  1197. }
  1198. param.MakeReference(paramType->IsReference());
  1199. param.MakeReadOnly(paramType->IsReadOnly());
  1200. }
  1201. else
  1202. param = *paramType;
  1203. asCDataType dt = param;
  1204. // Need to protect arguments by reference
  1205. if( isFunction && dt.IsReference() )
  1206. {
  1207. // Allocate a temporary variable of the same type as the argument
  1208. dt.MakeReference(false);
  1209. dt.MakeReadOnly(false);
  1210. int offset;
  1211. if( refType == asTM_INREF )
  1212. {
  1213. ProcessPropertyGetAccessor(ctx, node);
  1214. // Add the type id as hidden arg if the parameter is a ? type
  1215. if( paramType->GetTokenType() == ttQuestion )
  1216. {
  1217. asCByteCode tmpBC(engine);
  1218. // Place the type id on the stack as a hidden parameter
  1219. tmpBC.InstrDWORD(asBC_TYPEID, engine->GetTypeIdFromDataType(param));
  1220. // Insert the code before the expression code
  1221. tmpBC.AddCode(&ctx->bc);
  1222. ctx->bc.AddCode(&tmpBC);
  1223. }
  1224. if( dt.IsPrimitive() )
  1225. {
  1226. // If the reference is const, then it is not necessary to make a copy if the value already is a variable
  1227. // Even if the same variable is passed in another argument as non-const then there is no problem
  1228. IsVariableInitialized(&ctx->type, node);
  1229. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  1230. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true);
  1231. if( !(param.IsReadOnly() && ctx->type.isVariable) )
  1232. ConvertToTempVariable(ctx);
  1233. PushVariableOnStack(ctx, true);
  1234. ctx->type.dataType.MakeReadOnly(param.IsReadOnly());
  1235. }
  1236. else if( ctx->type.dataType.IsNullHandle() )
  1237. {
  1238. // Make sure the argument type can support handles (or is itself a handle)
  1239. if( !dt.SupportHandles() && !dt.IsObjectHandle() )
  1240. {
  1241. asCString str;
  1242. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), param.Format(outFunc->nameSpace).AddressOf());
  1243. Error(str, node);
  1244. ctx->type.Set(param);
  1245. return -1;
  1246. }
  1247. // Need to initialize a local temporary variable to
  1248. // represent the null handle when passed as reference
  1249. asASSERT( ctx->bc.GetLastInstr() == asBC_PshNull );
  1250. ctx->bc.Instr(asBC_PopPtr);
  1251. dt.MakeHandle(true);
  1252. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1253. // Push the reference to the variable on the stack
  1254. ctx->bc.InstrWORD(asBC_PSF, (short)offset);
  1255. ctx->type.SetVariable(dt, offset, true);
  1256. }
  1257. else
  1258. {
  1259. IsVariableInitialized(&ctx->type, node);
  1260. if( !isMakingCopy )
  1261. {
  1262. // Even though the parameter expects a reference, it is only meant to be
  1263. // used as input value and doesn't have to refer to the actual object, so it
  1264. // is OK to do an implicit conversion.
  1265. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true);
  1266. if( !ctx->type.dataType.IsEqualExceptRefAndConst(param) )
  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. // The compiler must guarantee that the object stays alive during the execution
  1275. // of the function, and it must also guarantee that the value isn't modified by
  1276. // the function.
  1277. // If the argument is a temporary local variable then it is safe to be passed to
  1278. // the function as it is, since the local variable will stay alive, and since it
  1279. // is temporary there is no side effect if the function modifies it.
  1280. // If the parameter is read-only and therefore guaranteed not to be modified by the
  1281. // function, then it is enough that the variable is local to guarantee the lifetime.
  1282. if( !ctx->type.isTemporary && !(param.IsReadOnly() && ctx->type.isVariable) )
  1283. {
  1284. if( ctx->type.dataType.IsFuncdef() || ((ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && param.IsReadOnly() && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCOPED)) )
  1285. {
  1286. // Funcdefs only need an extra handle to guarantee the lifetime.
  1287. // If the object is a reference type (except scoped reference types), and the
  1288. // parameter is a const reference, then it is not necessary to make a copy of the
  1289. // object. The compiler just needs to hold a handle to guarantee the lifetime.
  1290. // Allocate a handle variable
  1291. dt.MakeHandle(true);
  1292. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1293. // Copy the handle
  1294. Dereference(ctx, true);
  1295. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1296. if (ctx->type.dataType.IsFuncdef())
  1297. ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  1298. else
  1299. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo());
  1300. ctx->bc.Instr(asBC_PopPtr);
  1301. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1302. // The type should be set to the param type instead of dt to guarantee
  1303. // that the expression keeps the correct type for variable ? args. Otherwise
  1304. // MoveArgsToStack will use the wrong bytecode to move the arg to the stack
  1305. ctx->type.SetVariable(param, offset, true);
  1306. }
  1307. else
  1308. {
  1309. // Make a copy of the object to guarantee that the original isn't modified
  1310. asASSERT(!dt.IsFuncdef());
  1311. // Allocate and initialize a temporary local object
  1312. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1313. CompileInitAsCopy(dt, offset, &ctx->bc, ctx, node, false);
  1314. // Push the object pointer on the stack
  1315. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  1316. if( dt.IsObject() && !dt.IsObjectHandle() )
  1317. ctx->bc.Instr(asBC_RDSPtr);
  1318. // Set the resulting type
  1319. ctx->type.Set(dt);
  1320. ctx->type.isTemporary = true;
  1321. ctx->type.stackOffset = short(offset);
  1322. if( dt.IsObjectHandle() )
  1323. ctx->type.isExplicitHandle = true;
  1324. ctx->type.dataType.MakeReference(false);
  1325. if( paramType->IsReadOnly() )
  1326. ctx->type.dataType.MakeReadOnly(true);
  1327. }
  1328. }
  1329. }
  1330. else
  1331. {
  1332. // We must guarantee that the address to the value is on the stack
  1333. if( (ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) &&
  1334. !ctx->type.dataType.IsObjectHandle() &&
  1335. ctx->type.dataType.IsReference() )
  1336. Dereference(ctx, true);
  1337. }
  1338. }
  1339. }
  1340. else if( refType == asTM_OUTREF )
  1341. {
  1342. // Add the type id as hidden arg if the parameter is a ? type
  1343. if( paramType->GetTokenType() == ttQuestion )
  1344. {
  1345. asCByteCode tmpBC(engine);
  1346. // Place the type id on the stack as a hidden parameter
  1347. tmpBC.InstrDWORD(asBC_TYPEID, engine->GetTypeIdFromDataType(param));
  1348. // Insert the code before the expression code
  1349. tmpBC.AddCode(&ctx->bc);
  1350. ctx->bc.AddCode(&tmpBC);
  1351. }
  1352. // If the expression is marked as clean, then it can be used directly
  1353. // without the need to allocate another temporary value as it is known
  1354. // that the argument has no other value than the default
  1355. if( ctx->isCleanArg )
  1356. {
  1357. // Must be a local variable
  1358. asASSERT( ctx->type.isVariable );
  1359. }
  1360. else
  1361. {
  1362. // Make sure the variable is not used in the expression
  1363. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1364. if( dt.IsPrimitive() )
  1365. {
  1366. ctx->type.SetVariable(dt, offset, true);
  1367. PushVariableOnStack(ctx, true);
  1368. }
  1369. else
  1370. {
  1371. // TODO: Need to reserve variables, as the default constructor may need
  1372. // to allocate temporary variables to compute default args
  1373. // Allocate and construct the temporary object
  1374. asCByteCode tmpBC(engine);
  1375. CallDefaultConstructor(dt, offset, IsVariableOnHeap(offset), &tmpBC, node);
  1376. // Insert the code before the expression code
  1377. tmpBC.AddCode(&ctx->bc);
  1378. ctx->bc.AddCode(&tmpBC);
  1379. dt.MakeReference(!(dt.IsObject() || dt.IsFuncdef()) || dt.IsObjectHandle());
  1380. asCExprValue type;
  1381. type.Set(dt);
  1382. type.isTemporary = true;
  1383. type.stackOffset = (short)offset;
  1384. ctx->type = type;
  1385. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  1386. if( (dt.IsObject() || dt.IsFuncdef()) && !dt.IsObjectHandle() )
  1387. ctx->bc.Instr(asBC_RDSPtr);
  1388. }
  1389. // After the function returns the temporary variable will
  1390. // be assigned to the expression, if it is a valid lvalue
  1391. }
  1392. }
  1393. else if( refType == asTM_INOUTREF )
  1394. {
  1395. ProcessPropertyGetAccessor(ctx, node);
  1396. // Add the type id as hidden arg if the parameter is a ? type
  1397. if( paramType->GetTokenType() == ttQuestion )
  1398. {
  1399. asCByteCode tmpBC(engine);
  1400. // Place the type id on the stack as a hidden parameter
  1401. tmpBC.InstrDWORD(asBC_TYPEID, engine->GetTypeIdFromDataType(param));
  1402. // Insert the code before the expression code
  1403. tmpBC.AddCode(&ctx->bc);
  1404. ctx->bc.AddCode(&tmpBC);
  1405. }
  1406. // Literal constants cannot be passed to inout ref arguments
  1407. if( !ctx->type.isVariable && ctx->type.isConstant )
  1408. {
  1409. // Unless unsafe references are turned on and the reference is const
  1410. if( param.IsReadOnly() && engine->ep.allowUnsafeReferences )
  1411. {
  1412. // Since the parameter is a const & make a copy.
  1413. ConvertToTempVariable(ctx);
  1414. ctx->type.dataType.MakeReadOnly(true);
  1415. }
  1416. else
  1417. {
  1418. Error(TXT_NOT_VALID_REFERENCE, node);
  1419. return -1;
  1420. }
  1421. }
  1422. // Perform implicit ref cast if necessary, but don't allow the implicit conversion to create new objects
  1423. if( (ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) && ctx->type.dataType.GetTypeInfo() != dt.GetTypeInfo() )
  1424. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true, false);
  1425. // Only objects that support object handles
  1426. // can be guaranteed to be safe. Local variables are
  1427. // already safe, so there is no need to add an extra
  1428. // references
  1429. if( !engine->ep.allowUnsafeReferences &&
  1430. !ctx->type.isVariable &&
  1431. (ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) &&
  1432. !ctx->type.dataType.IsObjectHandle() &&
  1433. ((ctx->type.dataType.GetBehaviour()->addref &&
  1434. ctx->type.dataType.GetBehaviour()->release) ||
  1435. (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_NOCOUNT) ||
  1436. ctx->type.dataType.IsFuncdef()) )
  1437. {
  1438. // Store a handle to the object as local variable
  1439. asCExprContext tmp(engine);
  1440. dt = ctx->type.dataType;
  1441. dt.MakeHandle(true);
  1442. dt.MakeReference(false);
  1443. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1444. // Copy the handle
  1445. if( !ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReference() )
  1446. ctx->bc.Instr(asBC_RDSPtr);
  1447. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1448. if( ctx->type.dataType.IsFuncdef() )
  1449. ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  1450. else
  1451. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo());
  1452. ctx->bc.Instr(asBC_PopPtr);
  1453. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1454. dt.MakeHandle(false);
  1455. dt.MakeReference(true);
  1456. // Release previous temporary variable stored in the context (if any)
  1457. if( ctx->type.isTemporary )
  1458. ReleaseTemporaryVariable(ctx->type.stackOffset, &ctx->bc);
  1459. ctx->type.SetVariable(dt, offset, true);
  1460. }
  1461. // Make sure the reference to the value is on the stack
  1462. // For objects, the reference needs to be dereferenced so the pointer on the stack is to the actual object
  1463. // For handles, the reference shouldn't be changed because the pointer on the stack should be to the handle
  1464. if( (ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) && ctx->type.dataType.IsReference() && !param.IsObjectHandle() )
  1465. Dereference(ctx, true);
  1466. else if( ctx->type.isVariable && !(ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) )
  1467. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  1468. else if( ctx->type.dataType.IsPrimitive() )
  1469. ctx->bc.Instr(asBC_PshRPtr);
  1470. else if( ctx->type.dataType.IsObjectHandle() && !ctx->type.dataType.IsReference() )
  1471. ImplicitConversion(ctx, param, node, asIC_IMPLICIT_CONV, true, false);
  1472. }
  1473. }
  1474. else
  1475. {
  1476. ProcessPropertyGetAccessor(ctx, node);
  1477. if( dt.IsPrimitive() )
  1478. {
  1479. IsVariableInitialized(&ctx->type, node);
  1480. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  1481. // Implicitly convert primitives to the parameter type
  1482. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV);
  1483. if( ctx->type.isVariable )
  1484. {
  1485. PushVariableOnStack(ctx, dt.IsReference());
  1486. }
  1487. else if( ctx->type.isConstant )
  1488. {
  1489. ConvertToVariable(ctx);
  1490. PushVariableOnStack(ctx, dt.IsReference());
  1491. }
  1492. }
  1493. else
  1494. {
  1495. IsVariableInitialized(&ctx->type, node);
  1496. // Implicitly convert primitives to the parameter type
  1497. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV);
  1498. // Was the conversion successful?
  1499. if( !ctx->type.dataType.IsEqualExceptRef(dt) )
  1500. {
  1501. asCString str;
  1502. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), dt.Format(outFunc->nameSpace).AddressOf());
  1503. Error(str, node);
  1504. ctx->type.Set(dt);
  1505. return -1;
  1506. }
  1507. if( dt.IsObjectHandle() )
  1508. ctx->type.isExplicitHandle = true;
  1509. if( (dt.IsObject() || dt.IsFuncdef()) && !dt.IsNullHandle() && !dt.IsReference() )
  1510. {
  1511. // Objects passed by value must be placed in temporary variables
  1512. // so that they are guaranteed to not be referenced anywhere else.
  1513. // The object must also be allocated on the heap, as the memory will
  1514. // be deleted by the called function.
  1515. // Handles passed by value must also be placed in a temporary variable
  1516. // to guarantee that the object referred to isn't freed too early.
  1517. // TODO: value on stack: How can we avoid this unnecessary allocation?
  1518. // Don't make temporary copies of handles if it is going to be used
  1519. // for handle assignment anyway, i.e. REFCPY.
  1520. if( !(!isFunction && isMakingCopy && ctx->type.dataType.IsObjectHandle() && ctx->type.isVariable) )
  1521. PrepareTemporaryVariable(node, ctx, true);
  1522. }
  1523. }
  1524. }
  1525. // Don't put any pointer on the stack yet
  1526. if( param.IsReference() || ((param.IsObject() || param.IsFuncdef()) && !param.IsNullHandle()) )
  1527. {
  1528. // &inout parameter may leave the reference on the stack already
  1529. if( refType != asTM_INOUTREF )
  1530. {
  1531. asASSERT( ctx->type.isVariable || ctx->type.isTemporary || isMakingCopy );
  1532. if( ctx->type.isVariable || ctx->type.isTemporary )
  1533. {
  1534. ctx->bc.Instr(asBC_PopPtr);
  1535. ctx->bc.InstrSHORT(asBC_VAR, ctx->type.stackOffset);
  1536. ProcessDeferredParams(ctx);
  1537. }
  1538. }
  1539. }
  1540. return 0;
  1541. }
  1542. void asCCompiler::PrepareFunctionCall(int funcId, asCByteCode *bc, asCArray<asCExprContext *> &args)
  1543. {
  1544. // When a match has been found, compile the final byte code using correct parameter types
  1545. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  1546. asASSERT( descr->parameterTypes.GetLength() == args.GetLength() );
  1547. // If the function being called is the opAssign or copy constructor for the same type
  1548. // as the argument, then we should avoid making temporary copy of the argument
  1549. bool makingCopy = false;
  1550. if( descr->parameterTypes.GetLength() == 1 &&
  1551. descr->parameterTypes[0].IsEqualExceptRefAndConst(args[0]->type.dataType) &&
  1552. (((descr->name == "opAssign" || descr->name == "$beh0") && descr->objectType && descr->objectType == args[0]->type.dataType.GetTypeInfo()) ||
  1553. (descr->objectType == 0 && args[0]->type.dataType.GetTypeInfo() && descr->name == args[0]->type.dataType.GetTypeInfo()->name)) )
  1554. makingCopy = true;
  1555. // Add code for arguments
  1556. asCExprContext e(engine);
  1557. for( int n = (int)args.GetLength()-1; n >= 0; n-- )
  1558. {
  1559. // Make sure PrepareArgument doesn't use any variable that is already
  1560. // being used by the argument or any of the following argument expressions
  1561. int l = int(reservedVariables.GetLength());
  1562. for( int m = n; m >= 0; m-- )
  1563. args[m]->bc.GetVarsUsed(reservedVariables);
  1564. PrepareArgument2(&e, args[n], &descr->parameterTypes[n], true, descr->inOutFlags[n], makingCopy);
  1565. reservedVariables.SetLength(l);
  1566. }
  1567. bc->AddCode(&e.bc);
  1568. }
  1569. void asCCompiler::MoveArgsToStack(int funcId, asCByteCode *bc, asCArray<asCExprContext *> &args, bool addOneToOffset)
  1570. {
  1571. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  1572. int offset = 0;
  1573. if( addOneToOffset )
  1574. offset += AS_PTR_SIZE;
  1575. // The address of where the return value should be stored is push on top of the arguments
  1576. if( descr->DoesReturnOnStack() )
  1577. offset += AS_PTR_SIZE;
  1578. #ifdef AS_DEBUG
  1579. // If the function being called is the opAssign or copy constructor for the same type
  1580. // as the argument, then we should avoid making temporary copy of the argument
  1581. bool makingCopy = false;
  1582. if( descr->parameterTypes.GetLength() == 1 &&
  1583. descr->parameterTypes[0].IsEqualExceptRefAndConst(args[0]->type.dataType) &&
  1584. (((descr->name == "opAssign" || descr->name == "$beh0") && descr->objectType && descr->objectType == args[0]->type.dataType.GetTypeInfo()) ||
  1585. (descr->objectType == 0 && args[0]->type.dataType.GetTypeInfo() && descr->name == args[0]->type.dataType.GetTypeInfo()->name)) )
  1586. makingCopy = true;
  1587. #endif
  1588. // Move the objects that are sent by value to the stack just before the call
  1589. for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ )
  1590. {
  1591. if( descr->parameterTypes[n].IsReference() )
  1592. {
  1593. if( (descr->parameterTypes[n].IsObject() || descr->parameterTypes[n].IsFuncdef()) && !descr->parameterTypes[n].IsObjectHandle() )
  1594. {
  1595. if( descr->inOutFlags[n] != asTM_INOUTREF )
  1596. {
  1597. #ifdef AS_DEBUG
  1598. // This assert is inside AS_DEBUG because of the variable makingCopy which is only defined in debug mode
  1599. asASSERT( args[n]->type.isVariable || args[n]->type.isTemporary || makingCopy );
  1600. #endif
  1601. if( (args[n]->type.isVariable || args[n]->type.isTemporary) )
  1602. {
  1603. if( !IsVariableOnHeap(args[n]->type.stackOffset) )
  1604. // TODO: runtime optimize: Actually the reference can be pushed on the stack directly
  1605. // as the value allocated on the stack is guaranteed to be safe
  1606. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1607. else
  1608. bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset);
  1609. }
  1610. }
  1611. if( args[n]->type.dataType.IsObjectHandle() )
  1612. bc->InstrWORD(asBC_ChkNullS, (asWORD)offset);
  1613. }
  1614. else if( descr->inOutFlags[n] != asTM_INOUTREF )
  1615. {
  1616. if( descr->parameterTypes[n].GetTokenType() == ttQuestion &&
  1617. (args[n]->type.dataType.IsObject() || args[n]->type.dataType.IsFuncdef()) &&
  1618. !args[n]->type.dataType.IsObjectHandle() )
  1619. {
  1620. // Send the object as a reference to the object,
  1621. // and not to the variable holding the object
  1622. if( !IsVariableOnHeap(args[n]->type.stackOffset) )
  1623. // TODO: runtime optimize: Actually the reference can be pushed on the stack directly
  1624. // as the value allocated on the stack is guaranteed to be safe
  1625. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1626. else
  1627. bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset);
  1628. }
  1629. else
  1630. {
  1631. // If the variable is really an argument of @& type, then it is necessary
  1632. // to use asBC_GETOBJREF so the pointer is correctly dereferenced.
  1633. sVariable *var = variables->GetVariableByOffset(args[n]->type.stackOffset);
  1634. if (var == 0 || !var->type.IsReference() || !var->type.IsObjectHandle())
  1635. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1636. else
  1637. bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset);
  1638. }
  1639. }
  1640. }
  1641. else if( descr->parameterTypes[n].IsObject() || descr->parameterTypes[n].IsFuncdef() )
  1642. {
  1643. // TODO: value on stack: What can we do to avoid this unnecessary allocation?
  1644. // The object must be allocated on the heap, because this memory will be deleted in as_callfunc_xxx
  1645. asASSERT(IsVariableOnHeap(args[n]->type.stackOffset));
  1646. // The pointer in the variable will be moved to the stack
  1647. bc->InstrWORD(asBC_GETOBJ, (asWORD)offset);
  1648. // Deallocate the variable slot so it can be reused, but do not attempt to
  1649. // free the content of the variable since it was moved to the stack for the call
  1650. DeallocateVariable(args[n]->type.stackOffset);
  1651. args[n]->type.isTemporary = false;
  1652. }
  1653. offset += descr->parameterTypes[n].GetSizeOnStackDWords();
  1654. }
  1655. }
  1656. int asCCompiler::CompileArgumentList(asCScriptNode *node, asCArray<asCExprContext*> &args, asCArray<asSNamedArgument> &namedArgs)
  1657. {
  1658. asASSERT(node->nodeType == snArgList);
  1659. // Count arguments
  1660. asCScriptNode *arg = node->firstChild;
  1661. int argCount = 0;
  1662. while( arg )
  1663. {
  1664. if( arg->nodeType != snNamedArgument )
  1665. argCount++;
  1666. arg = arg->next;
  1667. }
  1668. // Prepare the arrays
  1669. args.SetLength(argCount);
  1670. int n;
  1671. for( n = 0; n < argCount; n++ )
  1672. args[n] = 0;
  1673. n = argCount-1;
  1674. // Compile the arguments in reverse order (as they will be pushed on the stack)
  1675. bool anyErrors = false, inPositionalArguments = false;
  1676. arg = node->lastChild;
  1677. while( arg )
  1678. {
  1679. asCScriptNode *asgNode = arg, *namedNode = 0;
  1680. if( asgNode->nodeType == snNamedArgument )
  1681. {
  1682. if( inPositionalArguments )
  1683. {
  1684. Error(TXT_POS_ARG_AFTER_NAMED_ARG, node);
  1685. return -1;
  1686. }
  1687. asgNode = arg->firstChild->next;
  1688. namedNode = arg->firstChild;
  1689. asASSERT( namedNode->nodeType == snIdentifier );
  1690. }
  1691. else
  1692. inPositionalArguments = true;
  1693. asCExprContext expr(engine);
  1694. int r = CompileAssignment(asgNode, &expr);
  1695. if( r < 0 ) anyErrors = true;
  1696. asCExprContext *ctx = asNEW(asCExprContext)(engine);
  1697. if( ctx == 0 )
  1698. {
  1699. // Out of memory
  1700. return -1;
  1701. }
  1702. MergeExprBytecodeAndType(ctx, &expr);
  1703. if( inPositionalArguments )
  1704. {
  1705. args[n] = ctx;
  1706. n--;
  1707. }
  1708. else
  1709. {
  1710. asSNamedArgument namedArg;
  1711. namedArg.name = asCString(&script->code[namedNode->tokenPos], namedNode->tokenLength);
  1712. namedArg.ctx = ctx;
  1713. // Error out when multiple arguments with the same name are passed
  1714. for( asUINT a = 0; a < namedArgs.GetLength(); ++a )
  1715. {
  1716. if( namedArgs[a].name == namedArg.name )
  1717. {
  1718. Error(TXT_DUPLICATE_NAMED_ARG, asgNode);
  1719. anyErrors = true;
  1720. break;
  1721. }
  1722. }
  1723. namedArgs.PushLast(namedArg);
  1724. }
  1725. arg = arg->prev;
  1726. }
  1727. return anyErrors ? -1 : 0;
  1728. }
  1729. int asCCompiler::CompileDefaultAndNamedArgs(asCScriptNode *node, asCArray<asCExprContext*> &args, int funcId, asCObjectType *objectType, asCArray<asSNamedArgument> *namedArgs)
  1730. {
  1731. asCScriptFunction *func = builder->GetFunctionDescription(funcId);
  1732. if( func == 0 || args.GetLength() >= (asUINT)func->GetParamCount() )
  1733. return 0;
  1734. // Make sure to use the real function for virtual functions
  1735. if( func->funcType == asFUNC_VIRTUAL )
  1736. {
  1737. asASSERT( objectType );
  1738. func = objectType->virtualFunctionTable[func->vfTableIdx];
  1739. }
  1740. // Make sure none of the variables used in the previous arguments are reused in the default arguments
  1741. bool anyErrors = false;
  1742. int prevReservedVars = reservedVariables.GetLength();
  1743. int explicitArgs = (int)args.GetLength();
  1744. for( int p = 0; p < explicitArgs; p++ )
  1745. args[p]->bc.GetVarsUsed(reservedVariables);
  1746. // Make space for all the new arguments
  1747. args.SetLength(func->parameterTypes.GetLength());
  1748. for( asUINT c = explicitArgs; c < args.GetLength(); c++ )
  1749. args[c] = 0;
  1750. // Add the named arguments to the argument list in the right position
  1751. if( namedArgs )
  1752. {
  1753. for( asUINT n = 0; n < namedArgs->GetLength(); ++n )
  1754. {
  1755. asSNamedArgument &named = (*namedArgs)[n];
  1756. named.ctx->bc.GetVarsUsed(reservedVariables);
  1757. // Find the right spot to put it in
  1758. asUINT index = asUINT(-1);
  1759. for( asUINT j = 0; j < func->parameterTypes.GetLength(); ++j )
  1760. {
  1761. if( func->parameterNames[j] == (*namedArgs)[n].name )
  1762. {
  1763. index = j;
  1764. break;
  1765. }
  1766. }
  1767. asASSERT( index < args.GetLength() );
  1768. args[index] = named.ctx;
  1769. named.ctx = 0;
  1770. }
  1771. }
  1772. // Compile the arguments in reverse order (as they will be pushed on the stack)
  1773. for( int n = (int)func->parameterTypes.GetLength() - 1; n >= explicitArgs; n-- )
  1774. {
  1775. if( args[n] != 0 ) continue;
  1776. if( func->defaultArgs[n] == 0 ) { anyErrors = true; continue; }
  1777. // Parse the default arg string
  1778. asCParser parser(builder);
  1779. asCScriptCode code;
  1780. code.SetCode("default arg", func->defaultArgs[n]->AddressOf(), false);
  1781. int r = parser.ParseExpression(&code);
  1782. if( r < 0 )
  1783. {
  1784. asCString msg;
  1785. msg.Format(TXT_FAILED_TO_COMPILE_DEF_ARG_d_IN_FUNC_s, n, func->GetDeclaration());
  1786. Error(msg, node);
  1787. anyErrors = true;
  1788. continue;
  1789. }
  1790. asCScriptNode *arg = parser.GetScriptNode();
  1791. // Temporarily set the script code to the default arg expression
  1792. asCScriptCode *origScript = script;
  1793. script = &code;
  1794. // Don't allow the expression to access local variables
  1795. isCompilingDefaultArg = true;
  1796. // Temporarily set the namespace in the output function to the namespace of the called
  1797. // function so that the default arguments are evaluated in the correct namespace
  1798. asSNameSpace *origNameSpace = outFunc->nameSpace;
  1799. outFunc->nameSpace = func->nameSpace;
  1800. asCExprContext expr(engine);
  1801. r = CompileExpression(arg, &expr);
  1802. // Restore the namespace
  1803. outFunc->nameSpace = origNameSpace;
  1804. // Don't allow address of class method
  1805. if( expr.IsClassMethod() )
  1806. {
  1807. // TODO: Improve error message
  1808. Error(TXT_DEF_ARG_TYPE_DOESNT_MATCH, arg);
  1809. r = -1;
  1810. }
  1811. // Make sure the expression can be implicitly converted to the parameter type
  1812. if( r >= 0 )
  1813. {
  1814. asCArray<int> funcs;
  1815. funcs.PushLast(func->id);
  1816. asCArray<asSOverloadCandidate> matches;
  1817. if( MatchArgument(funcs, matches, &expr, n) == 0 )
  1818. {
  1819. Error(TXT_DEF_ARG_TYPE_DOESNT_MATCH, arg);
  1820. r = -1;
  1821. }
  1822. }
  1823. isCompilingDefaultArg = false;
  1824. script = origScript;
  1825. if( r < 0 )
  1826. {
  1827. asCString msg;
  1828. msg.Format(TXT_FAILED_TO_COMPILE_DEF_ARG_d_IN_FUNC_s, n, func->GetDeclaration());
  1829. Error(msg, node);
  1830. anyErrors = true;
  1831. continue;
  1832. }
  1833. args[n] = asNEW(asCExprContext)(engine);
  1834. if( args[n] == 0 )
  1835. {
  1836. // Out of memory
  1837. reservedVariables.SetLength(prevReservedVars);
  1838. return -1;
  1839. }
  1840. MergeExprBytecodeAndType(args[n], &expr);
  1841. }
  1842. reservedVariables.SetLength(prevReservedVars);
  1843. return anyErrors ? -1 : 0;
  1844. }
  1845. 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)
  1846. {
  1847. asCArray<int> origFuncs = funcs; // Keep the original list for error message
  1848. asUINT cost = 0;
  1849. asUINT n;
  1850. if( funcs.GetLength() > 0 )
  1851. {
  1852. // Check the number of parameters in the found functions
  1853. asUINT totalArgs = (asUINT)args.GetLength();
  1854. if( namedArgs != 0 )
  1855. totalArgs += (asUINT)namedArgs->GetLength();
  1856. for( n = 0; n < funcs.GetLength(); ++n )
  1857. {
  1858. asCScriptFunction *desc = builder->GetFunctionDescription(funcs[n]);
  1859. if( desc->parameterTypes.GetLength() != totalArgs )
  1860. {
  1861. bool noMatch = true;
  1862. if( totalArgs < desc->parameterTypes.GetLength() )
  1863. {
  1864. // For virtual functions, the default args are defined in the real function of the object
  1865. if( desc->funcType == asFUNC_VIRTUAL )
  1866. desc = objectType->virtualFunctionTable[desc->vfTableIdx];
  1867. // Count the number of default args
  1868. asUINT defaultArgs = 0;
  1869. for( asUINT d = 0; d < desc->defaultArgs.GetLength(); d++ )
  1870. if( desc->defaultArgs[d] )
  1871. defaultArgs++;
  1872. if( totalArgs >= desc->parameterTypes.GetLength() - defaultArgs )
  1873. noMatch = false;
  1874. }
  1875. if( noMatch )
  1876. {
  1877. // remove it from the list
  1878. if( n == funcs.GetLength()-1 )
  1879. funcs.PopLast();
  1880. else
  1881. funcs[n] = funcs.PopLast();
  1882. n--;
  1883. }
  1884. }
  1885. }
  1886. // Match functions with the parameters, and discard those that do not match
  1887. asCArray<asSOverloadCandidate> matchingFuncs;
  1888. matchingFuncs.SetLengthNoConstruct( funcs.GetLength() );
  1889. for ( n = 0; n < funcs.GetLength(); ++n )
  1890. {
  1891. matchingFuncs[n].funcId = funcs[n];
  1892. matchingFuncs[n].cost = 0;
  1893. }
  1894. // Match positionally passed arguments
  1895. for( n = 0; n < args.GetLength(); ++n )
  1896. {
  1897. asCArray<asSOverloadCandidate> tempFuncs;
  1898. MatchArgument(funcs, tempFuncs, args[n], n, allowObjectConstruct);
  1899. // Intersect the found functions with the list of matching functions
  1900. for( asUINT f = 0; f < matchingFuncs.GetLength(); f++ )
  1901. {
  1902. asUINT c;
  1903. for( c = 0; c < tempFuncs.GetLength(); c++ )
  1904. {
  1905. if( matchingFuncs[f].funcId == tempFuncs[c].funcId )
  1906. {
  1907. // Sum argument cost
  1908. matchingFuncs[f].cost += tempFuncs[c].cost;
  1909. break;
  1910. } // End if match
  1911. }
  1912. // Was the function a match?
  1913. if( c == tempFuncs.GetLength() )
  1914. {
  1915. // No, remove it from the list
  1916. if( f == matchingFuncs.GetLength()-1 )
  1917. matchingFuncs.PopLast();
  1918. else
  1919. matchingFuncs[f] = matchingFuncs.PopLast();
  1920. f--;
  1921. }
  1922. }
  1923. }
  1924. // Match named arguments
  1925. if( namedArgs != 0 )
  1926. {
  1927. for( asUINT i = 0; i < matchingFuncs.GetLength(); ++i )
  1928. {
  1929. asCScriptFunction *desc = builder->GetFunctionDescription(matchingFuncs[i].funcId);
  1930. if( desc->funcType == asFUNC_VIRTUAL )
  1931. desc = objectType->virtualFunctionTable[desc->vfTableIdx];
  1932. // Match every named argument to an argument in the function
  1933. for( n = 0; n < namedArgs->GetLength(); ++n )
  1934. (*namedArgs)[n].match = asUINT(-1);
  1935. bool matchedAll = true;
  1936. for( asUINT j = 0; j < desc->parameterTypes.GetLength(); ++j )
  1937. {
  1938. asUINT match = asUINT(-1);
  1939. for( n = 0; n < namedArgs->GetLength(); ++n )
  1940. {
  1941. asSNamedArgument &namedArg = (*namedArgs)[n];
  1942. if( desc->parameterNames[j] == namedArg.name )
  1943. {
  1944. namedArg.match = j;
  1945. match = n;
  1946. break;
  1947. }
  1948. }
  1949. // Check that every position is filled somehow
  1950. if( j >= args.GetLength() )
  1951. {
  1952. if( match == asUINT(-1) && !desc->defaultArgs[j] )
  1953. {
  1954. // No argument was found for this, and there is no
  1955. // default, so it doesn't work.
  1956. matchedAll = false;
  1957. break;
  1958. }
  1959. }
  1960. else
  1961. {
  1962. if( match != asUINT(-1) )
  1963. {
  1964. // Can't name an argument that was already passed
  1965. matchedAll = false;
  1966. break;
  1967. }
  1968. }
  1969. }
  1970. // Check that every named argument was matched
  1971. if( matchedAll )
  1972. {
  1973. for( n = 0; n < namedArgs->GetLength(); ++n )
  1974. {
  1975. asSNamedArgument &named = (*namedArgs)[n];
  1976. if( named.match == asUINT(-1) )
  1977. {
  1978. matchedAll = false;
  1979. break;
  1980. }
  1981. // Add to the cost
  1982. cost = MatchArgument(desc, named.ctx, named.match, allowObjectConstruct);
  1983. if( cost == asUINT(-1) )
  1984. {
  1985. matchedAll = false;
  1986. break;
  1987. }
  1988. matchingFuncs[i].cost += cost;
  1989. }
  1990. }
  1991. if( !matchedAll )
  1992. {
  1993. // Remove the function, we didn't match all the arguments.
  1994. if( i == matchingFuncs.GetLength()-1 )
  1995. matchingFuncs.PopLast();
  1996. else
  1997. matchingFuncs[i] = matchingFuncs.PopLast();
  1998. i--;
  1999. }
  2000. }
  2001. }
  2002. // Select the overload(s) with the lowest overall cost
  2003. funcs.SetLength(0);
  2004. asUINT bestCost = asUINT(-1);
  2005. for( n = 0; n < matchingFuncs.GetLength(); ++n )
  2006. {
  2007. cost = matchingFuncs[n].cost;
  2008. if( cost < bestCost )
  2009. {
  2010. funcs.SetLength(0);
  2011. bestCost = cost;
  2012. }
  2013. if( cost == bestCost )
  2014. funcs.PushLast( matchingFuncs[n].funcId );
  2015. }
  2016. // Cost returned is equivalent to the best cost discovered
  2017. cost = bestCost;
  2018. }
  2019. if( !isConstMethod )
  2020. FilterConst(funcs);
  2021. if( funcs.GetLength() != 1 && !silent )
  2022. {
  2023. // Build a readable string of the function with parameter types
  2024. bool attemptsPassingClassMethod = false;
  2025. asCString str;
  2026. if( scope != "" && scope != "::" )
  2027. str = scope + "::";
  2028. str += name;
  2029. str += "(";
  2030. for( n = 0; n < args.GetLength(); n++ )
  2031. {
  2032. if( n > 0 )
  2033. str += ", ";
  2034. if( args[n]->methodName != "" )
  2035. {
  2036. if( args[n]->IsClassMethod() )
  2037. {
  2038. attemptsPassingClassMethod = true;
  2039. str += args[n]->type.dataType.GetTypeInfo()->GetName();
  2040. str += "::";
  2041. }
  2042. str += args[n]->methodName;
  2043. }
  2044. else if (args[n]->IsAnonymousInitList())
  2045. {
  2046. str += "{...}";
  2047. }
  2048. else
  2049. str += args[n]->type.dataType.Format(outFunc->nameSpace);
  2050. }
  2051. if( namedArgs != 0 )
  2052. {
  2053. for( n = 0; n < namedArgs->GetLength(); n++ )
  2054. {
  2055. if( n > 0 || args.GetLength() )
  2056. str += ", ";
  2057. asSNamedArgument &named = (*namedArgs)[n];
  2058. str += named.name;
  2059. str += "=";
  2060. if( named.ctx->methodName != "" )
  2061. str += named.ctx->methodName;
  2062. else
  2063. str += named.ctx->type.dataType.Format(outFunc->nameSpace);
  2064. }
  2065. }
  2066. str += ")";
  2067. if( isConstMethod )
  2068. str += " const";
  2069. if( objectType && scope == "" )
  2070. str = objectType->name + "::" + str;
  2071. if( funcs.GetLength() == 0 )
  2072. {
  2073. str.Format(TXT_NO_MATCHING_SIGNATURES_TO_s, str.AddressOf());
  2074. Error(str, node);
  2075. if( attemptsPassingClassMethod )
  2076. {
  2077. // Class methods must use delegate objects
  2078. Error(TXT_CANNOT_PASS_CLASS_METHOD_AS_ARG, node);
  2079. }
  2080. else
  2081. {
  2082. // Print the list of candidates
  2083. if( origFuncs.GetLength() > 0 )
  2084. {
  2085. int r = 0, c = 0;
  2086. asASSERT( node );
  2087. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  2088. builder->WriteInfo(script->name.AddressOf(), TXT_CANDIDATES_ARE, r, c, false);
  2089. PrintMatchingFuncs(origFuncs, node, objectType);
  2090. }
  2091. }
  2092. }
  2093. else
  2094. {
  2095. asASSERT( attemptsPassingClassMethod == false );
  2096. str.Format(TXT_MULTIPLE_MATCHING_SIGNATURES_TO_s, str.AddressOf());
  2097. Error(str, node);
  2098. PrintMatchingFuncs(funcs, node, objectType);
  2099. }
  2100. }
  2101. return cost;
  2102. }
  2103. bool asCCompiler::CompileAutoType(asCDataType &type, asCExprContext &compiledCtx, asCScriptNode *node, asCScriptNode *errNode)
  2104. {
  2105. if( node && node->nodeType == snAssignment )
  2106. {
  2107. int r = CompileAssignment(node, &compiledCtx);
  2108. if( r >= 0 )
  2109. {
  2110. // Must not have unused ambiguous names
  2111. if (compiledCtx.IsClassMethod() || compiledCtx.IsGlobalFunc())
  2112. {
  2113. // TODO: Should mention that the problem is the ambiguous name
  2114. Error(TXT_CANNOT_RESOLVE_AUTO, errNode);
  2115. return false;
  2116. }
  2117. // Must not have unused anonymous functions
  2118. if (compiledCtx.IsLambda())
  2119. {
  2120. // TODO: Should mention that the problem is the anonymous function
  2121. Error(TXT_CANNOT_RESOLVE_AUTO, errNode);
  2122. return false;
  2123. }
  2124. // Must not be a null handle
  2125. if (compiledCtx.type.dataType.IsNullHandle())
  2126. {
  2127. // TODO: Should mention that the problem is the null pointer
  2128. Error(TXT_CANNOT_RESOLVE_AUTO, errNode);
  2129. return false;
  2130. }
  2131. asCDataType newType = compiledCtx.type.dataType;
  2132. // Handle const qualifier on auto
  2133. if (type.IsReadOnly())
  2134. newType.MakeReadOnly(true);
  2135. else if (newType.IsPrimitive())
  2136. newType.MakeReadOnly(false);
  2137. // Handle reference/value stuff
  2138. newType.MakeReference(false);
  2139. if (!newType.IsObjectHandle())
  2140. {
  2141. // We got a value object or an object reference.
  2142. // Turn the variable into a handle if specified
  2143. // as auto@, otherwise make it a 'value'.
  2144. if (type.IsHandleToAuto())
  2145. {
  2146. if (newType.MakeHandle(true) < 0)
  2147. {
  2148. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, errNode);
  2149. return false;
  2150. }
  2151. }
  2152. }
  2153. type = newType;
  2154. return true;
  2155. }
  2156. return false;
  2157. }
  2158. else
  2159. {
  2160. Error(TXT_CANNOT_RESOLVE_AUTO, errNode);
  2161. type = asCDataType::CreatePrimitive(ttInt, false);
  2162. return false;
  2163. }
  2164. }
  2165. void asCCompiler::CompileDeclaration(asCScriptNode *decl, asCByteCode *bc)
  2166. {
  2167. // Get the data type
  2168. asCDataType type = builder->CreateDataTypeFromNode(decl->firstChild, script, outFunc->nameSpace, false, outFunc->objectType);
  2169. // Declare all variables in this declaration
  2170. asCScriptNode *node = decl->firstChild->next;
  2171. while( node )
  2172. {
  2173. // If this is an auto type, we have to compile the assignment now to figure out the type
  2174. asCExprContext compiledCtx(engine);
  2175. bool preCompiled = false;
  2176. if (type.IsAuto())
  2177. {
  2178. preCompiled = CompileAutoType(type, compiledCtx, node->next, node);
  2179. if (!preCompiled)
  2180. {
  2181. // If it wasn't possible to determine the type from the expression then there
  2182. // is no need to continue with the initialization. The error was already reported
  2183. // in CompileAutoType.
  2184. return;
  2185. }
  2186. }
  2187. // Is the type allowed?
  2188. if( !type.CanBeInstantiated() )
  2189. {
  2190. asCString str;
  2191. if( type.IsAbstractClass() )
  2192. str.Format(TXT_ABSTRACT_CLASS_s_CANNOT_BE_INSTANTIATED, type.Format(outFunc->nameSpace).AddressOf());
  2193. else if( type.IsInterface() )
  2194. str.Format(TXT_INTERFACE_s_CANNOT_BE_INSTANTIATED, type.Format(outFunc->nameSpace).AddressOf());
  2195. else
  2196. // TODO: Improve error message to explain why
  2197. str.Format(TXT_DATA_TYPE_CANT_BE_s, type.Format(outFunc->nameSpace).AddressOf());
  2198. Error(str, node);
  2199. // Don't continue, as it will most likely lead to further
  2200. // errors that may just mislead the script writer
  2201. return;
  2202. }
  2203. // A shared object may not declare variables of non-shared types
  2204. if( outFunc->IsShared() )
  2205. {
  2206. asCTypeInfo *ot = type.GetTypeInfo();
  2207. if( ot && !ot->IsShared() )
  2208. {
  2209. asCString msg;
  2210. msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, ot->name.AddressOf());
  2211. Error(msg, decl);
  2212. }
  2213. }
  2214. // Get the name of the identifier
  2215. asCString name(&script->code[node->tokenPos], node->tokenLength);
  2216. // Verify that the name isn't used by a dynamic data type
  2217. // TODO: Must check against registered funcdefs too
  2218. if( engine->GetRegisteredType(name.AddressOf(), outFunc->nameSpace) != 0 )
  2219. {
  2220. asCString str;
  2221. str.Format(TXT_ILLEGAL_VARIABLE_NAME_s, name.AddressOf());
  2222. Error(str, node);
  2223. }
  2224. int offset = AllocateVariable(type, false);
  2225. if( variables->DeclareVariable(name.AddressOf(), type, offset, IsVariableOnHeap(offset)) < 0 )
  2226. {
  2227. // TODO: It might be an out-of-memory too
  2228. asCString str;
  2229. str.Format(TXT_s_ALREADY_DECLARED, name.AddressOf());
  2230. Error(str, node);
  2231. // Don't continue after this error, as it will just
  2232. // lead to more errors that are likely false
  2233. return;
  2234. }
  2235. else
  2236. {
  2237. // Warn if this variable hides another variable in a higher scope
  2238. if( variables->parent && variables->parent->GetVariable(name.AddressOf()) )
  2239. {
  2240. asCString str;
  2241. str.Format(TXT_s_HIDES_VAR_IN_OUTER_SCOPE, name.AddressOf());
  2242. Warning(str, node);
  2243. }
  2244. }
  2245. // Add marker that the variable has been declared
  2246. bc->VarDecl((int)outFunc->scriptData->variables.GetLength());
  2247. outFunc->AddVariable(name, type, offset);
  2248. // Keep the node for the variable decl
  2249. asCScriptNode *varNode = node;
  2250. node = node->next;
  2251. if( node == 0 || node->nodeType == snIdentifier )
  2252. {
  2253. // Initialize with default constructor
  2254. CompileInitialization(0, bc, type, varNode, offset, 0, 0);
  2255. }
  2256. else
  2257. {
  2258. // Compile the initialization expression
  2259. asQWORD constantValue = 0;
  2260. if( CompileInitialization(node, bc, type, varNode, offset, &constantValue, 0, preCompiled ? &compiledCtx : 0) )
  2261. {
  2262. // Check if the variable should be marked as pure constant
  2263. if( type.IsPrimitive() && type.IsReadOnly() )
  2264. {
  2265. sVariable *v = variables->GetVariable(name.AddressOf());
  2266. v->isPureConstant = true;
  2267. v->constantValue = constantValue;
  2268. }
  2269. }
  2270. node = node->next;
  2271. }
  2272. }
  2273. bc->OptimizeLocally(tempVariableOffsets);
  2274. }
  2275. // Returns true if the initialization expression is a constant expression
  2276. bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, const asCDataType &type, asCScriptNode *errNode, int offset, asQWORD *constantValue, int isVarGlobOrMem, asCExprContext *preCompiled)
  2277. {
  2278. bool isConstantExpression = false;
  2279. if( node && node->nodeType == snArgList )
  2280. {
  2281. // Make sure it is an object and not a handle
  2282. if( type.GetTypeInfo() == 0 || type.IsObjectHandle() )
  2283. {
  2284. Error(TXT_MUST_BE_OBJECT, node);
  2285. }
  2286. else
  2287. {
  2288. // Compile the arguments
  2289. asCArray<asCExprContext *> args;
  2290. asCArray<asSNamedArgument> namedArgs;
  2291. if( CompileArgumentList(node, args, namedArgs) >= 0 )
  2292. {
  2293. // Find all constructors
  2294. asCArray<int> funcs;
  2295. asSTypeBehaviour *beh = type.GetBehaviour();
  2296. if( beh )
  2297. {
  2298. if( type.GetTypeInfo()->flags & asOBJ_REF )
  2299. funcs = beh->factories;
  2300. else
  2301. funcs = beh->constructors;
  2302. }
  2303. asCString str = type.Format(outFunc->nameSpace);
  2304. MatchFunctions(funcs, args, node, str.AddressOf(), &namedArgs);
  2305. if( funcs.GetLength() == 1 )
  2306. {
  2307. // Add the default values for arguments not explicitly supplied
  2308. int r = CompileDefaultAndNamedArgs(node, args, funcs[0], CastToObjectType(type.GetTypeInfo()), &namedArgs);
  2309. if( r == asSUCCESS )
  2310. {
  2311. asCExprContext ctx(engine);
  2312. if( type.GetTypeInfo() && (type.GetTypeInfo()->flags & asOBJ_REF) )
  2313. {
  2314. if( isVarGlobOrMem == 0 )
  2315. MakeFunctionCall(&ctx, funcs[0], 0, args, node, true, offset);
  2316. else
  2317. {
  2318. MakeFunctionCall(&ctx, funcs[0], 0, args, node);
  2319. ctx.bc.Instr(asBC_RDSPtr);
  2320. if( isVarGlobOrMem == 1 )
  2321. {
  2322. // Store the returned handle in the global variable
  2323. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  2324. }
  2325. else
  2326. {
  2327. // Store the returned handle in the member
  2328. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2329. ctx.bc.Instr(asBC_RDSPtr);
  2330. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2331. }
  2332. if( type.IsFuncdef())
  2333. ctx.bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  2334. else
  2335. ctx.bc.InstrPTR(asBC_REFCPY, type.GetTypeInfo());
  2336. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  2337. }
  2338. // Pop the reference left by the function call
  2339. ctx.bc.Instr(asBC_PopPtr);
  2340. }
  2341. else
  2342. {
  2343. bool onHeap = false;
  2344. if( isVarGlobOrMem == 0 )
  2345. {
  2346. // When the object is allocated on the heap, the address where the
  2347. // reference will be stored must be pushed on the stack before the
  2348. // arguments. This reference on the stack is safe, even if the script
  2349. // is suspended during the evaluation of the arguments.
  2350. onHeap = IsVariableOnHeap(offset);
  2351. if( onHeap )
  2352. ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
  2353. }
  2354. else if( isVarGlobOrMem == 1 )
  2355. {
  2356. // Push the address of the location where the variable will be stored on the stack.
  2357. // This reference is safe, because the addresses of the global variables cannot change.
  2358. onHeap = true;
  2359. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  2360. }
  2361. else
  2362. {
  2363. // Value types may be allocated inline if they are POD types
  2364. onHeap = !(type.IsObject() || type.IsFuncdef()) || type.IsReference() || (type.GetTypeInfo()->flags & asOBJ_REF);
  2365. if( onHeap )
  2366. {
  2367. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2368. ctx.bc.Instr(asBC_RDSPtr);
  2369. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2370. }
  2371. }
  2372. PrepareFunctionCall(funcs[0], &ctx.bc, args);
  2373. MoveArgsToStack(funcs[0], &ctx.bc, args, false);
  2374. // When the object is allocated on the stack, the address to the
  2375. // object is pushed on the stack after the arguments as the object pointer
  2376. if( !onHeap )
  2377. {
  2378. if( isVarGlobOrMem == 2 )
  2379. {
  2380. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2381. ctx.bc.Instr(asBC_RDSPtr);
  2382. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2383. }
  2384. else
  2385. {
  2386. ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
  2387. }
  2388. }
  2389. PerformFunctionCall(funcs[0], &ctx, onHeap, &args, CastToObjectType(type.GetTypeInfo()));
  2390. if( isVarGlobOrMem == 0 )
  2391. {
  2392. // Mark the object in the local variable as initialized
  2393. ctx.bc.ObjInfo(offset, asOBJ_INIT);
  2394. }
  2395. }
  2396. bc->AddCode(&ctx.bc);
  2397. }
  2398. }
  2399. }
  2400. // Cleanup
  2401. for( asUINT n = 0; n < args.GetLength(); n++ )
  2402. if( args[n] )
  2403. {
  2404. asDELETE(args[n], asCExprContext);
  2405. }
  2406. for( asUINT n = 0; n < namedArgs.GetLength(); n++ )
  2407. if( namedArgs[n].ctx )
  2408. {
  2409. asDELETE(namedArgs[n].ctx, asCExprContext);
  2410. }
  2411. }
  2412. }
  2413. else if( node && node->nodeType == snInitList )
  2414. {
  2415. asCExprValue ti;
  2416. ti.Set(type);
  2417. ti.isVariable = (isVarGlobOrMem == 0);
  2418. ti.isTemporary = false;
  2419. ti.stackOffset = (short)offset;
  2420. ti.isLValue = true;
  2421. CompileInitList(&ti, node, bc, isVarGlobOrMem);
  2422. }
  2423. else if( node && node->nodeType == snAssignment )
  2424. {
  2425. // Compile the expression
  2426. asCExprContext newExpr(engine);
  2427. asCExprContext* expr;
  2428. int r = 0;
  2429. if( preCompiled )
  2430. {
  2431. expr = preCompiled;
  2432. }
  2433. else
  2434. {
  2435. expr = &newExpr;
  2436. r = CompileAssignment(node, expr);
  2437. }
  2438. // handles initialized with null doesn't need any bytecode
  2439. // since handles will be initialized to null by default anyway
  2440. if (type.IsObjectHandle() && expr->type.IsNullConstant() && expr->bc.IsSimpleExpression() )
  2441. return false;
  2442. // Look for appropriate constructor
  2443. asCArray<int> funcs;
  2444. asCArray<asCExprContext *> args;
  2445. // Handles must use the handle assignment operation.
  2446. // Types that are ASHANDLE must not allow the use of the constructor in this case,
  2447. // because it is ambiguous whether a value assignment or handle assignment will be done.
  2448. // Only do this if the expression is of the same type, as the expression is an assignment
  2449. // and an initialization constructor may not have the same meaning.
  2450. // TODO: Should allow initialization constructor if it is declared as allowed for implicit conversions.
  2451. if( !type.IsObjectHandle() && !expr->type.isExplicitHandle &&
  2452. !(type.GetTypeInfo() && (type.GetTypeInfo()->GetFlags() & asOBJ_ASHANDLE)) &&
  2453. type.IsEqualExceptRefAndConst(expr->type.dataType) )
  2454. {
  2455. asSTypeBehaviour *beh = type.GetBehaviour();
  2456. if( beh )
  2457. {
  2458. if( type.GetTypeInfo()->flags & asOBJ_REF )
  2459. funcs = beh->factories;
  2460. else
  2461. funcs = beh->constructors;
  2462. }
  2463. asCString str = type.Format(outFunc->nameSpace);
  2464. args.PushLast(expr);
  2465. MatchFunctions(funcs, args, node, str.AddressOf(), 0, 0, 0, true);
  2466. // Make sure the argument is of the right type (and not just compatible with the expression)
  2467. if (funcs.GetLength() == 1)
  2468. {
  2469. asCScriptFunction *f = engine->scriptFunctions[funcs[0]];
  2470. if (!f->parameterTypes[0].IsEqualExceptRefAndConst(expr->type.dataType))
  2471. funcs.PopLast();
  2472. }
  2473. }
  2474. if( funcs.GetLength() == 1 )
  2475. {
  2476. // Use the constructor
  2477. // TODO: clean-up: A large part of this is identical to the initalization with argList above
  2478. // Add the default values for arguments not explicitly supplied
  2479. r = CompileDefaultAndNamedArgs(node, args, funcs[0], CastToObjectType(type.GetTypeInfo()));
  2480. if( r == asSUCCESS )
  2481. {
  2482. asCExprContext ctx(engine);
  2483. if( type.GetTypeInfo() && (type.GetTypeInfo()->flags & asOBJ_REF) )
  2484. {
  2485. if( isVarGlobOrMem == 0 )
  2486. MakeFunctionCall(&ctx, funcs[0], 0, args, node, true, offset);
  2487. else
  2488. {
  2489. MakeFunctionCall(&ctx, funcs[0], 0, args, node);
  2490. ctx.bc.Instr(asBC_RDSPtr);
  2491. if( isVarGlobOrMem == 1 )
  2492. {
  2493. // Store the returned handle in the global variable
  2494. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  2495. }
  2496. else
  2497. {
  2498. // Store the returned handle in the member
  2499. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2500. ctx.bc.Instr(asBC_RDSPtr);
  2501. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2502. }
  2503. if( type.IsFuncdef() )
  2504. ctx.bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  2505. else
  2506. ctx.bc.InstrPTR(asBC_REFCPY, type.GetTypeInfo());
  2507. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  2508. }
  2509. // Pop the reference left by the function call
  2510. ctx.bc.Instr(asBC_PopPtr);
  2511. }
  2512. else
  2513. {
  2514. bool onHeap = false;
  2515. if( isVarGlobOrMem == 0 )
  2516. {
  2517. // When the object is allocated on the heap, the address where the
  2518. // reference will be stored must be pushed on the stack before the
  2519. // arguments. This reference on the stack is safe, even if the script
  2520. // is suspended during the evaluation of the arguments.
  2521. onHeap = IsVariableOnHeap(offset);
  2522. if( onHeap )
  2523. ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
  2524. }
  2525. else if( isVarGlobOrMem == 1 )
  2526. {
  2527. // Push the address of the location where the variable will be stored on the stack.
  2528. // This reference is safe, because the addresses of the global variables cannot change.
  2529. onHeap = true;
  2530. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  2531. }
  2532. else
  2533. {
  2534. // Value types may be allocated inline if they are POD types
  2535. onHeap = !(type.IsObject() || type.IsFuncdef()) || type.IsReference() || (type.GetTypeInfo()->flags & asOBJ_REF);
  2536. if( onHeap )
  2537. {
  2538. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2539. ctx.bc.Instr(asBC_RDSPtr);
  2540. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2541. }
  2542. }
  2543. PrepareFunctionCall(funcs[0], &ctx.bc, args);
  2544. MoveArgsToStack(funcs[0], &ctx.bc, args, false);
  2545. // When the object is allocated on the stack, the address to the
  2546. // object is pushed on the stack after the arguments as the object pointer
  2547. if( !onHeap )
  2548. {
  2549. if( isVarGlobOrMem == 2 )
  2550. {
  2551. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2552. ctx.bc.Instr(asBC_RDSPtr);
  2553. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2554. }
  2555. else
  2556. {
  2557. ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
  2558. }
  2559. }
  2560. PerformFunctionCall(funcs[0], &ctx, onHeap, &args, CastToObjectType(type.GetTypeInfo()));
  2561. if( isVarGlobOrMem == 0 )
  2562. {
  2563. // Mark the object in the local variable as initialized
  2564. ctx.bc.ObjInfo(offset, asOBJ_INIT);
  2565. }
  2566. }
  2567. bc->AddCode(&ctx.bc);
  2568. }
  2569. }
  2570. else
  2571. {
  2572. // Call the default constructur, then call the assignment operator
  2573. asCExprContext ctx(engine);
  2574. // Call the default constructor here
  2575. if( isVarGlobOrMem == 0 )
  2576. CallDefaultConstructor(type, offset, IsVariableOnHeap(offset), &ctx.bc, errNode);
  2577. else if( isVarGlobOrMem == 1 )
  2578. CallDefaultConstructor(type, offset, true, &ctx.bc, errNode, isVarGlobOrMem);
  2579. else if( isVarGlobOrMem == 2 )
  2580. CallDefaultConstructor(type, offset, type.IsReference(), &ctx.bc, errNode, isVarGlobOrMem);
  2581. if( r >= 0 )
  2582. {
  2583. if( type.IsPrimitive() )
  2584. {
  2585. if( type.IsReadOnly() && expr->type.isConstant )
  2586. {
  2587. ImplicitConversion(expr, type, node, asIC_IMPLICIT_CONV);
  2588. // Tell caller that the expression is a constant so it can mark the variable as pure constant
  2589. isConstantExpression = true;
  2590. *constantValue = expr->type.GetConstantData();
  2591. }
  2592. asCExprContext lctx(engine);
  2593. if( isVarGlobOrMem == 0 )
  2594. lctx.type.SetVariable(type, offset, false);
  2595. else if( isVarGlobOrMem == 1 )
  2596. {
  2597. lctx.type.Set(type);
  2598. lctx.type.dataType.MakeReference(true);
  2599. // If it is an enum value, i.e. offset is negative, that is being compiled then
  2600. // we skip this as the bytecode won't be used anyway, only the constant value
  2601. if( offset >= 0 )
  2602. lctx.bc.InstrPTR(asBC_LDG, engine->globalProperties[offset]->GetAddressOfValue());
  2603. }
  2604. else
  2605. {
  2606. asASSERT( isVarGlobOrMem == 2 );
  2607. lctx.type.Set(type);
  2608. lctx.type.dataType.MakeReference(true);
  2609. // Load the reference of the primitive member into the register
  2610. lctx.bc.InstrSHORT(asBC_PSF, 0);
  2611. lctx.bc.Instr(asBC_RDSPtr);
  2612. lctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2613. lctx.bc.Instr(asBC_PopRPtr);
  2614. }
  2615. lctx.type.dataType.MakeReadOnly(false);
  2616. lctx.type.isLValue = true;
  2617. DoAssignment(&ctx, &lctx, expr, node, node, ttAssignment, node);
  2618. ProcessDeferredParams(&ctx);
  2619. }
  2620. else
  2621. {
  2622. // TODO: runtime optimize: Here we should look for the best matching constructor, instead of
  2623. // just the copy constructor. Only if no appropriate constructor is
  2624. // available should the assignment operator be used.
  2625. asCExprContext lexpr(engine);
  2626. lexpr.type.Set(type);
  2627. if( isVarGlobOrMem == 0 )
  2628. lexpr.type.dataType.MakeReference(IsVariableOnHeap(offset));
  2629. else if( isVarGlobOrMem == 1 )
  2630. lexpr.type.dataType.MakeReference(true);
  2631. else if( isVarGlobOrMem == 2 )
  2632. {
  2633. if( !lexpr.type.dataType.IsObject() || lexpr.type.dataType.IsFuncdef() || (lexpr.type.dataType.GetTypeInfo()->flags & asOBJ_REF) )
  2634. lexpr.type.dataType.MakeReference(true);
  2635. }
  2636. // Allow initialization of constant variables
  2637. lexpr.type.dataType.MakeReadOnly(false);
  2638. if( type.IsObjectHandle() )
  2639. lexpr.type.isExplicitHandle = true;
  2640. if( isVarGlobOrMem == 0 )
  2641. {
  2642. lexpr.bc.InstrSHORT(asBC_PSF, (short)offset);
  2643. lexpr.type.stackOffset = (short)offset;
  2644. lexpr.type.isVariable = true;
  2645. }
  2646. else if( isVarGlobOrMem == 1 )
  2647. {
  2648. lexpr.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  2649. }
  2650. else
  2651. {
  2652. lexpr.bc.InstrSHORT(asBC_PSF, 0);
  2653. lexpr.bc.Instr(asBC_RDSPtr);
  2654. lexpr.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2655. lexpr.type.stackOffset = -1;
  2656. }
  2657. lexpr.type.isLValue = true;
  2658. // If left expression resolves into a registered type
  2659. // check if the assignment operator is overloaded, and check
  2660. // the type of the right hand expression. If none is found
  2661. // the default action is a direct copy if it is the same type
  2662. // and a simple assignment.
  2663. bool assigned = false;
  2664. // Even though an ASHANDLE can be an explicit handle the overloaded operator needs to be called
  2665. if( (lexpr.type.dataType.IsObject() || lexpr.type.dataType.IsFuncdef()) && (!lexpr.type.isExplicitHandle || (lexpr.type.dataType.GetTypeInfo() && (lexpr.type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE))) )
  2666. {
  2667. bool useHndlAssign = lexpr.type.dataType.IsHandleToAsHandleType();
  2668. assigned = CompileOverloadedDualOperator(node, &lexpr, expr, false, &ctx, useHndlAssign);
  2669. if( assigned )
  2670. {
  2671. // Pop the resulting value
  2672. if( !ctx.type.dataType.IsPrimitive() )
  2673. ctx.bc.Instr(asBC_PopPtr);
  2674. // Release the argument
  2675. ProcessDeferredParams(&ctx);
  2676. // Release temporary variable that may be allocated by the overloaded operator
  2677. ReleaseTemporaryVariable(ctx.type, &ctx.bc);
  2678. }
  2679. }
  2680. if( !assigned )
  2681. {
  2682. PrepareForAssignment(&lexpr.type.dataType, expr, node, false);
  2683. // If the expression is constant and the variable also is constant
  2684. // then mark the variable as pure constant. This will allow the compiler
  2685. // to optimize expressions with this variable.
  2686. if( type.IsReadOnly() && expr->type.isConstant )
  2687. {
  2688. isConstantExpression = true;
  2689. *constantValue = expr->type.GetConstantQW();
  2690. }
  2691. // Add expression code to bytecode
  2692. MergeExprBytecode(&ctx, expr);
  2693. // Add byte code for storing value of expression in variable
  2694. ctx.bc.AddCode(&lexpr.bc);
  2695. PerformAssignment(&lexpr.type, &expr->type, &ctx.bc, errNode);
  2696. // Release temporary variables used by expression
  2697. ReleaseTemporaryVariable(expr->type, &ctx.bc);
  2698. ctx.bc.Instr(asBC_PopPtr);
  2699. ProcessDeferredParams(&ctx);
  2700. }
  2701. }
  2702. }
  2703. bc->AddCode(&ctx.bc);
  2704. }
  2705. }
  2706. else
  2707. {
  2708. asASSERT( node == 0 );
  2709. // Call the default constructor here, as no explicit initialization is done
  2710. if( isVarGlobOrMem == 0 )
  2711. CallDefaultConstructor(type, offset, IsVariableOnHeap(offset), bc, errNode);
  2712. else if( isVarGlobOrMem == 1 )
  2713. CallDefaultConstructor(type, offset, true, bc, errNode, isVarGlobOrMem);
  2714. else if( isVarGlobOrMem == 2 )
  2715. {
  2716. if( !(type.IsObject() || type.IsFuncdef()) || type.IsReference() || (type.GetTypeInfo()->flags & asOBJ_REF) )
  2717. CallDefaultConstructor(type, offset, true, bc, errNode, isVarGlobOrMem);
  2718. else
  2719. CallDefaultConstructor(type, offset, false, bc, errNode, isVarGlobOrMem);
  2720. }
  2721. }
  2722. return isConstantExpression;
  2723. }
  2724. void asCCompiler::CompileInitList(asCExprValue *var, asCScriptNode *node, asCByteCode *bc, int isVarGlobOrMem)
  2725. {
  2726. // Check if the type supports initialization lists
  2727. if( var->dataType.GetTypeInfo() == 0 ||
  2728. var->dataType.GetBehaviour()->listFactory == 0 )
  2729. {
  2730. asCString str;
  2731. str.Format(TXT_INIT_LIST_CANNOT_BE_USED_WITH_s, var->dataType.Format(outFunc->nameSpace).AddressOf());
  2732. Error(str, node);
  2733. return;
  2734. }
  2735. // Construct the buffer with the elements
  2736. // Find the list factory
  2737. int funcId = var->dataType.GetBehaviour()->listFactory;
  2738. asASSERT( engine->scriptFunctions[funcId]->listPattern );
  2739. // TODO: runtime optimize: A future optimization should be to use the stack space directly
  2740. // for small buffers so that the dynamic allocation is skipped
  2741. // Create a new special object type for the lists. Both asCRestore and the
  2742. // context exception handler will need this to know how to parse the buffer.
  2743. asCObjectType *listPatternType = engine->GetListPatternType(funcId);
  2744. // Allocate a temporary variable to hold the pointer to the buffer
  2745. int bufferVar = AllocateVariable(asCDataType::CreateType(listPatternType, false), true);
  2746. asUINT bufferSize = 0;
  2747. // Evaluate all elements of the list
  2748. asCExprContext valueExpr(engine);
  2749. asCScriptNode *el = node;
  2750. asSListPatternNode *patternNode = engine->scriptFunctions[listPatternType->templateSubTypes[0].GetBehaviour()->listFactory]->listPattern;
  2751. int elementsInSubList = -1;
  2752. int r = CompileInitListElement(patternNode, el, engine->GetTypeIdFromDataType(asCDataType::CreateType(listPatternType, false)), short(bufferVar), bufferSize, valueExpr.bc, elementsInSubList);
  2753. asASSERT( r || patternNode == 0 );
  2754. if (r < 0)
  2755. {
  2756. asCString msg;
  2757. msg.Format(TXT_PREV_ERROR_WHILE_COMP_LIST_FOR_TYPE_s, var->dataType.Format(outFunc->nameSpace).AddressOf());
  2758. Error(msg, node);
  2759. }
  2760. // After all values have been evaluated we know the final size of the buffer
  2761. asCExprContext allocExpr(engine);
  2762. allocExpr.bc.InstrSHORT_DW(asBC_AllocMem, short(bufferVar), bufferSize);
  2763. // Merge the bytecode into the final sequence
  2764. bc->AddCode(&allocExpr.bc);
  2765. bc->AddCode(&valueExpr.bc);
  2766. // The object itself is the last to be created and will receive the pointer to the buffer
  2767. asCArray<asCExprContext *> args;
  2768. asCExprContext arg1(engine);
  2769. arg1.type.Set(asCDataType::CreatePrimitive(ttUInt, false));
  2770. arg1.type.dataType.MakeReference(true);
  2771. arg1.bc.InstrSHORT(asBC_PshVPtr, short(bufferVar));
  2772. args.PushLast(&arg1);
  2773. asCExprContext ctx(engine);
  2774. if( var->isVariable )
  2775. {
  2776. asASSERT( isVarGlobOrMem == 0 );
  2777. if( var->dataType.GetTypeInfo()->GetFlags() & asOBJ_REF )
  2778. {
  2779. ctx.bc.AddCode(&arg1.bc);
  2780. // Call factory and store the handle in the given variable
  2781. PerformFunctionCall(funcId, &ctx, false, &args, 0, true, var->stackOffset);
  2782. ctx.bc.Instr(asBC_PopPtr);
  2783. }
  2784. else
  2785. {
  2786. // Call the constructor
  2787. // When the object is allocated on the heap, the address where the
  2788. // reference will be stored must be pushed on the stack before the
  2789. // arguments. This reference on the stack is safe, even if the script
  2790. // is suspended during the evaluation of the arguments.
  2791. bool onHeap = IsVariableOnHeap(var->stackOffset);
  2792. if( onHeap )
  2793. ctx.bc.InstrSHORT(asBC_PSF, var->stackOffset);
  2794. ctx.bc.AddCode(&arg1.bc);
  2795. // When the object is allocated on the stack, the address to the
  2796. // object is pushed on the stack after the arguments as the object pointer
  2797. if( !onHeap )
  2798. ctx.bc.InstrSHORT(asBC_PSF, var->stackOffset);
  2799. PerformFunctionCall(funcId, &ctx, onHeap, &args, CastToObjectType(var->dataType.GetTypeInfo()));
  2800. // Mark the object in the local variable as initialized
  2801. ctx.bc.ObjInfo(var->stackOffset, asOBJ_INIT);
  2802. }
  2803. }
  2804. else
  2805. {
  2806. if( var->dataType.GetTypeInfo()->GetFlags() & asOBJ_REF )
  2807. {
  2808. ctx.bc.AddCode(&arg1.bc);
  2809. PerformFunctionCall(funcId, &ctx, false, &args);
  2810. ctx.bc.Instr(asBC_RDSPtr);
  2811. if( isVarGlobOrMem == 1 )
  2812. {
  2813. // Store the returned handle in the global variable
  2814. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[var->stackOffset]->GetAddressOfValue());
  2815. }
  2816. else
  2817. {
  2818. // Store the returned handle in the member
  2819. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2820. ctx.bc.Instr(asBC_RDSPtr);
  2821. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)var->stackOffset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2822. }
  2823. if (var->dataType.IsFuncdef())
  2824. ctx.bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  2825. else
  2826. ctx.bc.InstrPTR(asBC_REFCPY, var->dataType.GetTypeInfo());
  2827. ctx.bc.Instr(asBC_PopPtr);
  2828. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  2829. }
  2830. else
  2831. {
  2832. bool onHeap = true;
  2833. // Put the address where the object pointer will be placed on the stack
  2834. if( isVarGlobOrMem == 1 )
  2835. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[var->stackOffset]->GetAddressOfValue());
  2836. else
  2837. {
  2838. onHeap = !(var->dataType.IsObject() || var->dataType.IsFuncdef()) || var->dataType.IsReference() || (var->dataType.GetTypeInfo()->flags & asOBJ_REF);
  2839. if( onHeap )
  2840. {
  2841. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2842. ctx.bc.Instr(asBC_RDSPtr);
  2843. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)var->stackOffset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2844. }
  2845. }
  2846. // Add the address of the list buffer as the argument
  2847. ctx.bc.AddCode(&arg1.bc);
  2848. if( !onHeap )
  2849. {
  2850. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2851. ctx.bc.Instr(asBC_RDSPtr);
  2852. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)var->stackOffset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2853. }
  2854. // Call the ALLOC instruction to allocate memory and invoke constructor
  2855. PerformFunctionCall(funcId, &ctx, onHeap, &args, CastToObjectType(var->dataType.GetTypeInfo()));
  2856. }
  2857. }
  2858. bc->AddCode(&ctx.bc);
  2859. // Free the temporary buffer. The FREE instruction will make sure to destroy
  2860. // each element in the buffer so there is no need to do this manually
  2861. bc->InstrW_PTR(asBC_FREE, short(bufferVar), listPatternType);
  2862. ReleaseTemporaryVariable(bufferVar, bc);
  2863. }
  2864. int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScriptNode *&valueNode, int bufferTypeId, short bufferVar, asUINT &bufferSize, asCByteCode &bcInit, int &elementsInSubList)
  2865. {
  2866. if( patternNode->type == asLPT_START )
  2867. {
  2868. if( valueNode == 0 || valueNode->nodeType != snInitList )
  2869. {
  2870. Error(TXT_EXPECTED_LIST, valueNode);
  2871. return -1;
  2872. }
  2873. // Compile all values until asLPT_END
  2874. patternNode = patternNode->next;
  2875. asCScriptNode *node = valueNode->firstChild;
  2876. while( patternNode->type != asLPT_END )
  2877. {
  2878. // Check for missing value here, else the error reporting will not have a source position to report the error for
  2879. if( node == 0 && patternNode->type == asLPT_TYPE )
  2880. {
  2881. Error(TXT_NOT_ENOUGH_VALUES_FOR_LIST, valueNode);
  2882. return -1;
  2883. }
  2884. asCScriptNode *errNode = node;
  2885. int r = CompileInitListElement(patternNode, node, bufferTypeId, bufferVar, bufferSize, bcInit, elementsInSubList);
  2886. if( r < 0 ) return r;
  2887. if( r == 1 )
  2888. {
  2889. asASSERT( engine->ep.disallowEmptyListElements );
  2890. // Empty elements in the middle are not allowed
  2891. Error(TXT_EMPTY_LIST_ELEMENT_IS_NOT_ALLOWED, errNode);
  2892. }
  2893. asASSERT( patternNode );
  2894. }
  2895. if( node )
  2896. {
  2897. Error(TXT_TOO_MANY_VALUES_FOR_LIST, valueNode);
  2898. return -1;
  2899. }
  2900. // Move to the next node
  2901. valueNode = valueNode->next;
  2902. patternNode = patternNode->next;
  2903. }
  2904. else if( patternNode->type == asLPT_REPEAT || patternNode->type == asLPT_REPEAT_SAME )
  2905. {
  2906. // TODO: list: repeat_inner should make sure the list has the same size as the inner list, i.e. square area
  2907. // TODO: list: repeat_prev should make sure the list is the same size as the previous
  2908. asEListPatternNodeType repeatType = patternNode->type;
  2909. asCScriptNode *firstValue = valueNode;
  2910. // The following values will be repeated N times
  2911. patternNode = patternNode->next;
  2912. // Keep track of the patternNode so it can be reset
  2913. asSListPatternNode *nextNode = patternNode;
  2914. // Align the buffer size to 4 bytes in case previous value was smaller than 4 bytes
  2915. if( bufferSize & 0x3 )
  2916. bufferSize += 4 - (bufferSize & 0x3);
  2917. // The first dword will hold the number of elements in the list
  2918. asDWORD currSize = bufferSize;
  2919. bufferSize += 4;
  2920. asUINT countElements = 0;
  2921. int elementsInSubSubList = -1;
  2922. asCExprContext ctx(engine);
  2923. while( valueNode )
  2924. {
  2925. patternNode = nextNode;
  2926. asCScriptNode *errNode = valueNode;
  2927. int r = CompileInitListElement(patternNode, valueNode, bufferTypeId, bufferVar, bufferSize, ctx.bc, elementsInSubSubList);
  2928. if( r < 0 ) return r;
  2929. if( r == 0 )
  2930. countElements++;
  2931. else
  2932. {
  2933. asASSERT( r == 1 && engine->ep.disallowEmptyListElements );
  2934. if( valueNode )
  2935. {
  2936. // Empty elements in the middle are not allowed
  2937. Error(TXT_EMPTY_LIST_ELEMENT_IS_NOT_ALLOWED, errNode);
  2938. }
  2939. }
  2940. }
  2941. if( countElements == 0 )
  2942. {
  2943. // Skip the sub pattern that was expected to be repeated, otherwise the caller will try to match these when we return
  2944. patternNode = nextNode;
  2945. if( patternNode->type == asLPT_TYPE )
  2946. patternNode = patternNode->next;
  2947. else if( patternNode->type == asLPT_START )
  2948. {
  2949. int subCount = 1;
  2950. do
  2951. {
  2952. patternNode = patternNode->next;
  2953. if( patternNode->type == asLPT_START )
  2954. subCount++;
  2955. else if( patternNode->type == asLPT_END )
  2956. subCount--;
  2957. } while( subCount > 0 );
  2958. patternNode = patternNode->next;
  2959. }
  2960. }
  2961. // For repeat_same each repeated sublist must have the same size to form a rectangular array
  2962. if( repeatType == asLPT_REPEAT_SAME && elementsInSubList != -1 && asUINT(elementsInSubList) != countElements )
  2963. {
  2964. if( countElements < asUINT(elementsInSubList) )
  2965. Error(TXT_NOT_ENOUGH_VALUES_FOR_LIST, firstValue);
  2966. else
  2967. Error(TXT_TOO_MANY_VALUES_FOR_LIST, firstValue);
  2968. return -1;
  2969. }
  2970. else
  2971. {
  2972. // Return to caller the amount of elments in this sublist
  2973. elementsInSubList = countElements;
  2974. }
  2975. // The first dword in the buffer will hold the number of elements
  2976. bcInit.InstrSHORT_DW_DW(asBC_SetListSize, bufferVar, currSize, countElements);
  2977. // Add the values
  2978. bcInit.AddCode(&ctx.bc);
  2979. }
  2980. else if( patternNode->type == asLPT_TYPE )
  2981. {
  2982. bool isEmpty = false;
  2983. // Determine the size of the element
  2984. asUINT size = 0;
  2985. asCDataType dt = reinterpret_cast<asSListPatternDataTypeNode*>(patternNode)->dataType;
  2986. if( valueNode->nodeType == snAssignment || valueNode->nodeType == snInitList )
  2987. {
  2988. asCExprContext lctx(engine);
  2989. asCExprContext rctx(engine);
  2990. if( valueNode->nodeType == snAssignment )
  2991. {
  2992. // Compile the assignment expression
  2993. CompileAssignment(valueNode, &rctx);
  2994. if( dt.GetTokenType() == ttQuestion )
  2995. {
  2996. // Make sure the type is not ambiguous
  2997. DetermineSingleFunc(&rctx, valueNode);
  2998. // We now know the type
  2999. dt = rctx.type.dataType;
  3000. dt.MakeReadOnly(false);
  3001. dt.MakeReference(false);
  3002. // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit.
  3003. if( bufferSize & 0x3 )
  3004. bufferSize += 4 - (bufferSize & 0x3);
  3005. // Place the type id in the buffer
  3006. bcInit.InstrSHORT_DW_DW(asBC_SetListType, bufferVar, bufferSize, engine->GetTypeIdFromDataType(dt));
  3007. bufferSize += 4;
  3008. }
  3009. }
  3010. else if( valueNode->nodeType == snInitList )
  3011. {
  3012. if( dt.GetTokenType() == ttQuestion )
  3013. {
  3014. // Can't use init lists with var type as it is not possible to determine what type should be allocated
  3015. asCString str;
  3016. str.Format(TXT_INIT_LIST_CANNOT_BE_USED_WITH_s, "?");
  3017. Error(str.AddressOf(), valueNode);
  3018. rctx.type.SetDummy();
  3019. dt = rctx.type.dataType;
  3020. }
  3021. else
  3022. {
  3023. // Allocate a temporary variable that will be initialized with the list
  3024. int offset = AllocateVariable(dt, true);
  3025. rctx.type.Set(dt);
  3026. rctx.type.isVariable = true;
  3027. rctx.type.isTemporary = true;
  3028. rctx.type.stackOffset = (short)offset;
  3029. CompileInitList(&rctx.type, valueNode, &rctx.bc, 0);
  3030. // Put the object on the stack
  3031. rctx.bc.InstrSHORT(asBC_PSF, rctx.type.stackOffset);
  3032. // It is a reference that we place on the stack
  3033. rctx.type.dataType.MakeReference(true);
  3034. }
  3035. }
  3036. // Determine size of the element
  3037. if( dt.IsPrimitive() || (!dt.IsNullHandle() && (dt.GetTypeInfo()->flags & asOBJ_VALUE)) )
  3038. size = dt.GetSizeInMemoryBytes();
  3039. else
  3040. size = AS_PTR_SIZE*4;
  3041. // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit.
  3042. if( size >= 4 && (bufferSize & 0x3) )
  3043. bufferSize += 4 - (bufferSize & 0x3);
  3044. // Compile the lvalue
  3045. lctx.bc.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize);
  3046. lctx.type.Set(dt);
  3047. lctx.type.isLValue = true;
  3048. if( dt.IsPrimitive() )
  3049. {
  3050. lctx.bc.Instr(asBC_PopRPtr);
  3051. lctx.type.dataType.MakeReference(true);
  3052. }
  3053. else if( dt.IsObjectHandle() ||
  3054. dt.GetTypeInfo()->flags & asOBJ_REF )
  3055. {
  3056. lctx.type.isExplicitHandle = true;
  3057. lctx.type.dataType.MakeReference(true);
  3058. }
  3059. else
  3060. {
  3061. asASSERT( dt.GetTypeInfo()->flags & asOBJ_VALUE );
  3062. // Make sure the object has been constructed before the assignment
  3063. // TODO: runtime optimize: Use copy constructor instead of assignment to initialize the objects
  3064. asSTypeBehaviour *beh = dt.GetBehaviour();
  3065. int func = 0;
  3066. if( beh ) func = beh->construct;
  3067. if( func == 0 && (dt.GetTypeInfo()->flags & asOBJ_POD) == 0 )
  3068. {
  3069. asCString str;
  3070. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetTypeInfo()->GetName());
  3071. Error(str, valueNode);
  3072. }
  3073. else if( func )
  3074. {
  3075. // Call the constructor as a normal function
  3076. bcInit.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize);
  3077. asCExprContext ctx(engine);
  3078. PerformFunctionCall(func, &ctx, false, 0, CastToObjectType(dt.GetTypeInfo()));
  3079. bcInit.AddCode(&ctx.bc);
  3080. }
  3081. }
  3082. if( lctx.type.dataType.IsNullHandle() )
  3083. {
  3084. // Don't add any code to assign a null handle. RefCpy doesn't work without a known type.
  3085. // The buffer is already initialized to zero in asBC_AllocMem anyway.
  3086. asASSERT( rctx.bc.GetLastInstr() == asBC_PshNull );
  3087. asASSERT( reinterpret_cast<asSListPatternDataTypeNode*>(patternNode)->dataType.GetTokenType() == ttQuestion );
  3088. }
  3089. else
  3090. {
  3091. asCExprContext ctx(engine);
  3092. DoAssignment(&ctx, &lctx, &rctx, valueNode, valueNode, ttAssignment, valueNode);
  3093. if( !lctx.type.dataType.IsPrimitive() )
  3094. ctx.bc.Instr(asBC_PopPtr);
  3095. // Release temporary variables used by expression
  3096. ReleaseTemporaryVariable(ctx.type, &ctx.bc);
  3097. ProcessDeferredParams(&ctx);
  3098. bcInit.AddCode(&ctx.bc);
  3099. }
  3100. }
  3101. else
  3102. {
  3103. if( builder->engine->ep.disallowEmptyListElements )
  3104. {
  3105. // Empty elements are not allowed, except if it is the last in the list
  3106. isEmpty = true;
  3107. }
  3108. else
  3109. {
  3110. // There is no specific value so we need to fill it with a default value
  3111. if( dt.GetTokenType() == ttQuestion )
  3112. {
  3113. // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit.
  3114. if( bufferSize & 0x3 )
  3115. bufferSize += 4 - (bufferSize & 0x3);
  3116. // Place the type id for a null handle in the buffer
  3117. bcInit.InstrSHORT_DW_DW(asBC_SetListType, bufferVar, bufferSize, 0);
  3118. bufferSize += 4;
  3119. dt = asCDataType::CreateNullHandle();
  3120. // No need to initialize the handle as the buffer is already initialized with zeroes
  3121. }
  3122. else if( dt.GetTypeInfo() && dt.GetTypeInfo()->flags & asOBJ_VALUE )
  3123. {
  3124. // For value types with default constructor we need to call the constructor
  3125. asSTypeBehaviour *beh = dt.GetBehaviour();
  3126. int func = 0;
  3127. if( beh ) func = beh->construct;
  3128. if( func == 0 && (dt.GetTypeInfo()->flags & asOBJ_POD) == 0 )
  3129. {
  3130. asCString str;
  3131. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetTypeInfo()->GetName());
  3132. Error(str, valueNode);
  3133. }
  3134. else if( func )
  3135. {
  3136. // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit.
  3137. if( bufferSize & 0x3 )
  3138. bufferSize += 4 - (bufferSize & 0x3);
  3139. // Call the constructor as a normal function
  3140. bcInit.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize);
  3141. asCExprContext ctx(engine);
  3142. PerformFunctionCall(func, &ctx, false, 0, CastToObjectType(dt.GetTypeInfo()));
  3143. bcInit.AddCode(&ctx.bc);
  3144. }
  3145. }
  3146. else if( !dt.IsObjectHandle() && dt.GetTypeInfo() && dt.GetTypeInfo()->flags & asOBJ_REF )
  3147. {
  3148. // For ref types (not handles) we need to call the default factory
  3149. asSTypeBehaviour *beh = dt.GetBehaviour();
  3150. int func = 0;
  3151. if( beh ) func = beh->factory;
  3152. if( func == 0 )
  3153. {
  3154. asCString str;
  3155. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetTypeInfo()->GetName());
  3156. Error(str, valueNode);
  3157. }
  3158. else if( func )
  3159. {
  3160. asCExprContext rctx(engine);
  3161. PerformFunctionCall(func, &rctx, false, 0, CastToObjectType(dt.GetTypeInfo()));
  3162. // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit.
  3163. if( bufferSize & 0x3 )
  3164. bufferSize += 4 - (bufferSize & 0x3);
  3165. asCExprContext lctx(engine);
  3166. lctx.bc.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize);
  3167. lctx.type.Set(dt);
  3168. lctx.type.isLValue = true;
  3169. lctx.type.isExplicitHandle = true;
  3170. lctx.type.dataType.MakeReference(true);
  3171. asCExprContext ctx(engine);
  3172. DoAssignment(&ctx, &lctx, &rctx, valueNode, valueNode, ttAssignment, valueNode);
  3173. if( !lctx.type.dataType.IsPrimitive() )
  3174. ctx.bc.Instr(asBC_PopPtr);
  3175. // Release temporary variables used by expression
  3176. ReleaseTemporaryVariable(ctx.type, &ctx.bc);
  3177. ProcessDeferredParams(&ctx);
  3178. bcInit.AddCode(&ctx.bc);
  3179. }
  3180. }
  3181. }
  3182. }
  3183. if( !isEmpty )
  3184. {
  3185. // Determine size of the element
  3186. if( dt.IsPrimitive() || (!dt.IsNullHandle() && (dt.GetTypeInfo()->flags & asOBJ_VALUE)) )
  3187. size = dt.GetSizeInMemoryBytes();
  3188. else
  3189. size = AS_PTR_SIZE*4;
  3190. asASSERT( size <= 4 || (size & 0x3) == 0 );
  3191. bufferSize += size;
  3192. }
  3193. // Move to the next element
  3194. patternNode = patternNode->next;
  3195. valueNode = valueNode->next;
  3196. if( isEmpty )
  3197. {
  3198. // The caller will determine if the empty element should be ignored or not
  3199. return 1;
  3200. }
  3201. }
  3202. else
  3203. asASSERT( false );
  3204. return 0;
  3205. }
  3206. void asCCompiler::CompileStatement(asCScriptNode *statement, bool *hasReturn, asCByteCode *bc)
  3207. {
  3208. // Don't clear the hasReturn flag if this is an empty statement
  3209. // to avoid false errors of 'not all paths return'
  3210. if( statement->nodeType != snExpressionStatement || statement->firstChild )
  3211. *hasReturn = false;
  3212. if( statement->nodeType == snStatementBlock )
  3213. CompileStatementBlock(statement, true, hasReturn, bc);
  3214. else if( statement->nodeType == snIf )
  3215. CompileIfStatement(statement, hasReturn, bc);
  3216. else if( statement->nodeType == snFor )
  3217. CompileForStatement(statement, bc);
  3218. else if( statement->nodeType == snWhile )
  3219. CompileWhileStatement(statement, bc);
  3220. else if( statement->nodeType == snDoWhile )
  3221. CompileDoWhileStatement(statement, bc);
  3222. else if( statement->nodeType == snExpressionStatement )
  3223. CompileExpressionStatement(statement, bc);
  3224. else if( statement->nodeType == snBreak )
  3225. CompileBreakStatement(statement, bc);
  3226. else if( statement->nodeType == snContinue )
  3227. CompileContinueStatement(statement, bc);
  3228. else if( statement->nodeType == snSwitch )
  3229. CompileSwitchStatement(statement, hasReturn, bc);
  3230. else if( statement->nodeType == snReturn )
  3231. {
  3232. CompileReturnStatement(statement, bc);
  3233. *hasReturn = true;
  3234. }
  3235. }
  3236. void asCCompiler::CompileSwitchStatement(asCScriptNode *snode, bool *, asCByteCode *bc)
  3237. {
  3238. // TODO: inheritance: Must guarantee that all options in the switch case call a constructor, or that none call it.
  3239. // Reserve label for break statements
  3240. int breakLabel = nextLabel++;
  3241. breakLabels.PushLast(breakLabel);
  3242. // Add a variable scope that will be used by CompileBreak
  3243. // to know where to stop deallocating variables
  3244. AddVariableScope(true, false);
  3245. //---------------------------
  3246. // Compile the switch expression
  3247. //-------------------------------
  3248. // Compile the switch expression
  3249. asCExprContext expr(engine);
  3250. CompileAssignment(snode->firstChild, &expr);
  3251. // Verify that the expression is a primitive type
  3252. if( !expr.type.dataType.IsIntegerType() && !expr.type.dataType.IsUnsignedType() )
  3253. {
  3254. Error(TXT_SWITCH_MUST_BE_INTEGRAL, snode->firstChild);
  3255. return;
  3256. }
  3257. ProcessPropertyGetAccessor(&expr, snode);
  3258. // TODO: Need to support 64bit integers
  3259. // Convert the expression to a 32bit variable
  3260. asCDataType to;
  3261. if( expr.type.dataType.IsIntegerType() )
  3262. to.SetTokenType(ttInt);
  3263. else if( expr.type.dataType.IsUnsignedType() )
  3264. to.SetTokenType(ttUInt);
  3265. // Make sure the value is in a variable
  3266. if( expr.type.dataType.IsReference() )
  3267. ConvertToVariable(&expr);
  3268. ImplicitConversion(&expr, to, snode->firstChild, asIC_IMPLICIT_CONV, true);
  3269. ConvertToVariable(&expr);
  3270. int offset = expr.type.stackOffset;
  3271. ProcessDeferredParams(&expr);
  3272. //-------------------------------
  3273. // Determine case values and labels
  3274. //--------------------------------
  3275. // Remember the first label so that we can later pass the
  3276. // correct label to each CompileCase()
  3277. int firstCaseLabel = nextLabel;
  3278. int defaultLabel = 0;
  3279. asCArray<int> caseValues;
  3280. asCArray<int> caseLabels;
  3281. // Compile all case comparisons and make them jump to the right label
  3282. asCScriptNode *cnode = snode->firstChild->next;
  3283. while( cnode )
  3284. {
  3285. // Each case should have a constant expression
  3286. if( cnode->firstChild && cnode->firstChild->nodeType == snExpression )
  3287. {
  3288. // Compile expression
  3289. asCExprContext c(engine);
  3290. CompileExpression(cnode->firstChild, &c);
  3291. // Verify that the result is a constant
  3292. if( !c.type.isConstant )
  3293. Error(TXT_SWITCH_CASE_MUST_BE_CONSTANT, cnode->firstChild);
  3294. // Verify that the result is an integral number
  3295. if (!c.type.dataType.IsIntegerType() && !c.type.dataType.IsUnsignedType())
  3296. Error(TXT_SWITCH_MUST_BE_INTEGRAL, cnode->firstChild);
  3297. else
  3298. {
  3299. ImplicitConversion(&c, to, cnode->firstChild, asIC_IMPLICIT_CONV, true);
  3300. // Has this case been declared already?
  3301. if (caseValues.IndexOf(c.type.GetConstantDW()) >= 0)
  3302. Error(TXT_DUPLICATE_SWITCH_CASE, cnode->firstChild);
  3303. // TODO: Optimize: We can insert the numbers sorted already
  3304. // Store constant for later use
  3305. caseValues.PushLast(c.type.GetConstantDW());
  3306. // Reserve label for this case
  3307. caseLabels.PushLast(nextLabel++);
  3308. }
  3309. }
  3310. else
  3311. {
  3312. // TODO: It shouldn't be necessary for the default case to be the last one.
  3313. // Is default the last case?
  3314. if( cnode->next )
  3315. {
  3316. Error(TXT_DEFAULT_MUST_BE_LAST, cnode);
  3317. break;
  3318. }
  3319. // Reserve label for this case
  3320. defaultLabel = nextLabel++;
  3321. }
  3322. cnode = cnode->next;
  3323. }
  3324. // check for empty switch
  3325. if (caseValues.GetLength() == 0)
  3326. {
  3327. Error(TXT_EMPTY_SWITCH, snode);
  3328. return;
  3329. }
  3330. if( defaultLabel == 0 )
  3331. defaultLabel = breakLabel;
  3332. //---------------------------------
  3333. // Output the optimized case comparisons
  3334. // with jumps to the case code
  3335. //------------------------------------
  3336. // Sort the case values by increasing value. Do the sort together with the labels
  3337. // A simple bubble sort is sufficient since we don't expect a huge number of values
  3338. for( asUINT fwd = 1; fwd < caseValues.GetLength(); fwd++ )
  3339. {
  3340. for( int bck = fwd - 1; bck >= 0; bck-- )
  3341. {
  3342. int bckp = bck + 1;
  3343. if( caseValues[bck] > caseValues[bckp] )
  3344. {
  3345. // Swap the values in both arrays
  3346. int swap = caseValues[bckp];
  3347. caseValues[bckp] = caseValues[bck];
  3348. caseValues[bck] = swap;
  3349. swap = caseLabels[bckp];
  3350. caseLabels[bckp] = caseLabels[bck];
  3351. caseLabels[bck] = swap;
  3352. }
  3353. else
  3354. break;
  3355. }
  3356. }
  3357. // Find ranges of consecutive numbers
  3358. asCArray<int> ranges;
  3359. ranges.PushLast(0);
  3360. asUINT n;
  3361. for( n = 1; n < caseValues.GetLength(); ++n )
  3362. {
  3363. // We can join numbers that are less than 5 numbers
  3364. // apart since the output code will still be smaller
  3365. if( caseValues[n] > caseValues[n-1] + 5 )
  3366. ranges.PushLast(n);
  3367. }
  3368. // If the value is larger than the largest case value, jump to default
  3369. int tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  3370. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[caseValues.GetLength()-1]);
  3371. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  3372. expr.bc.InstrDWORD(asBC_JP, defaultLabel);
  3373. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  3374. // TODO: runtime optimize: We could possibly optimize this even more by doing a
  3375. // binary search instead of a linear search through the ranges
  3376. // For each range
  3377. int range;
  3378. for( range = 0; range < (int)ranges.GetLength(); range++ )
  3379. {
  3380. // Find the largest value in this range
  3381. int maxRange = caseValues[ranges[range]];
  3382. int index = ranges[range];
  3383. for( ; (index < (int)caseValues.GetLength()) && (caseValues[index] <= maxRange + 5); index++ )
  3384. maxRange = caseValues[index];
  3385. // If there are only 2 numbers then it is better to compare them directly
  3386. if( index - ranges[range] > 2 )
  3387. {
  3388. // If the value is smaller than the smallest case value in the range, jump to default
  3389. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  3390. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[ranges[range]]);
  3391. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  3392. expr.bc.InstrDWORD(asBC_JS, defaultLabel);
  3393. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  3394. int nextRangeLabel = nextLabel++;
  3395. // If this is the last range we don't have to make this test
  3396. if( range < (int)ranges.GetLength() - 1 )
  3397. {
  3398. // If the value is larger than the largest case value in the range, jump to the next range
  3399. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  3400. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, maxRange);
  3401. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  3402. expr.bc.InstrDWORD(asBC_JP, nextRangeLabel);
  3403. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  3404. }
  3405. // Jump forward according to the value
  3406. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  3407. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[ranges[range]]);
  3408. expr.bc.InstrW_W_W(asBC_SUBi, tmpOffset, offset, tmpOffset);
  3409. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  3410. expr.bc.JmpP(tmpOffset, maxRange - caseValues[ranges[range]]);
  3411. // Add the list of jumps to the correct labels (any holes, jump to default)
  3412. index = ranges[range];
  3413. for( int i = caseValues[index]; i <= maxRange; i++ )
  3414. {
  3415. if( caseValues[index] == i )
  3416. expr.bc.InstrINT(asBC_JMP, caseLabels[index++]);
  3417. else
  3418. expr.bc.InstrINT(asBC_JMP, defaultLabel);
  3419. }
  3420. expr.bc.Label((short)nextRangeLabel);
  3421. }
  3422. else
  3423. {
  3424. // Simply make a comparison with each value
  3425. for( int i = ranges[range]; i < index; ++i )
  3426. {
  3427. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  3428. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[i]);
  3429. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  3430. expr.bc.InstrDWORD(asBC_JZ, caseLabels[i]);
  3431. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  3432. }
  3433. }
  3434. }
  3435. // Catch any value that falls trough
  3436. expr.bc.InstrINT(asBC_JMP, defaultLabel);
  3437. // Release the temporary variable previously stored
  3438. ReleaseTemporaryVariable(expr.type, &expr.bc);
  3439. // TODO: optimize: Should optimize each piece individually
  3440. expr.bc.OptimizeLocally(tempVariableOffsets);
  3441. //----------------------------------
  3442. // Output case implementations
  3443. //----------------------------------
  3444. // Compile case implementations, each one with the label before it
  3445. cnode = snode->firstChild->next;
  3446. while( cnode )
  3447. {
  3448. // Each case should have a constant expression
  3449. if( cnode->firstChild && cnode->firstChild->nodeType == snExpression )
  3450. {
  3451. expr.bc.Label((short)firstCaseLabel++);
  3452. CompileCase(cnode->firstChild->next, &expr.bc);
  3453. }
  3454. else
  3455. {
  3456. expr.bc.Label((short)defaultLabel);
  3457. // Is default the last case?
  3458. if( cnode->next )
  3459. {
  3460. // We've already reported this error
  3461. break;
  3462. }
  3463. CompileCase(cnode->firstChild, &expr.bc);
  3464. }
  3465. cnode = cnode->next;
  3466. }
  3467. //--------------------------------
  3468. bc->AddCode(&expr.bc);
  3469. // Add break label
  3470. bc->Label((short)breakLabel);
  3471. breakLabels.PopLast();
  3472. RemoveVariableScope();
  3473. }
  3474. void asCCompiler::CompileCase(asCScriptNode *node, asCByteCode *bc)
  3475. {
  3476. bool isFinished = false;
  3477. bool hasReturn = false;
  3478. bool hasUnreachableCode = false;
  3479. while( node )
  3480. {
  3481. if( !hasUnreachableCode && (hasReturn || isFinished) )
  3482. {
  3483. hasUnreachableCode = true;
  3484. Warning(TXT_UNREACHABLE_CODE, node);
  3485. break;
  3486. }
  3487. if( node->nodeType == snBreak || node->nodeType == snContinue )
  3488. isFinished = true;
  3489. asCByteCode statement(engine);
  3490. if( node->nodeType == snDeclaration )
  3491. {
  3492. Error(TXT_DECL_IN_SWITCH, node);
  3493. // Compile it anyway to avoid further compiler errors
  3494. CompileDeclaration(node, &statement);
  3495. }
  3496. else
  3497. CompileStatement(node, &hasReturn, &statement);
  3498. LineInstr(bc, node->tokenPos);
  3499. bc->AddCode(&statement);
  3500. if( !hasCompileErrors )
  3501. asASSERT( tempVariables.GetLength() == 0 );
  3502. node = node->next;
  3503. }
  3504. }
  3505. void asCCompiler::CompileIfStatement(asCScriptNode *inode, bool *hasReturn, asCByteCode *bc)
  3506. {
  3507. // We will use one label for the if statement
  3508. // and possibly another for the else statement
  3509. int afterLabel = nextLabel++;
  3510. // Compile the expression
  3511. asCExprContext expr(engine);
  3512. int r = CompileAssignment(inode->firstChild, &expr);
  3513. if( r == 0 )
  3514. {
  3515. // Allow value types to be converted to bool using 'bool opImplConv()'
  3516. if( expr.type.dataType.GetTypeInfo() && (expr.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
  3517. ImplicitConversion(&expr, asCDataType::CreatePrimitive(ttBool, false), inode, asIC_IMPLICIT_CONV);
  3518. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  3519. Error(TXT_EXPR_MUST_BE_BOOL, inode->firstChild);
  3520. else
  3521. {
  3522. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  3523. ProcessDeferredParams(&expr);
  3524. if( !expr.type.isConstant )
  3525. {
  3526. ProcessPropertyGetAccessor(&expr, inode);
  3527. ConvertToVariable(&expr);
  3528. // Add a test
  3529. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  3530. expr.bc.Instr(asBC_ClrHi);
  3531. expr.bc.InstrDWORD(asBC_JZ, afterLabel);
  3532. ReleaseTemporaryVariable(expr.type, &expr.bc);
  3533. expr.bc.OptimizeLocally(tempVariableOffsets);
  3534. bc->AddCode(&expr.bc);
  3535. }
  3536. #if AS_SIZEOF_BOOL == 1
  3537. else if( expr.type.GetConstantB() == 0 )
  3538. #else
  3539. else if (expr.type.GetConstantDW() == 0)
  3540. #endif
  3541. {
  3542. // Jump to the else case
  3543. bc->InstrINT(asBC_JMP, afterLabel);
  3544. // TODO: Should we warn that the expression will always go to the else?
  3545. }
  3546. }
  3547. }
  3548. // Compile the if statement
  3549. bool origIsConstructorCalled = m_isConstructorCalled;
  3550. bool hasReturn1;
  3551. asCByteCode ifBC(engine);
  3552. CompileStatement(inode->firstChild->next, &hasReturn1, &ifBC);
  3553. // Add the byte code
  3554. LineInstr(bc, inode->firstChild->next->tokenPos);
  3555. bc->AddCode(&ifBC);
  3556. if( inode->firstChild->next->nodeType == snExpressionStatement && inode->firstChild->next->firstChild == 0 )
  3557. {
  3558. // Don't allow if( expr );
  3559. Error(TXT_IF_WITH_EMPTY_STATEMENT, inode->firstChild->next);
  3560. }
  3561. // If one of the statements call the constructor, the other must as well
  3562. // otherwise it is possible the constructor is never called
  3563. bool constructorCall1 = false;
  3564. bool constructorCall2 = false;
  3565. if( !origIsConstructorCalled && m_isConstructorCalled )
  3566. constructorCall1 = true;
  3567. // Do we have an else statement?
  3568. if( inode->firstChild->next != inode->lastChild )
  3569. {
  3570. // Reset the constructor called flag so the else statement can call the constructor too
  3571. m_isConstructorCalled = origIsConstructorCalled;
  3572. int afterElse = 0;
  3573. if( !hasReturn1 )
  3574. {
  3575. afterElse = nextLabel++;
  3576. // Add jump to after the else statement
  3577. bc->InstrINT(asBC_JMP, afterElse);
  3578. }
  3579. // Add label for the else statement
  3580. bc->Label((short)afterLabel);
  3581. bool hasReturn2;
  3582. asCByteCode elseBC(engine);
  3583. CompileStatement(inode->lastChild, &hasReturn2, &elseBC);
  3584. // Add byte code for the else statement
  3585. LineInstr(bc, inode->lastChild->tokenPos);
  3586. bc->AddCode(&elseBC);
  3587. if( inode->lastChild->nodeType == snExpressionStatement && inode->lastChild->firstChild == 0 )
  3588. {
  3589. // Don't allow if( expr ) {} else;
  3590. Error(TXT_ELSE_WITH_EMPTY_STATEMENT, inode->lastChild);
  3591. }
  3592. if( !hasReturn1 )
  3593. {
  3594. // Add label for the end of else statement
  3595. bc->Label((short)afterElse);
  3596. }
  3597. // The if statement only has return if both alternatives have
  3598. *hasReturn = hasReturn1 && hasReturn2;
  3599. if( !origIsConstructorCalled && m_isConstructorCalled )
  3600. constructorCall2 = true;
  3601. }
  3602. else
  3603. {
  3604. // Add label for the end of if statement
  3605. bc->Label((short)afterLabel);
  3606. *hasReturn = false;
  3607. }
  3608. // Make sure both or neither conditions call a constructor
  3609. if( (constructorCall1 && !constructorCall2) ||
  3610. (constructorCall2 && !constructorCall1) )
  3611. {
  3612. Error(TXT_BOTH_CONDITIONS_MUST_CALL_CONSTRUCTOR, inode);
  3613. }
  3614. m_isConstructorCalled = origIsConstructorCalled || constructorCall1 || constructorCall2;
  3615. }
  3616. void asCCompiler::CompileForStatement(asCScriptNode *fnode, asCByteCode *bc)
  3617. {
  3618. // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables
  3619. AddVariableScope(true, true);
  3620. // We will use three labels for the for loop
  3621. int conditionLabel = nextLabel++;
  3622. int afterLabel = nextLabel++;
  3623. int continueLabel = nextLabel++;
  3624. int insideLabel = nextLabel++;
  3625. continueLabels.PushLast(continueLabel);
  3626. breakLabels.PushLast(afterLabel);
  3627. //---------------------------------------
  3628. // Compile the initialization statement
  3629. asCByteCode initBC(engine);
  3630. LineInstr(&initBC, fnode->firstChild->tokenPos);
  3631. if( fnode->firstChild->nodeType == snDeclaration )
  3632. CompileDeclaration(fnode->firstChild, &initBC);
  3633. else
  3634. CompileExpressionStatement(fnode->firstChild, &initBC);
  3635. //-----------------------------------
  3636. // Compile the condition statement
  3637. asCExprContext expr(engine);
  3638. asCScriptNode *second = fnode->firstChild->next;
  3639. if( second->firstChild )
  3640. {
  3641. int r = CompileAssignment(second->firstChild, &expr);
  3642. if( r >= 0 )
  3643. {
  3644. // Allow value types to be converted to bool using 'bool opImplConv()'
  3645. if( expr.type.dataType.GetTypeInfo() && (expr.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
  3646. ImplicitConversion(&expr, asCDataType::CreatePrimitive(ttBool, false), second->firstChild, asIC_IMPLICIT_CONV);
  3647. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  3648. Error(TXT_EXPR_MUST_BE_BOOL, second);
  3649. else
  3650. {
  3651. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  3652. ProcessDeferredParams(&expr);
  3653. ProcessPropertyGetAccessor(&expr, second);
  3654. // If expression is false exit the loop
  3655. ConvertToVariable(&expr);
  3656. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  3657. expr.bc.Instr(asBC_ClrHi);
  3658. expr.bc.InstrDWORD(asBC_JNZ, insideLabel);
  3659. ReleaseTemporaryVariable(expr.type, &expr.bc);
  3660. expr.bc.OptimizeLocally(tempVariableOffsets);
  3661. // Prepend the line instruction for the condition
  3662. asCByteCode tmp(engine);
  3663. LineInstr(&tmp, second->firstChild->tokenPos);
  3664. tmp.AddCode(&expr.bc);
  3665. expr.bc.AddCode(&tmp);
  3666. }
  3667. }
  3668. }
  3669. //---------------------------
  3670. // Compile the increment statement(s)
  3671. asCByteCode nextBC(engine);
  3672. asCScriptNode *cnode = second->next;
  3673. while( cnode && cnode->nodeType == snExpressionStatement && cnode != fnode->lastChild )
  3674. {
  3675. LineInstr(&nextBC, cnode->tokenPos);
  3676. CompileExpressionStatement(cnode, &nextBC);
  3677. cnode = cnode->next;
  3678. }
  3679. //------------------------------
  3680. // Compile loop statement
  3681. bool hasReturn;
  3682. asCByteCode forBC(engine);
  3683. CompileStatement(fnode->lastChild, &hasReturn, &forBC);
  3684. //-------------------------------
  3685. // Join the code pieces
  3686. bc->AddCode(&initBC);
  3687. bc->InstrDWORD(asBC_JMP, conditionLabel);
  3688. bc->Label((short)insideLabel);
  3689. // Add a suspend bytecode inside the loop to guarantee
  3690. // that the application can suspend the execution
  3691. bc->Instr(asBC_SUSPEND);
  3692. bc->InstrPTR(asBC_JitEntry, 0);
  3693. LineInstr(bc, fnode->lastChild->tokenPos);
  3694. bc->AddCode(&forBC);
  3695. bc->Label((short)continueLabel);
  3696. bc->AddCode(&nextBC);
  3697. bc->Label((short)conditionLabel);
  3698. if( expr.bc.GetLastInstr() == -1 )
  3699. // There is no condition, so we just always jump
  3700. bc->InstrDWORD(asBC_JMP, insideLabel);
  3701. else
  3702. bc->AddCode(&expr.bc);
  3703. bc->Label((short)afterLabel);
  3704. continueLabels.PopLast();
  3705. breakLabels.PopLast();
  3706. // Deallocate variables in this block, in reverse order
  3707. for( int n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  3708. {
  3709. sVariable *v = variables->variables[n];
  3710. // Call variable destructors here, for variables not yet destroyed
  3711. CallDestructor(v->type, v->stackOffset, v->onHeap, bc);
  3712. // Don't deallocate function parameters
  3713. if( v->stackOffset > 0 )
  3714. DeallocateVariable(v->stackOffset);
  3715. }
  3716. RemoveVariableScope();
  3717. }
  3718. void asCCompiler::CompileWhileStatement(asCScriptNode *wnode, asCByteCode *bc)
  3719. {
  3720. // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables
  3721. AddVariableScope(true, true);
  3722. // We will use two labels for the while loop
  3723. int beforeLabel = nextLabel++;
  3724. int afterLabel = nextLabel++;
  3725. continueLabels.PushLast(beforeLabel);
  3726. breakLabels.PushLast(afterLabel);
  3727. // Add label before the expression
  3728. bc->Label((short)beforeLabel);
  3729. // Compile expression
  3730. asCExprContext expr(engine);
  3731. int r = CompileAssignment(wnode->firstChild, &expr);
  3732. if( r == 0 )
  3733. {
  3734. // Allow value types to be converted to bool using 'bool opImplConv()'
  3735. if( expr.type.dataType.GetTypeInfo() && (expr.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
  3736. ImplicitConversion(&expr, asCDataType::CreatePrimitive(ttBool, false), wnode->firstChild, asIC_IMPLICIT_CONV);
  3737. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  3738. Error(TXT_EXPR_MUST_BE_BOOL, wnode->firstChild);
  3739. else
  3740. {
  3741. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  3742. ProcessDeferredParams(&expr);
  3743. ProcessPropertyGetAccessor(&expr, wnode);
  3744. // Add byte code for the expression
  3745. ConvertToVariable(&expr);
  3746. // Jump to end of statement if expression is false
  3747. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  3748. expr.bc.Instr(asBC_ClrHi);
  3749. expr.bc.InstrDWORD(asBC_JZ, afterLabel);
  3750. ReleaseTemporaryVariable(expr.type, &expr.bc);
  3751. expr.bc.OptimizeLocally(tempVariableOffsets);
  3752. bc->AddCode(&expr.bc);
  3753. }
  3754. }
  3755. // Add a suspend bytecode inside the loop to guarantee
  3756. // that the application can suspend the execution
  3757. bc->Instr(asBC_SUSPEND);
  3758. bc->InstrPTR(asBC_JitEntry, 0);
  3759. // Compile statement
  3760. bool hasReturn;
  3761. asCByteCode whileBC(engine);
  3762. CompileStatement(wnode->lastChild, &hasReturn, &whileBC);
  3763. // Add byte code for the statement
  3764. LineInstr(bc, wnode->lastChild->tokenPos);
  3765. bc->AddCode(&whileBC);
  3766. // Jump to the expression
  3767. bc->InstrINT(asBC_JMP, beforeLabel);
  3768. // Add label after the statement
  3769. bc->Label((short)afterLabel);
  3770. continueLabels.PopLast();
  3771. breakLabels.PopLast();
  3772. RemoveVariableScope();
  3773. }
  3774. void asCCompiler::CompileDoWhileStatement(asCScriptNode *wnode, asCByteCode *bc)
  3775. {
  3776. // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables
  3777. AddVariableScope(true, true);
  3778. // We will use two labels for the while loop
  3779. int beforeLabel = nextLabel++;
  3780. int beforeTest = nextLabel++;
  3781. int afterLabel = nextLabel++;
  3782. continueLabels.PushLast(beforeTest);
  3783. breakLabels.PushLast(afterLabel);
  3784. // Add label before the statement
  3785. bc->Label((short)beforeLabel);
  3786. // Compile statement
  3787. bool hasReturn;
  3788. asCByteCode whileBC(engine);
  3789. CompileStatement(wnode->firstChild, &hasReturn, &whileBC);
  3790. // Add byte code for the statement
  3791. LineInstr(bc, wnode->firstChild->tokenPos);
  3792. bc->AddCode(&whileBC);
  3793. // Add label before the expression
  3794. bc->Label((short)beforeTest);
  3795. // Add a suspend bytecode inside the loop to guarantee
  3796. // that the application can suspend the execution
  3797. bc->Instr(asBC_SUSPEND);
  3798. bc->InstrPTR(asBC_JitEntry, 0);
  3799. // Add a line instruction
  3800. LineInstr(bc, wnode->lastChild->tokenPos);
  3801. // Compile expression
  3802. asCExprContext expr(engine);
  3803. CompileAssignment(wnode->lastChild, &expr);
  3804. // Allow value types to be converted to bool using 'bool opImplConv()'
  3805. if( expr.type.dataType.GetTypeInfo() && (expr.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
  3806. ImplicitConversion(&expr, asCDataType::CreatePrimitive(ttBool, false), wnode->lastChild, asIC_IMPLICIT_CONV);
  3807. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  3808. Error(TXT_EXPR_MUST_BE_BOOL, wnode->firstChild);
  3809. else
  3810. {
  3811. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  3812. ProcessDeferredParams(&expr);
  3813. ProcessPropertyGetAccessor(&expr, wnode);
  3814. // Add byte code for the expression
  3815. ConvertToVariable(&expr);
  3816. // Jump to next iteration if expression is true
  3817. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  3818. expr.bc.Instr(asBC_ClrHi);
  3819. expr.bc.InstrDWORD(asBC_JNZ, beforeLabel);
  3820. ReleaseTemporaryVariable(expr.type, &expr.bc);
  3821. expr.bc.OptimizeLocally(tempVariableOffsets);
  3822. bc->AddCode(&expr.bc);
  3823. }
  3824. // Add label after the statement
  3825. bc->Label((short)afterLabel);
  3826. continueLabels.PopLast();
  3827. breakLabels.PopLast();
  3828. RemoveVariableScope();
  3829. }
  3830. void asCCompiler::CompileBreakStatement(asCScriptNode *node, asCByteCode *bc)
  3831. {
  3832. if( breakLabels.GetLength() == 0 )
  3833. {
  3834. Error(TXT_INVALID_BREAK, node);
  3835. return;
  3836. }
  3837. // Add destructor calls for all variables that will go out of scope
  3838. // Put this clean up in a block to allow exception handler to understand them
  3839. bc->Block(true);
  3840. asCVariableScope *vs = variables;
  3841. while( !vs->isBreakScope )
  3842. {
  3843. for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- )
  3844. CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc);
  3845. vs = vs->parent;
  3846. }
  3847. bc->Block(false);
  3848. bc->InstrINT(asBC_JMP, breakLabels[breakLabels.GetLength()-1]);
  3849. }
  3850. void asCCompiler::CompileContinueStatement(asCScriptNode *node, asCByteCode *bc)
  3851. {
  3852. if( continueLabels.GetLength() == 0 )
  3853. {
  3854. Error(TXT_INVALID_CONTINUE, node);
  3855. return;
  3856. }
  3857. // Add destructor calls for all variables that will go out of scope
  3858. // Put this clean up in a block to allow exception handler to understand them
  3859. bc->Block(true);
  3860. asCVariableScope *vs = variables;
  3861. while( !vs->isContinueScope )
  3862. {
  3863. for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- )
  3864. CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc);
  3865. vs = vs->parent;
  3866. }
  3867. bc->Block(false);
  3868. bc->InstrINT(asBC_JMP, continueLabels[continueLabels.GetLength()-1]);
  3869. }
  3870. void asCCompiler::CompileExpressionStatement(asCScriptNode *enode, asCByteCode *bc)
  3871. {
  3872. if( enode->firstChild )
  3873. {
  3874. // Compile the expression
  3875. asCExprContext expr(engine);
  3876. CompileAssignment(enode->firstChild, &expr);
  3877. // Must not have unused ambiguous names
  3878. if( expr.IsClassMethod() || expr.IsGlobalFunc() )
  3879. Error(TXT_INVALID_EXPRESSION_AMBIGUOUS_NAME, enode);
  3880. // Must not have unused anonymous functions
  3881. if( expr.IsLambda() )
  3882. Error(TXT_INVALID_EXPRESSION_LAMBDA, enode);
  3883. // If we get here and there is still an unprocessed property
  3884. // accessor, then process it as a get access. Don't call if there is
  3885. // already a compile error, or we might report an error that is not valid
  3886. if( !hasCompileErrors )
  3887. ProcessPropertyGetAccessor(&expr, enode);
  3888. // Pop the value from the stack
  3889. if( !expr.type.dataType.IsPrimitive() )
  3890. expr.bc.Instr(asBC_PopPtr);
  3891. // Release temporary variables used by expression
  3892. ReleaseTemporaryVariable(expr.type, &expr.bc);
  3893. ProcessDeferredParams(&expr);
  3894. expr.bc.OptimizeLocally(tempVariableOffsets);
  3895. bc->AddCode(&expr.bc);
  3896. }
  3897. }
  3898. void asCCompiler::PrepareTemporaryVariable(asCScriptNode *node, asCExprContext *ctx, bool forceOnHeap)
  3899. {
  3900. // The input can be either an object or funcdef, either as handle or reference
  3901. asASSERT(ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef());
  3902. // If the object already is stored in temporary variable then nothing needs to be done
  3903. // Note, a type can be temporary without being a variable, in which case it is holding off
  3904. // on releasing a previously used object.
  3905. if( ctx->type.isTemporary && ctx->type.isVariable &&
  3906. !(forceOnHeap && !IsVariableOnHeap(ctx->type.stackOffset)) )
  3907. {
  3908. // If the temporary object is currently not a reference
  3909. // the expression needs to be reevaluated to a reference
  3910. if( !ctx->type.dataType.IsReference() )
  3911. {
  3912. ctx->bc.Instr(asBC_PopPtr);
  3913. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  3914. ctx->type.dataType.MakeReference(true);
  3915. }
  3916. return;
  3917. }
  3918. // Allocate temporary variable
  3919. asCDataType dt = ctx->type.dataType;
  3920. dt.MakeReference(false);
  3921. dt.MakeReadOnly(false);
  3922. int offset = AllocateVariable(dt, true, forceOnHeap);
  3923. // Objects stored on the stack are not considered references
  3924. dt.MakeReference(IsVariableOnHeap(offset));
  3925. asCExprValue lvalue;
  3926. lvalue.Set(dt);
  3927. lvalue.isExplicitHandle = ctx->type.isExplicitHandle;
  3928. bool isExplicitHandle = ctx->type.isExplicitHandle;
  3929. CompileInitAsCopy(dt, offset, &ctx->bc, ctx, node, false);
  3930. // Push the reference to the temporary variable on the stack
  3931. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  3932. ctx->type.Set(dt);
  3933. ctx->type.isTemporary = true;
  3934. ctx->type.stackOffset = (short)offset;
  3935. ctx->type.isVariable = true;
  3936. ctx->type.isExplicitHandle = isExplicitHandle;
  3937. ctx->type.dataType.MakeReference(IsVariableOnHeap(offset));
  3938. }
  3939. void asCCompiler::CompileReturnStatement(asCScriptNode *rnode, asCByteCode *bc)
  3940. {
  3941. // Get return type and location
  3942. sVariable *v = variables->GetVariable("return");
  3943. // Basic validations
  3944. if( v->type.GetSizeOnStackDWords() > 0 && !rnode->firstChild )
  3945. {
  3946. Error(TXT_MUST_RETURN_VALUE, rnode);
  3947. return;
  3948. }
  3949. else if( v->type.GetSizeOnStackDWords() == 0 && rnode->firstChild )
  3950. {
  3951. Error(TXT_CANT_RETURN_VALUE, rnode);
  3952. return;
  3953. }
  3954. // Compile the expression
  3955. if( rnode->firstChild )
  3956. {
  3957. // Compile the expression
  3958. asCExprContext expr(engine);
  3959. int r = CompileAssignment(rnode->firstChild, &expr);
  3960. if( r < 0 ) return;
  3961. if( v->type.IsReference() )
  3962. {
  3963. // The expression that gives the reference must not use any of the
  3964. // variables that must be destroyed upon exit, because then it means
  3965. // reference will stay alive while the clean-up is done, which could
  3966. // potentially mean that the reference is invalidated by the clean-up.
  3967. //
  3968. // When the function is returning a reference, the clean-up of the
  3969. // variables must be done before the evaluation of the expression.
  3970. //
  3971. // A reference to a global variable, or a class member for class methods
  3972. // should be allowed to be returned.
  3973. if( !(expr.type.dataType.IsReference() ||
  3974. (expr.type.dataType.IsObject() && !expr.type.dataType.IsObjectHandle())) )
  3975. {
  3976. // Clean up the potential deferred parameters
  3977. ProcessDeferredParams(&expr);
  3978. Error(TXT_NOT_VALID_REFERENCE, rnode);
  3979. return;
  3980. }
  3981. // No references to local variables, temporary variables, or parameters
  3982. // are allowed to be returned, since they go out of scope when the function
  3983. // returns. Even reference parameters are disallowed, since it is not possible
  3984. // to know the scope of them. The exception is the 'this' pointer, which
  3985. // is treated by the compiler as a local variable, but isn't really so.
  3986. if( (expr.type.isVariable && !(expr.type.stackOffset == 0 && outFunc->objectType)) || expr.type.isTemporary )
  3987. {
  3988. // Clean up the potential deferred parameters
  3989. ProcessDeferredParams(&expr);
  3990. Error(TXT_CANNOT_RETURN_REF_TO_LOCAL, rnode);
  3991. return;
  3992. }
  3993. // The type must match exactly as we cannot convert
  3994. // the reference without loosing the original value
  3995. if( !(v->type.IsEqualExceptConst(expr.type.dataType) ||
  3996. ((expr.type.dataType.IsObject() || expr.type.dataType.IsFuncdef()) &&
  3997. !expr.type.dataType.IsObjectHandle() &&
  3998. v->type.IsEqualExceptRefAndConst(expr.type.dataType))) ||
  3999. (!v->type.IsReadOnly() && expr.type.dataType.IsReadOnly()) )
  4000. {
  4001. // Clean up the potential deferred parameters
  4002. ProcessDeferredParams(&expr);
  4003. asCString str;
  4004. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, expr.type.dataType.Format(outFunc->nameSpace).AddressOf(), v->type.Format(outFunc->nameSpace).AddressOf());
  4005. Error(str, rnode);
  4006. return;
  4007. }
  4008. // The expression must not have any deferred expressions, because the evaluation
  4009. // of these cannot be done without keeping the reference which is not safe
  4010. if( expr.deferredParams.GetLength() )
  4011. {
  4012. // Clean up the potential deferred parameters
  4013. ProcessDeferredParams(&expr);
  4014. Error(TXT_REF_CANT_BE_RETURNED_DEFERRED_PARAM, rnode);
  4015. return;
  4016. }
  4017. // Make sure the expression isn't using any local variables that
  4018. // will need to be cleaned up before the function completes
  4019. asCArray<int> usedVars;
  4020. expr.bc.GetVarsUsed(usedVars);
  4021. for( asUINT n = 0; n < usedVars.GetLength(); n++ )
  4022. {
  4023. int var = GetVariableSlot(usedVars[n]);
  4024. if( var != -1 )
  4025. {
  4026. asCDataType dt = variableAllocations[var];
  4027. if( dt.IsObject() )
  4028. {
  4029. ProcessDeferredParams(&expr);
  4030. Error(TXT_REF_CANT_BE_RETURNED_LOCAL_VARS, rnode);
  4031. return;
  4032. }
  4033. }
  4034. }
  4035. // Can't return the reference if could point to a local variable
  4036. if( expr.type.isRefToLocal )
  4037. {
  4038. ProcessDeferredParams(&expr);
  4039. Error(TXT_REF_CANT_BE_TO_LOCAL_VAR, rnode);
  4040. return;
  4041. }
  4042. // All objects in the function must be cleaned up before the expression
  4043. // is evaluated, otherwise there is a possibility that the cleanup will
  4044. // invalidate the reference.
  4045. // Destroy the local variables before loading
  4046. // the reference into the register. This will
  4047. // be done before the expression is evaluated.
  4048. DestroyVariables(bc);
  4049. // For primitives the reference is already in the register,
  4050. // but for non-primitives the reference is on the stack so we
  4051. // need to load it into the register
  4052. if( !expr.type.dataType.IsPrimitive() )
  4053. {
  4054. if( !expr.type.dataType.IsObjectHandle() &&
  4055. expr.type.dataType.IsReference() )
  4056. expr.bc.Instr(asBC_RDSPtr);
  4057. expr.bc.Instr(asBC_PopRPtr);
  4058. }
  4059. // There are no temporaries to release so we're done
  4060. }
  4061. else // if( !v->type.IsReference() )
  4062. {
  4063. ProcessPropertyGetAccessor(&expr, rnode);
  4064. // Prepare the value for assignment
  4065. IsVariableInitialized(&expr.type, rnode->firstChild);
  4066. if( v->type.IsPrimitive() )
  4067. {
  4068. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  4069. // Implicitly convert the value to the return type
  4070. ImplicitConversion(&expr, v->type, rnode->firstChild, asIC_IMPLICIT_CONV);
  4071. // Verify that the conversion was successful
  4072. if( expr.type.dataType != v->type )
  4073. {
  4074. asCString str;
  4075. str.Format(TXT_NO_CONVERSION_s_TO_s, expr.type.dataType.Format(outFunc->nameSpace).AddressOf(), v->type.Format(outFunc->nameSpace).AddressOf());
  4076. Error(str, rnode);
  4077. return;
  4078. }
  4079. else
  4080. {
  4081. ConvertToVariable(&expr);
  4082. // Clean up the local variables and process deferred parameters
  4083. DestroyVariables(&expr.bc);
  4084. ProcessDeferredParams(&expr);
  4085. ReleaseTemporaryVariable(expr.type, &expr.bc);
  4086. // Load the variable in the register
  4087. if( v->type.GetSizeOnStackDWords() == 1 )
  4088. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  4089. else
  4090. expr.bc.InstrSHORT(asBC_CpyVtoR8, expr.type.stackOffset);
  4091. }
  4092. }
  4093. else if( v->type.IsObject() || v->type.IsFuncdef() )
  4094. {
  4095. // Value types are returned on the stack, in a location
  4096. // that has been reserved by the calling function.
  4097. if( outFunc->DoesReturnOnStack() )
  4098. {
  4099. // TODO: runtime optimize: If the return type has a constructor that takes the type of the expression,
  4100. // it should be called directly instead of first converting the expression and
  4101. // then copy the value.
  4102. if( !v->type.IsEqualExceptRefAndConst(expr.type.dataType) )
  4103. {
  4104. ImplicitConversion(&expr, v->type, rnode->firstChild, asIC_IMPLICIT_CONV);
  4105. if( !v->type.IsEqualExceptRefAndConst(expr.type.dataType) )
  4106. {
  4107. asCString str;
  4108. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, expr.type.dataType.Format(outFunc->nameSpace).AddressOf(), v->type.Format(outFunc->nameSpace).AddressOf());
  4109. Error(str, rnode->firstChild);
  4110. return;
  4111. }
  4112. }
  4113. int offset = outFunc->objectType ? -AS_PTR_SIZE : 0;
  4114. CompileInitAsCopy(v->type, offset, &expr.bc, &expr, rnode->firstChild, true);
  4115. // Clean up the local variables and process deferred parameters
  4116. DestroyVariables(&expr.bc);
  4117. ProcessDeferredParams(&expr);
  4118. }
  4119. else
  4120. {
  4121. asASSERT( (v->type.GetTypeInfo()->flags & asOBJ_REF) || v->type.IsFuncdef() );
  4122. // Prepare the expression to be loaded into the object
  4123. // register. This will place the reference in local variable
  4124. PrepareArgument(&v->type, &expr, rnode->firstChild, false, 0);
  4125. // Pop the reference to the temporary variable
  4126. expr.bc.Instr(asBC_PopPtr);
  4127. // Clean up the local variables and process deferred parameters
  4128. DestroyVariables(&expr.bc);
  4129. ProcessDeferredParams(&expr);
  4130. // Load the object pointer into the object register
  4131. // LOADOBJ also clears the address in the variable
  4132. expr.bc.InstrSHORT(asBC_LOADOBJ, expr.type.stackOffset);
  4133. // LOADOBJ cleared the address in the variable so the object will not be freed
  4134. // here, but the temporary variable must still be freed so the slot can be reused
  4135. // By releasing without the bytecode we do just that.
  4136. ReleaseTemporaryVariable(expr.type, 0);
  4137. }
  4138. }
  4139. }
  4140. expr.bc.OptimizeLocally(tempVariableOffsets);
  4141. bc->AddCode(&expr.bc);
  4142. }
  4143. else
  4144. {
  4145. // For functions that don't return anything
  4146. // we just detroy the local variables
  4147. DestroyVariables(bc);
  4148. }
  4149. // Jump to the end of the function
  4150. bc->InstrINT(asBC_JMP, 0);
  4151. }
  4152. void asCCompiler::DestroyVariables(asCByteCode *bc)
  4153. {
  4154. // Call destructor on all variables except for the function parameters
  4155. // Put the clean-up in a block to allow exception handler to understand this
  4156. bc->Block(true);
  4157. asCVariableScope *vs = variables;
  4158. while( vs )
  4159. {
  4160. for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- )
  4161. if( vs->variables[n]->stackOffset > 0 )
  4162. CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc);
  4163. vs = vs->parent;
  4164. }
  4165. bc->Block(false);
  4166. }
  4167. void asCCompiler::AddVariableScope(bool isBreakScope, bool isContinueScope)
  4168. {
  4169. variables = asNEW(asCVariableScope)(variables);
  4170. if( variables == 0 )
  4171. {
  4172. // Out of memory
  4173. return;
  4174. }
  4175. variables->isBreakScope = isBreakScope;
  4176. variables->isContinueScope = isContinueScope;
  4177. }
  4178. void asCCompiler::RemoveVariableScope()
  4179. {
  4180. if( variables )
  4181. {
  4182. asCVariableScope *var = variables;
  4183. variables = variables->parent;
  4184. asDELETE(var,asCVariableScope);
  4185. }
  4186. }
  4187. void asCCompiler::Error(const asCString &msg, asCScriptNode *node)
  4188. {
  4189. asCString str;
  4190. int r = 0, c = 0;
  4191. asASSERT( node );
  4192. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  4193. builder->WriteError(script->name, msg, r, c);
  4194. hasCompileErrors = true;
  4195. }
  4196. void asCCompiler::Warning(const asCString &msg, asCScriptNode *node)
  4197. {
  4198. asCString str;
  4199. int r = 0, c = 0;
  4200. asASSERT( node );
  4201. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  4202. builder->WriteWarning(script->name, msg, r, c);
  4203. }
  4204. void asCCompiler::Information(const asCString &msg, asCScriptNode *node)
  4205. {
  4206. asCString str;
  4207. int r = 0, c = 0;
  4208. asASSERT( node );
  4209. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  4210. builder->WriteInfo(script->name, msg, r, c, false);
  4211. }
  4212. void asCCompiler::PrintMatchingFuncs(asCArray<int> &funcs, asCScriptNode *node, asCObjectType *inType)
  4213. {
  4214. int r = 0, c = 0;
  4215. asASSERT( node );
  4216. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  4217. for( unsigned int n = 0; n < funcs.GetLength(); n++ )
  4218. {
  4219. asCScriptFunction *func = builder->GetFunctionDescription(funcs[n]);
  4220. if( inType && func->funcType == asFUNC_VIRTUAL )
  4221. func = inType->virtualFunctionTable[func->vfTableIdx];
  4222. builder->WriteInfo(script->name, func->GetDeclaration(true, false, true), r, c, false);
  4223. }
  4224. }
  4225. int asCCompiler::AllocateVariableNotIn(const asCDataType &type, bool isTemporary, bool forceOnHeap, asCExprContext *ctx)
  4226. {
  4227. int l = int(reservedVariables.GetLength());
  4228. ctx->bc.GetVarsUsed(reservedVariables);
  4229. int var = AllocateVariable(type, isTemporary, forceOnHeap);
  4230. reservedVariables.SetLength(l);
  4231. return var;
  4232. }
  4233. int asCCompiler::AllocateVariable(const asCDataType &type, bool isTemporary, bool forceOnHeap)
  4234. {
  4235. asCDataType t(type);
  4236. t.MakeReference(false);
  4237. if( t.IsPrimitive() && t.GetSizeOnStackDWords() == 1 )
  4238. t.SetTokenType(ttInt);
  4239. if( t.IsPrimitive() && t.GetSizeOnStackDWords() == 2 )
  4240. t.SetTokenType(ttDouble);
  4241. // Only null handles have the token type unrecognized token
  4242. asASSERT( t.IsObjectHandle() || t.GetTokenType() != ttUnrecognizedToken );
  4243. bool isOnHeap = true;
  4244. if( t.IsPrimitive() ||
  4245. (t.GetTypeInfo() && (t.GetTypeInfo()->GetFlags() & asOBJ_VALUE) && !forceOnHeap) )
  4246. {
  4247. // Primitives and value types (unless overridden) are allocated on the stack
  4248. isOnHeap = false;
  4249. }
  4250. // Find a free location with the same type
  4251. for( asUINT n = 0; n < freeVariables.GetLength(); n++ )
  4252. {
  4253. int slot = freeVariables[n];
  4254. if( variableAllocations[slot].IsEqualExceptConst(t) &&
  4255. variableIsTemporary[slot] == isTemporary &&
  4256. variableIsOnHeap[slot] == isOnHeap )
  4257. {
  4258. // We can't return by slot, must count variable sizes
  4259. int offset = GetVariableOffset(slot);
  4260. // Verify that it is not in the list of reserved variables
  4261. bool isUsed = false;
  4262. if( reservedVariables.GetLength() )
  4263. isUsed = reservedVariables.Exists(offset);
  4264. if( !isUsed )
  4265. {
  4266. if( n != freeVariables.GetLength() - 1 )
  4267. freeVariables[n] = freeVariables.PopLast();
  4268. else
  4269. freeVariables.PopLast();
  4270. if( isTemporary )
  4271. tempVariables.PushLast(offset);
  4272. return offset;
  4273. }
  4274. }
  4275. }
  4276. variableAllocations.PushLast(t);
  4277. variableIsTemporary.PushLast(isTemporary);
  4278. variableIsOnHeap.PushLast(isOnHeap);
  4279. int offset = GetVariableOffset((int)variableAllocations.GetLength()-1);
  4280. if( isTemporary )
  4281. {
  4282. // Add offset to the currently allocated temporary variables
  4283. tempVariables.PushLast(offset);
  4284. // Add offset to all known offsets to temporary variables, whether allocated or not
  4285. tempVariableOffsets.PushLast(offset);
  4286. }
  4287. return offset;
  4288. }
  4289. int asCCompiler::GetVariableOffset(int varIndex)
  4290. {
  4291. // Return offset to the last dword on the stack
  4292. // Start at 1 as offset 0 is reserved for the this pointer (or first argument for global functions)
  4293. int varOffset = 1;
  4294. // Skip lower variables
  4295. for( int n = 0; n < varIndex; n++ )
  4296. {
  4297. if( !variableIsOnHeap[n] && variableAllocations[n].IsObject() )
  4298. varOffset += variableAllocations[n].GetSizeInMemoryDWords();
  4299. else
  4300. varOffset += variableAllocations[n].GetSizeOnStackDWords();
  4301. }
  4302. if( varIndex < (int)variableAllocations.GetLength() )
  4303. {
  4304. // For variables larger than 1 dword the returned offset should be to the last dword
  4305. int size;
  4306. if( !variableIsOnHeap[varIndex] && variableAllocations[varIndex].IsObject() )
  4307. size = variableAllocations[varIndex].GetSizeInMemoryDWords();
  4308. else
  4309. size = variableAllocations[varIndex].GetSizeOnStackDWords();
  4310. if( size > 1 )
  4311. varOffset += size-1;
  4312. }
  4313. return varOffset;
  4314. }
  4315. int asCCompiler::GetVariableSlot(int offset)
  4316. {
  4317. int varOffset = 1;
  4318. for( asUINT n = 0; n < variableAllocations.GetLength(); n++ )
  4319. {
  4320. if( !variableIsOnHeap[n] && variableAllocations[n].IsObject() )
  4321. varOffset += -1 + variableAllocations[n].GetSizeInMemoryDWords();
  4322. else
  4323. varOffset += -1 + variableAllocations[n].GetSizeOnStackDWords();
  4324. if( varOffset == offset )
  4325. return n;
  4326. varOffset++;
  4327. }
  4328. return -1;
  4329. }
  4330. bool asCCompiler::IsVariableOnHeap(int offset)
  4331. {
  4332. int varSlot = GetVariableSlot(offset);
  4333. if( varSlot < 0 )
  4334. {
  4335. // This happens for function arguments that are considered as on the heap
  4336. return true;
  4337. }
  4338. return variableIsOnHeap[varSlot];
  4339. }
  4340. void asCCompiler::DeallocateVariable(int offset)
  4341. {
  4342. // Remove temporary variable
  4343. int n;
  4344. for( n = 0; n < (int)tempVariables.GetLength(); n++ )
  4345. {
  4346. if( offset == tempVariables[n] )
  4347. {
  4348. if( n == (int)tempVariables.GetLength()-1 )
  4349. tempVariables.PopLast();
  4350. else
  4351. tempVariables[n] = tempVariables.PopLast();
  4352. break;
  4353. }
  4354. }
  4355. // Mark the variable slot available for new allocations
  4356. n = GetVariableSlot(offset);
  4357. if( n != -1 )
  4358. {
  4359. freeVariables.PushLast(n);
  4360. return;
  4361. }
  4362. // We might get here if the variable was implicitly declared
  4363. // because it was used before a formal declaration, in this case
  4364. // the offset is 0x7FFF
  4365. asASSERT(offset == 0x7FFF);
  4366. }
  4367. void asCCompiler::ReleaseTemporaryVariable(asCExprValue &t, asCByteCode *bc)
  4368. {
  4369. if( t.isTemporary )
  4370. {
  4371. ReleaseTemporaryVariable(t.stackOffset, bc);
  4372. t.isTemporary = false;
  4373. }
  4374. }
  4375. void asCCompiler::ReleaseTemporaryVariable(int offset, asCByteCode *bc)
  4376. {
  4377. asASSERT( tempVariables.Exists(offset) );
  4378. if( bc )
  4379. {
  4380. // We need to call the destructor on the true variable type
  4381. int n = GetVariableSlot(offset);
  4382. asASSERT( n >= 0 );
  4383. if( n >= 0 )
  4384. {
  4385. asCDataType dt = variableAllocations[n];
  4386. bool isOnHeap = variableIsOnHeap[n];
  4387. // Call destructor
  4388. CallDestructor(dt, offset, isOnHeap, bc);
  4389. }
  4390. }
  4391. DeallocateVariable(offset);
  4392. }
  4393. void asCCompiler::Dereference(asCExprContext *ctx, bool generateCode)
  4394. {
  4395. if( ctx->type.dataType.IsReference() )
  4396. {
  4397. if( ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef() )
  4398. {
  4399. ctx->type.dataType.MakeReference(false);
  4400. if( generateCode )
  4401. ctx->bc.Instr(asBC_RDSPtr);
  4402. }
  4403. else
  4404. {
  4405. // This should never happen as primitives are treated differently
  4406. asASSERT(false);
  4407. }
  4408. }
  4409. }
  4410. bool asCCompiler::IsVariableInitialized(asCExprValue *type, asCScriptNode *node)
  4411. {
  4412. // No need to check if there is no variable scope
  4413. if( variables == 0 ) return true;
  4414. // Temporary variables are assumed to be initialized
  4415. if( type->isTemporary ) return true;
  4416. // Verify that it is a variable
  4417. if( !type->isVariable ) return true;
  4418. // Find the variable
  4419. sVariable *v = variables->GetVariableByOffset(type->stackOffset);
  4420. // The variable isn't found if it is a constant, in which case it is guaranteed to be initialized
  4421. if( v == 0 ) return true;
  4422. if( v->isInitialized ) return true;
  4423. // Complex types don't need this test
  4424. if( v->type.IsObject() || v->type.IsFuncdef() ) return true;
  4425. // Mark as initialized so that the user will not be bothered again
  4426. v->isInitialized = true;
  4427. // Write warning
  4428. asCString str;
  4429. str.Format(TXT_s_NOT_INITIALIZED, (const char *)v->name.AddressOf());
  4430. Warning(str, node);
  4431. return false;
  4432. }
  4433. void asCCompiler::PrepareOperand(asCExprContext *ctx, asCScriptNode *node)
  4434. {
  4435. // Check if the variable is initialized (if it indeed is a variable)
  4436. IsVariableInitialized(&ctx->type, node);
  4437. asCDataType to = ctx->type.dataType;
  4438. to.MakeReference(false);
  4439. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV);
  4440. ProcessDeferredParams(ctx);
  4441. }
  4442. void asCCompiler::PrepareForAssignment(asCDataType *lvalue, asCExprContext *rctx, asCScriptNode *node, bool toTemporary, asCExprContext *lvalueExpr)
  4443. {
  4444. // Reserve the temporary variables used in the lvalue expression so they won't end up being used by the rvalue too
  4445. int l = int(reservedVariables.GetLength());
  4446. if( lvalueExpr ) lvalueExpr->bc.GetVarsUsed(reservedVariables);
  4447. ProcessPropertyGetAccessor(rctx, node);
  4448. // Make sure the rvalue is initialized if it is a variable
  4449. IsVariableInitialized(&rctx->type, node);
  4450. if( lvalue->IsPrimitive() )
  4451. {
  4452. if( rctx->type.dataType.IsPrimitive() )
  4453. {
  4454. if( rctx->type.dataType.IsReference() )
  4455. {
  4456. // Cannot do implicit conversion of references so we first convert the reference to a variable
  4457. ConvertToVariableNotIn(rctx, lvalueExpr);
  4458. }
  4459. }
  4460. // Implicitly convert the value to the right type
  4461. ImplicitConversion(rctx, *lvalue, node, asIC_IMPLICIT_CONV);
  4462. // Check data type
  4463. if( !lvalue->IsEqualExceptRefAndConst(rctx->type.dataType) )
  4464. {
  4465. asCString str;
  4466. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lvalue->Format(outFunc->nameSpace).AddressOf());
  4467. Error(str, node);
  4468. rctx->type.SetDummy();
  4469. }
  4470. // Make sure the rvalue is a variable
  4471. if( !rctx->type.isVariable )
  4472. ConvertToVariableNotIn(rctx, lvalueExpr);
  4473. }
  4474. else
  4475. {
  4476. asCDataType to = *lvalue;
  4477. to.MakeReference(false);
  4478. // TODO: ImplicitConversion should know to do this by itself
  4479. // First convert to a handle which will do a reference cast
  4480. if( !lvalue->IsObjectHandle() &&
  4481. (lvalue->GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) )
  4482. to.MakeHandle(true);
  4483. // Don't allow the implicit conversion to create an object
  4484. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true, !toTemporary);
  4485. if( !lvalue->IsObjectHandle() &&
  4486. (lvalue->GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) )
  4487. {
  4488. // Then convert to a reference, which will validate the handle
  4489. to.MakeHandle(false);
  4490. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true, !toTemporary);
  4491. }
  4492. // Check data type
  4493. if( !lvalue->IsEqualExceptRefAndConst(rctx->type.dataType) )
  4494. {
  4495. asCString str;
  4496. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lvalue->Format(outFunc->nameSpace).AddressOf());
  4497. Error(str, node);
  4498. }
  4499. else
  4500. {
  4501. // If the assignment will be made with the copy behaviour then the rvalue must not be a reference
  4502. asASSERT(!lvalue->IsObject() || !rctx->type.dataType.IsReference());
  4503. }
  4504. }
  4505. // Unreserve variables
  4506. reservedVariables.SetLength(l);
  4507. }
  4508. bool asCCompiler::IsLValue(asCExprValue &type)
  4509. {
  4510. if( !type.isLValue ) return false;
  4511. if( type.dataType.IsReadOnly() ) return false;
  4512. if( !type.dataType.IsObject() && !type.isVariable && !type.dataType.IsReference() ) return false;
  4513. return true;
  4514. }
  4515. int asCCompiler::PerformAssignment(asCExprValue *lvalue, asCExprValue *rvalue, asCByteCode *bc, asCScriptNode *node)
  4516. {
  4517. if( lvalue->dataType.IsReadOnly() )
  4518. {
  4519. Error(TXT_REF_IS_READ_ONLY, node);
  4520. return -1;
  4521. }
  4522. if( lvalue->dataType.IsPrimitive() )
  4523. {
  4524. if( lvalue->isVariable )
  4525. {
  4526. // Copy the value between the variables directly
  4527. if( lvalue->dataType.GetSizeInMemoryDWords() == 1 )
  4528. bc->InstrW_W(asBC_CpyVtoV4, lvalue->stackOffset, rvalue->stackOffset);
  4529. else
  4530. bc->InstrW_W(asBC_CpyVtoV8, lvalue->stackOffset, rvalue->stackOffset);
  4531. // Mark variable as initialized
  4532. sVariable *v = variables->GetVariableByOffset(lvalue->stackOffset);
  4533. if( v ) v->isInitialized = true;
  4534. }
  4535. else if( lvalue->dataType.IsReference() )
  4536. {
  4537. // Copy the value of the variable to the reference in the register
  4538. int s = lvalue->dataType.GetSizeInMemoryBytes();
  4539. if( s == 1 )
  4540. bc->InstrSHORT(asBC_WRTV1, rvalue->stackOffset);
  4541. else if( s == 2 )
  4542. bc->InstrSHORT(asBC_WRTV2, rvalue->stackOffset);
  4543. else if( s == 4 )
  4544. bc->InstrSHORT(asBC_WRTV4, rvalue->stackOffset);
  4545. else if( s == 8 )
  4546. bc->InstrSHORT(asBC_WRTV8, rvalue->stackOffset);
  4547. }
  4548. else
  4549. {
  4550. Error(TXT_NOT_VALID_LVALUE, node);
  4551. return -1;
  4552. }
  4553. }
  4554. else if( !lvalue->isExplicitHandle )
  4555. {
  4556. asCExprContext ctx(engine);
  4557. ctx.type = *lvalue;
  4558. Dereference(&ctx, true);
  4559. *lvalue = ctx.type;
  4560. bc->AddCode(&ctx.bc);
  4561. asSTypeBehaviour *beh = lvalue->dataType.GetBehaviour();
  4562. if( beh && beh->copy && beh->copy != engine->scriptTypeBehaviours.beh.copy )
  4563. {
  4564. asCExprContext res(engine);
  4565. PerformFunctionCall(beh->copy, &res, false, 0, CastToObjectType(lvalue->dataType.GetTypeInfo()));
  4566. bc->AddCode(&res.bc);
  4567. *lvalue = res.type;
  4568. }
  4569. else if( beh && beh->copy == engine->scriptTypeBehaviours.beh.copy )
  4570. {
  4571. // Call the default copy operator for script classes
  4572. // This is done differently because the default copy operator
  4573. // is registered as returning int&, but in reality it returns
  4574. // a reference to the object.
  4575. // TODO: Avoid this special case by implementing a copystub for
  4576. // script classes that uses the default copy operator
  4577. bc->Call(asBC_CALLSYS, beh->copy, 2*AS_PTR_SIZE);
  4578. bc->Instr(asBC_PshRPtr);
  4579. }
  4580. else
  4581. {
  4582. // Default copy operator
  4583. if( lvalue->dataType.GetSizeInMemoryDWords() == 0 ||
  4584. !(lvalue->dataType.GetTypeInfo()->flags & asOBJ_POD) )
  4585. {
  4586. asCString msg;
  4587. msg.Format(TXT_NO_DEFAULT_COPY_OP_FOR_s, lvalue->dataType.GetTypeInfo()->name.AddressOf());
  4588. Error(msg, node);
  4589. return -1;
  4590. }
  4591. // Copy larger data types from a reference
  4592. // TODO: runtime optimize: COPY should pop both arguments and store the reference in the register.
  4593. bc->InstrSHORT_DW(asBC_COPY, (short)lvalue->dataType.GetSizeInMemoryDWords(), engine->GetTypeIdFromDataType(lvalue->dataType));
  4594. }
  4595. }
  4596. else
  4597. {
  4598. // TODO: The object handle can be stored in a variable as well
  4599. if( !lvalue->dataType.IsReference() )
  4600. {
  4601. Error(TXT_NOT_VALID_REFERENCE, node);
  4602. return -1;
  4603. }
  4604. if( lvalue->dataType.IsFuncdef() )
  4605. bc->InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  4606. else
  4607. bc->InstrPTR(asBC_REFCPY, lvalue->dataType.GetTypeInfo());
  4608. // Mark variable as initialized
  4609. if( variables )
  4610. {
  4611. sVariable *v = variables->GetVariableByOffset(lvalue->stackOffset);
  4612. if( v ) v->isInitialized = true;
  4613. }
  4614. }
  4615. return 0;
  4616. }
  4617. bool asCCompiler::CompileRefCast(asCExprContext *ctx, const asCDataType &to, bool isExplicit, asCScriptNode *node, bool generateCode)
  4618. {
  4619. bool conversionDone = false;
  4620. asCArray<int> ops;
  4621. asUINT n;
  4622. // A ref cast must not remove the constness
  4623. bool isConst = ctx->type.dataType.IsObjectConst();
  4624. // Find a suitable opCast or opImplCast method
  4625. asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  4626. for( n = 0; ot && n < ot->methods.GetLength(); n++ )
  4627. {
  4628. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  4629. if( (isExplicit && func->name == "opCast") ||
  4630. func->name == "opImplCast" )
  4631. {
  4632. // Is the operator for the output type?
  4633. if( func->returnType.GetTypeInfo() != to.GetTypeInfo() )
  4634. continue;
  4635. // Can't call a non-const function on a const object
  4636. if( isConst && !func->IsReadOnly() )
  4637. continue;
  4638. ops.PushLast(func->id);
  4639. }
  4640. }
  4641. // Filter the list by constness to remove const methods if there are matching non-const methods
  4642. FilterConst(ops, !isConst);
  4643. // Give an error more than one opCast methods were found
  4644. if (ops.GetLength() > 1)
  4645. {
  4646. if (isExplicit && generateCode)
  4647. {
  4648. asCString str;
  4649. str.Format(TXT_MULTIPLE_MATCHING_SIGNATURES_TO_s, "opCast");
  4650. Error(str, node);
  4651. PrintMatchingFuncs(ops, node, ot);
  4652. }
  4653. // Return that the conversion was done to avoid further complaints
  4654. conversionDone = true;
  4655. ctx->type.Set(to);
  4656. return conversionDone;
  4657. }
  4658. // Should only have one behaviour for each output type
  4659. if( ops.GetLength() == 1 )
  4660. {
  4661. conversionDone = true;
  4662. if( generateCode )
  4663. {
  4664. // TODO: runtime optimize: Instead of producing bytecode for checking if the handle is
  4665. // null, we can create a special CALLSYS instruction that checks
  4666. // if the object pointer is null and if so sets the object register
  4667. // to null directly without executing the function.
  4668. //
  4669. // Alternatively I could force the ref cast behaviours be global
  4670. // functions with 1 parameter, even though they should still be
  4671. // registered with RegisterObjectBehaviour()
  4672. if( (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_NOHANDLE))
  4673. {
  4674. // Add code to avoid calling the cast behaviour if the handle is already null,
  4675. // because that will raise a null pointer exception due to the cast behaviour
  4676. // being a class method, and the this pointer cannot be null.
  4677. if (!ctx->type.isVariable)
  4678. {
  4679. Dereference(ctx, true);
  4680. ConvertToVariable(ctx);
  4681. }
  4682. // The reference on the stack will not be used
  4683. ctx->bc.Instr(asBC_PopPtr);
  4684. // TODO: runtime optimize: should have immediate comparison for null pointer
  4685. int offset = AllocateVariable(asCDataType::CreateNullHandle(), true);
  4686. // 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)
  4687. ctx->bc.InstrSHORT(asBC_ClrVPtr, (asWORD)offset);
  4688. ctx->bc.InstrW_W(asBC_CmpPtr, ctx->type.stackOffset, offset);
  4689. DeallocateVariable(offset);
  4690. int afterLabel = nextLabel++;
  4691. ctx->bc.InstrDWORD(asBC_JZ, afterLabel);
  4692. // Call the cast operator
  4693. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  4694. ctx->bc.Instr(asBC_RDSPtr);
  4695. ctx->type.dataType.MakeReference(false);
  4696. asCArray<asCExprContext *> args;
  4697. MakeFunctionCall(ctx, ops[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
  4698. ctx->bc.Instr(asBC_PopPtr);
  4699. int endLabel = nextLabel++;
  4700. ctx->bc.InstrINT(asBC_JMP, endLabel);
  4701. ctx->bc.Label((short)afterLabel);
  4702. // Make a NULL pointer
  4703. ctx->bc.InstrSHORT(asBC_ClrVPtr, ctx->type.stackOffset);
  4704. ctx->bc.Label((short)endLabel);
  4705. // Push the reference to the handle on the stack
  4706. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  4707. }
  4708. else
  4709. {
  4710. // Value types cannot be null, so there is no need to check for this.
  4711. // Likewise for reference types that are registered with asOBJ_NOHANDLE
  4712. // as those are only expected as registered global properties that cannot
  4713. // be modified anyway.
  4714. // Call the cast operator
  4715. asCArray<asCExprContext *> args;
  4716. MakeFunctionCall(ctx, ops[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
  4717. }
  4718. }
  4719. else
  4720. {
  4721. asCScriptFunction *func = engine->scriptFunctions[ops[0]];
  4722. ctx->type.Set(func->returnType);
  4723. }
  4724. }
  4725. else if( ops.GetLength() == 0 && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) )
  4726. {
  4727. // Check for the generic ref cast method: void opCast(?&out)
  4728. for( n = 0; ot && n < ot->methods.GetLength(); n++ )
  4729. {
  4730. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  4731. if( (isExplicit && func->name == "opCast") ||
  4732. func->name == "opImplCast" )
  4733. {
  4734. // Does the operator take the ?&out parameter?
  4735. if( func->returnType.GetTokenType() != ttVoid ||
  4736. func->parameterTypes.GetLength() != 1 ||
  4737. func->parameterTypes[0].GetTokenType() != ttQuestion ||
  4738. func->inOutFlags[0] != asTM_OUTREF )
  4739. continue;
  4740. ops.PushLast(func->id);
  4741. }
  4742. }
  4743. // It shouldn't be possible to have more than one
  4744. // TODO: Should be allowed to have different implementations for const and non-const references
  4745. asASSERT( ops.GetLength() <= 1 );
  4746. if( ops.GetLength() == 1 )
  4747. {
  4748. conversionDone = true;
  4749. if( generateCode )
  4750. {
  4751. asASSERT(to.IsObjectHandle());
  4752. int afterLabel = 0;
  4753. bool doNullCheck = false;
  4754. asCExprContext tmp(engine);
  4755. if ((ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_NOHANDLE))
  4756. {
  4757. tmp.bc.AddCode(&ctx->bc);
  4758. tmp.Merge(ctx);
  4759. // Add code to avoid calling the cast behaviour if the handle is already null,
  4760. // because that will raise a null pointer exception due to the cast behaviour
  4761. // being a class method, and the this pointer cannot be null.
  4762. doNullCheck = true;
  4763. if (!ctx->type.isVariable)
  4764. {
  4765. Dereference(&tmp, true);
  4766. ConvertToVariable(&tmp);
  4767. }
  4768. // The reference on the stack will not be used
  4769. tmp.bc.Instr(asBC_PopPtr);
  4770. // TODO: runtime optimize: should have immediate comparison for null pointer
  4771. int offset = AllocateVariable(asCDataType::CreateNullHandle(), true);
  4772. // 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)
  4773. tmp.bc.InstrSHORT(asBC_ClrVPtr, (asWORD)offset);
  4774. tmp.bc.InstrW_W(asBC_CmpPtr, tmp.type.stackOffset, offset);
  4775. DeallocateVariable(offset);
  4776. afterLabel = nextLabel++;
  4777. tmp.bc.InstrDWORD(asBC_JZ, afterLabel);
  4778. // Place the object pointer on the stack
  4779. ctx->bc.InstrSHORT(asBC_PSF, (short)tmp.type.stackOffset);
  4780. }
  4781. // Allocate a temporary variable of the requested handle type
  4782. int stackOffset = AllocateVariableNotIn(to, true, false, ctx);
  4783. // Pass the reference of that variable to the function as output parameter
  4784. asCDataType toRef(to);
  4785. toRef.MakeReference(true);
  4786. asCArray<asCExprContext *> args;
  4787. asCExprContext arg(engine);
  4788. arg.bc.InstrSHORT(asBC_PSF, (short)stackOffset);
  4789. // Don't mark the variable as temporary, so it won't be freed too early
  4790. arg.type.SetVariable(toRef, stackOffset, false);
  4791. arg.type.isLValue = true;
  4792. arg.type.isExplicitHandle = true;
  4793. args.PushLast(&arg);
  4794. // Call the behaviour method
  4795. MakeFunctionCall(ctx, ops[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
  4796. if (doNullCheck)
  4797. {
  4798. // Add the call after the null check
  4799. tmp.bc.AddCode(&ctx->bc);
  4800. ctx->bc.AddCode(&tmp.bc);
  4801. int endLabel = nextLabel++;
  4802. ctx->bc.InstrINT(asBC_JMP, endLabel);
  4803. ctx->bc.Label((short)afterLabel);
  4804. // Make a NULL pointer
  4805. ctx->bc.InstrSHORT(asBC_ClrVPtr, (short)stackOffset);
  4806. ctx->bc.Label((short)endLabel);
  4807. }
  4808. // Use the reference to the variable as the result of the expression
  4809. // Now we can mark the variable as temporary
  4810. ctx->type.SetVariable(toRef, stackOffset, true);
  4811. ctx->bc.InstrSHORT(asBC_PSF, (short)stackOffset);
  4812. }
  4813. else
  4814. {
  4815. // All casts are legal
  4816. ctx->type.Set(to);
  4817. }
  4818. }
  4819. }
  4820. // If the script object didn't implement a matching opCast or opImplCast
  4821. // then check if the desired type is part of the hierarchy
  4822. if( !conversionDone && (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) )
  4823. {
  4824. // We need it to be a reference
  4825. if( !ctx->type.dataType.IsReference() )
  4826. {
  4827. asCDataType toRef = ctx->type.dataType;
  4828. toRef.MakeReference(true);
  4829. ImplicitConversion(ctx, toRef, 0, isExplicit ? asIC_EXPLICIT_REF_CAST : asIC_IMPLICIT_CONV, generateCode);
  4830. }
  4831. if( isExplicit )
  4832. {
  4833. // Allow dynamic cast between object handles (only for script objects).
  4834. // At run time this may result in a null handle,
  4835. // which when used will throw an exception
  4836. conversionDone = true;
  4837. if( generateCode )
  4838. {
  4839. ctx->bc.InstrDWORD(asBC_Cast, engine->GetTypeIdFromDataType(to));
  4840. // Allocate a temporary variable for the returned object
  4841. int returnOffset = AllocateVariable(to, true);
  4842. // Move the pointer from the object register to the temporary variable
  4843. ctx->bc.InstrSHORT(asBC_STOREOBJ, (short)returnOffset);
  4844. ctx->bc.InstrSHORT(asBC_PSF, (short)returnOffset);
  4845. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4846. ctx->type.SetVariable(to, returnOffset, true);
  4847. ctx->type.dataType.MakeReference(true);
  4848. }
  4849. else
  4850. {
  4851. ctx->type.dataType = to;
  4852. ctx->type.dataType.MakeReference(true);
  4853. }
  4854. }
  4855. else
  4856. {
  4857. if( CastToObjectType(ctx->type.dataType.GetTypeInfo())->DerivesFrom(to.GetTypeInfo()) )
  4858. {
  4859. conversionDone = true;
  4860. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  4861. }
  4862. }
  4863. // A ref cast must not remove the constness
  4864. if( isConst )
  4865. ctx->type.dataType.MakeHandleToConst(true);
  4866. }
  4867. return conversionDone;
  4868. }
  4869. asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asCExprContext *ctx, const asCDataType &toOrig, asCScriptNode *node, EImplicitConv convType, bool generateCode)
  4870. {
  4871. asCDataType to = toOrig;
  4872. to.MakeReference(false);
  4873. asASSERT( !ctx->type.dataType.IsReference() );
  4874. // Maybe no conversion is needed
  4875. if( to.IsEqualExceptConst(ctx->type.dataType) )
  4876. {
  4877. // A primitive is const or not
  4878. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  4879. return asCC_NO_CONV;
  4880. }
  4881. // Is the conversion an ambiguous enum value?
  4882. if( ctx->enumValue != "" )
  4883. {
  4884. if( to.IsEnumType() )
  4885. {
  4886. // Attempt to resolve an ambiguous enum value
  4887. asCDataType out;
  4888. asDWORD value;
  4889. if( builder->GetEnumValueFromType(CastToEnumType(to.GetTypeInfo()), ctx->enumValue.AddressOf(), out, value) )
  4890. {
  4891. ctx->type.SetConstantDW(out, value);
  4892. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  4893. // Reset the enum value since we no longer need it
  4894. ctx->enumValue = "";
  4895. // It wasn't really a conversion. The compiler just resolved the ambiguity (or not)
  4896. return asCC_NO_CONV;
  4897. }
  4898. }
  4899. // The enum value is ambiguous
  4900. if( node && generateCode )
  4901. Error(TXT_FOUND_MULTIPLE_ENUM_VALUES, node);
  4902. // Set a dummy to allow the compiler to try to continue the conversion
  4903. ctx->type.SetDummy();
  4904. }
  4905. // Determine the cost of this conversion
  4906. asUINT cost = asCC_NO_CONV;
  4907. if( (to.IsIntegerType() || to.IsUnsignedType()) && (ctx->type.dataType.IsFloatType() || ctx->type.dataType.IsDoubleType()) )
  4908. cost = asCC_INT_FLOAT_CONV;
  4909. else if ((to.IsFloatType() || to.IsDoubleType()) && (ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType()))
  4910. cost = asCC_INT_FLOAT_CONV;
  4911. else if (ctx->type.dataType.IsEnumType() && to.IsIntegerType() && to.GetSizeInMemoryBytes() == ctx->type.dataType.GetSizeInMemoryBytes() )
  4912. cost = asCC_ENUM_SAME_SIZE_CONV;
  4913. else if (ctx->type.dataType.IsEnumType() && to.IsIntegerType() && to.GetSizeInMemoryBytes() != ctx->type.dataType.GetSizeInMemoryBytes())
  4914. cost = asCC_ENUM_DIFF_SIZE_CONV;
  4915. else if( to.IsUnsignedType() && ctx->type.dataType.IsIntegerType() )
  4916. cost = asCC_SIGNED_CONV;
  4917. else if( to.IsIntegerType() && ctx->type.dataType.IsUnsignedType() )
  4918. cost = asCC_SIGNED_CONV;
  4919. else if( to.GetSizeInMemoryBytes() != ctx->type.dataType.GetSizeInMemoryBytes() )
  4920. cost = asCC_PRIMITIVE_SIZE_CONV;
  4921. // Start by implicitly converting constant values
  4922. if( ctx->type.isConstant )
  4923. {
  4924. ImplicitConversionConstant(ctx, to, node, convType);
  4925. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  4926. return cost;
  4927. }
  4928. // Allow implicit conversion between numbers
  4929. if( generateCode )
  4930. {
  4931. // When generating the code the decision has already been made, so we don't bother determining the cost
  4932. // Convert smaller types to 32bit first
  4933. int s = ctx->type.dataType.GetSizeInMemoryBytes();
  4934. if( s < 4 )
  4935. {
  4936. ConvertToTempVariable(ctx);
  4937. if( ctx->type.dataType.IsIntegerType() )
  4938. {
  4939. if( s == 1 )
  4940. ctx->bc.InstrSHORT(asBC_sbTOi, ctx->type.stackOffset);
  4941. else if( s == 2 )
  4942. ctx->bc.InstrSHORT(asBC_swTOi, ctx->type.stackOffset);
  4943. ctx->type.dataType.SetTokenType(ttInt);
  4944. }
  4945. else if( ctx->type.dataType.IsUnsignedType() )
  4946. {
  4947. if( s == 1 )
  4948. ctx->bc.InstrSHORT(asBC_ubTOi, ctx->type.stackOffset);
  4949. else if( s == 2 )
  4950. ctx->bc.InstrSHORT(asBC_uwTOi, ctx->type.stackOffset);
  4951. ctx->type.dataType.SetTokenType(ttUInt);
  4952. }
  4953. }
  4954. if( (to.IsIntegerType() && to.GetSizeInMemoryDWords() == 1 && !to.IsEnumType()) ||
  4955. (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST) )
  4956. {
  4957. if( ctx->type.dataType.IsIntegerType() ||
  4958. ctx->type.dataType.IsUnsignedType() )
  4959. {
  4960. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  4961. {
  4962. ctx->type.dataType.SetTokenType(to.GetTokenType());
  4963. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  4964. }
  4965. else
  4966. {
  4967. ConvertToTempVariable(ctx);
  4968. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4969. int offset = AllocateVariable(to, true);
  4970. ctx->bc.InstrW_W(asBC_i64TOi, offset, ctx->type.stackOffset);
  4971. ctx->type.SetVariable(to, offset, true);
  4972. }
  4973. }
  4974. else if( ctx->type.dataType.IsFloatType() )
  4975. {
  4976. ConvertToTempVariable(ctx);
  4977. ctx->bc.InstrSHORT(asBC_fTOi, ctx->type.stackOffset);
  4978. ctx->type.dataType.SetTokenType(to.GetTokenType());
  4979. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  4980. if( convType != asIC_EXPLICIT_VAL_CAST )
  4981. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  4982. }
  4983. else if( ctx->type.dataType.IsDoubleType() )
  4984. {
  4985. ConvertToTempVariable(ctx);
  4986. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4987. int offset = AllocateVariable(to, true);
  4988. ctx->bc.InstrW_W(asBC_dTOi, offset, ctx->type.stackOffset);
  4989. ctx->type.SetVariable(to, offset, true);
  4990. if( convType != asIC_EXPLICIT_VAL_CAST )
  4991. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  4992. }
  4993. // Convert to smaller integer if necessary
  4994. s = to.GetSizeInMemoryBytes();
  4995. if( s < 4 )
  4996. {
  4997. ConvertToTempVariable(ctx);
  4998. if( s == 1 )
  4999. ctx->bc.InstrSHORT(asBC_iTOb, ctx->type.stackOffset);
  5000. else if( s == 2 )
  5001. ctx->bc.InstrSHORT(asBC_iTOw, ctx->type.stackOffset);
  5002. }
  5003. }
  5004. else if( to.IsIntegerType() && to.GetSizeInMemoryDWords() == 2 )
  5005. {
  5006. if( ctx->type.dataType.IsIntegerType() ||
  5007. ctx->type.dataType.IsUnsignedType() )
  5008. {
  5009. if( ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  5010. {
  5011. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5012. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5013. }
  5014. else
  5015. {
  5016. ConvertToTempVariable(ctx);
  5017. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5018. int offset = AllocateVariable(to, true);
  5019. if( ctx->type.dataType.IsUnsignedType() )
  5020. ctx->bc.InstrW_W(asBC_uTOi64, offset, ctx->type.stackOffset);
  5021. else
  5022. ctx->bc.InstrW_W(asBC_iTOi64, offset, ctx->type.stackOffset);
  5023. ctx->type.SetVariable(to, offset, true);
  5024. }
  5025. }
  5026. else if( ctx->type.dataType.IsFloatType() )
  5027. {
  5028. ConvertToTempVariable(ctx);
  5029. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5030. int offset = AllocateVariable(to, true);
  5031. ctx->bc.InstrW_W(asBC_fTOi64, offset, ctx->type.stackOffset);
  5032. ctx->type.SetVariable(to, offset, true);
  5033. if( convType != asIC_EXPLICIT_VAL_CAST )
  5034. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  5035. }
  5036. else if( ctx->type.dataType.IsDoubleType() )
  5037. {
  5038. ConvertToTempVariable(ctx);
  5039. ctx->bc.InstrSHORT(asBC_dTOi64, ctx->type.stackOffset);
  5040. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5041. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5042. if( convType != asIC_EXPLICIT_VAL_CAST )
  5043. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  5044. }
  5045. }
  5046. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 1 )
  5047. {
  5048. if( ctx->type.dataType.IsIntegerType() ||
  5049. ctx->type.dataType.IsUnsignedType() )
  5050. {
  5051. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  5052. {
  5053. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5054. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5055. }
  5056. else
  5057. {
  5058. ConvertToTempVariable(ctx);
  5059. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5060. int offset = AllocateVariable(to, true);
  5061. ctx->bc.InstrW_W(asBC_i64TOi, offset, ctx->type.stackOffset);
  5062. ctx->type.SetVariable(to, offset, true);
  5063. }
  5064. }
  5065. else if( ctx->type.dataType.IsFloatType() )
  5066. {
  5067. ConvertToTempVariable(ctx);
  5068. ctx->bc.InstrSHORT(asBC_fTOu, ctx->type.stackOffset);
  5069. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5070. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5071. if( convType != asIC_EXPLICIT_VAL_CAST )
  5072. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  5073. }
  5074. else if( ctx->type.dataType.IsDoubleType() )
  5075. {
  5076. ConvertToTempVariable(ctx);
  5077. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5078. int offset = AllocateVariable(to, true);
  5079. ctx->bc.InstrW_W(asBC_dTOu, offset, ctx->type.stackOffset);
  5080. ctx->type.SetVariable(to, offset, true);
  5081. if( convType != asIC_EXPLICIT_VAL_CAST )
  5082. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  5083. }
  5084. // Convert to smaller integer if necessary
  5085. s = to.GetSizeInMemoryBytes();
  5086. if( s < 4 )
  5087. {
  5088. ConvertToTempVariable(ctx);
  5089. if( s == 1 )
  5090. ctx->bc.InstrSHORT(asBC_iTOb, ctx->type.stackOffset);
  5091. else if( s == 2 )
  5092. ctx->bc.InstrSHORT(asBC_iTOw, ctx->type.stackOffset);
  5093. }
  5094. }
  5095. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 2 )
  5096. {
  5097. if( ctx->type.dataType.IsIntegerType() ||
  5098. ctx->type.dataType.IsUnsignedType() )
  5099. {
  5100. if( ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  5101. {
  5102. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5103. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5104. }
  5105. else
  5106. {
  5107. ConvertToTempVariable(ctx);
  5108. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5109. int offset = AllocateVariable(to, true);
  5110. if( ctx->type.dataType.IsUnsignedType() )
  5111. ctx->bc.InstrW_W(asBC_uTOi64, offset, ctx->type.stackOffset);
  5112. else
  5113. ctx->bc.InstrW_W(asBC_iTOi64, offset, ctx->type.stackOffset);
  5114. ctx->type.SetVariable(to, offset, true);
  5115. }
  5116. }
  5117. else if( ctx->type.dataType.IsFloatType() )
  5118. {
  5119. ConvertToTempVariable(ctx);
  5120. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5121. int offset = AllocateVariable(to, true);
  5122. ctx->bc.InstrW_W(asBC_fTOu64, offset, ctx->type.stackOffset);
  5123. ctx->type.SetVariable(to, offset, true);
  5124. if( convType != asIC_EXPLICIT_VAL_CAST )
  5125. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  5126. }
  5127. else if( ctx->type.dataType.IsDoubleType() )
  5128. {
  5129. ConvertToTempVariable(ctx);
  5130. ctx->bc.InstrSHORT(asBC_dTOu64, ctx->type.stackOffset);
  5131. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5132. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5133. if( convType != asIC_EXPLICIT_VAL_CAST )
  5134. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  5135. }
  5136. }
  5137. else if( to.IsFloatType() )
  5138. {
  5139. if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  5140. {
  5141. ConvertToTempVariable(ctx);
  5142. ctx->bc.InstrSHORT(asBC_iTOf, ctx->type.stackOffset);
  5143. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5144. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5145. }
  5146. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  5147. {
  5148. ConvertToTempVariable(ctx);
  5149. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5150. int offset = AllocateVariable(to, true);
  5151. ctx->bc.InstrW_W(asBC_i64TOf, offset, ctx->type.stackOffset);
  5152. ctx->type.SetVariable(to, offset, true);
  5153. }
  5154. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  5155. {
  5156. ConvertToTempVariable(ctx);
  5157. ctx->bc.InstrSHORT(asBC_uTOf, ctx->type.stackOffset);
  5158. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5159. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5160. }
  5161. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  5162. {
  5163. ConvertToTempVariable(ctx);
  5164. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5165. int offset = AllocateVariable(to, true);
  5166. ctx->bc.InstrW_W(asBC_u64TOf, offset, ctx->type.stackOffset);
  5167. ctx->type.SetVariable(to, offset, true);
  5168. }
  5169. else if( ctx->type.dataType.IsDoubleType() )
  5170. {
  5171. ConvertToTempVariable(ctx);
  5172. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5173. int offset = AllocateVariable(to, true);
  5174. ctx->bc.InstrW_W(asBC_dTOf, offset, ctx->type.stackOffset);
  5175. ctx->type.SetVariable(to, offset, true);
  5176. }
  5177. }
  5178. else if( to.IsDoubleType() )
  5179. {
  5180. if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  5181. {
  5182. ConvertToTempVariable(ctx);
  5183. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5184. int offset = AllocateVariable(to, true);
  5185. ctx->bc.InstrW_W(asBC_iTOd, offset, ctx->type.stackOffset);
  5186. ctx->type.SetVariable(to, offset, true);
  5187. }
  5188. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  5189. {
  5190. ConvertToTempVariable(ctx);
  5191. ctx->bc.InstrSHORT(asBC_i64TOd, ctx->type.stackOffset);
  5192. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5193. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5194. }
  5195. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  5196. {
  5197. ConvertToTempVariable(ctx);
  5198. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5199. int offset = AllocateVariable(to, true);
  5200. ctx->bc.InstrW_W(asBC_uTOd, offset, ctx->type.stackOffset);
  5201. ctx->type.SetVariable(to, offset, true);
  5202. }
  5203. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  5204. {
  5205. ConvertToTempVariable(ctx);
  5206. ctx->bc.InstrSHORT(asBC_u64TOd, ctx->type.stackOffset);
  5207. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5208. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5209. }
  5210. else if( ctx->type.dataType.IsFloatType() )
  5211. {
  5212. ConvertToTempVariable(ctx);
  5213. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5214. int offset = AllocateVariable(to, true);
  5215. ctx->bc.InstrW_W(asBC_fTOd, offset, ctx->type.stackOffset);
  5216. ctx->type.SetVariable(to, offset, true);
  5217. }
  5218. }
  5219. }
  5220. else
  5221. {
  5222. if( ((to.IsIntegerType() && !to.IsEnumType()) || to.IsUnsignedType() ||
  5223. to.IsFloatType() || to.IsDoubleType() ||
  5224. (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST)) &&
  5225. (ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType() ||
  5226. ctx->type.dataType.IsFloatType() || ctx->type.dataType.IsDoubleType()) )
  5227. {
  5228. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5229. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5230. }
  5231. }
  5232. // Primitive types on the stack, can be const or non-const
  5233. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  5234. return cost;
  5235. }
  5236. asUINT asCCompiler::ImplicitConvLambdaToFunc(asCExprContext *ctx, const asCDataType &to, asCScriptNode * /*node*/, EImplicitConv /*convType*/, bool generateCode)
  5237. {
  5238. asASSERT( to.IsFuncdef() && ctx->IsLambda() );
  5239. // Check that the lambda has the correct amount of arguments
  5240. asUINT count = 0;
  5241. asCScriptNode *argNode = ctx->exprNode->firstChild;
  5242. while( argNode->nodeType == snIdentifier )
  5243. {
  5244. count++;
  5245. argNode = argNode->next;
  5246. }
  5247. asASSERT( argNode->nodeType == snStatementBlock );
  5248. asCScriptFunction *funcDef = CastToFuncdefType(to.GetTypeInfo())->funcdef;
  5249. if( funcDef->parameterTypes.GetLength() != count )
  5250. return asCC_NO_CONV;
  5251. // The Lambda can be used as this funcdef
  5252. ctx->type.dataType = to;
  5253. if( generateCode )
  5254. {
  5255. // Build a unique name for the anonymous function
  5256. asCString name;
  5257. if( m_globalVar )
  5258. name.Format("$%s$%d", m_globalVar->name.AddressOf(), numLambdas++);
  5259. else
  5260. name.Format("$%s$%d", outFunc->GetDeclaration(), numLambdas++);
  5261. // Register the lambda with the builder for later compilation
  5262. asCScriptFunction *func = builder->RegisterLambda(ctx->exprNode, script, funcDef, name, outFunc->nameSpace);
  5263. asASSERT( func == 0 || funcDef->IsSignatureExceptNameEqual(func) );
  5264. ctx->bc.InstrPTR(asBC_FuncPtr, func);
  5265. // Clear the expression node as it is no longer valid
  5266. ctx->exprNode = 0;
  5267. }
  5268. return asCC_CONST_CONV;
  5269. }
  5270. asUINT asCCompiler::ImplicitConversion(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode, bool allowObjectConstruct)
  5271. {
  5272. asASSERT( ctx->type.dataType.GetTokenType() != ttUnrecognizedToken ||
  5273. ctx->type.dataType.IsNullHandle() ||
  5274. ctx->IsAnonymousInitList() );
  5275. if( to.IsFuncdef() && ctx->IsLambda() )
  5276. return ImplicitConvLambdaToFunc(ctx, to, node, convType, generateCode);
  5277. if (ctx->IsAnonymousInitList())
  5278. {
  5279. if (to.GetBehaviour() && to.GetBehaviour()->listFactory)
  5280. {
  5281. if (generateCode)
  5282. CompilerAnonymousInitList(ctx->exprNode, ctx, to);
  5283. else
  5284. ctx->type.dataType = to;
  5285. }
  5286. return asCC_NO_CONV;
  5287. }
  5288. // No conversion from void to any other type
  5289. if( ctx->type.dataType.GetTokenType() == ttVoid )
  5290. return asCC_NO_CONV;
  5291. // No conversion from class method to any type (it requires delegate)
  5292. if( ctx->IsClassMethod() )
  5293. return asCC_NO_CONV;
  5294. // Do we want a var type?
  5295. if( to.GetTokenType() == ttQuestion )
  5296. {
  5297. // Any type can be converted to a var type, but only when not generating code
  5298. asASSERT( !generateCode );
  5299. ctx->type.dataType = to;
  5300. return asCC_VARIABLE_CONV;
  5301. }
  5302. // Do we want a primitive?
  5303. else if( to.IsPrimitive() )
  5304. {
  5305. if( !ctx->type.dataType.IsPrimitive() )
  5306. return ImplicitConvObjectToPrimitive(ctx, to, node, convType, generateCode);
  5307. else
  5308. return ImplicitConvPrimitiveToPrimitive(ctx, to, node, convType, generateCode);
  5309. }
  5310. else // The target is a complex type
  5311. {
  5312. if( ctx->type.dataType.IsPrimitive() )
  5313. return ImplicitConvPrimitiveToObject(ctx, to, node, convType, generateCode, allowObjectConstruct);
  5314. else if( ctx->type.IsNullConstant() || ctx->type.dataType.GetTypeInfo() )
  5315. return ImplicitConvObjectToObject(ctx, to, node, convType, generateCode, allowObjectConstruct);
  5316. }
  5317. return asCC_NO_CONV;
  5318. }
  5319. asUINT asCCompiler::ImplicitConvObjectToPrimitive(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode)
  5320. {
  5321. if( ctx->type.isExplicitHandle )
  5322. {
  5323. // An explicit handle cannot be converted to a primitive
  5324. if( convType != asIC_IMPLICIT_CONV && node )
  5325. {
  5326. asCString str;
  5327. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  5328. Error(str, node);
  5329. }
  5330. return asCC_NO_CONV;
  5331. }
  5332. // TODO: Must use the const cast behaviour if the object is read-only
  5333. // Find matching value cast behaviours
  5334. // Here we're only interested in those that convert the type to a primitive type
  5335. asCArray<int> funcs;
  5336. asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  5337. if( ot == 0 )
  5338. {
  5339. if( convType != asIC_IMPLICIT_CONV && node )
  5340. {
  5341. asCString str;
  5342. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  5343. Error(str, node);
  5344. }
  5345. return asCC_NO_CONV;
  5346. }
  5347. if( convType == asIC_EXPLICIT_VAL_CAST )
  5348. {
  5349. for( unsigned int n = 0; n < ot->methods.GetLength(); n++ )
  5350. {
  5351. // accept both implicit and explicit cast
  5352. asCScriptFunction *mthd = engine->scriptFunctions[ot->methods[n]];
  5353. if( (mthd->name == "opConv" || mthd->name == "opImplConv") &&
  5354. mthd->parameterTypes.GetLength() == 0 &&
  5355. mthd->returnType.IsPrimitive() )
  5356. funcs.PushLast(ot->methods[n]);
  5357. }
  5358. }
  5359. else
  5360. {
  5361. for( unsigned int n = 0; n < ot->methods.GetLength(); n++ )
  5362. {
  5363. // accept only implicit cast
  5364. asCScriptFunction *mthd = engine->scriptFunctions[ot->methods[n]];
  5365. if( mthd->name == "opImplConv" &&
  5366. mthd->parameterTypes.GetLength() == 0 &&
  5367. mthd->returnType.IsPrimitive() )
  5368. funcs.PushLast(ot->methods[n]);
  5369. }
  5370. }
  5371. int funcId = 0;
  5372. if( to.IsMathType() )
  5373. {
  5374. // This matrix describes the priorities of the types to search for, for each target type
  5375. // The first column is the target type, the priorities goes from left to right
  5376. eTokenType matchMtx[10][10] =
  5377. {
  5378. {ttDouble, ttFloat, ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8},
  5379. {ttFloat, ttDouble, ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8},
  5380. {ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8, ttDouble, ttFloat},
  5381. {ttUInt64, ttInt64, ttUInt, ttInt, ttUInt16, ttInt16, ttUInt8, ttInt8, ttDouble, ttFloat},
  5382. {ttInt, ttUInt, ttInt64, ttUInt64, ttInt16, ttUInt16, ttInt8, ttUInt8, ttDouble, ttFloat},
  5383. {ttUInt, ttInt, ttUInt64, ttInt64, ttUInt16, ttInt16, ttUInt8, ttInt8, ttDouble, ttFloat},
  5384. {ttInt16, ttUInt16, ttInt, ttUInt, ttInt64, ttUInt64, ttInt8, ttUInt8, ttDouble, ttFloat},
  5385. {ttUInt16, ttInt16, ttUInt, ttInt, ttUInt64, ttInt64, ttUInt8, ttInt8, ttDouble, ttFloat},
  5386. {ttInt8, ttUInt8, ttInt16, ttUInt16, ttInt, ttUInt, ttInt64, ttUInt64, ttDouble, ttFloat},
  5387. {ttUInt8, ttInt8, ttUInt16, ttInt16, ttUInt, ttInt, ttUInt64, ttInt64, ttDouble, ttFloat},
  5388. };
  5389. // Which row to use?
  5390. eTokenType *row = 0;
  5391. for( unsigned int type = 0; type < 10; type++ )
  5392. {
  5393. if( to.GetTokenType() == matchMtx[type][0] )
  5394. {
  5395. row = &matchMtx[type][0];
  5396. break;
  5397. }
  5398. }
  5399. // Find the best matching cast operator
  5400. if( row )
  5401. {
  5402. asCDataType target(to);
  5403. // Priority goes from left to right in the matrix
  5404. for( unsigned int attempt = 0; attempt < 10 && funcId == 0; attempt++ )
  5405. {
  5406. target.SetTokenType(row[attempt]);
  5407. for( unsigned int n = 0; n < funcs.GetLength(); n++ )
  5408. {
  5409. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[n]);
  5410. if( descr->returnType.IsEqualExceptRefAndConst(target) )
  5411. {
  5412. funcId = funcs[n];
  5413. break;
  5414. }
  5415. }
  5416. }
  5417. }
  5418. }
  5419. else
  5420. {
  5421. // Only accept the exact conversion for non-math types
  5422. // Find the matching cast operator
  5423. for( unsigned int n = 0; n < funcs.GetLength(); n++ )
  5424. {
  5425. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[n]);
  5426. if( descr->returnType.IsEqualExceptRefAndConst(to) )
  5427. {
  5428. funcId = funcs[n];
  5429. break;
  5430. }
  5431. }
  5432. }
  5433. // Did we find a suitable function?
  5434. if( funcId != 0 )
  5435. {
  5436. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  5437. if( generateCode )
  5438. {
  5439. Dereference(ctx, true);
  5440. PerformFunctionCall(funcId, ctx);
  5441. }
  5442. else
  5443. ctx->type.Set(descr->returnType);
  5444. // Allow one more implicit conversion to another primitive type
  5445. return asCC_OBJ_TO_PRIMITIVE_CONV + ImplicitConversion(ctx, to, node, convType, generateCode, false);
  5446. }
  5447. // TODO: clean-up: This part is similar to what is in ImplicitConvObjectValue
  5448. // If no direct conversion is found we should look for the generic form 'void opConv(?&out)'
  5449. funcs.SetLength(0);
  5450. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  5451. {
  5452. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  5453. if( ((convType == asIC_EXPLICIT_VAL_CAST) && func->name == "opConv") ||
  5454. func->name == "opImplConv" )
  5455. {
  5456. // Does the operator take the ?&out parameter?
  5457. if( func->returnType != asCDataType::CreatePrimitive(ttVoid, false) ||
  5458. func->parameterTypes.GetLength() != 1 ||
  5459. func->parameterTypes[0].GetTokenType() != ttQuestion ||
  5460. func->inOutFlags[0] != asTM_OUTREF )
  5461. continue;
  5462. funcs.PushLast(ot->methods[n]);
  5463. }
  5464. }
  5465. // TODO: If there are multiple valid value casts, then we must choose the most appropriate one
  5466. asASSERT( funcs.GetLength() <= 1 );
  5467. if( funcs.GetLength() == 1 )
  5468. {
  5469. if( generateCode )
  5470. {
  5471. // Allocate a temporary variable of the requested type
  5472. int stackOffset = AllocateVariableNotIn(to, true, false, ctx);
  5473. CallDefaultConstructor(to, stackOffset, IsVariableOnHeap(stackOffset), &ctx->bc, node);
  5474. // Pass the reference of that variable to the function as output parameter
  5475. asCDataType toRef(to);
  5476. toRef.MakeReference(true);
  5477. toRef.MakeReadOnly(false);
  5478. asCArray<asCExprContext *> args;
  5479. asCExprContext arg(engine);
  5480. // Don't mark the variable as temporary, so it won't be freed too early
  5481. arg.type.SetVariable(toRef, stackOffset, false);
  5482. arg.type.isLValue = true;
  5483. arg.exprNode = node;
  5484. args.PushLast(&arg);
  5485. // Call the behaviour method
  5486. MakeFunctionCall(ctx, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
  5487. // Use the reference to the variable as the result of the expression
  5488. // Now we can mark the variable as temporary
  5489. toRef.MakeReference(false);
  5490. ctx->type.SetVariable(toRef, stackOffset, true);
  5491. }
  5492. else
  5493. ctx->type.Set(to);
  5494. return asCC_OBJ_TO_PRIMITIVE_CONV;
  5495. }
  5496. if( convType != asIC_IMPLICIT_CONV && node )
  5497. {
  5498. asCString str;
  5499. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  5500. Error(str, node);
  5501. }
  5502. return asCC_NO_CONV;
  5503. }
  5504. asUINT asCCompiler::ImplicitConvObjectRef(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode)
  5505. {
  5506. // Convert null to any object type handle, but not to a non-handle type
  5507. if( ctx->type.IsNullConstant() && ctx->methodName == "" )
  5508. {
  5509. if( to.IsObjectHandle() )
  5510. {
  5511. ctx->type.dataType = to;
  5512. return asCC_REF_CONV;
  5513. }
  5514. return asCC_NO_CONV;
  5515. }
  5516. asASSERT(ctx->type.dataType.GetTypeInfo() || ctx->methodName != "");
  5517. // First attempt to convert the base type without instantiating another instance
  5518. if( to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() && ctx->methodName == "" )
  5519. {
  5520. // If the to type is an interface and the from type implements it, then we can convert it immediately
  5521. if( ctx->type.dataType.GetTypeInfo()->Implements(to.GetTypeInfo()) )
  5522. {
  5523. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5524. return asCC_REF_CONV;
  5525. }
  5526. // If the to type is a class and the from type derives from it, then we can convert it immediately
  5527. else if( ctx->type.dataType.GetTypeInfo()->DerivesFrom(to.GetTypeInfo()) )
  5528. {
  5529. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5530. return asCC_REF_CONV;
  5531. }
  5532. // If the types are not equal yet, then we may still be able to find a reference cast
  5533. else if( ctx->type.dataType.GetTypeInfo() != to.GetTypeInfo() )
  5534. {
  5535. // We may still be able to find an implicit ref cast behaviour
  5536. CompileRefCast(ctx, to, convType == asIC_EXPLICIT_REF_CAST, node, generateCode);
  5537. // Was the conversion done?
  5538. if( ctx->type.dataType.GetTypeInfo() == to.GetTypeInfo() )
  5539. return asCC_REF_CONV;
  5540. }
  5541. }
  5542. // Convert matching function types
  5543. if( to.IsFuncdef() )
  5544. {
  5545. // If the input expression is already a funcdef, check if it can be converted
  5546. if( ctx->type.dataType.IsFuncdef() &&
  5547. to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() )
  5548. {
  5549. asCScriptFunction *toFunc = CastToFuncdefType(to.GetTypeInfo())->funcdef;
  5550. asCScriptFunction *fromFunc = CastToFuncdefType(ctx->type.dataType.GetTypeInfo())->funcdef;
  5551. if( toFunc->IsSignatureExceptNameEqual(fromFunc) )
  5552. {
  5553. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5554. return asCC_REF_CONV;
  5555. }
  5556. }
  5557. // If the input expression is a deferred function ref, check if there is a matching func
  5558. if( ctx->methodName != "" )
  5559. {
  5560. // Determine the namespace
  5561. asSNameSpace *ns = 0;
  5562. asCString name = "";
  5563. int pos = ctx->methodName.FindLast("::");
  5564. if( pos >= 0 )
  5565. {
  5566. asCString nsName = ctx->methodName.SubString(0, pos+2);
  5567. // Trim off the last ::
  5568. if( nsName.GetLength() > 2 )
  5569. nsName.SetLength(nsName.GetLength()-2);
  5570. ns = DetermineNameSpace(nsName);
  5571. name = ctx->methodName.SubString(pos+2);
  5572. }
  5573. else
  5574. {
  5575. DetermineNameSpace("");
  5576. name = ctx->methodName;
  5577. }
  5578. asCArray<int> funcs;
  5579. if( ns )
  5580. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  5581. // Check if any of the functions have perfect match
  5582. asCScriptFunction *toFunc = CastToFuncdefType(to.GetTypeInfo())->funcdef;
  5583. for( asUINT n = 0; n < funcs.GetLength(); n++ )
  5584. {
  5585. asCScriptFunction *func = builder->GetFunctionDescription(funcs[n]);
  5586. if( toFunc->IsSignatureExceptNameEqual(func) )
  5587. {
  5588. if( generateCode )
  5589. {
  5590. ctx->bc.InstrPTR(asBC_FuncPtr, func);
  5591. // Make sure the identified function is shared if we're compiling a shared function
  5592. if( !func->IsShared() && outFunc->IsShared() )
  5593. {
  5594. asCString msg;
  5595. msg.Format(TXT_SHARED_CANNOT_CALL_NON_SHARED_FUNC_s, func->GetDeclaration());
  5596. Error(msg, node);
  5597. }
  5598. }
  5599. ctx->type.dataType = asCDataType::CreateType(to.GetTypeInfo(), false);
  5600. return asCC_REF_CONV;
  5601. }
  5602. }
  5603. }
  5604. }
  5605. return asCC_NO_CONV;
  5606. }
  5607. asUINT asCCompiler::ImplicitConvObjectValue(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode)
  5608. {
  5609. asUINT cost = asCC_NO_CONV;
  5610. // If the base type is still different, and we are allowed to instance
  5611. // another object then we can try an implicit value cast
  5612. if( to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() )
  5613. {
  5614. // TODO: Implement support for implicit constructor/factory
  5615. asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  5616. if( ot == 0 )
  5617. return cost;
  5618. asCArray<int> funcs;
  5619. if( convType == asIC_EXPLICIT_VAL_CAST )
  5620. {
  5621. for( unsigned int n = 0; n < ot->methods.GetLength(); n++ )
  5622. {
  5623. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  5624. // accept both implicit and explicit cast
  5625. if( (func->name == "opConv" ||
  5626. func->name == "opImplConv") &&
  5627. func->returnType.GetTypeInfo() == to.GetTypeInfo() &&
  5628. func->parameterTypes.GetLength() == 0 )
  5629. funcs.PushLast(ot->methods[n]);
  5630. }
  5631. }
  5632. else
  5633. {
  5634. for( unsigned int n = 0; n < ot->methods.GetLength(); n++ )
  5635. {
  5636. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  5637. // accept only implicit cast
  5638. if( func->name == "opImplConv" &&
  5639. func->returnType.GetTypeInfo() == to.GetTypeInfo() &&
  5640. func->parameterTypes.GetLength() == 0 )
  5641. funcs.PushLast(ot->methods[n]);
  5642. }
  5643. }
  5644. // TODO: If there are multiple valid value casts, then we must choose the most appropriate one
  5645. asASSERT( funcs.GetLength() <= 1 );
  5646. if( funcs.GetLength() == 1 )
  5647. {
  5648. asCScriptFunction *f = builder->GetFunctionDescription(funcs[0]);
  5649. if( generateCode )
  5650. {
  5651. Dereference(ctx, true);
  5652. bool useVariable = false;
  5653. int stackOffset = 0;
  5654. if( f->DoesReturnOnStack() )
  5655. {
  5656. useVariable = true;
  5657. stackOffset = AllocateVariable(f->returnType, true);
  5658. // Push the pointer to the pre-allocated space for the return value
  5659. ctx->bc.InstrSHORT(asBC_PSF, short(stackOffset));
  5660. // The object pointer is already on the stack, but should be the top
  5661. // one, so we need to swap the pointers in order to get the correct
  5662. ctx->bc.Instr(asBC_SwapPtr);
  5663. }
  5664. PerformFunctionCall(funcs[0], ctx, false, 0, 0, useVariable, stackOffset);
  5665. }
  5666. else
  5667. ctx->type.Set(f->returnType);
  5668. cost = asCC_TO_OBJECT_CONV;
  5669. }
  5670. else
  5671. {
  5672. // TODO: cleanup: This part is similar to the second half of ImplicitConvObjectToPrimitive
  5673. // Look for a value cast with variable type
  5674. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  5675. {
  5676. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  5677. if( ((convType == asIC_EXPLICIT_VAL_CAST) && func->name == "opConv") ||
  5678. func->name == "opImplConv" )
  5679. {
  5680. // Does the operator take the ?&out parameter?
  5681. if( func->returnType != asCDataType::CreatePrimitive(ttVoid, false) ||
  5682. func->parameterTypes.GetLength() != 1 ||
  5683. func->parameterTypes[0].GetTokenType() != ttQuestion ||
  5684. func->inOutFlags[0] != asTM_OUTREF )
  5685. continue;
  5686. funcs.PushLast(ot->methods[n]);
  5687. }
  5688. }
  5689. // TODO: If there are multiple valid value casts, then we must choose the most appropriate one
  5690. asASSERT( funcs.GetLength() <= 1 );
  5691. if( funcs.GetLength() == 1 )
  5692. {
  5693. cost = asCC_TO_OBJECT_CONV;
  5694. if( generateCode )
  5695. {
  5696. // Allocate a temporary variable of the requested type
  5697. int stackOffset = AllocateVariableNotIn(to, true, false, ctx);
  5698. CallDefaultConstructor(to, stackOffset, IsVariableOnHeap(stackOffset), &ctx->bc, node);
  5699. // Pass the reference of that variable to the function as output parameter
  5700. asCDataType toRef(to);
  5701. toRef.MakeReference(false);
  5702. asCExprContext arg(engine);
  5703. arg.bc.InstrSHORT(asBC_PSF, (short)stackOffset);
  5704. // If this an object on the heap, the pointer must be dereferenced
  5705. if( IsVariableOnHeap(stackOffset) )
  5706. arg.bc.Instr(asBC_RDSPtr);
  5707. // Don't mark the variable as temporary, so it won't be freed too early
  5708. arg.type.SetVariable(toRef, stackOffset, false);
  5709. arg.type.isLValue = true;
  5710. arg.exprNode = node;
  5711. // Mark the argument as clean, so that MakeFunctionCall knows it
  5712. // doesn't have to make a copy of it in order to protect the value
  5713. arg.isCleanArg = true;
  5714. // Call the behaviour method
  5715. asCArray<asCExprContext *> args;
  5716. args.PushLast(&arg);
  5717. MakeFunctionCall(ctx, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
  5718. // Use the reference to the variable as the result of the expression
  5719. // Now we can mark the variable as temporary
  5720. ctx->type.SetVariable(toRef, stackOffset, true);
  5721. ctx->bc.InstrSHORT(asBC_PSF, (short)stackOffset);
  5722. }
  5723. else
  5724. {
  5725. // All casts are legal
  5726. ctx->type.Set(to);
  5727. }
  5728. }
  5729. }
  5730. }
  5731. return cost;
  5732. }
  5733. asUINT asCCompiler::ImplicitConvObjectToObject(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode, bool allowObjectConstruct)
  5734. {
  5735. // First try a ref cast
  5736. asUINT cost = ImplicitConvObjectRef(ctx, to, node, convType, generateCode);
  5737. // If the desired type is an asOBJ_ASHANDLE then we'll assume it is allowed to implicitly
  5738. // construct the object through any of the available constructors
  5739. if( to.GetTypeInfo() && (to.GetTypeInfo()->flags & asOBJ_ASHANDLE) && to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() && allowObjectConstruct )
  5740. {
  5741. asCArray<int> funcs;
  5742. funcs = CastToObjectType(to.GetTypeInfo())->beh.constructors;
  5743. asCArray<asCExprContext *> args;
  5744. args.PushLast(ctx);
  5745. cost = asCC_TO_OBJECT_CONV + MatchFunctions(funcs, args, node, 0, 0, 0, false, true, false);
  5746. // Did we find a matching constructor?
  5747. if( funcs.GetLength() == 1 )
  5748. {
  5749. if( generateCode )
  5750. {
  5751. // If the ASHANDLE receives a variable type parameter, then we need to
  5752. // make sure the expression is treated as a handle and not as a value
  5753. asCScriptFunction *func = engine->scriptFunctions[funcs[0]];
  5754. if( func->parameterTypes[0].GetTokenType() == ttQuestion )
  5755. {
  5756. if( !ctx->type.isExplicitHandle )
  5757. {
  5758. asCDataType toHandle = ctx->type.dataType;
  5759. toHandle.MakeHandle(true);
  5760. toHandle.MakeReference(true);
  5761. toHandle.MakeHandleToConst(ctx->type.dataType.IsReadOnly());
  5762. ImplicitConversion(ctx, toHandle, node, asIC_IMPLICIT_CONV, true, false);
  5763. asASSERT( ctx->type.dataType.IsObjectHandle() );
  5764. }
  5765. ctx->type.isExplicitHandle = true;
  5766. }
  5767. // TODO: This should really reuse the code from CompileConstructCall
  5768. // Allocate the new object
  5769. asCExprValue tempObj;
  5770. tempObj.dataType = to;
  5771. tempObj.dataType.MakeReference(false);
  5772. tempObj.stackOffset = (short)AllocateVariable(tempObj.dataType, true);
  5773. tempObj.dataType.MakeReference(true);
  5774. tempObj.isTemporary = true;
  5775. tempObj.isVariable = true;
  5776. bool onHeap = IsVariableOnHeap(tempObj.stackOffset);
  5777. // Push the address of the object on the stack
  5778. asCExprContext e(engine);
  5779. if( onHeap )
  5780. e.bc.InstrSHORT(asBC_VAR, tempObj.stackOffset);
  5781. PrepareFunctionCall(funcs[0], &e.bc, args);
  5782. MoveArgsToStack(funcs[0], &e.bc, args, false);
  5783. // If the object is allocated on the stack, then call the constructor as a normal function
  5784. if( onHeap )
  5785. {
  5786. int offset = 0;
  5787. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]);
  5788. offset = descr->parameterTypes[0].GetSizeOnStackDWords();
  5789. e.bc.InstrWORD(asBC_GETREF, (asWORD)offset);
  5790. }
  5791. else
  5792. e.bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  5793. PerformFunctionCall(funcs[0], &e, onHeap, &args, CastToObjectType(tempObj.dataType.GetTypeInfo()));
  5794. // Add tag that the object has been initialized
  5795. e.bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT);
  5796. // The constructor doesn't return anything,
  5797. // so we have to manually inform the type of
  5798. // the return value
  5799. e.type = tempObj;
  5800. if( !onHeap )
  5801. e.type.dataType.MakeReference(false);
  5802. // Push the address of the object on the stack again
  5803. e.bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  5804. MergeExprBytecodeAndType(ctx, &e);
  5805. }
  5806. else
  5807. {
  5808. ctx->type.Set(asCDataType::CreateType(to.GetTypeInfo(), false));
  5809. }
  5810. }
  5811. }
  5812. // If the base type is still different, and we are allowed to instance
  5813. // another object then we can try an implicit value cast
  5814. if( to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() && allowObjectConstruct )
  5815. {
  5816. // Attempt implicit value cast
  5817. cost = ImplicitConvObjectValue(ctx, to, node, convType, generateCode);
  5818. }
  5819. // If we still haven't converted the base type to the correct type, then there is
  5820. // no need to continue as it is not possible to do the conversion
  5821. if( to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() )
  5822. return asCC_NO_CONV;
  5823. if( to.IsObjectHandle() )
  5824. {
  5825. // There is no extra cost in converting to a handle
  5826. // reference to handle -> handle
  5827. // reference -> handle
  5828. // object -> handle
  5829. // handle -> reference to handle
  5830. // reference -> reference to handle
  5831. // object -> reference to handle
  5832. // TODO: If the type is handle, then we can't use IsReadOnly to determine the constness of the basetype
  5833. // If the rvalue is a handle to a const object, then
  5834. // the lvalue must also be a handle to a const object
  5835. if( ctx->type.dataType.IsReadOnly() && !to.IsReadOnly() )
  5836. {
  5837. if( convType != asIC_IMPLICIT_CONV )
  5838. {
  5839. asASSERT(node);
  5840. asCString str;
  5841. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  5842. Error(str, node);
  5843. }
  5844. }
  5845. if( !ctx->type.dataType.IsObjectHandle() )
  5846. {
  5847. // An object type can be directly converted to a handle of the
  5848. // same type by doing a ref copy to a new variable
  5849. if( ctx->type.dataType.SupportHandles() )
  5850. {
  5851. asCDataType dt = ctx->type.dataType;
  5852. dt.MakeHandle(true);
  5853. dt.MakeReference(false);
  5854. if( generateCode )
  5855. {
  5856. // If the expression is already a local variable, then it is not
  5857. // necessary to do a ref copy, as the ref objects on the stack are
  5858. // really handles, only the handles cannot be modified.
  5859. if( ctx->type.isVariable )
  5860. {
  5861. bool isHandleToConst = ctx->type.dataType.IsReadOnly();
  5862. ctx->type.dataType.MakeReadOnly(false);
  5863. ctx->type.dataType.MakeHandle(true);
  5864. ctx->type.dataType.MakeReadOnly(true);
  5865. ctx->type.dataType.MakeHandleToConst(isHandleToConst);
  5866. if( to.IsReference() && !ctx->type.dataType.IsReference() )
  5867. {
  5868. ctx->bc.Instr(asBC_PopPtr);
  5869. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  5870. ctx->type.dataType.MakeReference(true);
  5871. }
  5872. else if( ctx->type.dataType.IsReference() )
  5873. {
  5874. ctx->bc.Instr(asBC_RDSPtr);
  5875. ctx->type.dataType.MakeReference(false);
  5876. }
  5877. }
  5878. else
  5879. {
  5880. int offset = AllocateVariable(dt, true);
  5881. if( ctx->type.dataType.IsReference() )
  5882. ctx->bc.Instr(asBC_RDSPtr);
  5883. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  5884. if (dt.IsFuncdef())
  5885. ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  5886. else
  5887. ctx->bc.InstrPTR(asBC_REFCPY, dt.GetTypeInfo());
  5888. ctx->bc.Instr(asBC_PopPtr);
  5889. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  5890. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5891. if( to.IsReference() )
  5892. dt.MakeReference(true);
  5893. else
  5894. ctx->bc.Instr(asBC_RDSPtr);
  5895. ctx->type.SetVariable(dt, offset, true);
  5896. }
  5897. }
  5898. else
  5899. ctx->type.dataType = dt;
  5900. // When this conversion is done the expression is no longer an lvalue
  5901. ctx->type.isLValue = false;
  5902. }
  5903. }
  5904. if( ctx->type.dataType.IsObjectHandle() )
  5905. {
  5906. // A handle to non-const can be converted to a
  5907. // handle to const, but not the other way
  5908. if( to.IsHandleToConst() )
  5909. ctx->type.dataType.MakeHandleToConst(true);
  5910. // A const handle can be converted to a non-const
  5911. // handle and vice versa as the handle is just a value
  5912. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  5913. }
  5914. if( to.IsReference() && !ctx->type.dataType.IsReference() )
  5915. {
  5916. if( generateCode )
  5917. {
  5918. asASSERT( ctx->type.dataType.IsObjectHandle() );
  5919. // If the input type is a handle, then a simple ref copy is enough
  5920. bool isExplicitHandle = ctx->type.isExplicitHandle;
  5921. ctx->type.isExplicitHandle = ctx->type.dataType.IsObjectHandle();
  5922. // If the input type is read-only we'll need to temporarily
  5923. // remove this constness, otherwise the assignment will fail
  5924. bool typeIsReadOnly = ctx->type.dataType.IsReadOnly();
  5925. ctx->type.dataType.MakeReadOnly(false);
  5926. // If the object already is a temporary variable, then the copy
  5927. // doesn't have to be made as it is already a unique object
  5928. PrepareTemporaryVariable(node, ctx);
  5929. ctx->type.dataType.MakeReadOnly(typeIsReadOnly);
  5930. ctx->type.isExplicitHandle = isExplicitHandle;
  5931. }
  5932. // A non-reference can be converted to a reference,
  5933. // by putting the value in a temporary variable
  5934. ctx->type.dataType.MakeReference(true);
  5935. // Since it is a new temporary variable it doesn't have to be const
  5936. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  5937. }
  5938. else if( !to.IsReference() && ctx->type.dataType.IsReference() )
  5939. {
  5940. Dereference(ctx, generateCode);
  5941. }
  5942. }
  5943. else // if( !to.IsObjectHandle() )
  5944. {
  5945. if( !to.IsReference() )
  5946. {
  5947. // reference to handle -> object
  5948. // handle -> object
  5949. // reference -> object
  5950. // An implicit handle can be converted to an object by adding a check for null pointer
  5951. if( ctx->type.dataType.IsObjectHandle() && !ctx->type.isExplicitHandle )
  5952. {
  5953. if( generateCode )
  5954. {
  5955. if( ctx->type.dataType.IsReference() )
  5956. {
  5957. // The pointer on the stack refers to the handle
  5958. ctx->bc.Instr(asBC_ChkRefS);
  5959. }
  5960. else
  5961. {
  5962. // The pointer on the stack refers to the object
  5963. ctx->bc.Instr(asBC_CHKREF);
  5964. }
  5965. }
  5966. ctx->type.dataType.MakeHandle(false);
  5967. }
  5968. // A const object can be converted to a non-const object through a copy
  5969. if( ctx->type.dataType.IsReadOnly() && !to.IsReadOnly() &&
  5970. allowObjectConstruct )
  5971. {
  5972. // Does the object type allow a copy to be made?
  5973. if( ctx->type.dataType.CanBeCopied() )
  5974. {
  5975. if( generateCode )
  5976. {
  5977. // Make a temporary object with the copy
  5978. PrepareTemporaryVariable(node, ctx);
  5979. }
  5980. // In case the object was already in a temporary variable, then the function
  5981. // didn't really do anything so we need to remove the constness here
  5982. ctx->type.dataType.MakeReadOnly(false);
  5983. // Add the cost for the copy
  5984. cost += asCC_TO_OBJECT_CONV;
  5985. }
  5986. }
  5987. if( ctx->type.dataType.IsReference() )
  5988. {
  5989. // This may look strange, but a value type allocated on the stack is already
  5990. // correct, so nothing should be done other than remove the mark as reference.
  5991. // For types allocated on the heap, it is necessary to dereference the pointer
  5992. // that is currently on the stack
  5993. if( IsVariableOnHeap(ctx->type.stackOffset) )
  5994. Dereference(ctx, generateCode);
  5995. else
  5996. ctx->type.dataType.MakeReference(false);
  5997. }
  5998. // A non-const object can be converted to a const object directly
  5999. if( !ctx->type.dataType.IsReadOnly() && to.IsReadOnly() )
  6000. {
  6001. ctx->type.dataType.MakeReadOnly(true);
  6002. }
  6003. }
  6004. else // if( to.IsReference() )
  6005. {
  6006. // reference to handle -> reference
  6007. // handle -> reference
  6008. // object -> reference
  6009. if( ctx->type.dataType.IsReference() )
  6010. {
  6011. if( ctx->type.isExplicitHandle && ctx->type.dataType.GetTypeInfo() && (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) )
  6012. {
  6013. // ASHANDLE objects are really value types, so explicit handle can be removed
  6014. ctx->type.isExplicitHandle = false;
  6015. ctx->type.dataType.MakeHandle(false);
  6016. }
  6017. // A reference to a handle can be converted to a reference to an object
  6018. // by first reading the address, then verifying that it is not null
  6019. if( !to.IsObjectHandle() && ctx->type.dataType.IsObjectHandle() && !ctx->type.isExplicitHandle )
  6020. {
  6021. ctx->type.dataType.MakeHandle(false);
  6022. if( generateCode )
  6023. ctx->bc.Instr(asBC_ChkRefS);
  6024. }
  6025. // A reference to a non-const can be converted to a reference to a const
  6026. if( to.IsReadOnly() )
  6027. ctx->type.dataType.MakeReadOnly(true);
  6028. else if( ctx->type.dataType.IsReadOnly() && allowObjectConstruct )
  6029. {
  6030. // A reference to a const can be converted to a reference to a
  6031. // non-const by copying the object to a temporary variable
  6032. ctx->type.dataType.MakeReadOnly(false);
  6033. if( generateCode )
  6034. {
  6035. // If the object already is a temporary variable, then the copy
  6036. // doesn't have to be made as it is already a unique object
  6037. PrepareTemporaryVariable(node, ctx);
  6038. }
  6039. // Add the cost for the copy
  6040. cost += asCC_TO_OBJECT_CONV;
  6041. }
  6042. }
  6043. else // if( !ctx->type.dataType.IsReference() )
  6044. {
  6045. // A non-reference handle can be converted to a non-handle reference by checking against null handle
  6046. if( ctx->type.dataType.IsObjectHandle() )
  6047. {
  6048. bool readOnly = false;
  6049. if( ctx->type.dataType.IsHandleToConst() )
  6050. readOnly = true;
  6051. if( generateCode )
  6052. {
  6053. if( ctx->type.isVariable )
  6054. ctx->bc.InstrSHORT(asBC_ChkNullV, ctx->type.stackOffset);
  6055. else
  6056. ctx->bc.Instr(asBC_CHKREF);
  6057. }
  6058. ctx->type.dataType.MakeHandle(false);
  6059. ctx->type.dataType.MakeReference(true);
  6060. // Make sure a handle to const isn't converted to non-const reference
  6061. if( readOnly )
  6062. ctx->type.dataType.MakeReadOnly(true);
  6063. }
  6064. else
  6065. {
  6066. // A value type allocated on the stack is differentiated
  6067. // by it not being a reference. But it can be handled as
  6068. // reference by pushing the pointer on the stack
  6069. if( (ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) &&
  6070. (ctx->type.isVariable || ctx->type.isTemporary) &&
  6071. !IsVariableOnHeap(ctx->type.stackOffset) )
  6072. {
  6073. // Actually the pointer is already pushed on the stack in
  6074. // CompileVariableAccess, so we don't need to do anything else
  6075. }
  6076. else if( generateCode )
  6077. {
  6078. // A non-reference can be converted to a reference,
  6079. // by putting the value in a temporary variable
  6080. // If the input type is read-only we'll need to temporarily
  6081. // remove this constness, otherwise the assignment will fail
  6082. bool typeIsReadOnly = ctx->type.dataType.IsReadOnly();
  6083. ctx->type.dataType.MakeReadOnly(false);
  6084. // If the object already is a temporary variable, then the copy
  6085. // doesn't have to be made as it is already a unique object
  6086. PrepareTemporaryVariable(node, ctx);
  6087. ctx->type.dataType.MakeReadOnly(typeIsReadOnly);
  6088. // Add the cost for the copy
  6089. cost += asCC_TO_OBJECT_CONV;
  6090. }
  6091. // This may look strange as the conversion was to make the expression a reference
  6092. // but a value type allocated on the stack is a reference even without the type
  6093. // being marked as such.
  6094. ctx->type.dataType.MakeReference(IsVariableOnHeap(ctx->type.stackOffset));
  6095. }
  6096. // TODO: If the variable is an object allocated on the stack the following is not true as the copy may not have been made
  6097. // Since it is a new temporary variable it doesn't have to be const
  6098. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  6099. }
  6100. }
  6101. }
  6102. return cost;
  6103. }
  6104. asUINT asCCompiler::ImplicitConvPrimitiveToObject(asCExprContext *ctx, const asCDataType &to, asCScriptNode * /*node*/, EImplicitConv /*isExplicit*/, bool generateCode, bool /*allowObjectConstruct*/)
  6105. {
  6106. // Reference types currently don't allow implicit conversion from primitive to object
  6107. // TODO: Allow implicit conversion to scoped reference types as they are supposed to appear like ordinary value types
  6108. asCObjectType *objType = CastToObjectType(to.GetTypeInfo());
  6109. asASSERT( objType || CastToFuncdefType(to.GetTypeInfo()) );
  6110. if( !objType || (objType->flags & asOBJ_REF) )
  6111. return asCC_NO_CONV;
  6112. // For value types the object must have a constructor that takes a single primitive argument either by value or as input reference
  6113. asCArray<int> funcs;
  6114. for( asUINT n = 0; n < objType->beh.constructors.GetLength(); n++ )
  6115. {
  6116. asCScriptFunction *func = engine->scriptFunctions[objType->beh.constructors[n]];
  6117. if( func->parameterTypes.GetLength() == 1 &&
  6118. func->parameterTypes[0].IsPrimitive() &&
  6119. !(func->inOutFlags[0] & asTM_OUTREF) )
  6120. {
  6121. funcs.PushLast(func->id);
  6122. }
  6123. }
  6124. if( funcs.GetLength() == 0 )
  6125. return asCC_NO_CONV;
  6126. // Check if it is possible to choose a best match
  6127. asCExprContext arg(engine);
  6128. arg.type = ctx->type;
  6129. arg.exprNode = ctx->exprNode; // Use the same node for compiler messages
  6130. asCArray<asCExprContext*> args;
  6131. args.PushLast(&arg);
  6132. asUINT cost = asCC_TO_OBJECT_CONV + MatchFunctions(funcs, args, 0, 0, 0, objType, false, true, false);
  6133. if( funcs.GetLength() != 1 )
  6134. return asCC_NO_CONV;
  6135. if( !generateCode )
  6136. {
  6137. ctx->type.Set(to);
  6138. return cost;
  6139. }
  6140. // TODO: clean up: This part is similar to CompileConstructCall(). It should be put in a common function
  6141. // Clear the type of ctx, as the type is moved to the arg
  6142. ctx->type.SetDummy();
  6143. // Value types and script types are allocated through the constructor
  6144. asCExprValue tempObj;
  6145. tempObj.dataType = to;
  6146. tempObj.stackOffset = (short)AllocateVariable(to, true);
  6147. tempObj.dataType.MakeReference(true);
  6148. tempObj.isTemporary = true;
  6149. tempObj.isVariable = true;
  6150. bool onHeap = IsVariableOnHeap(tempObj.stackOffset);
  6151. // Push the address of the object on the stack
  6152. if( onHeap )
  6153. ctx->bc.InstrSHORT(asBC_VAR, tempObj.stackOffset);
  6154. PrepareFunctionCall(funcs[0], &ctx->bc, args);
  6155. MoveArgsToStack(funcs[0], &ctx->bc, args, false);
  6156. if( !(objType->flags & asOBJ_REF) )
  6157. {
  6158. // If the object is allocated on the stack, then call the constructor as a normal function
  6159. if( onHeap )
  6160. {
  6161. int offset = 0;
  6162. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]);
  6163. for( asUINT n = 0; n < args.GetLength(); n++ )
  6164. offset += descr->parameterTypes[n].GetSizeOnStackDWords();
  6165. ctx->bc.InstrWORD(asBC_GETREF, (asWORD)offset);
  6166. }
  6167. else
  6168. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  6169. PerformFunctionCall(funcs[0], ctx, onHeap, &args, CastToObjectType(tempObj.dataType.GetTypeInfo()));
  6170. // Add tag that the object has been initialized
  6171. ctx->bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT);
  6172. // The constructor doesn't return anything,
  6173. // so we have to manually inform the type of
  6174. // the return value
  6175. ctx->type = tempObj;
  6176. if( !onHeap )
  6177. ctx->type.dataType.MakeReference(false);
  6178. // Push the address of the object on the stack again
  6179. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  6180. }
  6181. else
  6182. {
  6183. asASSERT( objType->flags & asOBJ_SCOPED );
  6184. // Call the factory to create the reference type
  6185. PerformFunctionCall(funcs[0], ctx, false, &args);
  6186. }
  6187. return cost;
  6188. }
  6189. void asCCompiler::ImplicitConversionConstant(asCExprContext *from, const asCDataType &to, asCScriptNode *node, EImplicitConv convType)
  6190. {
  6191. asASSERT(from->type.isConstant);
  6192. // TODO: node should be the node of the value that is
  6193. // converted (not the operator that provokes the implicit
  6194. // conversion)
  6195. // If the base type is correct there is no more to do
  6196. if( to.IsEqualExceptRefAndConst(from->type.dataType) ) return;
  6197. // References cannot be constants
  6198. if( from->type.dataType.IsReference() ) return;
  6199. if( (to.IsIntegerType() && to.GetSizeInMemoryDWords() == 1 && !to.IsEnumType()) ||
  6200. (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST) )
  6201. {
  6202. if( from->type.dataType.IsFloatType() ||
  6203. from->type.dataType.IsDoubleType() ||
  6204. from->type.dataType.IsUnsignedType() ||
  6205. from->type.dataType.IsIntegerType() )
  6206. {
  6207. asCDataType targetDt;
  6208. if (to.IsEnumType())
  6209. targetDt = to;
  6210. else
  6211. targetDt = asCDataType::CreatePrimitive(ttInt, true);
  6212. // Transform the value
  6213. // Float constants can be implicitly converted to int
  6214. if( from->type.dataType.IsFloatType() )
  6215. {
  6216. float fc = from->type.GetConstantF();
  6217. int ic = int(fc);
  6218. if( float(ic) != fc )
  6219. {
  6220. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6221. }
  6222. from->type.SetConstantDW(targetDt, ic);
  6223. }
  6224. // Double constants can be implicitly converted to int
  6225. else if( from->type.dataType.IsDoubleType() )
  6226. {
  6227. double fc = from->type.GetConstantD();
  6228. int ic = int(fc);
  6229. if( double(ic) != fc )
  6230. {
  6231. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6232. }
  6233. from->type.SetConstantDW(targetDt, ic);
  6234. }
  6235. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  6236. {
  6237. // Verify that it is possible to convert to signed without getting negative
  6238. if( from->type.dataType.GetSizeInMemoryBytes() == 4 &&
  6239. int(from->type.GetConstantDW()) < 0 &&
  6240. convType != asIC_EXPLICIT_VAL_CAST &&
  6241. node != 0 )
  6242. Warning(TXT_CHANGE_SIGN, node);
  6243. // Convert to 32bit
  6244. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6245. from->type.SetConstantDW(targetDt, from->type.GetConstantB());
  6246. else if (from->type.dataType.GetSizeInMemoryBytes() == 2)
  6247. from->type.SetConstantDW(targetDt, from->type.GetConstantW());
  6248. else
  6249. from->type.dataType = targetDt;
  6250. }
  6251. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  6252. {
  6253. if (asQWORD(from->type.GetConstantQW()) >> 31)
  6254. if (convType != asIC_EXPLICIT_VAL_CAST && node) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6255. // Convert to 32bit
  6256. from->type.SetConstantDW(targetDt, int(from->type.GetConstantQW()));
  6257. }
  6258. else if (from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2)
  6259. {
  6260. if (int(from->type.GetConstantQW()) != asINT64(from->type.GetConstantQW()))
  6261. if (convType != asIC_EXPLICIT_VAL_CAST && node) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6262. // Convert to 32bit
  6263. from->type.SetConstantDW(targetDt, int(from->type.GetConstantQW()));
  6264. }
  6265. else if (from->type.dataType.IsIntegerType() &&
  6266. from->type.dataType.GetSizeInMemoryBytes() < 4)
  6267. {
  6268. // Convert to 32bit
  6269. if (from->type.dataType.GetSizeInMemoryBytes() == 1)
  6270. from->type.SetConstantDW(targetDt, (signed char)from->type.GetConstantB());
  6271. else if (from->type.dataType.GetSizeInMemoryBytes() == 2)
  6272. from->type.SetConstantDW(targetDt, (short)from->type.GetConstantW());
  6273. }
  6274. else
  6275. {
  6276. // Only int32 and enums should come here and as these are 32bit
  6277. // already nothing needs to be done except set the target type
  6278. asASSERT((from->type.dataType.GetTokenType() == ttInt ||
  6279. from->type.dataType.IsEnumType()) &&
  6280. from->type.dataType.GetSizeInMemoryBytes() == 4);
  6281. from->type.dataType = targetDt;
  6282. }
  6283. }
  6284. // Check if a downsize is necessary
  6285. if( to.IsIntegerType() &&
  6286. from->type.dataType.IsIntegerType() &&
  6287. from->type.dataType.GetSizeInMemoryBytes() > to.GetSizeInMemoryBytes() )
  6288. {
  6289. // Verify if it is possible
  6290. if( to.GetSizeInMemoryBytes() == 1 )
  6291. {
  6292. if( char(from->type.GetConstantDW()) != int(from->type.GetConstantDW()) )
  6293. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6294. from->type.SetConstantB(asCDataType::CreatePrimitive(to.GetTokenType(), true), char(from->type.GetConstantDW()));
  6295. }
  6296. else if( to.GetSizeInMemoryBytes() == 2 )
  6297. {
  6298. if( short(from->type.GetConstantDW()) != int(from->type.GetConstantDW()) )
  6299. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6300. from->type.SetConstantW(asCDataType::CreatePrimitive(to.GetTokenType(), true), short(from->type.GetConstantDW()));
  6301. }
  6302. }
  6303. }
  6304. else if( to.IsIntegerType() && to.GetSizeInMemoryDWords() == 2 )
  6305. {
  6306. // Float constants can be implicitly converted to int
  6307. if( from->type.dataType.IsFloatType() )
  6308. {
  6309. float fc = from->type.GetConstantF();
  6310. asINT64 ic = asINT64(fc);
  6311. if( float(ic) != fc )
  6312. {
  6313. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6314. }
  6315. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), ic);
  6316. }
  6317. // Double constants can be implicitly converted to int
  6318. else if( from->type.dataType.IsDoubleType() )
  6319. {
  6320. double fc = from->type.GetConstantD();
  6321. asINT64 ic = asINT64(fc);
  6322. if( double(ic) != fc )
  6323. {
  6324. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6325. }
  6326. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), ic);
  6327. }
  6328. else if( from->type.dataType.IsUnsignedType() )
  6329. {
  6330. // Convert to 64bit
  6331. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6332. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), from->type.GetConstantB());
  6333. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6334. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), from->type.GetConstantW());
  6335. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  6336. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), from->type.GetConstantDW());
  6337. else if( from->type.dataType.GetSizeInMemoryBytes() == 8 )
  6338. {
  6339. if( asINT64(from->type.GetConstantQW()) < 0 )
  6340. {
  6341. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  6342. }
  6343. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  6344. }
  6345. }
  6346. else if( from->type.dataType.IsIntegerType() )
  6347. {
  6348. // Convert to 64bit
  6349. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6350. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), (signed char)from->type.GetConstantB());
  6351. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6352. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), (short)from->type.GetConstantW());
  6353. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  6354. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), (int)from->type.GetConstantDW());
  6355. }
  6356. }
  6357. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 1 )
  6358. {
  6359. if( from->type.dataType.IsFloatType() )
  6360. {
  6361. float fc = from->type.GetConstantF();
  6362. // Some compilers set the value to 0 when converting a negative float to unsigned int.
  6363. // To maintain a consistent behaviour across compilers we convert to int first.
  6364. asUINT uic = asUINT(int(fc));
  6365. if( float(uic) != fc )
  6366. {
  6367. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6368. }
  6369. from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), uic);
  6370. // Try once more, in case of a smaller type
  6371. ImplicitConversionConstant(from, to, node, convType);
  6372. }
  6373. else if( from->type.dataType.IsDoubleType() )
  6374. {
  6375. double fc = from->type.GetConstantD();
  6376. // Some compilers set the value to 0 when converting a negative double to unsigned int.
  6377. // To maintain a consistent behaviour across compilers we convert to int first.
  6378. asUINT uic = asUINT(int(fc));
  6379. if( double(uic) != fc )
  6380. {
  6381. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6382. }
  6383. from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), uic);
  6384. // Try once more, in case of a smaller type
  6385. ImplicitConversionConstant(from, to, node, convType);
  6386. }
  6387. else if( from->type.dataType.IsIntegerType() )
  6388. {
  6389. // Verify that it is possible to convert to unsigned without loosing negative
  6390. if( (from->type.dataType.GetSizeInMemoryBytes() > 4 && asINT64(from->type.GetConstantQW()) < 0) ||
  6391. (from->type.dataType.GetSizeInMemoryBytes() == 4 && int(from->type.GetConstantDW()) < 0) ||
  6392. (from->type.dataType.GetSizeInMemoryBytes() == 2 && short(from->type.GetConstantW()) < 0) ||
  6393. (from->type.dataType.GetSizeInMemoryBytes() == 1 && char(from->type.GetConstantB()) < 0))
  6394. {
  6395. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  6396. }
  6397. // Check if any data is lost
  6398. if( from->type.dataType.GetSizeInMemoryBytes() > 4 && (from->type.GetConstantQW() >> 32) != 0 && (from->type.GetConstantQW() >> 32) != 0xFFFFFFFF )
  6399. {
  6400. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6401. }
  6402. // Convert to 32bit
  6403. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6404. from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), (signed char)from->type.GetConstantB());
  6405. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6406. from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), (short)from->type.GetConstantW());
  6407. else if (from->type.dataType.GetSizeInMemoryBytes() == 4 )
  6408. from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), (int)from->type.GetConstantDW());
  6409. else
  6410. from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), (int)(asINT64)from->type.GetConstantQW());
  6411. // Try once more, in case of a smaller type
  6412. ImplicitConversionConstant(from, to, node, convType);
  6413. }
  6414. else if( from->type.dataType.IsUnsignedType() &&
  6415. from->type.dataType.GetSizeInMemoryBytes() < 4 )
  6416. {
  6417. // Convert to 32bit
  6418. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6419. from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), from->type.GetConstantB());
  6420. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6421. from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), from->type.GetConstantW());
  6422. // Try once more, in case of a smaller type
  6423. ImplicitConversionConstant(from, to, node, convType);
  6424. }
  6425. else if( from->type.dataType.IsUnsignedType() &&
  6426. from->type.dataType.GetSizeInMemoryBytes() > to.GetSizeInMemoryBytes() )
  6427. {
  6428. // Verify if it is possible
  6429. if( to.GetSizeInMemoryBytes() == 1 )
  6430. {
  6431. if( asBYTE(from->type.GetConstantDW()) != from->type.GetConstantDW() )
  6432. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6433. from->type.SetConstantB(asCDataType::CreatePrimitive(to.GetTokenType(), true), asBYTE(from->type.GetConstantDW()));
  6434. }
  6435. else if( to.GetSizeInMemoryBytes() == 2 )
  6436. {
  6437. if( asWORD(from->type.GetConstantDW()) != from->type.GetConstantDW())
  6438. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6439. from->type.SetConstantW(asCDataType::CreatePrimitive(to.GetTokenType(), true), asWORD(from->type.GetConstantDW()));
  6440. }
  6441. else if (to.GetSizeInMemoryBytes() == 4)
  6442. {
  6443. if( asDWORD(from->type.GetConstantQW()) != from->type.GetConstantQW())
  6444. if (convType != asIC_EXPLICIT_VAL_CAST && node) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6445. from->type.SetConstantDW(asCDataType::CreatePrimitive(to.GetTokenType(), true), asDWORD(from->type.GetConstantQW()));
  6446. }
  6447. }
  6448. }
  6449. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 2 )
  6450. {
  6451. if( from->type.dataType.IsFloatType() )
  6452. {
  6453. float fc = from->type.GetConstantF();
  6454. // Convert first to int64 then to uint64 to avoid negative float becoming 0 on gnuc base compilers
  6455. asQWORD uic = asQWORD(asINT64(fc));
  6456. #if !defined(_MSC_VER) || _MSC_VER > 1200 // MSVC++ 6
  6457. // MSVC6 doesn't support this conversion
  6458. if( float(uic) != fc )
  6459. {
  6460. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6461. }
  6462. #endif
  6463. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), uic);
  6464. }
  6465. else if( from->type.dataType.IsDoubleType() )
  6466. {
  6467. double fc = from->type.GetConstantD();
  6468. // Convert first to int64 then to uint64 to avoid negative float becoming 0 on gnuc base compilers
  6469. asQWORD uic = asQWORD(asINT64(fc));
  6470. #if !defined(_MSC_VER) || _MSC_VER > 1200 // MSVC++ 6
  6471. // MSVC6 doesn't support this conversion
  6472. if( double(uic) != fc )
  6473. {
  6474. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6475. }
  6476. #endif
  6477. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), uic);
  6478. }
  6479. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  6480. {
  6481. // Convert to 64bit
  6482. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6483. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), (asINT64)(signed char)from->type.GetConstantB());
  6484. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6485. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), (asINT64)(short)from->type.GetConstantW());
  6486. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  6487. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), (asINT64)(int)from->type.GetConstantDW());
  6488. // Verify that it is possible to convert to unsigned without loosing negative
  6489. if( asINT64(from->type.GetConstantQW()) < 0 )
  6490. {
  6491. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  6492. }
  6493. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  6494. }
  6495. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  6496. {
  6497. // Verify that it is possible to convert to unsigned without loosing negative
  6498. if( asINT64(from->type.GetConstantQW()) < 0 )
  6499. {
  6500. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  6501. }
  6502. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  6503. }
  6504. else if( from->type.dataType.IsUnsignedType() )
  6505. {
  6506. // Convert to 64bit
  6507. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6508. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), from->type.GetConstantB());
  6509. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6510. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), from->type.GetConstantW());
  6511. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  6512. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), from->type.GetConstantDW());
  6513. }
  6514. }
  6515. else if( to.IsFloatType() )
  6516. {
  6517. if( from->type.dataType.IsDoubleType() )
  6518. {
  6519. double ic = from->type.GetConstantD();
  6520. float fc = float(ic);
  6521. from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  6522. }
  6523. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  6524. {
  6525. // Must properly convert value in case the from value is smaller
  6526. int ic;
  6527. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6528. ic = (signed char)from->type.GetConstantB();
  6529. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6530. ic = (short)from->type.GetConstantW();
  6531. else
  6532. ic = (int)from->type.GetConstantDW();
  6533. float fc = float(ic);
  6534. if( int(fc) != ic )
  6535. {
  6536. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6537. }
  6538. from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  6539. }
  6540. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  6541. {
  6542. float fc = float(asINT64(from->type.GetConstantQW()));
  6543. if( asINT64(fc) != asINT64(from->type.GetConstantQW()) )
  6544. {
  6545. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6546. }
  6547. from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  6548. }
  6549. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  6550. {
  6551. // Must properly convert value in case the from value is smaller
  6552. unsigned int uic;
  6553. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6554. uic = from->type.GetConstantB();
  6555. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6556. uic = from->type.GetConstantW();
  6557. else
  6558. uic = from->type.GetConstantDW();
  6559. float fc = float(uic);
  6560. if( (unsigned int)(fc) != uic )
  6561. {
  6562. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6563. }
  6564. from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  6565. }
  6566. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  6567. {
  6568. float fc = float((asINT64)from->type.GetConstantQW());
  6569. if( asQWORD(fc) != from->type.GetConstantQW())
  6570. {
  6571. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6572. }
  6573. from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  6574. }
  6575. }
  6576. else if( to.IsDoubleType() )
  6577. {
  6578. if( from->type.dataType.IsFloatType() )
  6579. {
  6580. float ic = from->type.GetConstantF();
  6581. double fc = double(ic);
  6582. from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  6583. }
  6584. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  6585. {
  6586. // Must properly convert value in case the from value is smaller
  6587. int ic;
  6588. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6589. ic = (signed char)from->type.GetConstantB();
  6590. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6591. ic = (short)from->type.GetConstantW();
  6592. else
  6593. ic = (int)from->type.GetConstantDW();
  6594. double fc = double(ic);
  6595. if( int(fc) != ic )
  6596. {
  6597. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6598. }
  6599. from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  6600. }
  6601. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  6602. {
  6603. double fc = double(asINT64(from->type.GetConstantQW()));
  6604. if( asINT64(fc) != asINT64(from->type.GetConstantQW()) )
  6605. {
  6606. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6607. }
  6608. from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  6609. }
  6610. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  6611. {
  6612. // Must properly convert value in case the from value is smaller
  6613. unsigned int uic;
  6614. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6615. uic = from->type.GetConstantB();
  6616. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6617. uic = from->type.GetConstantW();
  6618. else
  6619. uic = from->type.GetConstantDW();
  6620. double fc = double(uic);
  6621. if( (unsigned int)(fc) != uic )
  6622. {
  6623. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6624. }
  6625. from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  6626. }
  6627. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  6628. {
  6629. double fc = double((asINT64)from->type.GetConstantQW());
  6630. if( asQWORD(fc) != from->type.GetConstantQW())
  6631. {
  6632. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6633. }
  6634. from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  6635. }
  6636. }
  6637. }
  6638. int asCCompiler::DoAssignment(asCExprContext *ctx, asCExprContext *lctx, asCExprContext *rctx, asCScriptNode *lexpr, asCScriptNode *rexpr, eTokenType op, asCScriptNode *opNode)
  6639. {
  6640. // Don't allow any operators on expressions that take address of class method
  6641. // If methodName is set but the type is not an object, then it is a global function
  6642. if( lctx->methodName != "" || rctx->IsClassMethod() )
  6643. {
  6644. Error(TXT_INVALID_OP_ON_METHOD, opNode);
  6645. return -1;
  6646. }
  6647. // Implicit handle types should always be treated as handles in assignments
  6648. if (lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE) )
  6649. {
  6650. lctx->type.dataType.MakeHandle(true);
  6651. lctx->type.isExplicitHandle = true;
  6652. }
  6653. // Urho3D: if there is a handle type, and it does not have an overloaded assignment operator, convert to an explicit handle
  6654. // for scripting convenience. (For the Urho3D handle types, value assignment is not supported)
  6655. if (lctx->type.dataType.IsObjectHandle() && !lctx->type.dataType.IsTemplate() && !lctx->type.isExplicitHandle &&
  6656. (!lctx->type.dataType.GetBehaviour() || !lctx->type.dataType.GetBehaviour()->copy))
  6657. lctx->type.isExplicitHandle = true;
  6658. // If the left hand expression is a property accessor, then that should be used
  6659. // to do the assignment instead of the ordinary operator. The exception is when
  6660. // the property accessor is for a handle property, and the operation is a value
  6661. // assignment.
  6662. if( (lctx->property_get || lctx->property_set) &&
  6663. !(lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle) )
  6664. {
  6665. if( op != ttAssignment )
  6666. {
  6667. // Generate the code for the compound assignment, i.e. get the value, apply operator, then set the value
  6668. return ProcessPropertyGetSetAccessor(ctx, lctx, rctx, op, opNode);
  6669. }
  6670. // It is not allowed to do a handle assignment on a property
  6671. // accessor that doesn't take a handle in the set accessor.
  6672. if( lctx->property_set && lctx->type.isExplicitHandle )
  6673. {
  6674. // set_opIndex has 2 arguments, where as normal setters have only 1
  6675. asCArray<asCDataType>& parameterTypes =
  6676. builder->GetFunctionDescription(lctx->property_set)->parameterTypes;
  6677. if( !parameterTypes[parameterTypes.GetLength() - 1].IsObjectHandle() )
  6678. {
  6679. // Process the property to free the memory
  6680. ProcessPropertySetAccessor(lctx, rctx, opNode);
  6681. Error(TXT_HANDLE_ASSIGN_ON_NON_HANDLE_PROP, opNode);
  6682. return -1;
  6683. }
  6684. }
  6685. MergeExprBytecodeAndType(ctx, lctx);
  6686. return ProcessPropertySetAccessor(ctx, rctx, opNode);
  6687. }
  6688. else if( lctx->property_get && lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle )
  6689. {
  6690. // Get the handle to the object that will be used for the value assignment
  6691. ProcessPropertyGetAccessor(lctx, opNode);
  6692. }
  6693. if( lctx->type.dataType.IsPrimitive() )
  6694. {
  6695. if( !lctx->type.isLValue )
  6696. {
  6697. Error(TXT_NOT_LVALUE, lexpr);
  6698. return -1;
  6699. }
  6700. if( op != ttAssignment )
  6701. {
  6702. // Compute the operator before the assignment
  6703. asCExprValue lvalue = lctx->type;
  6704. if( lctx->type.isTemporary && !lctx->type.isVariable )
  6705. {
  6706. // The temporary variable must not be freed until the
  6707. // assignment has been performed. lvalue still holds
  6708. // the information about the temporary variable
  6709. lctx->type.isTemporary = false;
  6710. }
  6711. asCExprContext o(engine);
  6712. CompileOperator(opNode, lctx, rctx, &o);
  6713. MergeExprBytecode(rctx, &o);
  6714. rctx->type = o.type;
  6715. // Convert the rvalue to the right type and validate it
  6716. PrepareForAssignment(&lvalue.dataType, rctx, rexpr, false);
  6717. MergeExprBytecode(ctx, rctx);
  6718. lctx->type = lvalue;
  6719. // The lvalue continues the same, either it was a variable, or a reference in the register
  6720. }
  6721. else
  6722. {
  6723. // Convert the rvalue to the right type and validate it
  6724. PrepareForAssignment(&lctx->type.dataType, rctx, rexpr, false, lctx);
  6725. MergeExprBytecode(ctx, rctx);
  6726. MergeExprBytecode(ctx, lctx);
  6727. }
  6728. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  6729. PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode);
  6730. ctx->type = lctx->type;
  6731. }
  6732. else if( lctx->type.isExplicitHandle )
  6733. {
  6734. if( !lctx->type.isLValue )
  6735. {
  6736. Error(TXT_NOT_LVALUE, lexpr);
  6737. return -1;
  6738. }
  6739. // Object handles don't have any compound assignment operators
  6740. if( op != ttAssignment )
  6741. {
  6742. asCString str;
  6743. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  6744. Error(str, lexpr);
  6745. return -1;
  6746. }
  6747. if( lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) )
  6748. {
  6749. // The object is a value type but that should be treated as a handle
  6750. // Make sure the right hand value is a handle
  6751. if( !rctx->type.isExplicitHandle &&
  6752. !(rctx->type.dataType.GetTypeInfo() && (rctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE)) )
  6753. {
  6754. // Function names can be considered handles already
  6755. if( rctx->methodName == "" )
  6756. {
  6757. asCDataType dt = rctx->type.dataType;
  6758. dt.MakeHandle(true);
  6759. dt.MakeReference(false);
  6760. PrepareArgument(&dt, rctx, rexpr, true, asTM_INREF);
  6761. if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) )
  6762. {
  6763. asCString str;
  6764. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  6765. Error(str, rexpr);
  6766. return -1;
  6767. }
  6768. }
  6769. }
  6770. if( CompileOverloadedDualOperator(opNode, lctx, rctx, false, ctx, true) )
  6771. {
  6772. // An overloaded assignment operator was found (or a compilation error occured)
  6773. return 0;
  6774. }
  6775. // The object must implement the opAssign method
  6776. asCString msg;
  6777. msg.Format(TXT_NO_APPROPRIATE_OPHNDLASSIGN_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  6778. Error(msg.AddressOf(), opNode);
  6779. return -1;
  6780. }
  6781. else
  6782. {
  6783. asCDataType dt = lctx->type.dataType;
  6784. dt.MakeReference(false);
  6785. PrepareArgument(&dt, rctx, rexpr, false, asTM_INREF , true);
  6786. if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) )
  6787. {
  6788. asCString str;
  6789. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  6790. Error(str, rexpr);
  6791. return -1;
  6792. }
  6793. MergeExprBytecode(ctx, rctx);
  6794. MergeExprBytecode(ctx, lctx);
  6795. ctx->bc.InstrWORD(asBC_GETOBJREF, AS_PTR_SIZE);
  6796. PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode);
  6797. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  6798. ctx->type = lctx->type;
  6799. // After the handle assignment the original handle is left on the stack
  6800. ctx->type.dataType.MakeReference(false);
  6801. }
  6802. }
  6803. else // if( lctx->type.dataType.IsObject() )
  6804. {
  6805. // The lvalue reference may be marked as a temporary, if for example
  6806. // it was originated as a handle returned from a function. In such
  6807. // cases it must be possible to assign values to it anyway.
  6808. if( lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle )
  6809. {
  6810. // Convert the handle to a object reference
  6811. asCDataType to;
  6812. to = lctx->type.dataType;
  6813. to.MakeHandle(false);
  6814. ImplicitConversion(lctx, to, lexpr, asIC_IMPLICIT_CONV);
  6815. lctx->type.isLValue = true; // Handle may not have been an lvalue, but the dereferenced object is
  6816. }
  6817. // Check for overloaded assignment operator
  6818. if( CompileOverloadedDualOperator(opNode, lctx, rctx, false, ctx) )
  6819. {
  6820. // An overloaded assignment operator was found (or a compilation error occured)
  6821. return 0;
  6822. }
  6823. // No registered operator was found. In case the operation is a direct
  6824. // assignment and the rvalue is the same type as the lvalue, then we can
  6825. // still use the byte-for-byte copy to do the assignment
  6826. if( op != ttAssignment )
  6827. {
  6828. asCString str;
  6829. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  6830. Error(str, lexpr);
  6831. return -1;
  6832. }
  6833. // If the left hand expression is simple, i.e. without any
  6834. // function calls or allocations of memory, then we can avoid
  6835. // doing a copy of the right hand expression (done by PrepareArgument).
  6836. // Instead the reference to the value can be placed directly on the
  6837. // stack.
  6838. //
  6839. // This optimization should only be done for value types, where
  6840. // the application developer is responsible for making the
  6841. // implementation safe against unwanted destruction of the input
  6842. // reference before the time.
  6843. bool simpleExpr = (lctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) && lctx->bc.IsSimpleExpression();
  6844. // Implicitly convert the rvalue to the type of the lvalue
  6845. bool needConversion = false;
  6846. if( !lctx->type.dataType.IsEqualExceptRefAndConst(rctx->type.dataType) )
  6847. needConversion = true;
  6848. if( !simpleExpr || needConversion )
  6849. {
  6850. asCDataType dt = lctx->type.dataType;
  6851. dt.MakeReference(true);
  6852. dt.MakeReadOnly(true);
  6853. int r = PrepareArgument(&dt, rctx, rexpr, true, 1, !needConversion);
  6854. if( r < 0 )
  6855. return -1;
  6856. if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) )
  6857. {
  6858. asCString str;
  6859. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  6860. Error(str, rexpr);
  6861. return -1;
  6862. }
  6863. }
  6864. else
  6865. {
  6866. // Process any property accessor first, before placing the final reference on the stack
  6867. ProcessPropertyGetAccessor(rctx, rexpr);
  6868. if( rctx->type.dataType.IsReference() && (!(rctx->type.isVariable || rctx->type.isTemporary) || IsVariableOnHeap(rctx->type.stackOffset)) )
  6869. rctx->bc.Instr(asBC_RDSPtr);
  6870. }
  6871. MergeExprBytecode(ctx, rctx);
  6872. MergeExprBytecode(ctx, lctx);
  6873. if( !simpleExpr || needConversion )
  6874. {
  6875. if( (rctx->type.isVariable || rctx->type.isTemporary) )
  6876. {
  6877. if( !IsVariableOnHeap(rctx->type.stackOffset) )
  6878. // TODO: runtime optimize: Actually the reference can be pushed on the stack directly
  6879. // as the value allocated on the stack is guaranteed to be safe.
  6880. // The bytecode optimizer should be able to determine this and optimize away the VAR + GETREF
  6881. ctx->bc.InstrWORD(asBC_GETREF, AS_PTR_SIZE);
  6882. else
  6883. ctx->bc.InstrWORD(asBC_GETOBJREF, AS_PTR_SIZE);
  6884. }
  6885. }
  6886. PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode);
  6887. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  6888. ctx->type = lctx->type;
  6889. }
  6890. return 0;
  6891. }
  6892. int asCCompiler::CompileAssignment(asCScriptNode *expr, asCExprContext *ctx)
  6893. {
  6894. asCScriptNode *lexpr = expr->firstChild;
  6895. if( lexpr->next )
  6896. {
  6897. // Compile the two expression terms
  6898. asCExprContext lctx(engine), rctx(engine);
  6899. int rr = CompileAssignment(lexpr->next->next, &rctx);
  6900. int lr = CompileCondition(lexpr, &lctx);
  6901. if( lr >= 0 && rr >= 0 )
  6902. return DoAssignment(ctx, &lctx, &rctx, lexpr, lexpr->next->next, lexpr->next->tokenType, lexpr->next);
  6903. // Since the operands failed, the assignment was not computed
  6904. ctx->type.SetDummy();
  6905. return -1;
  6906. }
  6907. return CompileCondition(lexpr, ctx);
  6908. }
  6909. int asCCompiler::CompileCondition(asCScriptNode *expr, asCExprContext *ctx)
  6910. {
  6911. asCExprValue ctype;
  6912. // Compile the conditional expression
  6913. asCScriptNode *cexpr = expr->firstChild;
  6914. if( cexpr->next )
  6915. {
  6916. //-------------------------------
  6917. // Compile the condition
  6918. asCExprContext e(engine);
  6919. int r = CompileExpression(cexpr, &e);
  6920. if( r < 0 )
  6921. e.type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  6922. // Allow value types to be converted to bool using 'bool opImplConv()'
  6923. if( e.type.dataType.GetTypeInfo() && (e.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
  6924. ImplicitConversion(&e, asCDataType::CreatePrimitive(ttBool, false), cexpr, asIC_IMPLICIT_CONV);
  6925. if( r >= 0 && !e.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  6926. {
  6927. Error(TXT_EXPR_MUST_BE_BOOL, cexpr);
  6928. e.type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  6929. }
  6930. ctype = e.type;
  6931. ProcessPropertyGetAccessor(&e, cexpr);
  6932. if( e.type.dataType.IsReference() ) ConvertToVariable(&e);
  6933. ProcessDeferredParams(&e);
  6934. //-------------------------------
  6935. // Compile the left expression
  6936. asCExprContext le(engine);
  6937. int lr = CompileAssignment(cexpr->next, &le);
  6938. // Resolve any function names already
  6939. DetermineSingleFunc(&le, cexpr->next);
  6940. //-------------------------------
  6941. // Compile the right expression
  6942. asCExprContext re(engine);
  6943. int rr = CompileAssignment(cexpr->next->next, &re);
  6944. DetermineSingleFunc(&re, cexpr->next->next);
  6945. if( lr >= 0 && rr >= 0 )
  6946. {
  6947. // Don't allow any operators on expressions that take address of class method
  6948. if( le.IsClassMethod() || re.IsClassMethod() )
  6949. {
  6950. Error(TXT_INVALID_OP_ON_METHOD, expr);
  6951. return -1;
  6952. }
  6953. ProcessPropertyGetAccessor(&le, cexpr->next);
  6954. ProcessPropertyGetAccessor(&re, cexpr->next->next);
  6955. bool isExplicitHandle = le.type.isExplicitHandle || re.type.isExplicitHandle;
  6956. // Allow a 0 or null in the first case to be implicitly converted to the second type
  6957. if( le.type.isConstant && le.type.GetConstantData() == 0 && le.type.dataType.IsIntegerType() )
  6958. {
  6959. asCDataType to = re.type.dataType;
  6960. to.MakeReference(false);
  6961. to.MakeReadOnly(true);
  6962. ImplicitConversionConstant(&le, to, cexpr->next, asIC_IMPLICIT_CONV);
  6963. }
  6964. else if( le.type.IsNullConstant() )
  6965. {
  6966. asCDataType to = re.type.dataType;
  6967. to.MakeHandle(true);
  6968. ImplicitConversion(&le, to, cexpr->next, asIC_IMPLICIT_CONV);
  6969. }
  6970. // Allow either case to be converted to const @ if the other is const @
  6971. if( (le.type.dataType.IsHandleToConst() && !le.type.IsNullConstant()) || (re.type.dataType.IsHandleToConst() && !re.type.dataType.IsNullHandle()) )
  6972. {
  6973. le.type.dataType.MakeHandleToConst(true);
  6974. re.type.dataType.MakeHandleToConst(true);
  6975. }
  6976. //---------------------------------
  6977. // Output the byte code
  6978. int afterLabel = nextLabel++;
  6979. int elseLabel = nextLabel++;
  6980. // If left expression is void, then we don't need to store the result
  6981. if( le.type.dataType.IsEqualExceptConst(asCDataType::CreatePrimitive(ttVoid, false)) )
  6982. {
  6983. // Put the code for the condition expression on the output
  6984. MergeExprBytecode(ctx, &e);
  6985. // Added the branch decision
  6986. ctx->type = e.type;
  6987. ConvertToVariable(ctx);
  6988. ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset);
  6989. ctx->bc.Instr(asBC_ClrHi);
  6990. ctx->bc.InstrDWORD(asBC_JZ, elseLabel);
  6991. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  6992. // Add the left expression
  6993. MergeExprBytecode(ctx, &le);
  6994. ctx->bc.InstrINT(asBC_JMP, afterLabel);
  6995. // Add the right expression
  6996. ctx->bc.Label((short)elseLabel);
  6997. MergeExprBytecode(ctx, &re);
  6998. ctx->bc.Label((short)afterLabel);
  6999. // Make sure both expressions have the same type
  7000. if( le.type.dataType != re.type.dataType )
  7001. Error(TXT_BOTH_MUST_BE_SAME, expr);
  7002. // Set the type of the result
  7003. ctx->type = le.type;
  7004. }
  7005. else if (le.type.IsNullConstant() && re.type.IsNullConstant())
  7006. {
  7007. // Special case for when both results are 'null'
  7008. // TODO: Other expressions where both results are identical literal constants can probably also be handled this way
  7009. // Put the code for the condition expression on the output
  7010. MergeExprBytecode(ctx, &e);
  7011. // Load the result into the register, but ignore the value since both paths give the same response
  7012. ctx->type = e.type;
  7013. ConvertToVariable(ctx);
  7014. ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset);
  7015. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  7016. // Return a null constant
  7017. ctx->bc.Instr(asBC_PshNull);
  7018. ctx->type.SetNullConstant();
  7019. }
  7020. else
  7021. {
  7022. // Allow "(a ? b : c) = d;" and "return (a ? b : c);" (where the latter returns the reference)
  7023. //
  7024. // Restrictions for the condition to be used as lvalue:
  7025. // 1. both b and c must be of the same type and be lvalue references
  7026. // 2. neither of the expressions can have any deferred arguments
  7027. // that would have to be cleaned up after the reference
  7028. // 3. neither expression can be temporary
  7029. //
  7030. // If either expression is local, the resulting lvalue is not valid
  7031. // for return since it is not allowed to return references to local
  7032. // variables.
  7033. //
  7034. // The reference to the local variable must be loaded into the register,
  7035. // the resulting expression must not be considered as a local variable
  7036. // with a stack offset (i.e. it will not be allowed to use asBC_VAR)
  7037. if( le.type.isLValue && re.type.isLValue &&
  7038. le.deferredParams.GetLength() == 0 && re.deferredParams.GetLength() ==0 &&
  7039. !le.type.isTemporary && !re.type.isTemporary &&
  7040. le.type.dataType == re.type.dataType )
  7041. {
  7042. // Put the code for the condition expression on the output
  7043. MergeExprBytecode(ctx, &e);
  7044. // Add the branch decision
  7045. ctx->type = e.type;
  7046. ConvertToVariable(ctx);
  7047. ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset);
  7048. ctx->bc.Instr(asBC_ClrHi);
  7049. ctx->bc.InstrDWORD(asBC_JZ, elseLabel);
  7050. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  7051. // Start of the left expression
  7052. MergeExprBytecode(ctx, &le);
  7053. if( !le.type.dataType.IsReference() && le.type.isVariable )
  7054. {
  7055. // Load the address of the variable into the register
  7056. ctx->bc.InstrSHORT(asBC_LDV, le.type.stackOffset);
  7057. }
  7058. ctx->bc.InstrINT(asBC_JMP, afterLabel);
  7059. // Start of the right expression
  7060. ctx->bc.Label((short)elseLabel);
  7061. MergeExprBytecode(ctx, &re);
  7062. if( !re.type.dataType.IsReference() && re.type.isVariable )
  7063. {
  7064. // Load the address of the variable into the register
  7065. ctx->bc.InstrSHORT(asBC_LDV, re.type.stackOffset);
  7066. }
  7067. ctx->bc.Label((short)afterLabel);
  7068. // In case the options were to objects, it is necessary to dereference the pointer on
  7069. // the stack so it will point to the actual object, instead of the variable
  7070. if( le.type.dataType.IsReference() && le.type.dataType.IsObject() && !le.type.dataType.IsObjectHandle() )
  7071. {
  7072. asASSERT( re.type.dataType.IsReference() && re.type.dataType.IsObject() && !re.type.dataType.IsObjectHandle() );
  7073. ctx->bc.Instr(asBC_RDSPtr);
  7074. }
  7075. // The result is an lvalue
  7076. ctx->type.isLValue = true;
  7077. ctx->type.dataType = le.type.dataType;
  7078. if( ctx->type.dataType.IsPrimitive() || ctx->type.dataType.IsObjectHandle() )
  7079. ctx->type.dataType.MakeReference(true);
  7080. else
  7081. ctx->type.dataType.MakeReference(false);
  7082. // It can't be a treated as a variable, since we don't know which one was used
  7083. ctx->type.isVariable = false;
  7084. ctx->type.isTemporary = false;
  7085. // Must remember if the reference was to a local variable, since it must not be allowed to be returned
  7086. ctx->type.isRefToLocal = le.type.isVariable || le.type.isRefToLocal || re.type.isVariable || re.type.isRefToLocal;
  7087. }
  7088. else
  7089. {
  7090. // Allocate temporary variable and copy the result to that one
  7091. asCExprValue temp;
  7092. temp = le.type;
  7093. temp.dataType.MakeReference(false);
  7094. temp.dataType.MakeReadOnly(false);
  7095. // Make sure the variable isn't used in any of the expressions,
  7096. // as it would be overwritten which may cause crashes or less visible bugs
  7097. int l = int(reservedVariables.GetLength());
  7098. e.bc.GetVarsUsed(reservedVariables);
  7099. le.bc.GetVarsUsed(reservedVariables);
  7100. re.bc.GetVarsUsed(reservedVariables);
  7101. int offset = AllocateVariable(temp.dataType, true, false);
  7102. reservedVariables.SetLength(l);
  7103. temp.SetVariable(temp.dataType, offset, true);
  7104. // TODO: copy: Use copy constructor if available. See PrepareTemporaryVariable()
  7105. CallDefaultConstructor(temp.dataType, offset, IsVariableOnHeap(offset), &ctx->bc, expr);
  7106. // Put the code for the condition expression on the output
  7107. MergeExprBytecode(ctx, &e);
  7108. // Add the branch decision
  7109. ctx->type = e.type;
  7110. ConvertToVariable(ctx);
  7111. ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset);
  7112. ctx->bc.Instr(asBC_ClrHi);
  7113. ctx->bc.InstrDWORD(asBC_JZ, elseLabel);
  7114. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  7115. // Assign the result of the left expression to the temporary variable
  7116. asCExprValue rtemp;
  7117. rtemp = temp;
  7118. if( rtemp.dataType.IsObjectHandle() )
  7119. rtemp.isExplicitHandle = true;
  7120. PrepareForAssignment(&rtemp.dataType, &le, cexpr->next, true);
  7121. MergeExprBytecode(ctx, &le);
  7122. if( !rtemp.dataType.IsPrimitive() )
  7123. {
  7124. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  7125. rtemp.dataType.MakeReference(IsVariableOnHeap(offset));
  7126. }
  7127. asCExprValue result;
  7128. result = rtemp;
  7129. PerformAssignment(&result, &le.type, &ctx->bc, cexpr->next);
  7130. if( !result.dataType.IsPrimitive() )
  7131. ctx->bc.Instr(asBC_PopPtr); // Pop the original value (always a pointer)
  7132. // Release the old temporary variable
  7133. ReleaseTemporaryVariable(le.type, &ctx->bc);
  7134. ctx->bc.InstrINT(asBC_JMP, afterLabel);
  7135. // Start of the right expression
  7136. ctx->bc.Label((short)elseLabel);
  7137. // Copy the result to the same temporary variable
  7138. PrepareForAssignment(&rtemp.dataType, &re, cexpr->next, true);
  7139. MergeExprBytecode(ctx, &re);
  7140. if( !rtemp.dataType.IsPrimitive() )
  7141. {
  7142. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  7143. rtemp.dataType.MakeReference(IsVariableOnHeap(offset));
  7144. }
  7145. result = rtemp;
  7146. PerformAssignment(&result, &re.type, &ctx->bc, cexpr->next);
  7147. if( !result.dataType.IsPrimitive() )
  7148. ctx->bc.Instr(asBC_PopPtr); // Pop the original value (always a pointer)
  7149. // Release the old temporary variable
  7150. ReleaseTemporaryVariable(re.type, &ctx->bc);
  7151. ctx->bc.Label((short)afterLabel);
  7152. // Make sure both expressions have the same type
  7153. if( !le.type.dataType.IsEqualExceptConst(re.type.dataType) )
  7154. Error(TXT_BOTH_MUST_BE_SAME, expr);
  7155. // Set the temporary variable as output
  7156. ctx->type = rtemp;
  7157. ctx->type.isExplicitHandle = isExplicitHandle;
  7158. if( !ctx->type.dataType.IsPrimitive() )
  7159. {
  7160. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  7161. ctx->type.dataType.MakeReference(IsVariableOnHeap(offset));
  7162. }
  7163. // Make sure the output isn't marked as being a literal constant
  7164. ctx->type.isConstant = false;
  7165. }
  7166. }
  7167. }
  7168. else
  7169. {
  7170. ctx->type.SetDummy();
  7171. return -1;
  7172. }
  7173. }
  7174. else
  7175. return CompileExpression(cexpr, ctx);
  7176. return 0;
  7177. }
  7178. int asCCompiler::CompileExpression(asCScriptNode *expr, asCExprContext *ctx)
  7179. {
  7180. asASSERT(expr->nodeType == snExpression);
  7181. // Convert to polish post fix, i.e: a+b => ab+
  7182. asCArray<asCScriptNode *> postfix;
  7183. ConvertToPostFix(expr, postfix);
  7184. // Compile the postfix formatted expression
  7185. return CompilePostFixExpression(&postfix, ctx);
  7186. }
  7187. void asCCompiler::ConvertToPostFix(asCScriptNode *expr, asCArray<asCScriptNode *> &postfix)
  7188. {
  7189. // The algorithm that I've implemented here is similar to
  7190. // Djikstra's Shunting Yard algorithm, though I didn't know it at the time.
  7191. // ref: http://en.wikipedia.org/wiki/Shunting-yard_algorithm
  7192. // Count the nodes in order to preallocate the buffers
  7193. int count = 0;
  7194. asCScriptNode *node = expr->firstChild;
  7195. while( node )
  7196. {
  7197. count++;
  7198. node = node->next;
  7199. }
  7200. asCArray<asCScriptNode *> stackA(count);
  7201. asCArray<asCScriptNode *> &stackB = postfix;
  7202. stackB.Allocate(count, false);
  7203. node = expr->firstChild;
  7204. while( node )
  7205. {
  7206. int precedence = GetPrecedence(node);
  7207. while( stackA.GetLength() > 0 &&
  7208. precedence <= GetPrecedence(stackA[stackA.GetLength()-1]) )
  7209. stackB.PushLast(stackA.PopLast());
  7210. stackA.PushLast(node);
  7211. node = node->next;
  7212. }
  7213. while( stackA.GetLength() > 0 )
  7214. stackB.PushLast(stackA.PopLast());
  7215. }
  7216. int asCCompiler::CompilePostFixExpression(asCArray<asCScriptNode *> *postfix, asCExprContext *ctx)
  7217. {
  7218. // Shouldn't send any byte code
  7219. asASSERT(ctx->bc.GetLastInstr() == -1);
  7220. // Set the context to a dummy type to avoid further
  7221. // errors in case the expression fails to compile
  7222. ctx->type.SetDummy();
  7223. // Evaluate the operands and operators
  7224. asCArray<asCExprContext*> free;
  7225. asCArray<asCExprContext*> expr;
  7226. int ret = 0;
  7227. for( asUINT n = 0; ret == 0 && n < postfix->GetLength(); n++ )
  7228. {
  7229. asCScriptNode *node = (*postfix)[n];
  7230. if( node->nodeType == snExprTerm )
  7231. {
  7232. asCExprContext *e = free.GetLength() ? free.PopLast() : asNEW(asCExprContext)(engine);
  7233. expr.PushLast(e);
  7234. e->exprNode = node;
  7235. ret = CompileExpressionTerm(node, e);
  7236. }
  7237. else
  7238. {
  7239. asCExprContext *r = expr.PopLast();
  7240. asCExprContext *l = expr.PopLast();
  7241. // Now compile the operator
  7242. asCExprContext *e = free.GetLength() ? free.PopLast() : asNEW(asCExprContext)(engine);
  7243. ret = CompileOperator(node, l, r, e);
  7244. expr.PushLast(e);
  7245. // Free the operands
  7246. l->Clear();
  7247. free.PushLast(l);
  7248. r->Clear();
  7249. free.PushLast(r);
  7250. }
  7251. }
  7252. if( ret == 0 )
  7253. {
  7254. asASSERT(expr.GetLength() == 1);
  7255. // The final result should be moved to the output context
  7256. MergeExprBytecodeAndType(ctx, expr[0]);
  7257. }
  7258. // Clean up
  7259. for( asUINT e = 0; e < expr.GetLength(); e++ )
  7260. asDELETE(expr[e], asCExprContext);
  7261. for( asUINT f = 0; f < free.GetLength(); f++ )
  7262. asDELETE(free[f], asCExprContext);
  7263. return ret;
  7264. }
  7265. int asCCompiler::CompilerAnonymousInitList(asCScriptNode *node, asCExprContext *ctx, const asCDataType &dt)
  7266. {
  7267. asASSERT(node->nodeType == snInitList);
  7268. // Do not allow constructing non-shared types in shared functions
  7269. if (outFunc->IsShared() &&
  7270. dt.GetTypeInfo() && !dt.GetTypeInfo()->IsShared())
  7271. {
  7272. asCString msg;
  7273. msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, dt.GetTypeInfo()->name.AddressOf());
  7274. Error(msg, node);
  7275. }
  7276. // Allocate and initialize the temporary object
  7277. int offset = AllocateVariable(dt, true);
  7278. CompileInitialization(node, &ctx->bc, dt, node, offset, 0, 0);
  7279. // Push the reference to the object on the stack
  7280. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  7281. ctx->type.SetVariable(dt, offset, true);
  7282. ctx->type.isLValue = false;
  7283. // If the variable is allocated on the heap we have a reference,
  7284. // otherwise the actual object pointer is pushed on the stack.
  7285. if (IsVariableOnHeap(offset))
  7286. ctx->type.dataType.MakeReference(true);
  7287. return 0;
  7288. }
  7289. int asCCompiler::CompileExpressionTerm(asCScriptNode *node, asCExprContext *ctx)
  7290. {
  7291. // Shouldn't send any byte code
  7292. asASSERT(ctx->bc.GetLastInstr() == -1);
  7293. // Check if this is an initialization of a temp object with an initialization list
  7294. if (node->firstChild )
  7295. {
  7296. if (node->firstChild->nodeType == snDataType)
  7297. {
  7298. // Determine the type of the temporary object
  7299. asCDataType dt = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace);
  7300. return CompilerAnonymousInitList(node->lastChild, ctx, dt);
  7301. }
  7302. else if (node->firstChild->nodeType == snInitList)
  7303. {
  7304. // As the type is not yet known, the init list will be compiled at a
  7305. // later time when the type can be determined from the destination
  7306. ctx->SetAnonymousInitList(node->firstChild);
  7307. return 0;
  7308. }
  7309. }
  7310. // Set the type as a dummy by default, in case of any compiler errors
  7311. ctx->type.SetDummy();
  7312. // Compile the value node
  7313. asCScriptNode *vnode = node->firstChild;
  7314. while( vnode->nodeType != snExprValue )
  7315. vnode = vnode->next;
  7316. asCExprContext v(engine);
  7317. int r = CompileExpressionValue(vnode, &v); if( r < 0 ) return r;
  7318. // Compile post fix operators
  7319. asCScriptNode *pnode = vnode->next;
  7320. while( pnode )
  7321. {
  7322. r = CompileExpressionPostOp(pnode, &v); if( r < 0 ) return r;
  7323. pnode = pnode->next;
  7324. }
  7325. // Compile pre fix operators
  7326. pnode = vnode->prev;
  7327. while( pnode )
  7328. {
  7329. r = CompileExpressionPreOp(pnode, &v); if( r < 0 ) return r;
  7330. pnode = pnode->prev;
  7331. }
  7332. // Return the byte code and final type description
  7333. MergeExprBytecodeAndType(ctx, &v);
  7334. return 0;
  7335. }
  7336. int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &scope, asCExprContext *ctx, asCScriptNode *errNode, bool isOptional, bool noFunction, bool noGlobal, asCObjectType *objType)
  7337. {
  7338. bool found = false;
  7339. // It is a local variable or parameter?
  7340. // This is not accessible by default arg expressions
  7341. sVariable *v = 0;
  7342. if( !isCompilingDefaultArg && scope == "" && !objType && variables )
  7343. v = variables->GetVariable(name.AddressOf());
  7344. if( v )
  7345. {
  7346. found = true;
  7347. if( v->isPureConstant )
  7348. ctx->type.SetConstantData(v->type, v->constantValue);
  7349. else if( v->type.IsPrimitive() )
  7350. {
  7351. if( v->type.IsReference() )
  7352. {
  7353. // Copy the reference into the register
  7354. ctx->bc.InstrSHORT(asBC_PshVPtr, (short)v->stackOffset);
  7355. ctx->bc.Instr(asBC_PopRPtr);
  7356. ctx->type.Set(v->type);
  7357. }
  7358. else
  7359. ctx->type.SetVariable(v->type, v->stackOffset, false);
  7360. // Set as lvalue unless it is a const variable
  7361. if( !v->type.IsReadOnly() )
  7362. ctx->type.isLValue = true;
  7363. }
  7364. else
  7365. {
  7366. ctx->bc.InstrSHORT(asBC_PSF, (short)v->stackOffset);
  7367. ctx->type.SetVariable(v->type, v->stackOffset, false);
  7368. // If the variable is allocated on the heap we have a reference,
  7369. // otherwise the actual object pointer is pushed on the stack.
  7370. if( v->onHeap || v->type.IsObjectHandle() ) ctx->type.dataType.MakeReference(true);
  7371. // Implicitly dereference handle parameters sent by reference
  7372. if( v->type.IsReference() && (!v->type.IsObject() || v->type.IsObjectHandle()) )
  7373. ctx->bc.Instr(asBC_RDSPtr);
  7374. // Mark the object as safe for access unless it is a handle, as the
  7375. // life time of the object is guaranteed throughout the scope.
  7376. if( !v->type.IsObjectHandle() )
  7377. ctx->type.isHandleSafe = true;
  7378. // Set as lvalue unless it is a const variable
  7379. if (!v->type.IsReadOnly())
  7380. ctx->type.isLValue = true;
  7381. }
  7382. }
  7383. // Is it a class member?
  7384. // This is not accessible by default arg expressions
  7385. if( !isCompilingDefaultArg && !found && ((objType) || (outFunc && outFunc->objectType && scope == "")) )
  7386. {
  7387. if( name == THIS_TOKEN && !objType )
  7388. {
  7389. asCDataType dt = asCDataType::CreateType(outFunc->objectType, outFunc->isReadOnly);
  7390. // The object pointer is located at stack position 0
  7391. ctx->bc.InstrSHORT(asBC_PSF, 0);
  7392. ctx->type.SetVariable(dt, 0, false);
  7393. ctx->type.dataType.MakeReference(true);
  7394. ctx->type.isLValue = true;
  7395. // The 'this' handle is always considered safe (i.e. life time guaranteed)
  7396. ctx->type.isHandleSafe = true;
  7397. found = true;
  7398. }
  7399. if( !found )
  7400. {
  7401. // See if there are any matching property accessors
  7402. asCExprContext access(engine);
  7403. if( objType )
  7404. access.type.Set(asCDataType::CreateType(objType, false));
  7405. else
  7406. access.type.Set(asCDataType::CreateType(outFunc->objectType, outFunc->isReadOnly));
  7407. access.type.dataType.MakeReference(true);
  7408. int r = 0;
  7409. if( errNode->next && errNode->next->tokenType == ttOpenBracket )
  7410. {
  7411. // This is an index access, check if there is a property accessor that takes an index arg
  7412. asCExprContext dummyArg(engine);
  7413. r = FindPropertyAccessor(name, &access, &dummyArg, errNode, 0, true);
  7414. }
  7415. if( r == 0 )
  7416. {
  7417. // Normal property access
  7418. r = FindPropertyAccessor(name, &access, errNode, 0, true);
  7419. }
  7420. if( r < 0 ) return -1;
  7421. if( access.property_get || access.property_set )
  7422. {
  7423. if( !objType )
  7424. {
  7425. // Prepare the bytecode for the member access
  7426. // This is only done when accessing through the implicit this pointer
  7427. ctx->bc.InstrSHORT(asBC_PSF, 0);
  7428. }
  7429. MergeExprBytecodeAndType(ctx, &access);
  7430. found = true;
  7431. }
  7432. }
  7433. if( !found )
  7434. {
  7435. asCDataType dt;
  7436. if( objType )
  7437. dt = asCDataType::CreateType(objType, false);
  7438. else
  7439. dt = asCDataType::CreateType(outFunc->objectType, false);
  7440. asCObjectProperty *prop = builder->GetObjectProperty(dt, name.AddressOf());
  7441. if( prop )
  7442. {
  7443. // Is the property access allowed?
  7444. if( prop->isPrivate && prop->isInherited )
  7445. {
  7446. if( engine->ep.privatePropAsProtected )
  7447. {
  7448. // The application is allowing inherited classes to access private properties of the parent
  7449. // class. This option is allowed to provide backwards compatibility with pre-2.30.0 versions
  7450. // as it was how the compiler behaved earlier.
  7451. asCString msg;
  7452. msg.Format(TXT_ACCESSING_PRIVATE_PROP_s, name.AddressOf());
  7453. Warning(msg, errNode);
  7454. }
  7455. else
  7456. {
  7457. asCString msg;
  7458. msg.Format(TXT_INHERITED_PRIVATE_PROP_ACCESS_s, name.AddressOf());
  7459. Error(msg, errNode);
  7460. }
  7461. }
  7462. if( !objType )
  7463. {
  7464. // The object pointer is located at stack position 0
  7465. // This is only done when accessing through the implicit this pointer
  7466. ctx->bc.InstrSHORT(asBC_PSF, 0);
  7467. ctx->type.SetVariable(dt, 0, false);
  7468. ctx->type.dataType.MakeReference(true);
  7469. Dereference(ctx, true);
  7470. }
  7471. // TODO: This is the same as what is in CompileExpressionPostOp
  7472. // Put the offset on the stack
  7473. ctx->bc.InstrSHORT_DW(asBC_ADDSi, (short)prop->byteOffset, engine->GetTypeIdFromDataType(dt));
  7474. if( prop->type.IsReference() )
  7475. ctx->bc.Instr(asBC_RDSPtr);
  7476. // Reference to primitive must be stored in the temp register
  7477. if( prop->type.IsPrimitive() )
  7478. {
  7479. // TODO: runtime optimize: The ADD offset command should store the reference in the register directly
  7480. ctx->bc.Instr(asBC_PopRPtr);
  7481. }
  7482. // Set the new type (keeping info about temp variable)
  7483. ctx->type.dataType = prop->type;
  7484. ctx->type.dataType.MakeReference(true);
  7485. ctx->type.isVariable = false;
  7486. ctx->type.isLValue = true;
  7487. if( ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle() )
  7488. {
  7489. // Objects that are members are not references
  7490. ctx->type.dataType.MakeReference(false);
  7491. // Objects that are members but not handles are safe as long as the parent object is safe
  7492. if (!objType || ctx->type.isHandleSafe)
  7493. ctx->type.isHandleSafe = true;
  7494. }
  7495. else if (ctx->type.dataType.IsObjectHandle())
  7496. {
  7497. // Objects accessed through handles cannot be considered safe
  7498. // as the handle can be cleared at any time
  7499. ctx->type.isHandleSafe = false;
  7500. }
  7501. // If the object reference is const, the property will also be const
  7502. ctx->type.dataType.MakeReadOnly(outFunc->isReadOnly);
  7503. found = true;
  7504. }
  7505. else if( outFunc->objectType )
  7506. {
  7507. // If it is not a property, it may still be the name of a method which can be used to create delegates
  7508. asCObjectType *ot = outFunc->objectType;
  7509. asCScriptFunction *func = 0;
  7510. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  7511. {
  7512. asCScriptFunction *f = engine->scriptFunctions[ot->methods[n]];
  7513. if( f->name == name &&
  7514. (builder->module->accessMask & f->accessMask) )
  7515. {
  7516. func = f;
  7517. break;
  7518. }
  7519. }
  7520. if( func )
  7521. {
  7522. // An object method was found. Keep the name of the method in the expression, but
  7523. // don't actually modify the bytecode at this point since it is not yet known what
  7524. // the method will be used for, or even what overloaded method should be used.
  7525. ctx->methodName = name;
  7526. // Place the object pointer on the stack, as if the expression was this.func
  7527. if( !objType )
  7528. {
  7529. // The object pointer is located at stack position 0
  7530. // This is only done when accessing through the implicit this pointer
  7531. ctx->bc.InstrSHORT(asBC_PSF, 0);
  7532. ctx->type.SetVariable(asCDataType::CreateType(outFunc->objectType, false), 0, false);
  7533. ctx->type.dataType.MakeReference(true);
  7534. Dereference(ctx, true);
  7535. }
  7536. found = true;
  7537. }
  7538. }
  7539. }
  7540. }
  7541. // Recursively search parent namespaces for global entities
  7542. asCString currScope = scope;
  7543. // Get the namespace for this scope. This may return null if the scope is an enum
  7544. asSNameSpace *ns = DetermineNameSpace(currScope);
  7545. if( ns && currScope != "::" )
  7546. currScope = ns->name;
  7547. while( !found && !noGlobal && !objType )
  7548. {
  7549. // Is it a global property?
  7550. if( !found && ns )
  7551. {
  7552. // See if there are any matching global property accessors
  7553. asCExprContext access(engine);
  7554. int r = 0;
  7555. if( errNode->next && errNode->next->tokenType == ttOpenBracket )
  7556. {
  7557. // This is an index access, check if there is a property accessor that takes an index arg
  7558. asCExprContext dummyArg(engine);
  7559. r = FindPropertyAccessor(name, &access, &dummyArg, errNode, ns);
  7560. }
  7561. if( r == 0 )
  7562. {
  7563. // Normal property access
  7564. r = FindPropertyAccessor(name, &access, errNode, ns);
  7565. }
  7566. if( r < 0 ) return -1;
  7567. if( access.property_get || access.property_set )
  7568. {
  7569. // Prepare the bytecode for the function call
  7570. MergeExprBytecodeAndType(ctx, &access);
  7571. found = true;
  7572. }
  7573. // See if there is any matching global property
  7574. if( !found )
  7575. {
  7576. bool isCompiled = true;
  7577. bool isPureConstant = false;
  7578. bool isAppProp = false;
  7579. asQWORD constantValue = 0;
  7580. asCGlobalProperty *prop = builder->GetGlobalProperty(name.AddressOf(), ns, &isCompiled, &isPureConstant, &constantValue, &isAppProp);
  7581. if( prop )
  7582. {
  7583. found = true;
  7584. // Verify that the global property has been compiled already
  7585. if( isCompiled )
  7586. {
  7587. if( ctx->type.dataType.GetTypeInfo() && (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE) )
  7588. {
  7589. ctx->type.dataType.MakeHandle(true);
  7590. ctx->type.isExplicitHandle = true;
  7591. }
  7592. // If the global property is a pure constant
  7593. // we can allow the compiler to optimize it. Pure
  7594. // constants are global constant variables that were
  7595. // initialized by literal constants.
  7596. if (isPureConstant)
  7597. ctx->type.SetConstantData(prop->type, constantValue);
  7598. else
  7599. {
  7600. // A shared type must not access global vars, unless they
  7601. // too are shared, e.g. application registered vars
  7602. if( outFunc->IsShared() )
  7603. {
  7604. if( !isAppProp )
  7605. {
  7606. asCString str;
  7607. str.Format(TXT_SHARED_CANNOT_ACCESS_NON_SHARED_VAR_s, prop->name.AddressOf());
  7608. Error(str, errNode);
  7609. // Allow the compilation to continue to catch other problems
  7610. }
  7611. }
  7612. ctx->type.Set(prop->type);
  7613. ctx->type.isLValue = true;
  7614. if( ctx->type.dataType.IsPrimitive() )
  7615. {
  7616. // Load the address of the variable into the register
  7617. ctx->bc.InstrPTR(asBC_LDG, prop->GetAddressOfValue());
  7618. ctx->type.dataType.MakeReference(true);
  7619. }
  7620. else
  7621. {
  7622. // Push the address of the variable on the stack
  7623. ctx->bc.InstrPTR(asBC_PGA, prop->GetAddressOfValue());
  7624. // If the object is a value type or a non-handle variable to a reference type,
  7625. // then we must validate the existance as it could potentially be accessed
  7626. // before it is initialized.
  7627. // This check is not needed for application registered properties, since they
  7628. // are guaranteed to be valid by the application itself.
  7629. if( !isAppProp &&
  7630. ((ctx->type.dataType.GetTypeInfo()->flags & asOBJ_VALUE) ||
  7631. !ctx->type.dataType.IsObjectHandle()) )
  7632. {
  7633. ctx->bc.Instr(asBC_ChkRefS);
  7634. }
  7635. // If the address pushed on the stack is to a value type or an object
  7636. // handle, then mark the expression as a reference. Addresses to a reference
  7637. // type aren't marked as references to get correct behaviour
  7638. if( (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_VALUE) ||
  7639. ctx->type.dataType.IsObjectHandle() )
  7640. {
  7641. ctx->type.dataType.MakeReference(true);
  7642. }
  7643. else
  7644. {
  7645. asASSERT( (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !ctx->type.dataType.IsObjectHandle() );
  7646. // It's necessary to dereference the pointer so the pointer on the stack will point to the actual object
  7647. ctx->bc.Instr(asBC_RDSPtr);
  7648. }
  7649. }
  7650. }
  7651. }
  7652. else
  7653. {
  7654. asCString str;
  7655. str.Format(TXT_UNINITIALIZED_GLOBAL_VAR_s, prop->name.AddressOf());
  7656. Error(str, errNode);
  7657. return -1;
  7658. }
  7659. }
  7660. }
  7661. }
  7662. // Is it the name of a global function?
  7663. if( !noFunction && !found && ns )
  7664. {
  7665. asCArray<int> funcs;
  7666. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  7667. if( funcs.GetLength() > 0 )
  7668. {
  7669. found = true;
  7670. // Defer the evaluation of which function until it is actually used
  7671. // Store the namespace and name of the function for later
  7672. ctx->type.SetUndefinedFuncHandle(engine);
  7673. ctx->methodName = ns ? ns->name + "::" + name : name;
  7674. }
  7675. }
  7676. // Is it an enum value?
  7677. if( !found )
  7678. {
  7679. // The enum type may be declared in a namespace too
  7680. asCTypeInfo *scopeType = 0;
  7681. if( currScope != "" && currScope != "::" )
  7682. {
  7683. builder->GetNameSpaceByString(currScope, outFunc->objectType ? outFunc->objectType->nameSpace : outFunc->nameSpace, errNode, script, &scopeType, false);
  7684. if (CastToEnumType(scopeType) == 0)
  7685. scopeType = 0;
  7686. }
  7687. asDWORD value = 0;
  7688. asCDataType dt;
  7689. if( scopeType && builder->GetEnumValueFromType(CastToEnumType(scopeType), name.AddressOf(), dt, value) )
  7690. {
  7691. // scoped enum value found
  7692. found = true;
  7693. }
  7694. else if( !engine->ep.requireEnumScope )
  7695. {
  7696. // Look for the enum value without explicitly informing the enum type
  7697. asSNameSpace *nsEnum = DetermineNameSpace(currScope);
  7698. int e = 0;
  7699. if(nsEnum)
  7700. e = builder->GetEnumValue(name.AddressOf(), dt, value, nsEnum);
  7701. if( e )
  7702. {
  7703. found = true;
  7704. if( e == 2 )
  7705. {
  7706. // Ambiguous enum value: Save the name for resolution later.
  7707. // The ambiguity could be resolved now, but I hesitate
  7708. // to store too much information in the context.
  7709. ctx->enumValue = name.AddressOf();
  7710. // We cannot set a dummy value because it will pass through
  7711. // cleanly as an integer.
  7712. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttIdentifier, true), 0);
  7713. return 0;
  7714. }
  7715. }
  7716. }
  7717. if( found )
  7718. {
  7719. // Even if the enum type is not shared, and we're compiling a shared object,
  7720. // the use of the values are still allowed, since they are treated as constants.
  7721. // an enum value was resolved
  7722. ctx->type.SetConstantDW(dt, value);
  7723. }
  7724. else
  7725. {
  7726. // If nothing was found because the scope doesn't match a namespace or an enum
  7727. // then this should be reported as an error and the search interrupted
  7728. if( !ns && !scopeType )
  7729. {
  7730. ctx->type.SetDummy();
  7731. asCString str;
  7732. str.Format(TXT_UNKNOWN_SCOPE_s, scope.AddressOf());
  7733. Error(str, errNode);
  7734. return -1;
  7735. }
  7736. }
  7737. }
  7738. if( !found )
  7739. {
  7740. if( currScope == "" || currScope == "::" )
  7741. break;
  7742. // Move up to parent namespace
  7743. int pos = currScope.FindLast("::");
  7744. if( pos >= 0 )
  7745. currScope = currScope.SubString(0, pos);
  7746. else
  7747. currScope = "::";
  7748. if( ns )
  7749. ns = engine->GetParentNameSpace(ns);
  7750. }
  7751. }
  7752. // The name doesn't match any variable
  7753. if( !found )
  7754. {
  7755. // Give dummy value
  7756. ctx->type.SetDummy();
  7757. if( !isOptional )
  7758. {
  7759. // Prepend the scope to the name for the error message
  7760. asCString ename;
  7761. if( scope != "" && scope != "::" )
  7762. ename = scope + "::";
  7763. else
  7764. ename = scope;
  7765. ename += name;
  7766. asCString str;
  7767. str.Format(TXT_s_NOT_DECLARED, ename.AddressOf());
  7768. Error(str, errNode);
  7769. // Declare the variable now so that it will not be reported again
  7770. variables->DeclareVariable(name.AddressOf(), asCDataType::CreatePrimitive(ttInt, false), 0x7FFF, true);
  7771. // Mark the variable as initialized so that the user will not be bother by it again
  7772. v = variables->GetVariable(name.AddressOf());
  7773. asASSERT(v);
  7774. if( v ) v->isInitialized = true;
  7775. }
  7776. // Return -1 to signal that the variable wasn't found
  7777. return -1;
  7778. }
  7779. return 0;
  7780. }
  7781. int asCCompiler::CompileExpressionValue(asCScriptNode *node, asCExprContext *ctx)
  7782. {
  7783. // Shouldn't receive any byte code
  7784. asASSERT(ctx->bc.GetLastInstr() == -1);
  7785. asCScriptNode *vnode = node->firstChild;
  7786. ctx->exprNode = vnode;
  7787. if( vnode->nodeType == snVariableAccess )
  7788. {
  7789. // Determine the scope resolution of the variable
  7790. asCString scope = builder->GetScopeFromNode(vnode->firstChild, script, &vnode);
  7791. // Determine the name of the variable
  7792. asASSERT(vnode->nodeType == snIdentifier );
  7793. asCString name(&script->code[vnode->tokenPos], vnode->tokenLength);
  7794. return CompileVariableAccess(name, scope, ctx, node);
  7795. }
  7796. else if( vnode->nodeType == snConstant )
  7797. {
  7798. if( vnode->tokenType == ttIntConstant )
  7799. {
  7800. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  7801. bool overflow = false;
  7802. asQWORD val = asStringScanUInt64(value.AddressOf(), 10, 0, &overflow);
  7803. // Is the number bigger than a 64bit word?
  7804. if (overflow)
  7805. {
  7806. Error(TXT_VALUE_TOO_LARGE_FOR_TYPE, vnode);
  7807. // Set the value to zero to avoid further warnings
  7808. val = 0;
  7809. }
  7810. // Do we need 64 bits?
  7811. // If the 31st bit is set we'll treat the value as a signed 64bit number to avoid
  7812. // incorrect warnings about changing signs if the value is assigned to a 64bit variable
  7813. if( val>>31 )
  7814. {
  7815. // Only if the value uses the last bit of a 64bit word do we consider the number unsigned
  7816. if( val>>63 )
  7817. ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), val);
  7818. else
  7819. ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), val);
  7820. }
  7821. else
  7822. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), asDWORD(val));
  7823. }
  7824. else if( vnode->tokenType == ttBitsConstant )
  7825. {
  7826. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  7827. // Let the function determine the radix from the prefix 0x = 16, 0d = 10, 0o = 8, or 0b = 2
  7828. bool overflow = false;
  7829. asQWORD val = asStringScanUInt64(value.AddressOf(), 0, 0, &overflow);
  7830. // Is the number bigger than a 64bit word?
  7831. if (overflow)
  7832. {
  7833. Error(TXT_VALUE_TOO_LARGE_FOR_TYPE, vnode);
  7834. // Set the value to zero to avoid further warnings
  7835. val = 0;
  7836. }
  7837. // Do we need 64 bits?
  7838. if( val>>32 )
  7839. ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), val);
  7840. else
  7841. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), asDWORD(val));
  7842. }
  7843. else if( vnode->tokenType == ttFloatConstant )
  7844. {
  7845. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  7846. // TODO: Check for overflow
  7847. size_t numScanned;
  7848. float v = float(asStringScanDouble(value.AddressOf(), &numScanned));
  7849. ctx->type.SetConstantF(asCDataType::CreatePrimitive(ttFloat, true), v);
  7850. #ifndef AS_USE_DOUBLE_AS_FLOAT
  7851. // Don't check this if we have double as float, because then the whole token would be scanned (i.e. no f suffix)
  7852. asASSERT(numScanned == vnode->tokenLength - 1);
  7853. #endif
  7854. }
  7855. else if( vnode->tokenType == ttDoubleConstant )
  7856. {
  7857. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  7858. // TODO: Check for overflow
  7859. size_t numScanned;
  7860. double v = asStringScanDouble(value.AddressOf(), &numScanned);
  7861. ctx->type.SetConstantD(asCDataType::CreatePrimitive(ttDouble, true), v);
  7862. asASSERT(numScanned == vnode->tokenLength);
  7863. }
  7864. else if( vnode->tokenType == ttTrue ||
  7865. vnode->tokenType == ttFalse )
  7866. {
  7867. #if AS_SIZEOF_BOOL == 1
  7868. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), vnode->tokenType == ttTrue ? VALUE_OF_BOOLEAN_TRUE : 0);
  7869. #else
  7870. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), vnode->tokenType == ttTrue ? VALUE_OF_BOOLEAN_TRUE : 0);
  7871. #endif
  7872. }
  7873. else if( vnode->tokenType == ttStringConstant ||
  7874. vnode->tokenType == ttMultilineStringConstant ||
  7875. vnode->tokenType == ttHeredocStringConstant )
  7876. {
  7877. asCString str;
  7878. asCScriptNode *snode = vnode->firstChild;
  7879. if( script->code[snode->tokenPos] == '\'' && engine->ep.useCharacterLiterals )
  7880. {
  7881. // Treat the single quoted string as a single character literal
  7882. str.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2);
  7883. asDWORD val = 0;
  7884. if( str.GetLength() && (unsigned char)str[0] > 127 && engine->ep.scanner == 1 )
  7885. {
  7886. // This is the start of a UTF8 encoded character. We need to decode it
  7887. val = asStringDecodeUTF8(str.AddressOf(), 0);
  7888. if( val == (asDWORD)-1 )
  7889. Error(TXT_INVALID_CHAR_LITERAL, vnode);
  7890. }
  7891. else
  7892. {
  7893. val = ProcessStringConstant(str, snode);
  7894. if( val == (asDWORD)-1 )
  7895. Error(TXT_INVALID_CHAR_LITERAL, vnode);
  7896. }
  7897. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), val);
  7898. }
  7899. else
  7900. {
  7901. // Process the string constants
  7902. while( snode )
  7903. {
  7904. asCString cat;
  7905. if( snode->tokenType == ttStringConstant )
  7906. {
  7907. cat.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2);
  7908. ProcessStringConstant(cat, snode);
  7909. }
  7910. else if( snode->tokenType == ttMultilineStringConstant )
  7911. {
  7912. if( !engine->ep.allowMultilineStrings )
  7913. Error(TXT_MULTILINE_STRINGS_NOT_ALLOWED, snode);
  7914. cat.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2);
  7915. ProcessStringConstant(cat, snode);
  7916. }
  7917. else if( snode->tokenType == ttHeredocStringConstant )
  7918. {
  7919. cat.Assign(&script->code[snode->tokenPos+3], snode->tokenLength-6);
  7920. ProcessHeredocStringConstant(cat, snode);
  7921. }
  7922. str += cat;
  7923. snode = snode->next;
  7924. }
  7925. // Call the string factory function to create a string object
  7926. asCScriptFunction *descr = engine->stringFactory;
  7927. if( descr == 0 )
  7928. {
  7929. // Error
  7930. Error(TXT_STRINGS_NOT_RECOGNIZED, vnode);
  7931. // Give dummy value
  7932. ctx->type.SetDummy();
  7933. return -1;
  7934. }
  7935. else
  7936. {
  7937. // Register the constant string with the engine
  7938. int id = engine->AddConstantString(str.AddressOf(), str.GetLength());
  7939. ctx->bc.InstrWORD(asBC_STR, (asWORD)id);
  7940. bool useVariable = false;
  7941. int stackOffset = 0;
  7942. if( descr->DoesReturnOnStack() )
  7943. {
  7944. useVariable = true;
  7945. stackOffset = AllocateVariable(descr->returnType, true);
  7946. ctx->bc.InstrSHORT(asBC_PSF, short(stackOffset));
  7947. }
  7948. PerformFunctionCall(descr->id, ctx, false, 0, 0, useVariable, stackOffset);
  7949. }
  7950. }
  7951. }
  7952. else if( vnode->tokenType == ttNull )
  7953. {
  7954. ctx->bc.Instr(asBC_PshNull);
  7955. ctx->type.SetNullConstant();
  7956. }
  7957. else
  7958. asASSERT(false);
  7959. }
  7960. else if( vnode->nodeType == snFunctionCall )
  7961. {
  7962. // Determine the scope resolution
  7963. asCString scope = builder->GetScopeFromNode(vnode->firstChild, script);
  7964. return CompileFunctionCall(vnode, ctx, 0, false, scope);
  7965. }
  7966. else if( vnode->nodeType == snConstructCall )
  7967. {
  7968. return CompileConstructCall(vnode, ctx);
  7969. }
  7970. else if( vnode->nodeType == snAssignment )
  7971. {
  7972. asCExprContext e(engine);
  7973. int r = CompileAssignment(vnode, &e);
  7974. if( r < 0 )
  7975. {
  7976. ctx->type.SetDummy();
  7977. return r;
  7978. }
  7979. MergeExprBytecodeAndType(ctx, &e);
  7980. }
  7981. else if( vnode->nodeType == snCast )
  7982. {
  7983. // Implement the cast operator
  7984. return CompileConversion(vnode, ctx);
  7985. }
  7986. else if( vnode->nodeType == snUndefined && vnode->tokenType == ttVoid )
  7987. {
  7988. // This is a void expression
  7989. ctx->SetVoidExpression();
  7990. }
  7991. else if( vnode->nodeType == snFunction )
  7992. {
  7993. // This is an anonymous function
  7994. // Defer the evaluation of the function until it known where it
  7995. // will be used, which is where the signature will be defined
  7996. ctx->SetLambda(vnode);
  7997. }
  7998. else
  7999. asASSERT(false);
  8000. return 0;
  8001. }
  8002. asUINT asCCompiler::ProcessStringConstant(asCString &cstr, asCScriptNode *node, bool processEscapeSequences)
  8003. {
  8004. int charLiteral = -1;
  8005. // Process escape sequences
  8006. asCArray<char> str((int)cstr.GetLength());
  8007. for( asUINT n = 0; n < cstr.GetLength(); n++ )
  8008. {
  8009. #ifdef AS_DOUBLEBYTE_CHARSET
  8010. // Double-byte charset is only allowed for ASCII and not UTF16 encoded strings
  8011. if( (cstr[n] & 0x80) && engine->ep.scanner == 0 && engine->ep.stringEncoding != 1 )
  8012. {
  8013. // This is the lead character of a double byte character
  8014. // include the trail character without checking it's value.
  8015. str.PushLast(cstr[n]);
  8016. n++;
  8017. str.PushLast(cstr[n]);
  8018. continue;
  8019. }
  8020. #endif
  8021. asUINT val;
  8022. if( processEscapeSequences && cstr[n] == '\\' )
  8023. {
  8024. ++n;
  8025. if( n == cstr.GetLength() )
  8026. {
  8027. if( charLiteral == -1 ) charLiteral = 0;
  8028. return charLiteral;
  8029. }
  8030. // Hexadecimal escape sequences will allow the construction of
  8031. // invalid unicode sequences, but the string should also work as
  8032. // a bytearray so we must support this. The code for working with
  8033. // unicode text must be prepared to handle invalid unicode sequences
  8034. if( cstr[n] == 'x' || cstr[n] == 'X' )
  8035. {
  8036. ++n;
  8037. if( n == cstr.GetLength() ) break;
  8038. val = 0;
  8039. int c = engine->ep.stringEncoding == 1 ? 4 : 2;
  8040. for( ; c > 0 && n < cstr.GetLength(); c--, n++ )
  8041. {
  8042. if( cstr[n] >= '0' && cstr[n] <= '9' )
  8043. val = val*16 + cstr[n] - '0';
  8044. else if( cstr[n] >= 'a' && cstr[n] <= 'f' )
  8045. val = val*16 + cstr[n] - 'a' + 10;
  8046. else if( cstr[n] >= 'A' && cstr[n] <= 'F' )
  8047. val = val*16 + cstr[n] - 'A' + 10;
  8048. else
  8049. break;
  8050. }
  8051. // Rewind one, since the loop will increment it again
  8052. n--;
  8053. // Hexadecimal escape sequences produce exact value, even if it is not proper unicode chars
  8054. if( engine->ep.stringEncoding == 0 )
  8055. {
  8056. str.PushLast((asBYTE)val);
  8057. }
  8058. else
  8059. {
  8060. #ifndef AS_BIG_ENDIAN
  8061. str.PushLast((asBYTE)val);
  8062. str.PushLast((asBYTE)(val>>8));
  8063. #else
  8064. str.PushLast((asBYTE)(val>>8));
  8065. str.PushLast((asBYTE)val);
  8066. #endif
  8067. }
  8068. if( charLiteral == -1 ) charLiteral = val;
  8069. continue;
  8070. }
  8071. else if( cstr[n] == 'u' || cstr[n] == 'U' )
  8072. {
  8073. // \u expects 4 hex digits
  8074. // \U expects 8 hex digits
  8075. bool expect2 = cstr[n] == 'u';
  8076. int c = expect2 ? 4 : 8;
  8077. val = 0;
  8078. for( ; c > 0; c-- )
  8079. {
  8080. ++n;
  8081. if( n == cstr.GetLength() ) break;
  8082. if( cstr[n] >= '0' && cstr[n] <= '9' )
  8083. val = val*16 + cstr[n] - '0';
  8084. else if( cstr[n] >= 'a' && cstr[n] <= 'f' )
  8085. val = val*16 + cstr[n] - 'a' + 10;
  8086. else if( cstr[n] >= 'A' && cstr[n] <= 'F' )
  8087. val = val*16 + cstr[n] - 'A' + 10;
  8088. else
  8089. break;
  8090. }
  8091. if( c != 0 )
  8092. {
  8093. // Give warning about invalid code point
  8094. // TODO: Need code position for warning
  8095. asCString msg;
  8096. msg.Format(TXT_INVALID_UNICODE_FORMAT_EXPECTED_d, expect2 ? 4 : 8);
  8097. Warning(msg, node);
  8098. continue;
  8099. }
  8100. }
  8101. else
  8102. {
  8103. if( cstr[n] == '"' )
  8104. val = '"';
  8105. else if( cstr[n] == '\'' )
  8106. val = '\'';
  8107. else if( cstr[n] == 'n' )
  8108. val = '\n';
  8109. else if( cstr[n] == 'r' )
  8110. val = '\r';
  8111. else if( cstr[n] == 't' )
  8112. val = '\t';
  8113. else if( cstr[n] == '0' )
  8114. val = '\0';
  8115. else if( cstr[n] == '\\' )
  8116. val = '\\';
  8117. else
  8118. {
  8119. // Invalid escape sequence
  8120. Warning(TXT_INVALID_ESCAPE_SEQUENCE, node);
  8121. continue;
  8122. }
  8123. }
  8124. }
  8125. else
  8126. {
  8127. if( engine->ep.scanner == 1 && (cstr[n] & 0x80) )
  8128. {
  8129. unsigned int len;
  8130. val = asStringDecodeUTF8(&cstr[n], &len);
  8131. if( val == 0xFFFFFFFF )
  8132. {
  8133. // Incorrect UTF8 encoding. Use only the first byte
  8134. // TODO: Need code position for warning
  8135. Warning(TXT_INVALID_UNICODE_SEQUENCE_IN_SRC, node);
  8136. val = (unsigned char)cstr[n];
  8137. }
  8138. else
  8139. n += len-1;
  8140. }
  8141. else
  8142. val = (unsigned char)cstr[n];
  8143. }
  8144. // Add the character to the final string
  8145. char encodedValue[5];
  8146. int len;
  8147. if( engine->ep.scanner == 1 && engine->ep.stringEncoding == 0 )
  8148. {
  8149. // Convert to UTF8 encoded
  8150. len = asStringEncodeUTF8(val, encodedValue);
  8151. }
  8152. else if( engine->ep.stringEncoding == 1 )
  8153. {
  8154. // Convert to 16bit wide character string (even if the script is scanned as ASCII)
  8155. len = asStringEncodeUTF16(val, encodedValue);
  8156. }
  8157. else
  8158. {
  8159. // Do not convert ASCII characters
  8160. encodedValue[0] = (asBYTE)val;
  8161. len = 1;
  8162. }
  8163. if( len < 0 )
  8164. {
  8165. // Give warning about invalid code point
  8166. // TODO: Need code position for warning
  8167. Warning(TXT_INVALID_UNICODE_VALUE, node);
  8168. }
  8169. else
  8170. {
  8171. // Add the encoded value to the final string
  8172. str.Concatenate(encodedValue, len);
  8173. if( charLiteral == -1 ) charLiteral = val;
  8174. }
  8175. }
  8176. cstr.Assign(str.AddressOf(), str.GetLength());
  8177. return charLiteral;
  8178. }
  8179. void asCCompiler::ProcessHeredocStringConstant(asCString &str, asCScriptNode *node)
  8180. {
  8181. // Remove first line if it only contains whitespace
  8182. bool isMultiline = false;
  8183. int start;
  8184. for( start = 0; start < (int)str.GetLength(); start++ )
  8185. {
  8186. if( str[start] == '\n' )
  8187. {
  8188. isMultiline = true;
  8189. // Remove the linebreak as well
  8190. start++;
  8191. break;
  8192. }
  8193. if( str[start] != ' ' &&
  8194. str[start] != '\t' &&
  8195. str[start] != '\r' )
  8196. {
  8197. // Don't remove anything
  8198. start = 0;
  8199. break;
  8200. }
  8201. }
  8202. // Remove the line after the last line break if it only contains whitespaces
  8203. int end;
  8204. for( end = (int)str.GetLength() - 1; end >= 0; end-- )
  8205. {
  8206. if( str[end] == '\n' )
  8207. {
  8208. // Don't remove the last line break
  8209. end++;
  8210. break;
  8211. }
  8212. if( str[end] != ' ' &&
  8213. str[end] != '\t' &&
  8214. str[end] != '\r' )
  8215. {
  8216. // Don't remove anything
  8217. end = (int)str.GetLength();
  8218. break;
  8219. }
  8220. }
  8221. if( end < 0 ) end = 0;
  8222. asCString tmp;
  8223. if (end > start || engine->ep.heredocTrimMode != 2 )
  8224. {
  8225. // if heredocTrimMode == 0 the string shouldn't be trimmed
  8226. // if heredocTrimMode == 1 the string should only be trimmed if it is multiline
  8227. // if heredocTrimMode == 2 the string should always be trimmed
  8228. if (engine->ep.heredocTrimMode == 2 || (isMultiline && engine->ep.heredocTrimMode == 1))
  8229. tmp.Assign(&str[start], end - start);
  8230. else
  8231. tmp = str;
  8232. }
  8233. ProcessStringConstant(tmp, node, false);
  8234. str = tmp;
  8235. }
  8236. int asCCompiler::CompileConversion(asCScriptNode *node, asCExprContext *ctx)
  8237. {
  8238. asCExprContext expr(engine);
  8239. asCDataType to;
  8240. bool anyErrors = false;
  8241. EImplicitConv convType;
  8242. if( node->nodeType == snConstructCall || node->nodeType == snFunctionCall )
  8243. {
  8244. convType = asIC_EXPLICIT_VAL_CAST;
  8245. // Verify that there is only one argument
  8246. if( node->lastChild->firstChild == 0 ||
  8247. node->lastChild->firstChild != node->lastChild->lastChild )
  8248. {
  8249. Error(TXT_ONLY_ONE_ARGUMENT_IN_CAST, node->lastChild);
  8250. expr.type.SetDummy();
  8251. anyErrors = true;
  8252. }
  8253. else
  8254. {
  8255. // Compile the expression
  8256. int r = CompileAssignment(node->lastChild->firstChild, &expr);
  8257. if( r < 0 )
  8258. anyErrors = true;
  8259. }
  8260. // Determine the requested type
  8261. to = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace);
  8262. to.MakeReadOnly(true); // Default to const
  8263. asASSERT(to.IsPrimitive());
  8264. }
  8265. else
  8266. {
  8267. convType = asIC_EXPLICIT_REF_CAST;
  8268. // Compile the expression
  8269. int r = CompileAssignment(node->lastChild, &expr);
  8270. if( r < 0 )
  8271. anyErrors = true;
  8272. // Determine the requested type
  8273. to = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace);
  8274. // If the type support object handles, then use it
  8275. if( to.SupportHandles() )
  8276. {
  8277. to.MakeHandle(true);
  8278. if( expr.type.dataType.IsObjectConst() )
  8279. to.MakeHandleToConst(true);
  8280. }
  8281. else if( !to.IsObjectHandle() )
  8282. {
  8283. // The cast<type> operator can only be used for reference casts
  8284. Error(TXT_ILLEGAL_TARGET_TYPE_FOR_REF_CAST, node->firstChild);
  8285. anyErrors = true;
  8286. }
  8287. }
  8288. // Do not allow casting to non shared type if we're compiling a shared method
  8289. if( outFunc->IsShared() &&
  8290. to.GetTypeInfo() && !to.GetTypeInfo()->IsShared() )
  8291. {
  8292. asCString msg;
  8293. msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, to.GetTypeInfo()->name.AddressOf());
  8294. Error(msg, node);
  8295. anyErrors = true;
  8296. }
  8297. if( anyErrors )
  8298. {
  8299. // Assume that the error can be fixed and allow the compilation to continue
  8300. ctx->type.Set(to);
  8301. return -1;
  8302. }
  8303. ProcessPropertyGetAccessor(&expr, node);
  8304. // Don't allow any operators on expressions that take address of class method
  8305. if( expr.IsClassMethod() )
  8306. {
  8307. Error(TXT_INVALID_OP_ON_METHOD, node);
  8308. return -1;
  8309. }
  8310. // We don't want a reference for conversion casts
  8311. if( convType == asIC_EXPLICIT_VAL_CAST && expr.type.dataType.IsReference() )
  8312. {
  8313. if( expr.type.dataType.IsObject() )
  8314. Dereference(&expr, true);
  8315. else
  8316. ConvertToVariable(&expr);
  8317. }
  8318. ImplicitConversion(&expr, to, node, convType);
  8319. IsVariableInitialized(&expr.type, node);
  8320. // If no type conversion is really tried ignore it
  8321. if( to == expr.type.dataType )
  8322. {
  8323. // This will keep information about constant type
  8324. MergeExprBytecode(ctx, &expr);
  8325. ctx->type = expr.type;
  8326. return 0;
  8327. }
  8328. if( to.IsEqualExceptRefAndConst(expr.type.dataType) && to.IsPrimitive() )
  8329. {
  8330. MergeExprBytecode(ctx, &expr);
  8331. ctx->type = expr.type;
  8332. ctx->type.dataType.MakeReadOnly(true);
  8333. return 0;
  8334. }
  8335. // The implicit conversion already does most of the conversions permitted,
  8336. // here we'll only treat those conversions that require an explicit cast.
  8337. bool conversionOK = false;
  8338. if( !expr.type.isConstant && expr.type.dataType != asCDataType::CreatePrimitive(ttVoid, false) )
  8339. {
  8340. if( !expr.type.dataType.IsObject() )
  8341. ConvertToTempVariable(&expr);
  8342. if( to.IsObjectHandle() &&
  8343. expr.type.dataType.IsObjectHandle() &&
  8344. !(!to.IsHandleToConst() && expr.type.dataType.IsHandleToConst()) )
  8345. {
  8346. conversionOK = CompileRefCast(&expr, to, true, node);
  8347. MergeExprBytecode(ctx, &expr);
  8348. ctx->type = expr.type;
  8349. }
  8350. }
  8351. if( conversionOK )
  8352. return 0;
  8353. // Conversion not available
  8354. ctx->type.SetDummy();
  8355. asCString strTo, strFrom;
  8356. strTo = to.Format(outFunc->nameSpace);
  8357. strFrom = expr.type.dataType.Format(outFunc->nameSpace);
  8358. asCString msg;
  8359. msg.Format(TXT_NO_CONVERSION_s_TO_s, strFrom.AddressOf(), strTo.AddressOf());
  8360. Error(msg, node);
  8361. return -1;
  8362. }
  8363. void asCCompiler::AfterFunctionCall(int funcID, asCArray<asCExprContext*> &args, asCExprContext *ctx, bool deferAll)
  8364. {
  8365. // deferAll is set to true if for example the function returns a reference, since in
  8366. // this case the function might be returning a reference to one of the arguments.
  8367. asCScriptFunction *descr = builder->GetFunctionDescription(funcID);
  8368. // Parameters that are sent by reference should be assigned
  8369. // to the evaluated expression if it is an lvalue
  8370. // Evaluate the arguments from last to first
  8371. int n = (int)descr->parameterTypes.GetLength() - 1;
  8372. for( ; n >= 0; n-- )
  8373. {
  8374. // All &out arguments must be deferred, except if the argument is clean, in which case the actual reference was passed in to the function
  8375. // If deferAll is set all objects passed by reference or handle must be deferred
  8376. if( (descr->parameterTypes[n].IsReference() && (descr->inOutFlags[n] & asTM_OUTREF) && !args[n]->isCleanArg) ||
  8377. (descr->parameterTypes[n].IsObject() && deferAll && (descr->parameterTypes[n].IsReference() || descr->parameterTypes[n].IsObjectHandle())) )
  8378. {
  8379. asASSERT( !(descr->parameterTypes[n].IsReference() && (descr->inOutFlags[n] == asTM_OUTREF) && !args[n]->isCleanArg) || args[n]->origExpr );
  8380. // For &inout, only store the argument if it is for a temporary variable
  8381. if( engine->ep.allowUnsafeReferences ||
  8382. descr->inOutFlags[n] != asTM_INOUTREF || args[n]->type.isTemporary )
  8383. {
  8384. // Store the argument for later processing
  8385. asSDeferredParam outParam;
  8386. outParam.argNode = args[n]->exprNode;
  8387. outParam.argType = args[n]->type;
  8388. outParam.argInOutFlags = descr->inOutFlags[n];
  8389. outParam.origExpr = args[n]->origExpr;
  8390. ctx->deferredParams.PushLast(outParam);
  8391. }
  8392. }
  8393. else
  8394. {
  8395. // Release the temporary variable now
  8396. ReleaseTemporaryVariable(args[n]->type, &ctx->bc);
  8397. }
  8398. // Move the argument's deferred expressions over to the final expression
  8399. for( asUINT m = 0; m < args[n]->deferredParams.GetLength(); m++ )
  8400. {
  8401. ctx->deferredParams.PushLast(args[n]->deferredParams[m]);
  8402. args[n]->deferredParams[m].origExpr = 0;
  8403. }
  8404. args[n]->deferredParams.SetLength(0);
  8405. }
  8406. }
  8407. void asCCompiler::ProcessDeferredParams(asCExprContext *ctx)
  8408. {
  8409. if( isProcessingDeferredParams ) return;
  8410. isProcessingDeferredParams = true;
  8411. for( asUINT n = 0; n < ctx->deferredParams.GetLength(); n++ )
  8412. {
  8413. asSDeferredParam outParam = ctx->deferredParams[n];
  8414. if( outParam.argInOutFlags < asTM_OUTREF ) // &in, or not reference
  8415. {
  8416. // Just release the variable
  8417. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  8418. }
  8419. else if( outParam.argInOutFlags == asTM_OUTREF )
  8420. {
  8421. asCExprContext *expr = outParam.origExpr;
  8422. outParam.origExpr = 0;
  8423. if( outParam.argType.dataType.IsObjectHandle() )
  8424. {
  8425. // Implicitly convert the value to a handle
  8426. if( expr->type.dataType.IsObjectHandle() )
  8427. expr->type.isExplicitHandle = true;
  8428. }
  8429. // Verify that the expression result in a lvalue, or a property accessor
  8430. if( IsLValue(expr->type) || expr->property_get || expr->property_set )
  8431. {
  8432. asCExprContext rctx(engine);
  8433. rctx.type = outParam.argType;
  8434. if( rctx.type.dataType.IsPrimitive() )
  8435. rctx.type.dataType.MakeReference(false);
  8436. else
  8437. {
  8438. rctx.bc.InstrSHORT(asBC_PSF, outParam.argType.stackOffset);
  8439. rctx.type.dataType.MakeReference(IsVariableOnHeap(outParam.argType.stackOffset));
  8440. if( expr->type.isExplicitHandle )
  8441. rctx.type.isExplicitHandle = true;
  8442. }
  8443. asCExprContext o(engine);
  8444. DoAssignment(&o, expr, &rctx, outParam.argNode, outParam.argNode, ttAssignment, outParam.argNode);
  8445. if( !o.type.dataType.IsPrimitive() ) o.bc.Instr(asBC_PopPtr);
  8446. // The assignment may itself have resulted in a new temporary variable, e.g. if
  8447. // the opAssign returns a non-reference. We must release this temporary variable
  8448. // since it won't be used
  8449. ReleaseTemporaryVariable(o.type, &o.bc);
  8450. MergeExprBytecode(ctx, &o);
  8451. }
  8452. else
  8453. {
  8454. // We must still evaluate the expression
  8455. MergeExprBytecode(ctx, expr);
  8456. if( !expr->IsVoidExpression() && (!expr->type.isConstant || expr->type.IsNullConstant()) )
  8457. ctx->bc.Instr(asBC_PopPtr);
  8458. // Give an error, except if the argument is void, null or 0 which indicate the argument is explicitly to be ignored
  8459. if( !expr->IsVoidExpression() && !expr->type.IsNullConstant() && !(expr->type.isConstant && expr->type.GetConstantData() == 0) )
  8460. Error(TXT_ARG_NOT_LVALUE, outParam.argNode);
  8461. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  8462. }
  8463. ReleaseTemporaryVariable(expr->type, &ctx->bc);
  8464. // Delete the original expression context
  8465. asDELETE(expr, asCExprContext);
  8466. }
  8467. else // &inout
  8468. {
  8469. if( outParam.argType.isTemporary )
  8470. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  8471. else if( !outParam.argType.isVariable )
  8472. {
  8473. if( outParam.argType.dataType.IsObject() &&
  8474. ((outParam.argType.dataType.GetBehaviour()->addref &&
  8475. outParam.argType.dataType.GetBehaviour()->release) ||
  8476. (outParam.argType.dataType.GetTypeInfo()->flags & asOBJ_NOCOUNT)) )
  8477. {
  8478. // Release the object handle that was taken to guarantee the reference
  8479. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  8480. }
  8481. }
  8482. }
  8483. }
  8484. ctx->deferredParams.SetLength(0);
  8485. isProcessingDeferredParams = false;
  8486. }
  8487. int asCCompiler::CompileConstructCall(asCScriptNode *node, asCExprContext *ctx)
  8488. {
  8489. // The first node is a datatype node
  8490. asCString name;
  8491. asCExprValue tempObj;
  8492. bool onHeap = true;
  8493. asCArray<int> funcs;
  8494. bool error = false;
  8495. // It is possible that the name is really a constructor
  8496. asCDataType dt;
  8497. dt = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace);
  8498. if( dt.IsPrimitive() )
  8499. {
  8500. // This is a cast to a primitive type
  8501. return CompileConversion(node, ctx);
  8502. }
  8503. if( dt.GetTypeInfo() && (dt.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE) )
  8504. {
  8505. // Types declared as implicit handle must not attempt to construct a handle
  8506. dt.MakeHandle(false);
  8507. }
  8508. // Don't accept syntax like object@(expr)
  8509. if( dt.IsObjectHandle() )
  8510. {
  8511. asCString str;
  8512. str.Format(TXT_CANT_CONSTRUCT_s_USE_REF_CAST, dt.Format(outFunc->nameSpace).AddressOf());
  8513. Error(str, node);
  8514. ctx->type.SetDummy();
  8515. return -1;
  8516. }
  8517. // Make sure the desired type can actually be instantiated
  8518. // Delegates are allowed to be created through construct calls,
  8519. // even though they cannot be instantiated as variables
  8520. if( !dt.CanBeInstantiated() && !dt.IsFuncdef() )
  8521. {
  8522. asCString str;
  8523. if( dt.IsAbstractClass() )
  8524. str.Format(TXT_ABSTRACT_CLASS_s_CANNOT_BE_INSTANTIATED, dt.Format(outFunc->nameSpace).AddressOf());
  8525. else if( dt.IsInterface() )
  8526. str.Format(TXT_INTERFACE_s_CANNOT_BE_INSTANTIATED, dt.Format(outFunc->nameSpace).AddressOf());
  8527. else
  8528. // TODO: Improve error message to explain why
  8529. str.Format(TXT_DATA_TYPE_CANT_BE_s, dt.Format(outFunc->nameSpace).AddressOf());
  8530. Error(str, node);
  8531. ctx->type.SetDummy();
  8532. return -1;
  8533. }
  8534. // Do not allow constructing non-shared types in shared functions
  8535. if( outFunc->IsShared() &&
  8536. dt.GetTypeInfo() && !dt.GetTypeInfo()->IsShared() )
  8537. {
  8538. asCString msg;
  8539. msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, dt.GetTypeInfo()->name.AddressOf());
  8540. Error(msg, node);
  8541. return -1;
  8542. }
  8543. // Compile the arguments
  8544. asCArray<asCExprContext *> args;
  8545. asCArray<asSNamedArgument> namedArgs;
  8546. asCArray<asCExprValue> temporaryVariables;
  8547. if( CompileArgumentList(node->lastChild, args, namedArgs) >= 0 )
  8548. {
  8549. // Check for a value cast behaviour
  8550. if( args.GetLength() == 1 && args[0]->type.dataType.GetTypeInfo() )
  8551. {
  8552. asCExprContext conv(engine);
  8553. conv.type = args[0]->type;
  8554. asUINT cost = ImplicitConversion(&conv, dt, node->lastChild, asIC_EXPLICIT_VAL_CAST, false);
  8555. // Don't use this if the cost is 0 because it would mean that nothing
  8556. // is done and the scipt wants a new value to be constructed
  8557. if( conv.type.dataType.IsEqualExceptRef(dt) && cost > 0 )
  8558. {
  8559. // Make sure any property accessor is already evaluated
  8560. ProcessPropertyGetAccessor(args[0], args[0]->exprNode);
  8561. ImplicitConversion(args[0], dt, node->lastChild, asIC_EXPLICIT_VAL_CAST);
  8562. ctx->bc.AddCode(&args[0]->bc);
  8563. ctx->type = args[0]->type;
  8564. asDELETE(args[0], asCExprContext);
  8565. return 0;
  8566. }
  8567. }
  8568. // Check for possible constructor/factory
  8569. name = dt.Format(outFunc->nameSpace);
  8570. asSTypeBehaviour *beh = dt.GetBehaviour();
  8571. if( !(dt.GetTypeInfo()->flags & asOBJ_REF) && !dt.IsFuncdef() )
  8572. {
  8573. funcs = beh->constructors;
  8574. // Value types and script types are allocated through the constructor
  8575. tempObj.dataType = dt;
  8576. tempObj.stackOffset = (short)AllocateVariable(dt, true);
  8577. tempObj.dataType.MakeReference(true);
  8578. tempObj.isTemporary = true;
  8579. tempObj.isVariable = true;
  8580. onHeap = IsVariableOnHeap(tempObj.stackOffset);
  8581. // Push the address of the object on the stack
  8582. if( onHeap )
  8583. ctx->bc.InstrSHORT(asBC_VAR, tempObj.stackOffset);
  8584. }
  8585. else if( beh )
  8586. funcs = beh->factories;
  8587. // Special case: Allow calling func(void) with a void expression.
  8588. if( args.GetLength() == 1 && args[0]->type.dataType == asCDataType::CreatePrimitive(ttVoid, false) )
  8589. {
  8590. // Evaluate the expression before the function call
  8591. MergeExprBytecode(ctx, args[0]);
  8592. asDELETE(args[0], asCExprContext);
  8593. args.SetLength(0);
  8594. }
  8595. // Special case: If this is an object constructor and there are no arguments use the default constructor.
  8596. // If none has been registered, just allocate the variable and push it on the stack.
  8597. if( args.GetLength() == 0 )
  8598. {
  8599. beh = tempObj.dataType.GetBehaviour();
  8600. if( beh && beh->construct == 0 && !(dt.GetTypeInfo()->flags & asOBJ_REF) )
  8601. {
  8602. // Call the default constructor
  8603. ctx->type = tempObj;
  8604. if( onHeap )
  8605. {
  8606. asASSERT(ctx->bc.GetLastInstr() == asBC_VAR);
  8607. ctx->bc.RemoveLastInstr();
  8608. }
  8609. CallDefaultConstructor(tempObj.dataType, tempObj.stackOffset, IsVariableOnHeap(tempObj.stackOffset), &ctx->bc, node);
  8610. // Push the reference on the stack
  8611. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  8612. return 0;
  8613. }
  8614. }
  8615. // Special case: If this is a construction of a delegate and the expression names an object method
  8616. if( dt.IsFuncdef() && args.GetLength() == 1 && args[0]->methodName != "" )
  8617. {
  8618. // TODO: delegate: It is possible that the argument returns a function pointer already, in which
  8619. // case no object delegate will be created, but instead a delegate for a function pointer
  8620. // In theory a simple cast would be good in this case, but this is a construct call so it
  8621. // is expected that a new object is created.
  8622. dt.MakeHandle(true);
  8623. ctx->type.Set(dt);
  8624. // The delegate must be able to hold on to a reference to the object
  8625. if( !args[0]->type.dataType.SupportHandles() )
  8626. {
  8627. Error(TXT_CANNOT_CREATE_DELEGATE_FOR_NOREF_TYPES, node);
  8628. error = true;
  8629. }
  8630. else
  8631. {
  8632. // Filter the available object methods to find the one that matches the func def
  8633. asCObjectType *type = CastToObjectType(args[0]->type.dataType.GetTypeInfo());
  8634. asCScriptFunction *bestMethod = 0;
  8635. for( asUINT n = 0; n < type->methods.GetLength(); n++ )
  8636. {
  8637. asCScriptFunction *func = engine->scriptFunctions[type->methods[n]];
  8638. if( func->name != args[0]->methodName )
  8639. continue;
  8640. // If the expression is for a const object, then only const methods should be accepted
  8641. if( args[0]->type.dataType.IsReadOnly() && !func->IsReadOnly() )
  8642. continue;
  8643. if( func->IsSignatureExceptNameAndObjectTypeEqual(CastToFuncdefType(dt.GetTypeInfo())->funcdef) )
  8644. {
  8645. bestMethod = func;
  8646. // If the expression is non-const the non-const overloaded method has priority
  8647. if( args[0]->type.dataType.IsReadOnly() == func->IsReadOnly() )
  8648. break;
  8649. }
  8650. }
  8651. if( bestMethod )
  8652. {
  8653. // The object pointer is already on the stack
  8654. MergeExprBytecode(ctx, args[0]);
  8655. // Push the function pointer as an additional argument
  8656. ctx->bc.InstrPTR(asBC_FuncPtr, bestMethod);
  8657. // Call the factory function for the delegate
  8658. asCArray<int> delegateFuncs;
  8659. builder->GetFunctionDescriptions(DELEGATE_FACTORY, delegateFuncs, engine->nameSpaces[0]);
  8660. asASSERT(delegateFuncs.GetLength() == 1 );
  8661. ctx->bc.Call(asBC_CALLSYS , delegateFuncs[0], 2*AS_PTR_SIZE);
  8662. // Store the returned delegate in a temporary variable
  8663. int returnOffset = AllocateVariable(dt, true, false);
  8664. dt.MakeReference(true);
  8665. ctx->type.SetVariable(dt, returnOffset, true);
  8666. ctx->bc.InstrSHORT(asBC_STOREOBJ, (short)returnOffset);
  8667. // Push a reference to the temporary variable on the stack
  8668. ctx->bc.InstrSHORT(asBC_PSF, (short)returnOffset);
  8669. // Clean up arguments
  8670. ReleaseTemporaryVariable(args[0]->type, &ctx->bc);
  8671. }
  8672. else
  8673. {
  8674. asCString msg;
  8675. msg.Format(TXT_NO_MATCHING_SIGNATURES_TO_s, CastToFuncdefType(dt.GetTypeInfo())->funcdef->GetDeclaration());
  8676. Error(msg.AddressOf(), node);
  8677. error = true;
  8678. }
  8679. }
  8680. // Clean-up arg
  8681. asDELETE(args[0], asCExprContext);
  8682. return error ? -1 : 0;
  8683. }
  8684. MatchFunctions(funcs, args, node, name.AddressOf(), &namedArgs, 0, false);
  8685. if( funcs.GetLength() != 1 )
  8686. {
  8687. // The error was reported by MatchFunctions()
  8688. error = true;
  8689. // Dummy value
  8690. ctx->type.SetDummy();
  8691. }
  8692. else
  8693. {
  8694. // TODO: Clean up: Merge this with MakeFunctionCall
  8695. // Add the default values for arguments not explicitly supplied
  8696. int r = CompileDefaultAndNamedArgs(node, args, funcs[0], CastToObjectType(dt.GetTypeInfo()), &namedArgs);
  8697. if( r == asSUCCESS )
  8698. {
  8699. asCByteCode objBC(engine);
  8700. PrepareFunctionCall(funcs[0], &ctx->bc, args);
  8701. MoveArgsToStack(funcs[0], &ctx->bc, args, false);
  8702. if( !(dt.GetTypeInfo()->flags & asOBJ_REF) )
  8703. {
  8704. // If the object is allocated on the stack, then call the constructor as a normal function
  8705. if( onHeap )
  8706. {
  8707. int offset = 0;
  8708. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]);
  8709. for( asUINT n = 0; n < args.GetLength(); n++ )
  8710. offset += descr->parameterTypes[n].GetSizeOnStackDWords();
  8711. ctx->bc.InstrWORD(asBC_GETREF, (asWORD)offset);
  8712. }
  8713. else
  8714. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  8715. PerformFunctionCall(funcs[0], ctx, onHeap, &args, CastToObjectType(tempObj.dataType.GetTypeInfo()));
  8716. // Add tag that the object has been initialized
  8717. ctx->bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT);
  8718. // The constructor doesn't return anything,
  8719. // so we have to manually inform the type of
  8720. // the return value
  8721. ctx->type = tempObj;
  8722. if( !onHeap )
  8723. ctx->type.dataType.MakeReference(false);
  8724. // Push the address of the object on the stack again
  8725. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  8726. }
  8727. else
  8728. {
  8729. // Call the factory to create the reference type
  8730. PerformFunctionCall(funcs[0], ctx, false, &args);
  8731. }
  8732. }
  8733. else
  8734. error = true;
  8735. }
  8736. }
  8737. else
  8738. {
  8739. // Failed to compile the argument list, set the result to the dummy type
  8740. ctx->type.SetDummy();
  8741. error = true;
  8742. }
  8743. // Cleanup
  8744. for( asUINT n = 0; n < args.GetLength(); n++ )
  8745. if( args[n] )
  8746. {
  8747. asDELETE(args[n], asCExprContext);
  8748. }
  8749. for( asUINT n = 0; n < namedArgs.GetLength(); n++ )
  8750. if( namedArgs[n].ctx )
  8751. {
  8752. asDELETE(namedArgs[n].ctx, asCExprContext);
  8753. }
  8754. return error ? -1 : 0;
  8755. }
  8756. int asCCompiler::CompileFunctionCall(asCScriptNode *node, asCExprContext *ctx, asCObjectType *objectType, bool objIsConst, const asCString &scope)
  8757. {
  8758. asCExprValue tempObj;
  8759. asCArray<int> funcs;
  8760. int localVar = -1;
  8761. bool initializeMembers = false;
  8762. asCExprContext funcExpr(engine);
  8763. asCScriptNode *nm = node->lastChild->prev;
  8764. asCString name(&script->code[nm->tokenPos], nm->tokenLength);
  8765. // First check for a local variable as it would take precedence
  8766. // Must not allow function names, nor global variables to be returned in this instance
  8767. // If objectType is set then this is a post op expression and we shouldn't look for local variables
  8768. if( objectType == 0 )
  8769. {
  8770. localVar = CompileVariableAccess(name, scope, &funcExpr, node, true, true, true);
  8771. if( localVar >= 0 &&
  8772. !(funcExpr.type.dataType.IsFuncdef() || funcExpr.type.dataType.IsObject()) &&
  8773. funcExpr.methodName == "" )
  8774. {
  8775. // The variable is not a function or object with opCall
  8776. asCString msg;
  8777. msg.Format(TXT_NOT_A_FUNC_s_IS_VAR, name.AddressOf());
  8778. Error(msg, node);
  8779. return -1;
  8780. }
  8781. // If the name matches a method name, then reset the indicator that nothing was found
  8782. if( funcExpr.methodName != "" )
  8783. localVar = -1;
  8784. }
  8785. if( localVar < 0 )
  8786. {
  8787. // If this is an expression post op, or if a class method is
  8788. // being compiled, then we should look for matching class methods
  8789. if( objectType || (outFunc && outFunc->objectType && scope != "::") )
  8790. {
  8791. // If we're compiling a constructor and the name of the function is super then
  8792. // the constructor of the base class is being called.
  8793. // super cannot be prefixed with a scope operator
  8794. if( scope == "" && m_isConstructor && name == SUPER_TOKEN )
  8795. {
  8796. // If the class is not derived from anyone else, calling super should give an error
  8797. if( outFunc && outFunc->objectType->derivedFrom )
  8798. funcs = outFunc->objectType->derivedFrom->beh.constructors;
  8799. // Must not allow calling base class' constructor multiple times
  8800. if( continueLabels.GetLength() > 0 )
  8801. {
  8802. // If a continue label is set we are in a loop
  8803. Error(TXT_CANNOT_CALL_CONSTRUCTOR_IN_LOOPS, node);
  8804. }
  8805. else if( breakLabels.GetLength() > 0 )
  8806. {
  8807. // TODO: inheritance: Should eventually allow constructors in switch statements
  8808. // If a break label is set we are either in a loop or a switch statements
  8809. Error(TXT_CANNOT_CALL_CONSTRUCTOR_IN_SWITCH, node);
  8810. }
  8811. else if( m_isConstructorCalled )
  8812. {
  8813. Error(TXT_CANNOT_CALL_CONSTRUCTOR_TWICE, node);
  8814. }
  8815. m_isConstructorCalled = true;
  8816. // We need to initialize the class members, but only after all the deferred arguments have been completed
  8817. initializeMembers = true;
  8818. }
  8819. else
  8820. {
  8821. // The scope can be used to specify the base class
  8822. builder->GetObjectMethodDescriptions(name.AddressOf(), objectType ? objectType : outFunc->objectType, funcs, objIsConst, scope, node, script);
  8823. }
  8824. // It is still possible that there is a class member of a function type or a type with opCall methods
  8825. if( funcs.GetLength() == 0 )
  8826. {
  8827. int r = CompileVariableAccess(name, scope, &funcExpr, node, true, true, true, objectType);
  8828. if( r >= 0 &&
  8829. !(funcExpr.type.dataType.IsFuncdef() || funcExpr.type.dataType.IsObject()) &&
  8830. funcExpr.methodName == "" )
  8831. {
  8832. // The variable is not a function
  8833. asCString msg;
  8834. msg.Format(TXT_NOT_A_FUNC_s_IS_VAR, name.AddressOf());
  8835. Error(msg, node);
  8836. return -1;
  8837. }
  8838. // If the name is an access property, make sure the original value isn't
  8839. // dereferenced when calling the access property as part a dot post operator
  8840. if( objectType && (funcExpr.property_get || funcExpr.property_set) && !ctx->type.dataType.IsReference() )
  8841. funcExpr.property_ref = false;
  8842. }
  8843. // If a class method is being called implicitly, then add the this pointer for the call
  8844. if( funcs.GetLength() && !objectType )
  8845. {
  8846. objectType = outFunc->objectType;
  8847. asCDataType dt = asCDataType::CreateType(objectType, false);
  8848. // The object pointer is located at stack position 0
  8849. ctx->bc.InstrSHORT(asBC_PSF, 0);
  8850. ctx->type.SetVariable(dt, 0, false);
  8851. ctx->type.dataType.MakeReference(true);
  8852. Dereference(ctx, true);
  8853. }
  8854. }
  8855. // If it is not a class method or member function pointer,
  8856. // then look for global functions or global function pointers,
  8857. // unless this is an expression post op, incase only member
  8858. // functions are expected
  8859. if( objectType == 0 && funcs.GetLength() == 0 && (!funcExpr.type.dataType.IsFuncdef() || funcExpr.type.dataType.IsObject()) )
  8860. {
  8861. // The scope is used to define the namespace
  8862. asSNameSpace *ns = DetermineNameSpace(scope);
  8863. if( ns )
  8864. {
  8865. // Search recursively in parent namespaces
  8866. while( ns && funcs.GetLength() == 0 && !funcExpr.type.dataType.IsFuncdef() )
  8867. {
  8868. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  8869. if( funcs.GetLength() == 0 )
  8870. {
  8871. int r = CompileVariableAccess(name, scope, &funcExpr, node, true, true);
  8872. if( r >= 0 &&
  8873. !(funcExpr.type.dataType.IsFuncdef() || funcExpr.type.dataType.IsObject()) &&
  8874. funcExpr.methodName == "" )
  8875. {
  8876. // The variable is not a function
  8877. asCString msg;
  8878. msg.Format(TXT_NOT_A_FUNC_s_IS_VAR, name.AddressOf());
  8879. Error(msg, node);
  8880. return -1;
  8881. }
  8882. }
  8883. ns = engine->GetParentNameSpace(ns);
  8884. }
  8885. }
  8886. else
  8887. {
  8888. asCString msg;
  8889. msg.Format(TXT_NAMESPACE_s_DOESNT_EXIST, scope.AddressOf());
  8890. Error(msg, node);
  8891. return -1;
  8892. }
  8893. }
  8894. }
  8895. if( funcs.GetLength() == 0 )
  8896. {
  8897. if( funcExpr.type.dataType.IsFuncdef() )
  8898. {
  8899. funcs.PushLast(CastToFuncdefType(funcExpr.type.dataType.GetTypeInfo())->funcdef->id);
  8900. }
  8901. else if( funcExpr.type.dataType.IsObject() )
  8902. {
  8903. // Keep information about temporary variables as deferred expression so it can be properly cleaned up after the call
  8904. if( ctx->type.isTemporary )
  8905. {
  8906. asASSERT( objectType );
  8907. asSDeferredParam deferred;
  8908. deferred.origExpr = 0;
  8909. deferred.argInOutFlags = asTM_INREF;
  8910. deferred.argNode = 0;
  8911. deferred.argType.SetVariable(ctx->type.dataType, ctx->type.stackOffset, true);
  8912. ctx->deferredParams.PushLast(deferred);
  8913. }
  8914. if( funcExpr.property_get == 0 )
  8915. Dereference(ctx, true);
  8916. // Add the bytecode for accessing the object on which opCall will be called
  8917. MergeExprBytecodeAndType(ctx, &funcExpr);
  8918. ProcessPropertyGetAccessor(ctx, node);
  8919. Dereference(ctx, true);
  8920. objectType = CastToObjectType(funcExpr.type.dataType.GetTypeInfo());
  8921. // Get the opCall methods from the object type
  8922. if( funcExpr.type.dataType.IsObjectHandle() )
  8923. objIsConst = funcExpr.type.dataType.IsHandleToConst();
  8924. else
  8925. objIsConst = funcExpr.type.dataType.IsReadOnly();
  8926. builder->GetObjectMethodDescriptions("opCall", CastToObjectType(funcExpr.type.dataType.GetTypeInfo()), funcs, objIsConst);
  8927. }
  8928. }
  8929. // If at this point no functions have been identified, then this may be a construct call
  8930. if (funcs.GetLength() == 0)
  8931. {
  8932. bool isValid = false;
  8933. asCDataType dt = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace, false, 0, false, &isValid);
  8934. if (isValid)
  8935. return CompileConstructCall(node, ctx);
  8936. }
  8937. // Compile the arguments
  8938. asCArray<asCExprContext *> args;
  8939. asCArray<asSNamedArgument> namedArgs;
  8940. bool isOK = true;
  8941. if( CompileArgumentList(node->lastChild, args, namedArgs) >= 0 )
  8942. {
  8943. // Special case: Allow calling func(void) with an expression that evaluates to no datatype, but isn't exactly 'void'
  8944. if( args.GetLength() == 1 && args[0]->type.IsVoid() && !args[0]->IsVoidExpression() )
  8945. {
  8946. // Evaluate the expression before the function call
  8947. MergeExprBytecode(ctx, args[0]);
  8948. asDELETE(args[0], asCExprContext);
  8949. args.SetLength(0);
  8950. }
  8951. MatchFunctions(funcs, args, node, name.AddressOf(), &namedArgs, objectType, objIsConst, false, true, scope);
  8952. if( funcs.GetLength() != 1 )
  8953. {
  8954. // The error was reported by MatchFunctions()
  8955. // Dummy value
  8956. ctx->type.SetDummy();
  8957. isOK = false;
  8958. }
  8959. else
  8960. {
  8961. // Add the default values for arguments not explicitly supplied
  8962. int r = CompileDefaultAndNamedArgs(node, args, funcs[0], objectType, &namedArgs);
  8963. // TODO: funcdef: Do we have to make sure the handle is stored in a temporary variable, or
  8964. // is it enough to make sure it is in a local variable?
  8965. // For function pointer we must guarantee that the function is safe, i.e.
  8966. // by first storing the function pointer in a local variable (if it isn't already in one)
  8967. if( r == asSUCCESS )
  8968. {
  8969. asCScriptFunction *func = builder->GetFunctionDescription(funcs[0]);
  8970. if( func->funcType == asFUNC_FUNCDEF )
  8971. {
  8972. if( objectType && funcExpr.property_get <= 0 )
  8973. {
  8974. // Dereference the object pointer to access the member
  8975. Dereference(ctx, true);
  8976. }
  8977. if( funcExpr.property_get > 0 )
  8978. {
  8979. ProcessPropertyGetAccessor(&funcExpr, node);
  8980. Dereference(&funcExpr, true);
  8981. }
  8982. else
  8983. {
  8984. Dereference(&funcExpr, true);
  8985. ConvertToVariable(&funcExpr);
  8986. }
  8987. // The actual function should be called as if a global function
  8988. objectType = 0;
  8989. // The function call will be made directly from the local variable so the function pointer shouldn't be on the stack
  8990. funcExpr.bc.Instr(asBC_PopPtr);
  8991. asCExprValue tmp = ctx->type;
  8992. MergeExprBytecodeAndType(ctx, &funcExpr);
  8993. ReleaseTemporaryVariable(tmp, &ctx->bc);
  8994. }
  8995. MakeFunctionCall(ctx, funcs[0], objectType, args, node, false, 0, funcExpr.type.stackOffset);
  8996. }
  8997. else
  8998. isOK = false;
  8999. }
  9000. }
  9001. else
  9002. {
  9003. // Failed to compile the argument list, set the dummy type and continue compilation
  9004. ctx->type.SetDummy();
  9005. isOK = false;
  9006. }
  9007. // Cleanup
  9008. for( asUINT n = 0; n < args.GetLength(); n++ )
  9009. if( args[n] )
  9010. {
  9011. asDELETE(args[n], asCExprContext);
  9012. }
  9013. for( asUINT n = 0; n < namedArgs.GetLength(); n++ )
  9014. if( namedArgs[n].ctx )
  9015. {
  9016. asDELETE(namedArgs[n].ctx, asCExprContext);
  9017. }
  9018. if( initializeMembers )
  9019. {
  9020. asASSERT( m_isConstructor );
  9021. // Need to initialize members here, as they may use the properties of the base class
  9022. // If there are multiple paths that call super(), then there will also be multiple
  9023. // locations with initializations of the members. It is not possible to consolidate
  9024. // these in one place, as the expressions for the initialization are evaluated where
  9025. // they are compiled, which means that they may access different variables depending
  9026. // on the scope where super() is called.
  9027. // Members that don't have an explicit initialization expression will be initialized
  9028. // beginning of the constructor as they are guaranteed not to use at the any
  9029. // members of the base class.
  9030. CompileMemberInitialization(&ctx->bc, false);
  9031. }
  9032. return isOK ? 0 : -1;
  9033. }
  9034. asSNameSpace *asCCompiler::DetermineNameSpace(const asCString &scope)
  9035. {
  9036. asSNameSpace *ns;
  9037. if( scope == "" )
  9038. {
  9039. // When compiling default argument expression the correct namespace is stored in the outFunc even for objects
  9040. if( outFunc->nameSpace->name != "" || isCompilingDefaultArg )
  9041. ns = outFunc->nameSpace;
  9042. else if( outFunc->objectType && outFunc->objectType->nameSpace->name != "" )
  9043. ns = outFunc->objectType->nameSpace;
  9044. else
  9045. ns = engine->nameSpaces[0];
  9046. }
  9047. else if( scope == "::" )
  9048. ns = engine->nameSpaces[0];
  9049. else
  9050. ns = engine->FindNameSpace(scope.AddressOf());
  9051. return ns;
  9052. }
  9053. int asCCompiler::CompileExpressionPreOp(asCScriptNode *node, asCExprContext *ctx)
  9054. {
  9055. int op = node->tokenType;
  9056. // Don't allow any prefix operators except handle on expressions that take address of class method
  9057. if( ctx->IsClassMethod() && op != ttHandle )
  9058. {
  9059. Error(TXT_INVALID_OP_ON_METHOD, node);
  9060. return -1;
  9061. }
  9062. // Don't allow any operators on void expressions
  9063. if( ctx->IsVoidExpression() )
  9064. {
  9065. Error(TXT_VOID_CANT_BE_OPERAND, node);
  9066. return -1;
  9067. }
  9068. IsVariableInitialized(&ctx->type, node);
  9069. if( op == ttHandle )
  9070. {
  9071. if( ctx->methodName != "" )
  9072. {
  9073. // Don't allow taking the handle of a handle
  9074. if( ctx->type.isExplicitHandle )
  9075. {
  9076. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node);
  9077. return -1;
  9078. }
  9079. }
  9080. else
  9081. {
  9082. // Don't allow taking handle of a handle, i.e. @@
  9083. if( ctx->type.isExplicitHandle )
  9084. {
  9085. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node);
  9086. return -1;
  9087. }
  9088. // @null is allowed even though it is implicit
  9089. if( !ctx->type.IsNullConstant() )
  9090. {
  9091. // Verify that the type allow its handle to be taken
  9092. if( !ctx->type.dataType.SupportHandles() && !ctx->type.dataType.IsObjectHandle() )
  9093. {
  9094. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node);
  9095. return -1;
  9096. }
  9097. // Objects that are not local variables are not references
  9098. // Objects allocated on the stack are also not marked as references
  9099. if( !ctx->type.dataType.IsReference() &&
  9100. !((ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) && !ctx->type.isVariable) &&
  9101. !(ctx->type.isVariable && !IsVariableOnHeap(ctx->type.stackOffset)) )
  9102. {
  9103. Error(TXT_NOT_VALID_REFERENCE, node);
  9104. return -1;
  9105. }
  9106. // Convert the expression to a handle
  9107. if( !ctx->type.dataType.IsObjectHandle() && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) )
  9108. {
  9109. asCDataType to = ctx->type.dataType;
  9110. to.MakeHandle(true);
  9111. to.MakeReference(true);
  9112. to.MakeHandleToConst(ctx->type.dataType.IsReadOnly());
  9113. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV, true, false);
  9114. asASSERT( ctx->type.dataType.IsObjectHandle() );
  9115. }
  9116. else if( ctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE )
  9117. {
  9118. // For the ASHANDLE type we'll simply set the expression as a handle
  9119. ctx->type.dataType.MakeHandle(true);
  9120. }
  9121. }
  9122. }
  9123. // Mark the expression as an explicit handle to avoid implicit conversions to non-handle expressions
  9124. ctx->type.isExplicitHandle = true;
  9125. }
  9126. else if( (op == ttMinus || op == ttPlus || op == ttBitNot || op == ttInc || op == ttDec) && ctx->type.dataType.IsObject() )
  9127. {
  9128. // Look for the appropriate method
  9129. // There is no overloadable operator for unary plus
  9130. const char *opName = 0;
  9131. switch( op )
  9132. {
  9133. case ttMinus: opName = "opNeg"; break;
  9134. case ttBitNot: opName = "opCom"; break;
  9135. case ttInc: opName = "opPreInc"; break;
  9136. case ttDec: opName = "opPreDec"; break;
  9137. }
  9138. if( opName )
  9139. {
  9140. // TODO: Should convert this to something similar to CompileOverloadedDualOperator2
  9141. ProcessPropertyGetAccessor(ctx, node);
  9142. // 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
  9143. // Find the correct method
  9144. bool isConst = ctx->type.dataType.IsObjectConst();
  9145. asCArray<int> funcs;
  9146. asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  9147. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  9148. {
  9149. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  9150. if( func->name == opName &&
  9151. func->parameterTypes.GetLength() == 0 &&
  9152. (!isConst || func->isReadOnly) )
  9153. {
  9154. funcs.PushLast(func->id);
  9155. }
  9156. }
  9157. // Did we find the method?
  9158. if( funcs.GetLength() == 1 )
  9159. {
  9160. asCArray<asCExprContext *> args;
  9161. MakeFunctionCall(ctx, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
  9162. return 0;
  9163. }
  9164. else if( funcs.GetLength() == 0 )
  9165. {
  9166. asCString str;
  9167. str = asCString(opName) + "()";
  9168. if( isConst )
  9169. str += " const";
  9170. str.Format(TXT_FUNCTION_s_NOT_FOUND, str.AddressOf());
  9171. Error(str, node);
  9172. ctx->type.SetDummy();
  9173. return -1;
  9174. }
  9175. else if( funcs.GetLength() > 1 )
  9176. {
  9177. Error(TXT_MORE_THAN_ONE_MATCHING_OP, node);
  9178. PrintMatchingFuncs(funcs, node);
  9179. ctx->type.SetDummy();
  9180. return -1;
  9181. }
  9182. }
  9183. else if( op == ttPlus )
  9184. {
  9185. Error(TXT_ILLEGAL_OPERATION, node);
  9186. ctx->type.SetDummy();
  9187. return -1;
  9188. }
  9189. }
  9190. else if( op == ttPlus || op == ttMinus )
  9191. {
  9192. // This is only for primitives. Objects are treated in the above block
  9193. // Make sure the type is a math type
  9194. if( !(ctx->type.dataType.IsIntegerType() ||
  9195. ctx->type.dataType.IsUnsignedType() ||
  9196. ctx->type.dataType.IsFloatType() ||
  9197. ctx->type.dataType.IsDoubleType() ) )
  9198. {
  9199. Error(TXT_ILLEGAL_OPERATION, node);
  9200. return -1;
  9201. }
  9202. ProcessPropertyGetAccessor(ctx, node);
  9203. asCDataType to = ctx->type.dataType;
  9204. if( ctx->type.dataType.IsUnsignedType() )
  9205. {
  9206. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  9207. to = asCDataType::CreatePrimitive(ttInt8, false);
  9208. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  9209. to = asCDataType::CreatePrimitive(ttInt16, false);
  9210. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 )
  9211. to = asCDataType::CreatePrimitive(ttInt, false);
  9212. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 8 )
  9213. to = asCDataType::CreatePrimitive(ttInt64, false);
  9214. else
  9215. {
  9216. Error(TXT_INVALID_TYPE, node);
  9217. return -1;
  9218. }
  9219. }
  9220. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  9221. // Use an explicit conversion in case of constants to avoid unnecessary warning about change of sign
  9222. ImplicitConversion(ctx, to, node, ctx->type.isConstant ? asIC_EXPLICIT_VAL_CAST : asIC_IMPLICIT_CONV);
  9223. if( !ctx->type.isConstant )
  9224. {
  9225. ConvertToTempVariable(ctx);
  9226. asASSERT(!ctx->type.isLValue);
  9227. if( op == ttMinus )
  9228. {
  9229. if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  9230. ctx->bc.InstrSHORT(asBC_NEGi, ctx->type.stackOffset);
  9231. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  9232. ctx->bc.InstrSHORT(asBC_NEGi64, ctx->type.stackOffset);
  9233. else if( ctx->type.dataType.IsFloatType() )
  9234. ctx->bc.InstrSHORT(asBC_NEGf, ctx->type.stackOffset);
  9235. else if( ctx->type.dataType.IsDoubleType() )
  9236. ctx->bc.InstrSHORT(asBC_NEGd, ctx->type.stackOffset);
  9237. else
  9238. {
  9239. Error(TXT_ILLEGAL_OPERATION, node);
  9240. return -1;
  9241. }
  9242. return 0;
  9243. }
  9244. }
  9245. else
  9246. {
  9247. if( op == ttMinus )
  9248. {
  9249. if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  9250. ctx->type.SetConstantDW(-(int)ctx->type.GetConstantDW());
  9251. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  9252. ctx->type.SetConstantQW(-(asINT64)ctx->type.GetConstantQW());
  9253. else if( ctx->type.dataType.IsFloatType() )
  9254. ctx->type.SetConstantF(-ctx->type.GetConstantF());
  9255. else if( ctx->type.dataType.IsDoubleType() )
  9256. ctx->type.SetConstantD(-ctx->type.GetConstantD());
  9257. else
  9258. {
  9259. Error(TXT_ILLEGAL_OPERATION, node);
  9260. return -1;
  9261. }
  9262. return 0;
  9263. }
  9264. }
  9265. }
  9266. else if( op == ttNot )
  9267. {
  9268. // Allow value types to be converted to bool using 'bool opImplConv()'
  9269. if( ctx->type.dataType.GetTypeInfo() && (ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
  9270. ImplicitConversion(ctx, asCDataType::CreatePrimitive(ttBool, false), node, asIC_IMPLICIT_CONV);
  9271. if( ctx->type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  9272. {
  9273. if( ctx->type.isConstant )
  9274. {
  9275. #if AS_SIZEOF_BOOL == 1
  9276. ctx->type.SetConstantB(ctx->type.GetConstantB() == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  9277. #else
  9278. ctx->type.SetConstantDW(ctx->type.GetConstantDW() == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  9279. #endif
  9280. return 0;
  9281. }
  9282. ProcessPropertyGetAccessor(ctx, node);
  9283. ConvertToTempVariable(ctx);
  9284. asASSERT(!ctx->type.isLValue);
  9285. ctx->bc.InstrSHORT(asBC_NOT, ctx->type.stackOffset);
  9286. }
  9287. else
  9288. {
  9289. Error(TXT_ILLEGAL_OPERATION, node);
  9290. return -1;
  9291. }
  9292. }
  9293. else if( op == ttBitNot )
  9294. {
  9295. ProcessPropertyGetAccessor(ctx, node);
  9296. asCDataType to = ctx->type.dataType;
  9297. if( ctx->type.dataType.IsIntegerType() )
  9298. {
  9299. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  9300. to = asCDataType::CreatePrimitive(ttUInt8, false);
  9301. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  9302. to = asCDataType::CreatePrimitive(ttUInt16, false);
  9303. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 )
  9304. to = asCDataType::CreatePrimitive(ttUInt, false);
  9305. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 8 )
  9306. to = asCDataType::CreatePrimitive(ttUInt64, false);
  9307. else
  9308. {
  9309. Error(TXT_INVALID_TYPE, node);
  9310. return -1;
  9311. }
  9312. }
  9313. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  9314. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV);
  9315. if( ctx->type.dataType.IsUnsignedType() )
  9316. {
  9317. if( ctx->type.isConstant )
  9318. {
  9319. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  9320. ctx->type.SetConstantB(~ctx->type.GetConstantB());
  9321. else if (ctx->type.dataType.GetSizeInMemoryBytes() == 2)
  9322. ctx->type.SetConstantW(~ctx->type.GetConstantW());
  9323. else if (ctx->type.dataType.GetSizeInMemoryBytes() == 4)
  9324. ctx->type.SetConstantDW(~ctx->type.GetConstantDW());
  9325. else
  9326. ctx->type.SetConstantQW(~ctx->type.GetConstantQW());
  9327. return 0;
  9328. }
  9329. ConvertToTempVariable(ctx);
  9330. asASSERT(!ctx->type.isLValue);
  9331. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  9332. ctx->bc.InstrSHORT(asBC_BNOT, ctx->type.stackOffset);
  9333. else
  9334. ctx->bc.InstrSHORT(asBC_BNOT64, ctx->type.stackOffset);
  9335. }
  9336. else
  9337. {
  9338. Error(TXT_ILLEGAL_OPERATION, node);
  9339. return -1;
  9340. }
  9341. }
  9342. else if( op == ttInc || op == ttDec )
  9343. {
  9344. // Need a reference to the primitive that will be updated
  9345. // The result of this expression is the same reference as before
  9346. // Make sure the reference isn't a temporary variable
  9347. if( ctx->type.isTemporary )
  9348. {
  9349. Error(TXT_REF_IS_TEMP, node);
  9350. return -1;
  9351. }
  9352. if( ctx->type.dataType.IsReadOnly() )
  9353. {
  9354. Error(TXT_REF_IS_READ_ONLY, node);
  9355. return -1;
  9356. }
  9357. if( ctx->property_get || ctx->property_set )
  9358. {
  9359. Error(TXT_INVALID_REF_PROP_ACCESS, node);
  9360. return -1;
  9361. }
  9362. if( !ctx->type.isLValue )
  9363. {
  9364. Error(TXT_NOT_LVALUE, node);
  9365. return -1;
  9366. }
  9367. if( ctx->type.isVariable && !ctx->type.dataType.IsReference() )
  9368. ConvertToReference(ctx);
  9369. else if( !ctx->type.dataType.IsReference() )
  9370. {
  9371. Error(TXT_NOT_VALID_REFERENCE, node);
  9372. return -1;
  9373. }
  9374. if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt64, false)) ||
  9375. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt64, false)) )
  9376. {
  9377. if( op == ttInc )
  9378. ctx->bc.Instr(asBC_INCi64);
  9379. else
  9380. ctx->bc.Instr(asBC_DECi64);
  9381. }
  9382. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt, false)) ||
  9383. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt, false)) )
  9384. {
  9385. if( op == ttInc )
  9386. ctx->bc.Instr(asBC_INCi);
  9387. else
  9388. ctx->bc.Instr(asBC_DECi);
  9389. }
  9390. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt16, false)) ||
  9391. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt16, false)) )
  9392. {
  9393. if( op == ttInc )
  9394. ctx->bc.Instr(asBC_INCi16);
  9395. else
  9396. ctx->bc.Instr(asBC_DECi16);
  9397. }
  9398. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt8, false)) ||
  9399. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt8, false)) )
  9400. {
  9401. if( op == ttInc )
  9402. ctx->bc.Instr(asBC_INCi8);
  9403. else
  9404. ctx->bc.Instr(asBC_DECi8);
  9405. }
  9406. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttFloat, false)) )
  9407. {
  9408. if( op == ttInc )
  9409. ctx->bc.Instr(asBC_INCf);
  9410. else
  9411. ctx->bc.Instr(asBC_DECf);
  9412. }
  9413. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttDouble, false)) )
  9414. {
  9415. if( op == ttInc )
  9416. ctx->bc.Instr(asBC_INCd);
  9417. else
  9418. ctx->bc.Instr(asBC_DECd);
  9419. }
  9420. else
  9421. {
  9422. Error(TXT_ILLEGAL_OPERATION, node);
  9423. return -1;
  9424. }
  9425. }
  9426. else
  9427. {
  9428. // Unknown operator
  9429. asASSERT(false);
  9430. return -1;
  9431. }
  9432. return 0;
  9433. }
  9434. void asCCompiler::ConvertToReference(asCExprContext *ctx)
  9435. {
  9436. if( ctx->type.isVariable && !ctx->type.dataType.IsReference() )
  9437. {
  9438. ctx->bc.InstrSHORT(asBC_LDV, ctx->type.stackOffset);
  9439. ctx->type.dataType.MakeReference(true);
  9440. ctx->type.SetVariable(ctx->type.dataType, ctx->type.stackOffset, ctx->type.isTemporary);
  9441. }
  9442. }
  9443. int asCCompiler::FindPropertyAccessor(const asCString &name, asCExprContext *ctx, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess)
  9444. {
  9445. return FindPropertyAccessor(name, ctx, 0, node, ns, isThisAccess);
  9446. }
  9447. int asCCompiler::FindPropertyAccessor(const asCString &name, asCExprContext *ctx, asCExprContext *arg, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess)
  9448. {
  9449. if( engine->ep.propertyAccessorMode == 0 )
  9450. {
  9451. // Property accessors have been disabled by the application
  9452. return 0;
  9453. }
  9454. int getId = 0, setId = 0;
  9455. asCString getName = "get_" + name;
  9456. asCString setName = "set_" + name;
  9457. asCArray<int> multipleGetFuncs, multipleSetFuncs;
  9458. if( ctx->type.dataType.IsObject() )
  9459. {
  9460. asASSERT( ns == 0 );
  9461. // Don't look for property accessors in script classes if the script
  9462. // property accessors have been disabled by the application
  9463. if( !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) ||
  9464. engine->ep.propertyAccessorMode == 2 )
  9465. {
  9466. // Check if the object has any methods with the corresponding accessor name(s)
  9467. asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  9468. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  9469. {
  9470. asCScriptFunction *f = engine->scriptFunctions[ot->methods[n]];
  9471. // TODO: The type of the parameter should match the argument (unless the arg is a dummy)
  9472. if( f->name == getName && (int)f->parameterTypes.GetLength() == (arg?1:0) )
  9473. {
  9474. if( getId == 0 )
  9475. getId = ot->methods[n];
  9476. else
  9477. {
  9478. if( multipleGetFuncs.GetLength() == 0 )
  9479. multipleGetFuncs.PushLast(getId);
  9480. multipleGetFuncs.PushLast(ot->methods[n]);
  9481. }
  9482. }
  9483. // TODO: getset: If the parameter is a reference, it must not be an out reference. Should we allow inout ref?
  9484. if( f->name == setName && (int)f->parameterTypes.GetLength() == (arg?2:1) )
  9485. {
  9486. if( setId == 0 )
  9487. setId = ot->methods[n];
  9488. else
  9489. {
  9490. if( multipleSetFuncs.GetLength() == 0 )
  9491. multipleSetFuncs.PushLast(setId);
  9492. multipleSetFuncs.PushLast(ot->methods[n]);
  9493. }
  9494. }
  9495. }
  9496. }
  9497. }
  9498. else
  9499. {
  9500. asASSERT( ns != 0 );
  9501. // Look for appropriate global functions.
  9502. asCArray<int> funcs;
  9503. asUINT n;
  9504. builder->GetFunctionDescriptions(getName.AddressOf(), funcs, ns);
  9505. for( n = 0; n < funcs.GetLength(); n++ )
  9506. {
  9507. asCScriptFunction *f = builder->GetFunctionDescription(funcs[n]);
  9508. // TODO: The type of the parameter should match the argument (unless the arg is a dummy)
  9509. if( (int)f->parameterTypes.GetLength() == (arg?1:0) )
  9510. {
  9511. if( getId == 0 )
  9512. getId = funcs[n];
  9513. else
  9514. {
  9515. if( multipleGetFuncs.GetLength() == 0 )
  9516. multipleGetFuncs.PushLast(getId);
  9517. multipleGetFuncs.PushLast(funcs[n]);
  9518. }
  9519. }
  9520. }
  9521. funcs.SetLength(0);
  9522. builder->GetFunctionDescriptions(setName.AddressOf(), funcs, ns);
  9523. for( n = 0; n < funcs.GetLength(); n++ )
  9524. {
  9525. asCScriptFunction *f = builder->GetFunctionDescription(funcs[n]);
  9526. // TODO: getset: If the parameter is a reference, it must not be an out reference. Should we allow inout ref?
  9527. if( (int)f->parameterTypes.GetLength() == (arg?2:1) )
  9528. {
  9529. if( setId == 0 )
  9530. setId = funcs[n];
  9531. else
  9532. {
  9533. if( multipleSetFuncs.GetLength() == 0 )
  9534. multipleSetFuncs.PushLast(getId);
  9535. multipleSetFuncs.PushLast(funcs[n]);
  9536. }
  9537. }
  9538. }
  9539. }
  9540. bool isConst = ctx->type.dataType.IsObjectConst();
  9541. // Check for multiple matches
  9542. if( multipleGetFuncs.GetLength() > 0 )
  9543. {
  9544. // Filter the list by constness
  9545. FilterConst(multipleGetFuncs, !isConst);
  9546. if( multipleGetFuncs.GetLength() > 1 )
  9547. {
  9548. asCString str;
  9549. str.Format(TXT_MULTIPLE_PROP_GET_ACCESSOR_FOR_s, name.AddressOf());
  9550. Error(str, node);
  9551. PrintMatchingFuncs(multipleGetFuncs, node);
  9552. return -1;
  9553. }
  9554. else
  9555. {
  9556. // The id may have changed
  9557. getId = multipleGetFuncs[0];
  9558. }
  9559. }
  9560. if( multipleSetFuncs.GetLength() > 0 )
  9561. {
  9562. // Filter the list by constness
  9563. FilterConst(multipleSetFuncs, !isConst);
  9564. if( multipleSetFuncs.GetLength() > 1 )
  9565. {
  9566. asCString str;
  9567. str.Format(TXT_MULTIPLE_PROP_SET_ACCESSOR_FOR_s, name.AddressOf());
  9568. Error(str, node);
  9569. PrintMatchingFuncs(multipleSetFuncs, node);
  9570. return -1;
  9571. }
  9572. else
  9573. {
  9574. // The id may have changed
  9575. setId = multipleSetFuncs[0];
  9576. }
  9577. }
  9578. // Check for type compatibility between get and set accessor
  9579. if( getId && setId )
  9580. {
  9581. asCScriptFunction *getFunc = builder->GetFunctionDescription(getId);
  9582. asCScriptFunction *setFunc = builder->GetFunctionDescription(setId);
  9583. // It is permitted for a getter to return a handle and the setter to take a reference
  9584. int idx = (arg?1:0);
  9585. if( !getFunc->returnType.IsEqualExceptRefAndConst(setFunc->parameterTypes[idx]) &&
  9586. !((getFunc->returnType.IsObjectHandle() && !setFunc->parameterTypes[idx].IsObjectHandle()) &&
  9587. (getFunc->returnType.GetTypeInfo() == setFunc->parameterTypes[idx].GetTypeInfo())) )
  9588. {
  9589. asCString str;
  9590. str.Format(TXT_GET_SET_ACCESSOR_TYPE_MISMATCH_FOR_s, name.AddressOf());
  9591. Error(str, node);
  9592. asCArray<int> funcs;
  9593. funcs.PushLast(getId);
  9594. funcs.PushLast(setId);
  9595. PrintMatchingFuncs(funcs, node);
  9596. return -1;
  9597. }
  9598. }
  9599. // Check if we are within one of the accessors
  9600. int realGetId = getId;
  9601. int realSetId = setId;
  9602. if( outFunc->objectType && isThisAccess )
  9603. {
  9604. // The property accessors would be virtual functions, so we need to find the real implementation
  9605. asCScriptFunction *getFunc = getId ? builder->GetFunctionDescription(getId) : 0;
  9606. if( getFunc &&
  9607. getFunc->funcType == asFUNC_VIRTUAL &&
  9608. outFunc->objectType->DerivesFrom(getFunc->objectType) )
  9609. realGetId = outFunc->objectType->virtualFunctionTable[getFunc->vfTableIdx]->id;
  9610. asCScriptFunction *setFunc = setId ? builder->GetFunctionDescription(setId) : 0;
  9611. if( setFunc &&
  9612. setFunc->funcType == asFUNC_VIRTUAL &&
  9613. outFunc->objectType->DerivesFrom(setFunc->objectType) )
  9614. realSetId = outFunc->objectType->virtualFunctionTable[setFunc->vfTableIdx]->id;
  9615. }
  9616. // Avoid recursive call, by not treating this as a property accessor call.
  9617. // This will also allow having the real property with the same name as the accessors.
  9618. if( (isThisAccess || outFunc->objectType == 0) &&
  9619. ((realGetId && realGetId == outFunc->id) ||
  9620. (realSetId && realSetId == outFunc->id)) )
  9621. {
  9622. getId = 0;
  9623. setId = 0;
  9624. }
  9625. // Check if the application has disabled script written property accessors
  9626. if( engine->ep.propertyAccessorMode == 1 )
  9627. {
  9628. if( getId && builder->GetFunctionDescription(getId)->funcType != asFUNC_SYSTEM )
  9629. getId = 0;
  9630. if( setId && builder->GetFunctionDescription(setId)->funcType != asFUNC_SYSTEM )
  9631. setId = 0;
  9632. }
  9633. if( getId || setId )
  9634. {
  9635. // Property accessors were found, but we don't know which is to be used yet, so
  9636. // we just prepare the bytecode for the method call, and then store the function ids
  9637. // so that the right one can be used when we get there.
  9638. ctx->property_get = getId;
  9639. ctx->property_set = setId;
  9640. bool isHandleSafe = ctx->type.isHandleSafe;
  9641. if( ctx->type.dataType.IsObject() )
  9642. {
  9643. // If the object is read-only then we need to remember that
  9644. if( (!ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReadOnly()) ||
  9645. (ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsHandleToConst()) )
  9646. ctx->property_const = true;
  9647. else
  9648. ctx->property_const = false;
  9649. // If the object is a handle then we need to remember that
  9650. ctx->property_handle = ctx->type.dataType.IsObjectHandle();
  9651. ctx->property_ref = ctx->type.dataType.IsReference();
  9652. }
  9653. // The setter's parameter type is used as the property type,
  9654. // unless only the getter is available
  9655. asCDataType dt;
  9656. if( setId )
  9657. dt = builder->GetFunctionDescription(setId)->parameterTypes[(arg?1:0)];
  9658. else
  9659. dt = builder->GetFunctionDescription(getId)->returnType;
  9660. // Just change the type, the context must still maintain information
  9661. // about previous variable offset and the indicator of temporary variable.
  9662. int offset = ctx->type.stackOffset;
  9663. bool isTemp = ctx->type.isTemporary;
  9664. ctx->type.Set(dt);
  9665. ctx->type.stackOffset = (short)offset;
  9666. ctx->type.isTemporary = isTemp;
  9667. ctx->exprNode = node;
  9668. // Remember if the object is safe, so the invocation of the property
  9669. // accessor doesn't needlessly make a safe copy of the handle
  9670. ctx->type.isHandleSafe = isHandleSafe;
  9671. // Store the argument for later use
  9672. if( arg )
  9673. {
  9674. ctx->property_arg = asNEW(asCExprContext)(engine);
  9675. if( ctx->property_arg == 0 )
  9676. {
  9677. // Out of memory
  9678. return -1;
  9679. }
  9680. MergeExprBytecodeAndType(ctx->property_arg, arg);
  9681. }
  9682. return 1;
  9683. }
  9684. // No accessor was found
  9685. return 0;
  9686. }
  9687. int asCCompiler::ProcessPropertySetAccessor(asCExprContext *ctx, asCExprContext *arg, asCScriptNode *node)
  9688. {
  9689. // TODO: A lot of this code is similar to ProcessPropertyGetAccessor. Can we unify them?
  9690. if( !ctx->property_set )
  9691. {
  9692. Error(TXT_PROPERTY_HAS_NO_SET_ACCESSOR, node);
  9693. return -1;
  9694. }
  9695. asCScriptFunction *func = builder->GetFunctionDescription(ctx->property_set);
  9696. // Make sure the arg match the property
  9697. asCArray<int> funcs;
  9698. funcs.PushLast(ctx->property_set);
  9699. asCArray<asCExprContext *> args;
  9700. if( ctx->property_arg )
  9701. args.PushLast(ctx->property_arg);
  9702. args.PushLast(arg);
  9703. MatchFunctions(funcs, args, node, func->GetName(), 0, func->objectType, ctx->property_const);
  9704. if( funcs.GetLength() == 0 )
  9705. {
  9706. // MatchFunctions already reported the error
  9707. if( ctx->property_arg )
  9708. {
  9709. asDELETE(ctx->property_arg, asCExprContext);
  9710. ctx->property_arg = 0;
  9711. }
  9712. return -1;
  9713. }
  9714. if( func->objectType )
  9715. {
  9716. // Setup the context with the original type so the method call gets built correctly
  9717. ctx->type.dataType = asCDataType::CreateType(func->objectType, ctx->property_const);
  9718. if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
  9719. if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
  9720. // Don't allow the call if the object is read-only and the property accessor is not const
  9721. if( ctx->property_const && !func->isReadOnly )
  9722. {
  9723. Error(TXT_NON_CONST_METHOD_ON_CONST_OBJ, node);
  9724. asCArray<int> funcCandidates;
  9725. funcCandidates.PushLast(ctx->property_set);
  9726. PrintMatchingFuncs(funcCandidates, node);
  9727. }
  9728. }
  9729. // Call the accessor
  9730. MakeFunctionCall(ctx, ctx->property_set, func->objectType, args, node);
  9731. ctx->property_get = 0;
  9732. ctx->property_set = 0;
  9733. if( ctx->property_arg )
  9734. {
  9735. asDELETE(ctx->property_arg, asCExprContext);
  9736. ctx->property_arg = 0;
  9737. }
  9738. return 0;
  9739. }
  9740. int asCCompiler::ProcessPropertyGetSetAccessor(asCExprContext *ctx, asCExprContext *lctx, asCExprContext *rctx, eTokenType op, asCScriptNode *errNode)
  9741. {
  9742. // TODO: Perhaps it might be interesting to allow the definition of compound setters for better
  9743. // performance, e.g. set_add_prop, set_mul_prop, etc. With these it would also be possible
  9744. // to support value types, since it would be a single call
  9745. // Compound assignment for indexed property accessors is not supported yet
  9746. if( lctx->property_arg != 0 )
  9747. {
  9748. // Process the property to free the memory
  9749. ProcessPropertySetAccessor(lctx, rctx, errNode);
  9750. Error(TXT_COMPOUND_ASGN_WITH_IDX_PROP, errNode);
  9751. return -1;
  9752. }
  9753. // Compound assignments require both get and set accessors
  9754. if( lctx->property_set == 0 || lctx->property_get == 0 )
  9755. {
  9756. // Process the property to free the memory
  9757. ProcessPropertySetAccessor(lctx, rctx, errNode);
  9758. Error(TXT_COMPOUND_ASGN_REQUIRE_GET_SET, errNode);
  9759. return -1;
  9760. }
  9761. // Property accessors on value types (or scoped references types) are not supported since
  9762. // it is not possible to guarantee that the object will stay alive between the two calls
  9763. asCScriptFunction *func = engine->scriptFunctions[lctx->property_set];
  9764. if( func->objectType && (func->objectType->flags & (asOBJ_VALUE | asOBJ_SCOPED)) )
  9765. {
  9766. // Process the property to free the memory
  9767. ProcessPropertySetAccessor(lctx, rctx, errNode);
  9768. Error(TXT_COMPOUND_ASGN_ON_VALUE_TYPE, errNode);
  9769. return -1;
  9770. }
  9771. // Translate the compound assignment to the corresponding dual operator
  9772. switch( op )
  9773. {
  9774. case ttAddAssign: op = ttPlus; break;
  9775. case ttSubAssign: op = ttMinus; break;
  9776. case ttMulAssign: op = ttStar; break;
  9777. case ttDivAssign: op = ttSlash; break;
  9778. case ttModAssign: op = ttPercent; break;
  9779. case ttPowAssign: op = ttStarStar; break;
  9780. case ttAndAssign: op = ttAmp; break;
  9781. case ttOrAssign: op = ttBitOr; break;
  9782. case ttXorAssign: op = ttBitXor; break;
  9783. case ttShiftLeftAssign: op = ttBitShiftLeft; break;
  9784. case ttShiftRightAAssign: op = ttBitShiftRightArith; break;
  9785. case ttShiftRightLAssign: op = ttBitShiftRight; break;
  9786. default: op = ttUnrecognizedToken; break;
  9787. }
  9788. if( op == ttUnrecognizedToken )
  9789. {
  9790. // Shouldn't happen
  9791. asASSERT(false);
  9792. // Process the property to free the memory
  9793. ProcessPropertySetAccessor(lctx, rctx, errNode);
  9794. return -1;
  9795. }
  9796. asCExprContext before(engine);
  9797. if( func->objectType && (func->objectType->flags & (asOBJ_REF|asOBJ_SCOPED)) == asOBJ_REF )
  9798. {
  9799. // Keep a reference to the object in a local variable
  9800. before.bc.AddCode(&lctx->bc);
  9801. asUINT len = reservedVariables.GetLength();
  9802. rctx->bc.GetVarsUsed(reservedVariables);
  9803. before.bc.GetVarsUsed(reservedVariables);
  9804. asCDataType dt = asCDataType::CreateObjectHandle(func->objectType, false);
  9805. int offset = AllocateVariable(dt, true);
  9806. reservedVariables.SetLength(len);
  9807. before.type.SetVariable(dt, offset, true);
  9808. if( lctx->property_ref )
  9809. before.bc.Instr(asBC_RDSPtr);
  9810. before.bc.InstrSHORT(asBC_PSF, (short)offset);
  9811. before.bc.InstrPTR(asBC_REFCPY, func->objectType);
  9812. before.bc.Instr(asBC_PopPtr);
  9813. if( lctx->type.isTemporary )
  9814. {
  9815. // Add the release of the temporary variable as a deferred expression
  9816. asSDeferredParam deferred;
  9817. deferred.origExpr = 0;
  9818. deferred.argInOutFlags = asTM_INREF;
  9819. deferred.argNode = 0;
  9820. deferred.argType.SetVariable(ctx->type.dataType, lctx->type.stackOffset, true);
  9821. before.deferredParams.PushLast(deferred);
  9822. }
  9823. // Update the left expression to use the local variable
  9824. lctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  9825. lctx->type.stackOffset = (short)offset;
  9826. lctx->property_ref = true;
  9827. // Don't release the temporary variable too early
  9828. lctx->type.isTemporary = false;
  9829. ctx->bc.AddCode(&before.bc);
  9830. }
  9831. // Keep the original information on the property
  9832. asCExprContext llctx(engine);
  9833. llctx.type = lctx->type;
  9834. llctx.property_arg = lctx->property_arg;
  9835. llctx.property_const = lctx->property_const;
  9836. llctx.property_get = lctx->property_get;
  9837. llctx.property_handle = lctx->property_handle;
  9838. llctx.property_ref = lctx->property_ref;
  9839. llctx.property_set = lctx->property_set;
  9840. // Compile the dual operator using the get accessor
  9841. CompileOperator(errNode, lctx, rctx, ctx, op, false);
  9842. // If we made a local variable to hold the reference it must be reused
  9843. if( before.type.stackOffset )
  9844. llctx.bc.InstrSHORT(asBC_PSF, before.type.stackOffset);
  9845. // Compile the assignment using the set accessor
  9846. ProcessPropertySetAccessor(&llctx, ctx, errNode);
  9847. MergeExprBytecodeAndType(ctx, &llctx);
  9848. if( before.type.stackOffset )
  9849. ReleaseTemporaryVariable(before.type.stackOffset, &ctx->bc);
  9850. asASSERT( ctx->deferredParams.GetLength() == 0 );
  9851. ctx->deferredParams = before.deferredParams;
  9852. ProcessDeferredParams(ctx);
  9853. return 0;
  9854. }
  9855. void asCCompiler::ProcessPropertyGetAccessor(asCExprContext *ctx, asCScriptNode *node)
  9856. {
  9857. // If no property accessor has been prepared then don't do anything
  9858. if( !ctx->property_get && !ctx->property_set )
  9859. return;
  9860. if( !ctx->property_get )
  9861. {
  9862. // Raise error on missing accessor
  9863. Error(TXT_PROPERTY_HAS_NO_GET_ACCESSOR, node);
  9864. ctx->type.SetDummy();
  9865. return;
  9866. }
  9867. asCExprValue objType = ctx->type;
  9868. asCScriptFunction *func = builder->GetFunctionDescription(ctx->property_get);
  9869. // Make sure the arg match the property
  9870. asCArray<int> funcs;
  9871. funcs.PushLast(ctx->property_get);
  9872. asCArray<asCExprContext *> args;
  9873. if( ctx->property_arg )
  9874. args.PushLast(ctx->property_arg);
  9875. MatchFunctions(funcs, args, node, func->GetName(), 0, func->objectType, ctx->property_const);
  9876. if( funcs.GetLength() == 0 )
  9877. {
  9878. // MatchFunctions already reported the error
  9879. if( ctx->property_arg )
  9880. {
  9881. asDELETE(ctx->property_arg, asCExprContext);
  9882. ctx->property_arg = 0;
  9883. }
  9884. ctx->type.SetDummy();
  9885. return;
  9886. }
  9887. if( func->objectType )
  9888. {
  9889. // Setup the context with the original type so the method call gets built correctly
  9890. ctx->type.dataType = asCDataType::CreateType(func->objectType, ctx->property_const);
  9891. if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
  9892. if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
  9893. // Don't allow the call if the object is read-only and the property accessor is not const
  9894. if( ctx->property_const && !func->isReadOnly )
  9895. {
  9896. Error(TXT_NON_CONST_METHOD_ON_CONST_OBJ, node);
  9897. asCArray<int> funcCandidates;
  9898. funcCandidates.PushLast(ctx->property_get);
  9899. PrintMatchingFuncs(funcCandidates, node);
  9900. }
  9901. }
  9902. // The explicit handle flag must be remembered
  9903. bool isExplicitHandle = ctx->type.isExplicitHandle;
  9904. // Call the accessor
  9905. MakeFunctionCall(ctx, ctx->property_get, func->objectType, args, node);
  9906. if( isExplicitHandle )
  9907. ctx->type.isExplicitHandle = true;
  9908. // Clear the property get/set ids
  9909. ctx->property_get = 0;
  9910. ctx->property_set = 0;
  9911. if( ctx->property_arg )
  9912. {
  9913. asDELETE(ctx->property_arg, asCExprContext);
  9914. ctx->property_arg = 0;
  9915. }
  9916. }
  9917. int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asCExprContext *ctx)
  9918. {
  9919. // Don't allow any postfix operators on expressions that take address of class method
  9920. if( ctx->IsClassMethod() )
  9921. {
  9922. Error(TXT_INVALID_OP_ON_METHOD, node);
  9923. return -1;
  9924. }
  9925. // Don't allow any operators on void expressions
  9926. if( ctx->IsVoidExpression() )
  9927. {
  9928. Error(TXT_VOID_CANT_BE_OPERAND, node);
  9929. return -1;
  9930. }
  9931. // Check if the variable is initialized (if it indeed is a variable)
  9932. IsVariableInitialized(&ctx->type, node);
  9933. int op = node->tokenType;
  9934. if( (op == ttInc || op == ttDec) && ctx->type.dataType.IsObject() )
  9935. {
  9936. const char *opName = 0;
  9937. switch( op )
  9938. {
  9939. case ttInc: opName = "opPostInc"; break;
  9940. case ttDec: opName = "opPostDec"; break;
  9941. }
  9942. if( opName )
  9943. {
  9944. // TODO: Should convert this to something similar to CompileOverloadedDualOperator2
  9945. ProcessPropertyGetAccessor(ctx, node);
  9946. // 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
  9947. // Find the correct method
  9948. bool isConst = ctx->type.dataType.IsObjectConst();
  9949. asCArray<int> funcs;
  9950. asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  9951. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  9952. {
  9953. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  9954. if( func->name == opName &&
  9955. func->parameterTypes.GetLength() == 0 &&
  9956. (!isConst || func->isReadOnly) )
  9957. {
  9958. funcs.PushLast(func->id);
  9959. }
  9960. }
  9961. // Did we find the method?
  9962. if( funcs.GetLength() == 1 )
  9963. {
  9964. asCArray<asCExprContext *> args;
  9965. MakeFunctionCall(ctx, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
  9966. return 0;
  9967. }
  9968. else if( funcs.GetLength() == 0 )
  9969. {
  9970. asCString str;
  9971. str = asCString(opName) + "()";
  9972. if( isConst )
  9973. str += " const";
  9974. str.Format(TXT_FUNCTION_s_NOT_FOUND, str.AddressOf());
  9975. Error(str, node);
  9976. ctx->type.SetDummy();
  9977. return -1;
  9978. }
  9979. else if( funcs.GetLength() > 1 )
  9980. {
  9981. Error(TXT_MORE_THAN_ONE_MATCHING_OP, node);
  9982. PrintMatchingFuncs(funcs, node);
  9983. ctx->type.SetDummy();
  9984. return -1;
  9985. }
  9986. }
  9987. }
  9988. else if( op == ttInc || op == ttDec )
  9989. {
  9990. // Make sure the reference isn't a temporary variable
  9991. if( ctx->type.isTemporary )
  9992. {
  9993. Error(TXT_REF_IS_TEMP, node);
  9994. return -1;
  9995. }
  9996. if( ctx->type.dataType.IsReadOnly() )
  9997. {
  9998. Error(TXT_REF_IS_READ_ONLY, node);
  9999. return -1;
  10000. }
  10001. if( ctx->property_get || ctx->property_set )
  10002. {
  10003. Error(TXT_INVALID_REF_PROP_ACCESS, node);
  10004. return -1;
  10005. }
  10006. if( !ctx->type.isLValue )
  10007. {
  10008. Error(TXT_NOT_LVALUE, node);
  10009. return -1;
  10010. }
  10011. if( ctx->type.isVariable && !ctx->type.dataType.IsReference() )
  10012. ConvertToReference(ctx);
  10013. else if( !ctx->type.dataType.IsReference() )
  10014. {
  10015. Error(TXT_NOT_VALID_REFERENCE, node);
  10016. return -1;
  10017. }
  10018. // Copy the value to a temp before changing it
  10019. ConvertToTempVariable(ctx);
  10020. asASSERT(!ctx->type.isLValue);
  10021. // Increment the value pointed to by the reference still in the register
  10022. asEBCInstr iInc = asBC_INCi, iDec = asBC_DECi;
  10023. if( ctx->type.dataType.IsDoubleType() )
  10024. {
  10025. iInc = asBC_INCd;
  10026. iDec = asBC_DECd;
  10027. }
  10028. else if( ctx->type.dataType.IsFloatType() )
  10029. {
  10030. iInc = asBC_INCf;
  10031. iDec = asBC_DECf;
  10032. }
  10033. else if( ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType() )
  10034. {
  10035. if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt16, false)) ||
  10036. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt16, false)) )
  10037. {
  10038. iInc = asBC_INCi16;
  10039. iDec = asBC_DECi16;
  10040. }
  10041. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt8, false)) ||
  10042. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt8, false)) )
  10043. {
  10044. iInc = asBC_INCi8;
  10045. iDec = asBC_DECi8;
  10046. }
  10047. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt64, false)) ||
  10048. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt64, false)) )
  10049. {
  10050. iInc = asBC_INCi64;
  10051. iDec = asBC_DECi64;
  10052. }
  10053. }
  10054. else
  10055. {
  10056. Error(TXT_ILLEGAL_OPERATION, node);
  10057. return -1;
  10058. }
  10059. if( op == ttInc ) ctx->bc.Instr(iInc); else ctx->bc.Instr(iDec);
  10060. }
  10061. else if( op == ttDot )
  10062. {
  10063. if( node->firstChild->nodeType == snIdentifier )
  10064. {
  10065. ProcessPropertyGetAccessor(ctx, node);
  10066. // Get the property name
  10067. asCString name(&script->code[node->firstChild->tokenPos], node->firstChild->tokenLength);
  10068. if( ctx->type.dataType.IsObject() )
  10069. {
  10070. // We need to look for get/set property accessors.
  10071. // If found, the context stores information on the get/set accessors
  10072. // until it is known which is to be used.
  10073. int r = 0;
  10074. if( node->next && node->next->tokenType == ttOpenBracket )
  10075. {
  10076. // The property accessor should take an index arg
  10077. asCExprContext dummyArg(engine);
  10078. r = FindPropertyAccessor(name, ctx, &dummyArg, node, 0);
  10079. }
  10080. if( r == 0 )
  10081. r = FindPropertyAccessor(name, ctx, node, 0);
  10082. if( r != 0 )
  10083. return r;
  10084. if( !ctx->type.dataType.IsPrimitive() )
  10085. Dereference(ctx, true);
  10086. if( ctx->type.dataType.IsObjectHandle() )
  10087. {
  10088. // Convert the handle to a normal object
  10089. asCDataType dt = ctx->type.dataType;
  10090. dt.MakeHandle(false);
  10091. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV);
  10092. // The handle may not have been an lvalue, but the dereferenced object is
  10093. ctx->type.isLValue = true;
  10094. }
  10095. bool isConst = ctx->type.dataType.IsObjectConst();
  10096. asCObjectProperty *prop = builder->GetObjectProperty(ctx->type.dataType, name.AddressOf());
  10097. if( prop )
  10098. {
  10099. // Is the property access allowed?
  10100. if( (prop->isPrivate || prop->isProtected) && (!outFunc || outFunc->objectType != ctx->type.dataType.GetTypeInfo()) )
  10101. {
  10102. asCString msg;
  10103. if( prop->isPrivate )
  10104. msg.Format(TXT_PRIVATE_PROP_ACCESS_s, name.AddressOf());
  10105. else
  10106. msg.Format(TXT_PROTECTED_PROP_ACCESS_s, name.AddressOf());
  10107. Error(msg, node);
  10108. }
  10109. // Put the offset on the stack
  10110. ctx->bc.InstrSHORT_DW(asBC_ADDSi, (short)prop->byteOffset, engine->GetTypeIdFromDataType(asCDataType::CreateType(ctx->type.dataType.GetTypeInfo(), false)));
  10111. if( prop->type.IsReference() )
  10112. ctx->bc.Instr(asBC_RDSPtr);
  10113. // Reference to primitive must be stored in the temp register
  10114. if( prop->type.IsPrimitive() )
  10115. {
  10116. ctx->bc.Instr(asBC_PopRPtr);
  10117. }
  10118. // Keep information about temporary variables as deferred expression
  10119. if( ctx->type.isTemporary )
  10120. {
  10121. // Add the release of this reference, as a deferred expression
  10122. asSDeferredParam deferred;
  10123. deferred.origExpr = 0;
  10124. deferred.argInOutFlags = asTM_INREF;
  10125. deferred.argNode = 0;
  10126. deferred.argType.SetVariable(ctx->type.dataType, ctx->type.stackOffset, true);
  10127. ctx->deferredParams.PushLast(deferred);
  10128. }
  10129. // Set the new type and make sure it is not treated as a variable anymore
  10130. ctx->type.dataType = prop->type;
  10131. ctx->type.dataType.MakeReference(true);
  10132. ctx->type.isVariable = false;
  10133. ctx->type.isTemporary = false;
  10134. if( (ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) && !ctx->type.dataType.IsObjectHandle() )
  10135. {
  10136. // Objects that are members are not references
  10137. ctx->type.dataType.MakeReference(false);
  10138. // The object is safe (life time guaranteed) if the parent object is also safe
  10139. }
  10140. else if (ctx->type.dataType.IsObjectHandle())
  10141. {
  10142. // A object accessed through a handle cannot be considered safe,
  10143. // as it can be cleared at any time
  10144. ctx->type.isHandleSafe = false;
  10145. }
  10146. ctx->type.dataType.MakeReadOnly(isConst ? true : prop->type.IsReadOnly());
  10147. }
  10148. else
  10149. {
  10150. // If the name is not a property, the compiler must check if the name matches
  10151. // a method, which can be used for constructing delegates
  10152. asIScriptFunction *func = 0;
  10153. asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  10154. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  10155. {
  10156. if( engine->scriptFunctions[ot->methods[n]]->name == name )
  10157. {
  10158. func = engine->scriptFunctions[ot->methods[n]];
  10159. break;
  10160. }
  10161. }
  10162. if( func )
  10163. {
  10164. // An object method was found. Keep the name of the method in the expression, but
  10165. // don't actually modify the bytecode at this point since it is not yet known what
  10166. // the method will be used for, or even what overloaded method should be used.
  10167. ctx->methodName = name;
  10168. }
  10169. else
  10170. {
  10171. asCString str;
  10172. str.Format(TXT_s_NOT_MEMBER_OF_s, name.AddressOf(), ctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  10173. Error(str, node);
  10174. return -1;
  10175. }
  10176. }
  10177. }
  10178. else
  10179. {
  10180. asCString str;
  10181. str.Format(TXT_s_NOT_MEMBER_OF_s, name.AddressOf(), ctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  10182. Error(str, node);
  10183. return -1;
  10184. }
  10185. }
  10186. else
  10187. {
  10188. // Make sure it is an object we are accessing
  10189. if( !ctx->type.dataType.IsObject() )
  10190. {
  10191. asCString str;
  10192. str.Format(TXT_ILLEGAL_OPERATION_ON_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  10193. Error(str, node);
  10194. return -1;
  10195. }
  10196. // Process the get property accessor
  10197. ProcessPropertyGetAccessor(ctx, node);
  10198. // Compile function call
  10199. int r = CompileFunctionCall(node->firstChild, ctx, CastToObjectType(ctx->type.dataType.GetTypeInfo()), ctx->type.dataType.IsObjectConst());
  10200. if( r < 0 ) return r;
  10201. }
  10202. }
  10203. else if( op == ttOpenBracket )
  10204. {
  10205. // If the property access takes an index arg and the argument hasn't been evaluated yet,
  10206. // then we should use that instead of processing it now. If the argument has already been
  10207. // evaluated, then we should process the property accessor as a get access now as the new
  10208. // index operator is on the result of that accessor.
  10209. asCString propertyName;
  10210. asSNameSpace *ns = 0;
  10211. if( ((ctx->property_get && builder->GetFunctionDescription(ctx->property_get)->GetParamCount() == 1) ||
  10212. (ctx->property_set && builder->GetFunctionDescription(ctx->property_set)->GetParamCount() == 2)) &&
  10213. (ctx->property_arg && ctx->property_arg->type.dataType.GetTokenType() == ttUnrecognizedToken) )
  10214. {
  10215. // Determine the name of the property accessor
  10216. asCScriptFunction *func = 0;
  10217. if( ctx->property_get )
  10218. func = builder->GetFunctionDescription(ctx->property_get);
  10219. else
  10220. func = builder->GetFunctionDescription(ctx->property_set);
  10221. propertyName = func->GetName();
  10222. propertyName = propertyName.SubString(4);
  10223. // Set the original type of the expression so we can re-evaluate the property accessor
  10224. if( func->objectType )
  10225. {
  10226. ctx->type.dataType = asCDataType::CreateType(func->objectType, ctx->property_const);
  10227. if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
  10228. if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
  10229. }
  10230. else
  10231. {
  10232. // Store the namespace where the function is declared
  10233. // so the same function can be found later
  10234. ctx->type.SetDummy();
  10235. ns = func->nameSpace;
  10236. }
  10237. ctx->property_get = ctx->property_set = 0;
  10238. if( ctx->property_arg )
  10239. {
  10240. asDELETE(ctx->property_arg, asCExprContext);
  10241. ctx->property_arg = 0;
  10242. }
  10243. }
  10244. else
  10245. {
  10246. if( !ctx->type.dataType.IsObject() )
  10247. {
  10248. asCString str;
  10249. str.Format(TXT_OBJECT_DOESNT_SUPPORT_INDEX_OP, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  10250. Error(str, node);
  10251. return -1;
  10252. }
  10253. ProcessPropertyGetAccessor(ctx, node);
  10254. }
  10255. // Compile the expression
  10256. bool isOK = true;
  10257. asCArray<asCExprContext *> args;
  10258. asCArray<asSNamedArgument> namedArgs;
  10259. asASSERT( node->firstChild->nodeType == snArgList );
  10260. if( CompileArgumentList(node->firstChild, args, namedArgs) >= 0 )
  10261. {
  10262. // Check for the existence of the opIndex method
  10263. bool lookForProperty = true;
  10264. if( propertyName == "" )
  10265. {
  10266. bool isConst = ctx->type.dataType.IsObjectConst();
  10267. asCObjectType *objectType = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  10268. asCArray<int> funcs;
  10269. builder->GetObjectMethodDescriptions("opIndex", objectType, funcs, isConst);
  10270. if( funcs.GetLength() > 0 )
  10271. {
  10272. // Since there are opIndex methods, the compiler should not look for get/set_opIndex accessors
  10273. lookForProperty = false;
  10274. // Determine which of opIndex methods that match
  10275. MatchFunctions(funcs, args, node, "opIndex", 0, objectType, isConst);
  10276. if( funcs.GetLength() != 1 )
  10277. {
  10278. // The error has already been reported by MatchFunctions
  10279. isOK = false;
  10280. }
  10281. else
  10282. {
  10283. // Add the default values for arguments not explicitly supplied
  10284. int r = CompileDefaultAndNamedArgs(node, args, funcs[0], objectType);
  10285. if( r == 0 )
  10286. MakeFunctionCall(ctx, funcs[0], objectType, args, node, false, 0, ctx->type.stackOffset);
  10287. else
  10288. isOK = false;
  10289. }
  10290. }
  10291. }
  10292. if( lookForProperty && isOK )
  10293. {
  10294. if( args.GetLength() != 1 )
  10295. {
  10296. // TODO: opIndex: Implement support for multiple index arguments in set_opIndex too
  10297. Error(TXT_PROP_ACCESS_WITH_INDEX_ONE_ARG, node);
  10298. isOK = false;
  10299. }
  10300. else
  10301. {
  10302. Dereference(ctx, true);
  10303. asCExprContext lctx(engine);
  10304. MergeExprBytecodeAndType(&lctx, ctx);
  10305. // Check for accessors methods for the opIndex, either as get/set_opIndex or as get/set with the property name
  10306. int r = FindPropertyAccessor(propertyName == "" ? "opIndex" : propertyName.AddressOf(), &lctx, args[0], node, ns);
  10307. if (r == 0)
  10308. {
  10309. asCString str;
  10310. str.Format(TXT_OBJECT_DOESNT_SUPPORT_INDEX_OP, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  10311. Error(str, node);
  10312. isOK = false;
  10313. }
  10314. else if (r < 0)
  10315. isOK = false;
  10316. if (isOK)
  10317. MergeExprBytecodeAndType(ctx, &lctx);
  10318. }
  10319. }
  10320. }
  10321. else
  10322. isOK = false;
  10323. // Cleanup
  10324. for( asUINT n = 0; n < args.GetLength(); n++ )
  10325. if( args[n] )
  10326. {
  10327. asDELETE(args[n], asCExprContext);
  10328. }
  10329. if( !isOK )
  10330. return -1;
  10331. }
  10332. else if( op == ttOpenParanthesis )
  10333. {
  10334. // TODO: Most of this is already done by CompileFunctionCall(). Can we share the code?
  10335. // Make sure the expression is a funcdef or an object that may have opCall methods
  10336. if( !ctx->type.dataType.GetTypeInfo() || (!ctx->type.dataType.IsFuncdef() && !ctx->type.dataType.IsObject()) )
  10337. {
  10338. Error(TXT_EXPR_DOESNT_EVAL_TO_FUNC, node);
  10339. return -1;
  10340. }
  10341. // Compile arguments
  10342. asCArray<asCExprContext *> args;
  10343. asCArray<asSNamedArgument> namedArgs;
  10344. if( CompileArgumentList(node->lastChild, args, namedArgs) >= 0 )
  10345. {
  10346. // Match arguments with the funcdef
  10347. asCArray<int> funcs;
  10348. if( ctx->type.dataType.IsFuncdef() )
  10349. {
  10350. funcs.PushLast(CastToFuncdefType(ctx->type.dataType.GetTypeInfo())->funcdef->id);
  10351. MatchFunctions(funcs, args, node, ctx->type.dataType.GetTypeInfo()->name.AddressOf(), &namedArgs);
  10352. }
  10353. else
  10354. {
  10355. bool isConst = ctx->type.dataType.IsObjectConst();
  10356. builder->GetObjectMethodDescriptions("opCall", CastToObjectType(ctx->type.dataType.GetTypeInfo()), funcs, isConst);
  10357. MatchFunctions(funcs, args, node, "opCall", &namedArgs, CastToObjectType(ctx->type.dataType.GetTypeInfo()), isConst);
  10358. }
  10359. if( funcs.GetLength() != 1 )
  10360. {
  10361. // The error was reported by MatchFunctions()
  10362. // Dummy value
  10363. ctx->type.SetDummy();
  10364. }
  10365. else
  10366. {
  10367. // Add the default values for arguments not explicitly supplied
  10368. int r = CompileDefaultAndNamedArgs(node, args, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), &namedArgs);
  10369. // TODO: funcdef: Do we have to make sure the handle is stored in a temporary variable, or
  10370. // is it enough to make sure it is in a local variable?
  10371. // For function pointer we must guarantee that the function is safe, i.e.
  10372. // by first storing the function pointer in a local variable (if it isn't already in one)
  10373. if( r == asSUCCESS )
  10374. {
  10375. Dereference(ctx, true);
  10376. if( ctx->type.dataType.IsFuncdef() )
  10377. {
  10378. if( !ctx->type.isVariable )
  10379. ConvertToVariable(ctx);
  10380. // Remove the reference from the stack as the asBC_CALLPTR instruction takes the variable as argument
  10381. ctx->bc.Instr(asBC_PopPtr);
  10382. }
  10383. MakeFunctionCall(ctx, funcs[0], ctx->type.dataType.IsFuncdef() ? 0 : CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node, false, 0, ctx->type.stackOffset);
  10384. }
  10385. }
  10386. }
  10387. else
  10388. ctx->type.SetDummy();
  10389. // Cleanup
  10390. for( asUINT n = 0; n < args.GetLength(); n++ )
  10391. if( args[n] )
  10392. {
  10393. asDELETE(args[n], asCExprContext);
  10394. }
  10395. for( asUINT n = 0; n < namedArgs.GetLength(); n++ )
  10396. if( namedArgs[n].ctx )
  10397. {
  10398. asDELETE(namedArgs[n].ctx, asCExprContext);
  10399. }
  10400. }
  10401. return 0;
  10402. }
  10403. int asCCompiler::GetPrecedence(asCScriptNode *op)
  10404. {
  10405. // x ** y
  10406. // x * y, x / y, x % y
  10407. // x + y, x - y
  10408. // x <= y, x < y, x >= y, x > y
  10409. // x = =y, x != y, x xor y, x is y, x !is y
  10410. // x and y
  10411. // x or y
  10412. // The following are not used in this function,
  10413. // but should have lower precedence than the above
  10414. // x ? y : z
  10415. // x = y
  10416. // The expression term have the highest precedence
  10417. if( op->nodeType == snExprTerm )
  10418. return 1;
  10419. // Evaluate operators by token
  10420. int tokenType = op->tokenType;
  10421. if( tokenType == ttStarStar )
  10422. return 0;
  10423. if( tokenType == ttStar || tokenType == ttSlash || tokenType == ttPercent )
  10424. return -1;
  10425. if( tokenType == ttPlus || tokenType == ttMinus )
  10426. return -2;
  10427. if( tokenType == ttBitShiftLeft ||
  10428. tokenType == ttBitShiftRight ||
  10429. tokenType == ttBitShiftRightArith )
  10430. return -3;
  10431. if( tokenType == ttAmp )
  10432. return -4;
  10433. if( tokenType == ttBitXor )
  10434. return -5;
  10435. if( tokenType == ttBitOr )
  10436. return -6;
  10437. if( tokenType == ttLessThanOrEqual ||
  10438. tokenType == ttLessThan ||
  10439. tokenType == ttGreaterThanOrEqual ||
  10440. tokenType == ttGreaterThan )
  10441. return -7;
  10442. if( tokenType == ttEqual || tokenType == ttNotEqual || tokenType == ttXor || tokenType == ttIs || tokenType == ttNotIs )
  10443. return -8;
  10444. if( tokenType == ttAnd )
  10445. return -9;
  10446. if( tokenType == ttOr )
  10447. return -10;
  10448. // Unknown operator
  10449. asASSERT(false);
  10450. return 0;
  10451. }
  10452. asUINT asCCompiler::MatchArgument(asCArray<int> &funcs, asCArray<asSOverloadCandidate> &matches, const asCExprContext *argExpr, int paramNum, bool allowObjectConstruct)
  10453. {
  10454. matches.SetLength(0);
  10455. for( asUINT n = 0; n < funcs.GetLength(); n++ )
  10456. {
  10457. asCScriptFunction *desc = builder->GetFunctionDescription(funcs[n]);
  10458. // Does the function have arguments enough?
  10459. if( (int)desc->parameterTypes.GetLength() <= paramNum )
  10460. continue;
  10461. int cost = MatchArgument(desc, argExpr, paramNum, allowObjectConstruct);
  10462. if( cost != -1 )
  10463. matches.PushLast(asSOverloadCandidate(funcs[n], asUINT(cost)));
  10464. }
  10465. return (asUINT)matches.GetLength();
  10466. }
  10467. int asCCompiler::MatchArgument(asCScriptFunction *desc, const asCExprContext *argExpr, int paramNum, bool allowObjectConstruct)
  10468. {
  10469. // void expressions can match any out parameter, but nothing else
  10470. if( argExpr->IsVoidExpression() )
  10471. {
  10472. if( desc->inOutFlags[paramNum] == asTM_OUTREF )
  10473. return 0;
  10474. return -1;
  10475. }
  10476. // Anonymous init lists can only match parameters that can be initialized with a list
  10477. if (argExpr->IsAnonymousInitList())
  10478. {
  10479. if ((desc->parameterTypes[paramNum].IsReference() && desc->inOutFlags[paramNum] != asTM_INREF) ||
  10480. desc->parameterTypes[paramNum].GetTypeInfo() == 0 ||
  10481. desc->parameterTypes[paramNum].GetBehaviour()->listFactory == 0)
  10482. {
  10483. return -1;
  10484. }
  10485. return 0;
  10486. }
  10487. // Can we make the match by implicit conversion?
  10488. asCExprContext ti(engine);
  10489. ti.type = argExpr->type;
  10490. ti.methodName = argExpr->methodName;
  10491. ti.enumValue = argExpr->enumValue;
  10492. ti.exprNode = argExpr->exprNode;
  10493. if( argExpr->type.dataType.IsPrimitive() )
  10494. ti.type.dataType.MakeReference(false);
  10495. // Don't allow the implicit conversion to make a copy in case the argument is expecting a reference to the true value
  10496. if (desc->parameterTypes[paramNum].IsReference() && desc->inOutFlags[paramNum] == asTM_INOUTREF)
  10497. allowObjectConstruct = false;
  10498. int cost = ImplicitConversion(&ti, desc->parameterTypes[paramNum], 0, asIC_IMPLICIT_CONV, false, allowObjectConstruct);
  10499. // If the function parameter is an inout-reference then it must not be possible to call the
  10500. // function with an incorrect argument type, even though the type can normally be converted.
  10501. if( desc->parameterTypes[paramNum].IsReference() &&
  10502. desc->inOutFlags[paramNum] == asTM_INOUTREF &&
  10503. desc->parameterTypes[paramNum].GetTokenType() != ttQuestion )
  10504. {
  10505. // Observe, that the below checks are only necessary for when unsafe references have been
  10506. // enabled by the application. Without this the &inout reference form wouldn't be allowed
  10507. // for these value types.
  10508. // Don't allow a primitive to be converted to a reference of another primitive type
  10509. if( desc->parameterTypes[paramNum].IsPrimitive() &&
  10510. desc->parameterTypes[paramNum].GetTokenType() != argExpr->type.dataType.GetTokenType() )
  10511. {
  10512. asASSERT( engine->ep.allowUnsafeReferences );
  10513. return -1;
  10514. }
  10515. // Don't allow an enum to be converted to a reference of another enum type
  10516. if( desc->parameterTypes[paramNum].IsEnumType() &&
  10517. desc->parameterTypes[paramNum].GetTypeInfo() != argExpr->type.dataType.GetTypeInfo() )
  10518. {
  10519. asASSERT( engine->ep.allowUnsafeReferences );
  10520. return -1;
  10521. }
  10522. // Don't allow a non-handle expression to be converted to a reference to a handle
  10523. if( desc->parameterTypes[paramNum].IsObjectHandle() &&
  10524. !argExpr->type.dataType.IsObjectHandle() )
  10525. {
  10526. asASSERT( engine->ep.allowUnsafeReferences );
  10527. return -1;
  10528. }
  10529. // Don't allow a value type to be converted
  10530. if( (desc->parameterTypes[paramNum].GetTypeInfo() && (desc->parameterTypes[paramNum].GetTypeInfo()->GetFlags() & asOBJ_VALUE)) &&
  10531. (desc->parameterTypes[paramNum].GetTypeInfo() != argExpr->type.dataType.GetTypeInfo()) )
  10532. {
  10533. asASSERT( engine->ep.allowUnsafeReferences );
  10534. return -1;
  10535. }
  10536. }
  10537. // How well does the argument match the function parameter?
  10538. if( desc->parameterTypes[paramNum].IsEqualExceptRef(ti.type.dataType) )
  10539. return cost;
  10540. // No match is available
  10541. return -1;
  10542. }
  10543. void asCCompiler::PrepareArgument2(asCExprContext *ctx, asCExprContext *arg, asCDataType *paramType, bool isFunction, int refType, bool isMakingCopy)
  10544. {
  10545. // Reference parameters whose value won't be used don't evaluate the expression
  10546. // Clean arguments (i.e. default value) will be passed in directly as there is nothing to protect
  10547. if( paramType->IsReference() && !(refType & asTM_INREF) && !arg->isCleanArg )
  10548. {
  10549. // Store the original bytecode so that it can be reused when processing the deferred output parameter
  10550. asCExprContext *orig = asNEW(asCExprContext)(engine);
  10551. if( orig == 0 )
  10552. {
  10553. // Out of memory
  10554. return;
  10555. }
  10556. MergeExprBytecodeAndType(orig, arg);
  10557. arg->origExpr = orig;
  10558. }
  10559. PrepareArgument(paramType, arg, arg->exprNode, isFunction, refType, isMakingCopy);
  10560. // arg still holds the original expression for output parameters
  10561. ctx->bc.AddCode(&arg->bc);
  10562. }
  10563. bool asCCompiler::CompileOverloadedDualOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, bool leftToRight, asCExprContext *ctx, bool isHandle, eTokenType token)
  10564. {
  10565. DetermineSingleFunc(lctx, node);
  10566. DetermineSingleFunc(rctx, node);
  10567. ctx->exprNode = node;
  10568. // What type of operator is it?
  10569. if( token == ttUnrecognizedToken )
  10570. token = node->tokenType;
  10571. if( token == ttUnrecognizedToken )
  10572. {
  10573. // This happens when the compiler is inferring an assignment
  10574. // operation from another action, for example in preparing a value
  10575. // as a function argument
  10576. token = ttAssignment;
  10577. }
  10578. // boolean operators are not overloadable
  10579. if( token == ttAnd ||
  10580. token == ttOr ||
  10581. token == ttXor )
  10582. return false;
  10583. // Dual operators can also be implemented as class methods
  10584. if( token == ttEqual ||
  10585. token == ttNotEqual )
  10586. {
  10587. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  10588. // Find the matching opEquals method
  10589. int r = CompileOverloadedDualOperator2(node, "opEquals", lctx, rctx, leftToRight, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  10590. if( r == 0 )
  10591. {
  10592. // Try again by switching the order of the operands
  10593. r = CompileOverloadedDualOperator2(node, "opEquals", rctx, lctx, !leftToRight, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  10594. }
  10595. if( r == 1 )
  10596. {
  10597. if( token == ttNotEqual )
  10598. ctx->bc.InstrSHORT(asBC_NOT, ctx->type.stackOffset);
  10599. // Success, don't continue
  10600. return true;
  10601. }
  10602. else if( r < 0 )
  10603. {
  10604. // Compiler error, don't continue
  10605. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  10606. return true;
  10607. }
  10608. }
  10609. if( token == ttEqual ||
  10610. token == ttNotEqual ||
  10611. token == ttLessThan ||
  10612. token == ttLessThanOrEqual ||
  10613. token == ttGreaterThan ||
  10614. token == ttGreaterThanOrEqual )
  10615. {
  10616. bool swappedOrder = false;
  10617. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  10618. // Find the matching opCmp method
  10619. int r = CompileOverloadedDualOperator2(node, "opCmp", lctx, rctx, leftToRight, ctx, true, asCDataType::CreatePrimitive(ttInt, false));
  10620. if( r == 0 )
  10621. {
  10622. // Try again by switching the order of the operands
  10623. swappedOrder = true;
  10624. r = CompileOverloadedDualOperator2(node, "opCmp", rctx, lctx, !leftToRight, ctx, true, asCDataType::CreatePrimitive(ttInt, false));
  10625. }
  10626. if( r == 1 )
  10627. {
  10628. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  10629. int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, false), true);
  10630. ctx->bc.InstrW_DW(asBC_CMPIi, ctx->type.stackOffset, 0);
  10631. if( token == ttEqual )
  10632. ctx->bc.Instr(asBC_TZ);
  10633. else if( token == ttNotEqual )
  10634. ctx->bc.Instr(asBC_TNZ);
  10635. else if( (token == ttLessThan && !swappedOrder) ||
  10636. (token == ttGreaterThan && swappedOrder) )
  10637. ctx->bc.Instr(asBC_TS);
  10638. else if( (token == ttLessThanOrEqual && !swappedOrder) ||
  10639. (token == ttGreaterThanOrEqual && swappedOrder) )
  10640. ctx->bc.Instr(asBC_TNP);
  10641. else if( (token == ttGreaterThan && !swappedOrder) ||
  10642. (token == ttLessThan && swappedOrder) )
  10643. ctx->bc.Instr(asBC_TP);
  10644. else if( (token == ttGreaterThanOrEqual && !swappedOrder) ||
  10645. (token == ttLessThanOrEqual && swappedOrder) )
  10646. ctx->bc.Instr(asBC_TNS);
  10647. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  10648. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, false), a, true);
  10649. // Success, don't continue
  10650. return true;
  10651. }
  10652. else if( r < 0 )
  10653. {
  10654. // Compiler error, don't continue
  10655. #if AS_SIZEOF_BOOL == 1
  10656. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  10657. #else
  10658. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  10659. #endif
  10660. return true;
  10661. }
  10662. }
  10663. // The rest of the operators are not commutative, and doesn't require specific return type
  10664. const char *op = 0, *op_r = 0;
  10665. switch( int(token) ) // convert to int to avoid warning in gnuc that not all values are tested
  10666. {
  10667. case ttPlus: op = "opAdd"; op_r = "opAdd_r"; break;
  10668. case ttMinus: op = "opSub"; op_r = "opSub_r"; break;
  10669. case ttStar: op = "opMul"; op_r = "opMul_r"; break;
  10670. case ttSlash: op = "opDiv"; op_r = "opDiv_r"; break;
  10671. case ttPercent: op = "opMod"; op_r = "opMod_r"; break;
  10672. case ttStarStar: op = "opPow"; op_r = "opPow_r"; break;
  10673. case ttBitOr: op = "opOr"; op_r = "opOr_r"; break;
  10674. case ttAmp: op = "opAnd"; op_r = "opAnd_r"; break;
  10675. case ttBitXor: op = "opXor"; op_r = "opXor_r"; break;
  10676. case ttBitShiftLeft: op = "opShl"; op_r = "opShl_r"; break;
  10677. case ttBitShiftRight: op = "opShr"; op_r = "opShr_r"; break;
  10678. case ttBitShiftRightArith: op = "opUShr"; op_r = "opUShr_r"; break;
  10679. }
  10680. // TODO: Might be interesting to support a concatenation operator, e.g. ~
  10681. if( op && op_r )
  10682. {
  10683. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  10684. // Find the matching operator method
  10685. int r = CompileOverloadedDualOperator2(node, op, lctx, rctx, leftToRight, ctx);
  10686. if( r == 0 )
  10687. {
  10688. // Try again by switching the order of the operands, and using the reversed operator
  10689. r = CompileOverloadedDualOperator2(node, op_r, rctx, lctx, !leftToRight, ctx);
  10690. }
  10691. if( r == 1 )
  10692. {
  10693. // Success, don't continue
  10694. return true;
  10695. }
  10696. else if( r < 0 )
  10697. {
  10698. // Compiler error, don't continue
  10699. ctx->type.SetDummy();
  10700. return true;
  10701. }
  10702. }
  10703. // Assignment operators
  10704. op = 0;
  10705. if( isHandle )
  10706. {
  10707. // Only asOBJ_ASHANDLE types can get here
  10708. asASSERT( lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) );
  10709. asASSERT( token == ttAssignment );
  10710. if( token == ttAssignment )
  10711. op = "opHndlAssign";
  10712. }
  10713. else
  10714. {
  10715. switch( int(token) ) // convert to int to avoid warning in gnuc that not all values are tested
  10716. {
  10717. case ttAssignment: op = "opAssign"; break;
  10718. case ttAddAssign: op = "opAddAssign"; break;
  10719. case ttSubAssign: op = "opSubAssign"; break;
  10720. case ttMulAssign: op = "opMulAssign"; break;
  10721. case ttDivAssign: op = "opDivAssign"; break;
  10722. case ttModAssign: op = "opModAssign"; break;
  10723. case ttPowAssign: op = "opPowAssign"; break;
  10724. case ttOrAssign: op = "opOrAssign"; break;
  10725. case ttAndAssign: op = "opAndAssign"; break;
  10726. case ttXorAssign: op = "opXorAssign"; break;
  10727. case ttShiftLeftAssign: op = "opShlAssign"; break;
  10728. case ttShiftRightLAssign: op = "opShrAssign"; break;
  10729. case ttShiftRightAAssign: op = "opUShrAssign"; break;
  10730. }
  10731. }
  10732. if( op )
  10733. {
  10734. if( builder->engine->ep.disallowValueAssignForRefType &&
  10735. lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !(lctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCOPED) )
  10736. {
  10737. if( token == ttAssignment )
  10738. Error(TXT_DISALLOW_ASSIGN_ON_REF_TYPE, node);
  10739. else
  10740. Error(TXT_DISALLOW_COMPOUND_ASSIGN_ON_REF_TYPE, node);
  10741. // Set a dummy output
  10742. ctx->type.Set(lctx->type.dataType);
  10743. return true;
  10744. }
  10745. // TODO: Shouldn't accept const lvalue with the assignment operators
  10746. // Find the matching operator method
  10747. int r = CompileOverloadedDualOperator2(node, op, lctx, rctx, false, ctx);
  10748. if( r == 1 )
  10749. {
  10750. // Success, don't continue
  10751. return true;
  10752. }
  10753. else if( r < 0 )
  10754. {
  10755. // Compiler error, don't continue
  10756. ctx->type.SetDummy();
  10757. return true;
  10758. }
  10759. }
  10760. // No suitable operator was found
  10761. return false;
  10762. }
  10763. // Returns negative on compile error
  10764. // zero on no matching operator
  10765. // one on matching operator
  10766. int asCCompiler::CompileOverloadedDualOperator2(asCScriptNode *node, const char *methodName, asCExprContext *lctx, asCExprContext *rctx, bool leftToRight, asCExprContext *ctx, bool specificReturn, const asCDataType &returnType)
  10767. {
  10768. // Find the matching method
  10769. if( lctx->type.dataType.IsObject() &&
  10770. (!lctx->type.isExplicitHandle ||
  10771. lctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) )
  10772. {
  10773. asUINT n;
  10774. // Is the left value a const?
  10775. bool isConst = lctx->type.dataType.IsObjectConst();
  10776. asCArray<int> funcs;
  10777. asCObjectType *ot = CastToObjectType(lctx->type.dataType.GetTypeInfo());
  10778. for( n = 0; n < ot->methods.GetLength(); n++ )
  10779. {
  10780. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  10781. asASSERT( func );
  10782. if( func && func->name == methodName &&
  10783. (!specificReturn || func->returnType == returnType) &&
  10784. func->parameterTypes.GetLength() == 1 &&
  10785. (!isConst || func->isReadOnly) )
  10786. {
  10787. // Make sure the method is accessible by the module
  10788. if( builder->module->accessMask & func->accessMask )
  10789. {
  10790. funcs.PushLast(func->id);
  10791. }
  10792. }
  10793. }
  10794. // Which is the best matching function?
  10795. asCArray<asSOverloadCandidate> tempFuncs;
  10796. MatchArgument(funcs, tempFuncs, rctx, 0);
  10797. // Find the lowest cost operator(s)
  10798. asCArray<int> ops;
  10799. asUINT bestCost = asUINT(-1);
  10800. for( n = 0; n < tempFuncs.GetLength(); ++n )
  10801. {
  10802. asUINT cost = tempFuncs[n].cost;
  10803. if( cost < bestCost )
  10804. {
  10805. ops.SetLength(0);
  10806. bestCost = cost;
  10807. }
  10808. if( cost == bestCost )
  10809. ops.PushLast(tempFuncs[n].funcId);
  10810. }
  10811. // If the object is not const, then we need to prioritize non-const methods
  10812. if( !isConst )
  10813. FilterConst(ops);
  10814. // Did we find an operator?
  10815. if( ops.GetLength() == 1 )
  10816. {
  10817. // Reserve the variables used in the right expression so the new temporary
  10818. // variable allocated for the left operand isn't accidentally overwritten.
  10819. int l = int(reservedVariables.GetLength());
  10820. rctx->bc.GetVarsUsed(reservedVariables);
  10821. // Process the lctx expression as get accessor
  10822. ProcessPropertyGetAccessor(lctx, node);
  10823. reservedVariables.SetLength(l);
  10824. asCExprContext tmpCtx(engine);
  10825. if (leftToRight)
  10826. {
  10827. // Make sure lctx is in fact a variable. If it is a reference there is no
  10828. // guarantee that the reference will stay alive throughout the evaluation of rctx
  10829. if (!lctx->type.isVariable)
  10830. {
  10831. // Reserve the variables used in the right expression so the new temporary
  10832. // variable allocated for the left operand isn't accidentally overwritten.
  10833. l = int(reservedVariables.GetLength());
  10834. rctx->bc.GetVarsUsed(reservedVariables);
  10835. if (lctx->type.dataType.SupportHandles())
  10836. lctx->type.dataType.MakeHandle(true);
  10837. PrepareTemporaryVariable(node, lctx);
  10838. reservedVariables.SetLength(l);
  10839. }
  10840. // Move the bytecode for the left operand to a temporary context
  10841. // so we can later make sure this is computed first
  10842. tmpCtx.bc.AddCode(&lctx->bc);
  10843. tmpCtx.bc.Instr(asBC_PopPtr);
  10844. // Add bytecode to push the object pointer computed in the left operand on the stack as the this pointer
  10845. // This will be placed after rctx by MakeFunctionCall below
  10846. lctx->bc.InstrWORD(asBC_PSF, lctx->type.stackOffset);
  10847. // Implicitly dereference handle parameters sent by reference
  10848. sVariable *v = variables->GetVariableByOffset(lctx->type.stackOffset);
  10849. if (v && v->type.IsReference() && (!v->type.IsObject() || v->type.IsObjectHandle()))
  10850. lctx->bc.Instr(asBC_RDSPtr);
  10851. }
  10852. else
  10853. {
  10854. // Make sure the rvalue doesn't have deferred temporary variables that are also used in the lvalue,
  10855. // since that would cause the VM to overwrite the variable while executing the bytecode for the lvalue.
  10856. asCArray<int> usedVars;
  10857. lctx->bc.GetVarsUsed(usedVars);
  10858. asUINT oldReservedVars = reservedVariables.GetLength();
  10859. for (n = 0; n < rctx->deferredParams.GetLength(); n++)
  10860. {
  10861. if (rctx->deferredParams[n].argType.isTemporary &&
  10862. usedVars.Exists(rctx->deferredParams[n].argType.stackOffset))
  10863. {
  10864. if (reservedVariables.GetLength() == oldReservedVars)
  10865. reservedVariables.Concatenate(usedVars);
  10866. // Allocate a new variable for the deferred argument
  10867. int offset = AllocateVariableNotIn(rctx->deferredParams[n].argType.dataType, true, false, rctx);
  10868. int oldVar = rctx->deferredParams[n].argType.stackOffset;
  10869. rctx->deferredParams[n].argType.stackOffset = short(offset);
  10870. rctx->bc.ExchangeVar(oldVar, offset);
  10871. ReleaseTemporaryVariable(oldVar, 0);
  10872. }
  10873. }
  10874. reservedVariables.SetLength(oldReservedVars);
  10875. }
  10876. // Merge the bytecode so that it forms lvalue.methodName(rvalue)
  10877. asCArray<asCExprContext *> args;
  10878. args.PushLast(rctx);
  10879. MergeExprBytecode(ctx, lctx);
  10880. ctx->type = lctx->type;
  10881. MakeFunctionCall(ctx, ops[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
  10882. // Rearrange the bytecode so the left argument is computed first
  10883. if (leftToRight)
  10884. {
  10885. tmpCtx.bc.AddCode(&ctx->bc);
  10886. ctx->bc.AddCode(&tmpCtx.bc);
  10887. }
  10888. // Found matching operator
  10889. return 1;
  10890. }
  10891. else if( ops.GetLength() > 1 )
  10892. {
  10893. Error(TXT_MORE_THAN_ONE_MATCHING_OP, node);
  10894. PrintMatchingFuncs(ops, node);
  10895. ctx->type.SetDummy();
  10896. // Compiler error
  10897. return -1;
  10898. }
  10899. }
  10900. // No matching operator
  10901. return 0;
  10902. }
  10903. void asCCompiler::MakeFunctionCall(asCExprContext *ctx, int funcId, asCObjectType *objectType, asCArray<asCExprContext*> &args, asCScriptNode *node, bool useVariable, int stackOffset, int funcPtrVar)
  10904. {
  10905. if( objectType )
  10906. Dereference(ctx, true);
  10907. // Store the expression node for error reporting
  10908. if( ctx->exprNode == 0 )
  10909. ctx->exprNode = node;
  10910. asCByteCode objBC(engine);
  10911. objBC.AddCode(&ctx->bc);
  10912. PrepareFunctionCall(funcId, &ctx->bc, args);
  10913. // Verify if any of the args variable offsets are used in the other code.
  10914. // If they are exchange the offset for a new one
  10915. asUINT n;
  10916. for( n = 0; n < args.GetLength(); n++ )
  10917. {
  10918. if( args[n]->type.isTemporary && objBC.IsVarUsed(args[n]->type.stackOffset) )
  10919. {
  10920. // Release the current temporary variable
  10921. ReleaseTemporaryVariable(args[n]->type, 0);
  10922. asCDataType dt = args[n]->type.dataType;
  10923. dt.MakeReference(false);
  10924. int l = int(reservedVariables.GetLength());
  10925. objBC.GetVarsUsed(reservedVariables);
  10926. ctx->bc.GetVarsUsed(reservedVariables);
  10927. int newOffset = AllocateVariable(dt, true, IsVariableOnHeap(args[n]->type.stackOffset));
  10928. reservedVariables.SetLength(l);
  10929. asASSERT( IsVariableOnHeap(args[n]->type.stackOffset) == IsVariableOnHeap(newOffset) );
  10930. ctx->bc.ExchangeVar(args[n]->type.stackOffset, newOffset);
  10931. args[n]->type.stackOffset = (short)newOffset;
  10932. args[n]->type.isTemporary = true;
  10933. args[n]->type.isVariable = true;
  10934. }
  10935. }
  10936. // If the function will return a value type on the stack, then we must allocate space
  10937. // for that here and push the address on the stack as a hidden argument to the function
  10938. asCScriptFunction *func = builder->GetFunctionDescription(funcId);
  10939. if( func->DoesReturnOnStack() )
  10940. {
  10941. asASSERT(!useVariable);
  10942. useVariable = true;
  10943. stackOffset = AllocateVariable(func->returnType, true);
  10944. ctx->bc.InstrSHORT(asBC_PSF, short(stackOffset));
  10945. }
  10946. ctx->bc.AddCode(&objBC);
  10947. MoveArgsToStack(funcId, &ctx->bc, args, objectType ? true : false);
  10948. PerformFunctionCall(funcId, ctx, false, &args, 0, useVariable, stackOffset, funcPtrVar);
  10949. }
  10950. int asCCompiler::CompileOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType op, bool leftToRight)
  10951. {
  10952. // Don't allow any operators on expressions that take address of class method, but allow it on global functions
  10953. if( (lctx->IsClassMethod()) || (rctx->IsClassMethod()) )
  10954. {
  10955. Error(TXT_INVALID_OP_ON_METHOD, node);
  10956. return -1;
  10957. }
  10958. // Don't allow any operators on void expressions
  10959. if( lctx->IsVoidExpression() || rctx->IsVoidExpression() )
  10960. {
  10961. Error(TXT_VOID_CANT_BE_OPERAND, node);
  10962. return -1;
  10963. }
  10964. if( op == ttUnrecognizedToken )
  10965. op = node->tokenType;
  10966. IsVariableInitialized(&lctx->type, node);
  10967. IsVariableInitialized(&rctx->type, node);
  10968. if( lctx->type.isExplicitHandle || rctx->type.isExplicitHandle ||
  10969. lctx->type.IsNullConstant() || rctx->type.IsNullConstant() ||
  10970. op == ttIs || op == ttNotIs )
  10971. {
  10972. CompileOperatorOnHandles(node, lctx, rctx, ctx, op);
  10973. return 0;
  10974. }
  10975. else
  10976. {
  10977. // Compile an overloaded operator for the two operands
  10978. if( CompileOverloadedDualOperator(node, lctx, rctx, leftToRight, ctx, false, op) )
  10979. return 0;
  10980. // If both operands are objects, then we shouldn't continue
  10981. if( lctx->type.dataType.IsObject() && rctx->type.dataType.IsObject() )
  10982. {
  10983. asCString str;
  10984. 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());
  10985. Error(str, node);
  10986. ctx->type.SetDummy();
  10987. return -1;
  10988. }
  10989. // Process the property get accessors (if any)
  10990. ProcessPropertyGetAccessor(lctx, node);
  10991. ProcessPropertyGetAccessor(rctx, node);
  10992. // Make sure we have two variables or constants
  10993. if( lctx->type.dataType.IsReference() ) ConvertToVariableNotIn(lctx, rctx);
  10994. if( rctx->type.dataType.IsReference() ) ConvertToVariableNotIn(rctx, lctx);
  10995. // Make sure lctx doesn't end up with a variable used in rctx
  10996. if( lctx->type.isTemporary && rctx->bc.IsVarUsed(lctx->type.stackOffset) )
  10997. {
  10998. int offset = AllocateVariableNotIn(lctx->type.dataType, true, false, rctx);
  10999. rctx->bc.ExchangeVar(lctx->type.stackOffset, offset);
  11000. ReleaseTemporaryVariable(offset, 0);
  11001. }
  11002. // Math operators
  11003. // + - * / % ** += -= *= /= %= **=
  11004. if( op == ttPlus || op == ttAddAssign ||
  11005. op == ttMinus || op == ttSubAssign ||
  11006. op == ttStar || op == ttMulAssign ||
  11007. op == ttSlash || op == ttDivAssign ||
  11008. op == ttPercent || op == ttModAssign ||
  11009. op == ttStarStar || op == ttPowAssign )
  11010. {
  11011. CompileMathOperator(node, lctx, rctx, ctx, op);
  11012. return 0;
  11013. }
  11014. // Bitwise operators
  11015. // << >> >>> & | ^ <<= >>= >>>= &= |= ^=
  11016. if( op == ttAmp || op == ttAndAssign ||
  11017. op == ttBitOr || op == ttOrAssign ||
  11018. op == ttBitXor || op == ttXorAssign ||
  11019. op == ttBitShiftLeft || op == ttShiftLeftAssign ||
  11020. op == ttBitShiftRight || op == ttShiftRightLAssign ||
  11021. op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  11022. {
  11023. CompileBitwiseOperator(node, lctx, rctx, ctx, op);
  11024. return 0;
  11025. }
  11026. // Comparison operators
  11027. // == != < > <= >=
  11028. if( op == ttEqual || op == ttNotEqual ||
  11029. op == ttLessThan || op == ttLessThanOrEqual ||
  11030. op == ttGreaterThan || op == ttGreaterThanOrEqual )
  11031. {
  11032. CompileComparisonOperator(node, lctx, rctx, ctx, op);
  11033. return 0;
  11034. }
  11035. // Boolean operators
  11036. // && || ^^
  11037. if( op == ttAnd || op == ttOr || op == ttXor )
  11038. {
  11039. CompileBooleanOperator(node, lctx, rctx, ctx, op);
  11040. return 0;
  11041. }
  11042. }
  11043. asASSERT(false);
  11044. return -1;
  11045. }
  11046. void asCCompiler::ConvertToTempVariableNotIn(asCExprContext *ctx, asCExprContext *exclude)
  11047. {
  11048. int l = int(reservedVariables.GetLength());
  11049. if( exclude ) exclude->bc.GetVarsUsed(reservedVariables);
  11050. ConvertToTempVariable(ctx);
  11051. reservedVariables.SetLength(l);
  11052. }
  11053. void asCCompiler::ConvertToTempVariable(asCExprContext *ctx)
  11054. {
  11055. // This is only used for primitive types and null handles
  11056. asASSERT( ctx->type.dataType.IsPrimitive() || ctx->type.dataType.IsNullHandle() );
  11057. ConvertToVariable(ctx);
  11058. if( !ctx->type.isTemporary )
  11059. {
  11060. if( ctx->type.dataType.IsPrimitive() )
  11061. {
  11062. // Copy the variable to a temporary variable
  11063. int offset = AllocateVariable(ctx->type.dataType, true);
  11064. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  11065. ctx->bc.InstrW_W(asBC_CpyVtoV4, offset, ctx->type.stackOffset);
  11066. else
  11067. ctx->bc.InstrW_W(asBC_CpyVtoV8, offset, ctx->type.stackOffset);
  11068. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  11069. }
  11070. else
  11071. {
  11072. // We should never get here
  11073. asASSERT(false);
  11074. }
  11075. }
  11076. }
  11077. void asCCompiler::ConvertToVariable(asCExprContext *ctx)
  11078. {
  11079. // We should never get here while the context is still an unprocessed property accessor
  11080. asASSERT(ctx->property_get == 0 && ctx->property_set == 0);
  11081. int offset;
  11082. if( !ctx->type.isVariable &&
  11083. (ctx->type.dataType.IsObjectHandle() ||
  11084. (ctx->type.dataType.IsObject() && ctx->type.dataType.SupportHandles())) )
  11085. {
  11086. offset = AllocateVariable(ctx->type.dataType, true);
  11087. if( ctx->type.IsNullConstant() )
  11088. {
  11089. if( ctx->bc.GetLastInstr() == asBC_PshNull )
  11090. ctx->bc.Instr(asBC_PopPtr); // Pop the null constant pushed onto the stack
  11091. ctx->bc.InstrSHORT(asBC_ClrVPtr, (short)offset);
  11092. }
  11093. else
  11094. {
  11095. Dereference(ctx, true);
  11096. // Copy the object handle to a variable
  11097. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  11098. if( ctx->type.dataType.IsFuncdef() )
  11099. ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  11100. else
  11101. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo());
  11102. ctx->bc.Instr(asBC_PopPtr);
  11103. }
  11104. // As this is an object the reference must be placed on the stack
  11105. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  11106. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  11107. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  11108. ctx->type.dataType.MakeHandle(true);
  11109. ctx->type.dataType.MakeReference(true);
  11110. }
  11111. else if( (!ctx->type.isVariable || ctx->type.dataType.IsReference()) &&
  11112. ctx->type.dataType.IsPrimitive() )
  11113. {
  11114. if( ctx->type.isConstant )
  11115. {
  11116. offset = AllocateVariable(ctx->type.dataType, true);
  11117. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  11118. ctx->bc.InstrSHORT_B(asBC_SetV1, (short)offset, ctx->type.GetConstantB());
  11119. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  11120. ctx->bc.InstrSHORT_W(asBC_SetV2, (short)offset, ctx->type.GetConstantW());
  11121. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 )
  11122. ctx->bc.InstrSHORT_DW(asBC_SetV4, (short)offset, ctx->type.GetConstantDW());
  11123. else
  11124. ctx->bc.InstrSHORT_QW(asBC_SetV8, (short)offset, ctx->type.GetConstantQW());
  11125. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  11126. return;
  11127. }
  11128. else
  11129. {
  11130. asASSERT(ctx->type.dataType.IsPrimitive());
  11131. asASSERT(ctx->type.dataType.IsReference());
  11132. ctx->type.dataType.MakeReference(false);
  11133. offset = AllocateVariable(ctx->type.dataType, true);
  11134. // Read the value from the address in the register directly into the variable
  11135. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  11136. ctx->bc.InstrSHORT(asBC_RDR1, (short)offset);
  11137. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  11138. ctx->bc.InstrSHORT(asBC_RDR2, (short)offset);
  11139. else if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  11140. ctx->bc.InstrSHORT(asBC_RDR4, (short)offset);
  11141. else
  11142. ctx->bc.InstrSHORT(asBC_RDR8, (short)offset);
  11143. }
  11144. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  11145. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  11146. }
  11147. }
  11148. void asCCompiler::ConvertToVariableNotIn(asCExprContext *ctx, asCExprContext *exclude)
  11149. {
  11150. int l = int(reservedVariables.GetLength());
  11151. if( exclude ) exclude->bc.GetVarsUsed(reservedVariables);
  11152. ConvertToVariable(ctx);
  11153. reservedVariables.SetLength(l);
  11154. }
  11155. void asCCompiler::ImplicitConvObjectToBestMathType(asCExprContext *ctx, asCScriptNode *node)
  11156. {
  11157. asCArray<int> funcs;
  11158. asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  11159. if( ot )
  11160. {
  11161. for( unsigned int n = 0; n < ot->methods.GetLength(); n++ )
  11162. {
  11163. // Consider only implicit casts
  11164. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  11165. if( func->name == "opImplConv" &&
  11166. func->returnType.IsPrimitive() &&
  11167. func->parameterTypes.GetLength() == 0 )
  11168. funcs.PushLast(ot->methods[n]);
  11169. }
  11170. // Use the one with the highest precision
  11171. const eTokenType match[10] = {ttDouble, ttFloat, ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8};
  11172. while( funcs.GetLength() > 1 )
  11173. {
  11174. eTokenType returnType = builder->GetFunctionDescription(funcs[0])->returnType.GetTokenType();
  11175. int value1 = 11, value2 = 11;
  11176. for( asUINT i = 0; i < 10; i++ )
  11177. {
  11178. if( returnType == match[i] )
  11179. {
  11180. value1 = i;
  11181. break;
  11182. }
  11183. }
  11184. for( asUINT n = 1; n < funcs.GetLength(); n++ )
  11185. {
  11186. returnType = builder->GetFunctionDescription(funcs[n])->returnType.GetTokenType();
  11187. for( asUINT i = 0; i < 10; i++ )
  11188. {
  11189. if( returnType == match[i] )
  11190. {
  11191. value2 = i;
  11192. break;
  11193. }
  11194. }
  11195. if( value2 >= value1 )
  11196. {
  11197. // Remove this and continue searching
  11198. funcs.RemoveIndexUnordered(n--);
  11199. }
  11200. else
  11201. {
  11202. // Remove the first, and start over
  11203. funcs.RemoveIndexUnordered(0);
  11204. break;
  11205. }
  11206. }
  11207. }
  11208. // Do the conversion
  11209. if( funcs.GetLength() )
  11210. ImplicitConvObjectToPrimitive(ctx, builder->GetFunctionDescription(funcs[0])->returnType, node, asIC_IMPLICIT_CONV);
  11211. }
  11212. }
  11213. void asCCompiler::CompileMathOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType op)
  11214. {
  11215. // TODO: If a constant is only using 32bits, then a 32bit operation is preferred
  11216. // TODO: clean up: This initial part is identical to CompileComparisonOperator. Make a common function out of it
  11217. // If either operand is a non-primitive then use the primitive type
  11218. if( !lctx->type.dataType.IsPrimitive() )
  11219. {
  11220. int l = int(reservedVariables.GetLength());
  11221. rctx->bc.GetVarsUsed(reservedVariables);
  11222. ImplicitConvObjectToBestMathType(lctx, node);
  11223. reservedVariables.SetLength(l);
  11224. }
  11225. if( !rctx->type.dataType.IsPrimitive() )
  11226. {
  11227. int l = int(reservedVariables.GetLength());
  11228. lctx->bc.GetVarsUsed(reservedVariables);
  11229. ImplicitConvObjectToBestMathType(rctx, node);
  11230. reservedVariables.SetLength(l);
  11231. }
  11232. // Both types must now be primitives. Implicitly convert them so they match
  11233. asCDataType to;
  11234. if( lctx->type.dataType.IsDoubleType() || rctx->type.dataType.IsDoubleType() )
  11235. to.SetTokenType(ttDouble);
  11236. else if( lctx->type.dataType.IsFloatType() || rctx->type.dataType.IsFloatType() )
  11237. to.SetTokenType(ttFloat);
  11238. else if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 || rctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  11239. {
  11240. // Convert to int64 if both are signed or if one is non-constant and signed
  11241. if( (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) ||
  11242. (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) )
  11243. to.SetTokenType(ttInt64);
  11244. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  11245. to.SetTokenType(ttUInt64);
  11246. else
  11247. to.SetTokenType(ttInt64);
  11248. }
  11249. else
  11250. {
  11251. // Convert to int32 if both are signed or if one is non-constant and signed
  11252. if( (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) ||
  11253. (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) )
  11254. to.SetTokenType(ttInt);
  11255. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  11256. to.SetTokenType(ttUInt);
  11257. else
  11258. to.SetTokenType(ttInt);
  11259. }
  11260. // If doing an operation with double constant and float variable, the constant should be converted to float
  11261. if( (lctx->type.isConstant && lctx->type.dataType.IsDoubleType() && !rctx->type.isConstant && rctx->type.dataType.IsFloatType()) ||
  11262. (rctx->type.isConstant && rctx->type.dataType.IsDoubleType() && !lctx->type.isConstant && lctx->type.dataType.IsFloatType()) )
  11263. to.SetTokenType(ttFloat);
  11264. if( op == ttUnrecognizedToken )
  11265. op = node->tokenType;
  11266. // If integer division is disabled, convert to floating-point
  11267. if( engine->ep.disableIntegerDivision &&
  11268. (op == ttSlash || op == ttDivAssign) &&
  11269. (to.IsIntegerType() || to.IsUnsignedType()) )
  11270. {
  11271. // Use double to avoid losing precision when dividing with 32bit ints
  11272. // For 64bit ints there is unfortunately no greater type so with those
  11273. // there is still a risk of loosing precision
  11274. to.SetTokenType(ttDouble);
  11275. }
  11276. // Do the actual conversion
  11277. int l = int(reservedVariables.GetLength());
  11278. rctx->bc.GetVarsUsed(reservedVariables);
  11279. lctx->bc.GetVarsUsed(reservedVariables);
  11280. if( lctx->type.dataType.IsReference() )
  11281. ConvertToVariable(lctx);
  11282. if( rctx->type.dataType.IsReference() )
  11283. ConvertToVariable(rctx);
  11284. if( to.IsPrimitive() )
  11285. {
  11286. // ttStarStar allows an integer, right-hand operand and a double
  11287. // left-hand operand.
  11288. if( (op == ttStarStar || op == ttPowAssign) &&
  11289. lctx->type.dataType.IsDoubleType() &&
  11290. (rctx->type.dataType.IsIntegerType() ||
  11291. rctx->type.dataType.IsUnsignedType()) )
  11292. {
  11293. to.SetTokenType(ttInt);
  11294. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true);
  11295. to.SetTokenType(ttDouble);
  11296. }
  11297. else
  11298. {
  11299. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true);
  11300. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true);
  11301. }
  11302. }
  11303. reservedVariables.SetLength(l);
  11304. // Verify that the conversion was successful
  11305. if( !lctx->type.dataType.IsIntegerType() &&
  11306. !lctx->type.dataType.IsUnsignedType() &&
  11307. !lctx->type.dataType.IsFloatType() &&
  11308. !lctx->type.dataType.IsDoubleType() )
  11309. {
  11310. asCString str;
  11311. str.Format(TXT_NO_CONVERSION_s_TO_MATH_TYPE, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  11312. Error(str, node);
  11313. ctx->type.SetDummy();
  11314. return;
  11315. }
  11316. if( !rctx->type.dataType.IsIntegerType() &&
  11317. !rctx->type.dataType.IsUnsignedType() &&
  11318. !rctx->type.dataType.IsFloatType() &&
  11319. !rctx->type.dataType.IsDoubleType() )
  11320. {
  11321. asCString str;
  11322. str.Format(TXT_NO_CONVERSION_s_TO_MATH_TYPE, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  11323. Error(str, node);
  11324. ctx->type.SetDummy();
  11325. return;
  11326. }
  11327. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  11328. // Verify if we are dividing with a constant zero
  11329. if( rctx->type.isConstant &&
  11330. (op == ttSlash || op == ttDivAssign ||
  11331. op == ttPercent || op == ttModAssign) &&
  11332. ((rctx->type.dataType.GetSizeInMemoryBytes() == 4 && rctx->type.GetConstantDW() == 0) ||
  11333. (rctx->type.dataType.GetSizeInMemoryBytes() == 8 && rctx->type.GetConstantQW() == 0) ||
  11334. (rctx->type.dataType.GetSizeInMemoryBytes() == 1 && rctx->type.GetConstantB() == 0) ||
  11335. (rctx->type.dataType.GetSizeInMemoryBytes() == 2 && rctx->type.GetConstantW() == 0)) )
  11336. {
  11337. Error(TXT_DIVIDE_BY_ZERO, node);
  11338. }
  11339. if( !isConstant )
  11340. {
  11341. ConvertToVariableNotIn(lctx, rctx);
  11342. ConvertToVariableNotIn(rctx, lctx);
  11343. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  11344. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  11345. if( op == ttAddAssign || op == ttSubAssign ||
  11346. op == ttMulAssign || op == ttDivAssign ||
  11347. op == ttModAssign || op == ttPowAssign )
  11348. {
  11349. // Merge the operands in the different order so that they are evaluated correctly
  11350. MergeExprBytecode(ctx, rctx);
  11351. MergeExprBytecode(ctx, lctx);
  11352. // We must not process the deferred parameters yet, as
  11353. // it may overwrite the lvalue kept in the register
  11354. }
  11355. else
  11356. {
  11357. MergeExprBytecode(ctx, lctx);
  11358. MergeExprBytecode(ctx, rctx);
  11359. ProcessDeferredParams(ctx);
  11360. }
  11361. asEBCInstr instruction = asBC_ADDi;
  11362. if( lctx->type.dataType.IsIntegerType() ||
  11363. lctx->type.dataType.IsUnsignedType() )
  11364. {
  11365. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  11366. {
  11367. if( op == ttPlus || op == ttAddAssign )
  11368. instruction = asBC_ADDi;
  11369. else if( op == ttMinus || op == ttSubAssign )
  11370. instruction = asBC_SUBi;
  11371. else if( op == ttStar || op == ttMulAssign )
  11372. instruction = asBC_MULi;
  11373. else if( op == ttSlash || op == ttDivAssign )
  11374. {
  11375. if( lctx->type.dataType.IsIntegerType() )
  11376. instruction = asBC_DIVi;
  11377. else
  11378. instruction = asBC_DIVu;
  11379. }
  11380. else if( op == ttPercent || op == ttModAssign )
  11381. {
  11382. if( lctx->type.dataType.IsIntegerType() )
  11383. instruction = asBC_MODi;
  11384. else
  11385. instruction = asBC_MODu;
  11386. }
  11387. else if( op == ttStarStar || op == ttPowAssign )
  11388. {
  11389. if( lctx->type.dataType.IsIntegerType() )
  11390. instruction = asBC_POWi;
  11391. else
  11392. instruction = asBC_POWu;
  11393. }
  11394. }
  11395. else
  11396. {
  11397. if( op == ttPlus || op == ttAddAssign )
  11398. instruction = asBC_ADDi64;
  11399. else if( op == ttMinus || op == ttSubAssign )
  11400. instruction = asBC_SUBi64;
  11401. else if( op == ttStar || op == ttMulAssign )
  11402. instruction = asBC_MULi64;
  11403. else if( op == ttSlash || op == ttDivAssign )
  11404. {
  11405. if( lctx->type.dataType.IsIntegerType() )
  11406. instruction = asBC_DIVi64;
  11407. else
  11408. instruction = asBC_DIVu64;
  11409. }
  11410. else if( op == ttPercent || op == ttModAssign )
  11411. {
  11412. if( lctx->type.dataType.IsIntegerType() )
  11413. instruction = asBC_MODi64;
  11414. else
  11415. instruction = asBC_MODu64;
  11416. }
  11417. else if( op == ttStarStar || op == ttPowAssign )
  11418. {
  11419. if( lctx->type.dataType.IsIntegerType() )
  11420. instruction = asBC_POWi64;
  11421. else
  11422. instruction = asBC_POWu64;
  11423. }
  11424. }
  11425. }
  11426. else if( lctx->type.dataType.IsFloatType() )
  11427. {
  11428. if( op == ttPlus || op == ttAddAssign )
  11429. instruction = asBC_ADDf;
  11430. else if( op == ttMinus || op == ttSubAssign )
  11431. instruction = asBC_SUBf;
  11432. else if( op == ttStar || op == ttMulAssign )
  11433. instruction = asBC_MULf;
  11434. else if( op == ttSlash || op == ttDivAssign )
  11435. instruction = asBC_DIVf;
  11436. else if( op == ttPercent || op == ttModAssign )
  11437. instruction = asBC_MODf;
  11438. else if( op == ttStarStar || op == ttPowAssign )
  11439. instruction = asBC_POWf;
  11440. }
  11441. else if( lctx->type.dataType.IsDoubleType() )
  11442. {
  11443. if( rctx->type.dataType.IsIntegerType() )
  11444. {
  11445. asASSERT(rctx->type.dataType.GetSizeInMemoryDWords() == 1);
  11446. if( op == ttStarStar || op == ttPowAssign )
  11447. instruction = asBC_POWdi;
  11448. else
  11449. asASSERT(false); // Should not be possible
  11450. }
  11451. else
  11452. {
  11453. if( op == ttPlus || op == ttAddAssign )
  11454. instruction = asBC_ADDd;
  11455. else if( op == ttMinus || op == ttSubAssign )
  11456. instruction = asBC_SUBd;
  11457. else if( op == ttStar || op == ttMulAssign )
  11458. instruction = asBC_MULd;
  11459. else if( op == ttSlash || op == ttDivAssign )
  11460. instruction = asBC_DIVd;
  11461. else if( op == ttPercent || op == ttModAssign )
  11462. instruction = asBC_MODd;
  11463. else if( op == ttStarStar || op == ttPowAssign )
  11464. instruction = asBC_POWd;
  11465. }
  11466. }
  11467. else
  11468. {
  11469. // Shouldn't be possible
  11470. asASSERT(false);
  11471. }
  11472. // Do the operation
  11473. int a = AllocateVariable(lctx->type.dataType, true);
  11474. int b = lctx->type.stackOffset;
  11475. int c = rctx->type.stackOffset;
  11476. ctx->bc.InstrW_W_W(instruction, a, b, c);
  11477. ctx->type.SetVariable(lctx->type.dataType, a, true);
  11478. }
  11479. else
  11480. {
  11481. // Both values are constants
  11482. if( lctx->type.dataType.IsIntegerType() ||
  11483. lctx->type.dataType.IsUnsignedType() )
  11484. {
  11485. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  11486. {
  11487. int v = 0;
  11488. if( op == ttPlus )
  11489. v = int(lctx->type.GetConstantDW()) + int(rctx->type.GetConstantDW());
  11490. else if( op == ttMinus )
  11491. v = int(lctx->type.GetConstantDW()) - int(rctx->type.GetConstantDW());
  11492. else if( op == ttStar )
  11493. v = int(lctx->type.GetConstantDW()) * int(rctx->type.GetConstantDW());
  11494. else if( op == ttSlash )
  11495. {
  11496. // TODO: Should probably report an error, rather than silently convert the value to 0
  11497. if( rctx->type.GetConstantDW() == 0 || (int(rctx->type.GetConstantDW()) == -1 && lctx->type.GetConstantDW() == 0x80000000) )
  11498. v = 0;
  11499. else
  11500. if( lctx->type.dataType.IsIntegerType() )
  11501. v = int(lctx->type.GetConstantDW()) / int(rctx->type.GetConstantDW());
  11502. else
  11503. v = lctx->type.GetConstantDW() / rctx->type.GetConstantDW();
  11504. }
  11505. else if( op == ttPercent )
  11506. {
  11507. // TODO: Should probably report an error, rather than silently convert the value to 0
  11508. if( rctx->type.GetConstantDW() == 0 || (int(rctx->type.GetConstantDW()) == -1 && lctx->type.GetConstantDW() == 0x80000000) )
  11509. v = 0;
  11510. else
  11511. if( lctx->type.dataType.IsIntegerType() )
  11512. v = int(lctx->type.GetConstantDW()) % int(rctx->type.GetConstantDW());
  11513. else
  11514. v = lctx->type.GetConstantDW() % rctx->type.GetConstantDW();
  11515. }
  11516. else if( op == ttStarStar )
  11517. {
  11518. bool isOverflow;
  11519. if( lctx->type.dataType.IsIntegerType() )
  11520. v = as_powi(int(lctx->type.GetConstantDW()), int(rctx->type.GetConstantDW()), isOverflow);
  11521. else
  11522. v = as_powu(lctx->type.GetConstantDW(), rctx->type.GetConstantDW(), isOverflow);
  11523. if( isOverflow )
  11524. Error(TXT_POW_OVERFLOW, node);
  11525. }
  11526. ctx->type.SetConstantDW(lctx->type.dataType, v);
  11527. // If the right value is greater than the left value in a minus operation, then we need to convert the type to int
  11528. if( lctx->type.dataType.GetTokenType() == ttUInt && op == ttMinus && lctx->type.GetConstantDW() < rctx->type.GetConstantDW())
  11529. ctx->type.dataType.SetTokenType(ttInt);
  11530. }
  11531. else
  11532. {
  11533. asQWORD v = 0;
  11534. if( op == ttPlus )
  11535. v = asINT64(lctx->type.GetConstantQW()) + asINT64(rctx->type.GetConstantQW());
  11536. else if( op == ttMinus )
  11537. v = asINT64(lctx->type.GetConstantQW()) - asINT64(rctx->type.GetConstantQW());
  11538. else if( op == ttStar )
  11539. v = asINT64(lctx->type.GetConstantQW()) * asINT64(rctx->type.GetConstantQW());
  11540. else if( op == ttSlash )
  11541. {
  11542. // TODO: Should probably report an error, rather than silently convert the value to 0
  11543. if( rctx->type.GetConstantQW() == 0 || (rctx->type.GetConstantQW() == asQWORD(-1) && lctx->type.GetConstantQW() == (asQWORD(1)<<63)) )
  11544. v = 0;
  11545. else
  11546. if( lctx->type.dataType.IsIntegerType() )
  11547. v = asINT64(lctx->type.GetConstantQW()) / asINT64(rctx->type.GetConstantQW());
  11548. else
  11549. v = lctx->type.GetConstantQW() / rctx->type.GetConstantQW();
  11550. }
  11551. else if( op == ttPercent )
  11552. {
  11553. // TODO: Should probably report an error, rather than silently convert the value to 0
  11554. if( rctx->type.GetConstantQW() == 0 || (rctx->type.GetConstantQW() == asQWORD(-1) && lctx->type.GetConstantQW() == (asQWORD(1)<<63)) )
  11555. v = 0;
  11556. else
  11557. if( lctx->type.dataType.IsIntegerType() )
  11558. v = asINT64(lctx->type.GetConstantQW()) % asINT64(rctx->type.GetConstantQW());
  11559. else
  11560. v = lctx->type.GetConstantQW() % rctx->type.GetConstantQW();
  11561. }
  11562. else if( op == ttStarStar )
  11563. {
  11564. bool isOverflow;
  11565. if( lctx->type.dataType.IsIntegerType() )
  11566. v = as_powi64(asINT64(lctx->type.GetConstantQW()), asINT64(rctx->type.GetConstantQW()), isOverflow);
  11567. else
  11568. v = as_powu64(lctx->type.GetConstantQW(), rctx->type.GetConstantQW(), isOverflow);
  11569. if( isOverflow )
  11570. Error(TXT_POW_OVERFLOW, node);
  11571. }
  11572. ctx->type.SetConstantQW(lctx->type.dataType, v);
  11573. // If the right value is greater than the left value in a minus operation, then we need to convert the type to int
  11574. if( lctx->type.dataType.GetTokenType() == ttUInt64 && op == ttMinus && lctx->type.GetConstantQW() < rctx->type.GetConstantQW())
  11575. ctx->type.dataType.SetTokenType(ttInt64);
  11576. }
  11577. }
  11578. else if( lctx->type.dataType.IsFloatType() )
  11579. {
  11580. float v = 0.0f;
  11581. if( op == ttPlus )
  11582. v = lctx->type.GetConstantF() + rctx->type.GetConstantF();
  11583. else if( op == ttMinus )
  11584. v = lctx->type.GetConstantF() - rctx->type.GetConstantF();
  11585. else if( op == ttStar )
  11586. v = lctx->type.GetConstantF() * rctx->type.GetConstantF();
  11587. else if( op == ttSlash )
  11588. {
  11589. if( rctx->type.GetConstantF() == 0 )
  11590. v = 0;
  11591. else
  11592. v = lctx->type.GetConstantF() / rctx->type.GetConstantF();
  11593. }
  11594. else if( op == ttPercent )
  11595. {
  11596. if( rctx->type.GetConstantF() == 0 )
  11597. v = 0;
  11598. else
  11599. v = fmodf(lctx->type.GetConstantF(), rctx->type.GetConstantF());
  11600. }
  11601. else if( op == ttStarStar )
  11602. {
  11603. v = powf(lctx->type.GetConstantF(), rctx->type.GetConstantF());
  11604. if( v == HUGE_VAL )
  11605. Error(TXT_POW_OVERFLOW, node);
  11606. }
  11607. ctx->type.SetConstantF(lctx->type.dataType, v);
  11608. }
  11609. else if( lctx->type.dataType.IsDoubleType() )
  11610. {
  11611. double v = 0.0;
  11612. if( rctx->type.dataType.IsIntegerType() )
  11613. {
  11614. asASSERT(rctx->type.dataType.GetSizeInMemoryDWords() == 1);
  11615. if( op == ttStarStar || op == ttPowAssign )
  11616. {
  11617. v = pow(lctx->type.GetConstantD(), int(rctx->type.GetConstantDW()));
  11618. if( v == HUGE_VAL )
  11619. Error(TXT_POW_OVERFLOW, node);
  11620. }
  11621. else
  11622. asASSERT(false); // Should not be possible
  11623. }
  11624. else
  11625. {
  11626. if( op == ttPlus )
  11627. v = lctx->type.GetConstantD() + rctx->type.GetConstantD();
  11628. else if( op == ttMinus )
  11629. v = lctx->type.GetConstantD() - rctx->type.GetConstantD();
  11630. else if( op == ttStar )
  11631. v = lctx->type.GetConstantD() * rctx->type.GetConstantD();
  11632. else if( op == ttSlash )
  11633. {
  11634. if( rctx->type.GetConstantD() == 0 )
  11635. v = 0;
  11636. else
  11637. v = lctx->type.GetConstantD() / rctx->type.GetConstantD();
  11638. }
  11639. else if( op == ttPercent )
  11640. {
  11641. if( rctx->type.GetConstantD() == 0 )
  11642. v = 0;
  11643. else
  11644. v = fmod(lctx->type.GetConstantD(), rctx->type.GetConstantD());
  11645. }
  11646. else if( op == ttStarStar )
  11647. {
  11648. v = pow(lctx->type.GetConstantD(), rctx->type.GetConstantD());
  11649. if( v == HUGE_VAL )
  11650. Error(TXT_POW_OVERFLOW, node);
  11651. }
  11652. }
  11653. ctx->type.SetConstantD(lctx->type.dataType, v);
  11654. }
  11655. else
  11656. {
  11657. // Shouldn't be possible
  11658. asASSERT(false);
  11659. }
  11660. }
  11661. }
  11662. void asCCompiler::CompileBitwiseOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType op)
  11663. {
  11664. // TODO: If a constant is only using 32bits, then a 32bit operation is preferred
  11665. if( op == ttUnrecognizedToken )
  11666. op = node->tokenType;
  11667. if( op == ttAmp || op == ttAndAssign ||
  11668. op == ttBitOr || op == ttOrAssign ||
  11669. op == ttBitXor || op == ttXorAssign )
  11670. {
  11671. // Convert left hand operand to integer if it's not already one
  11672. asCDataType to;
  11673. if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 ||
  11674. rctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  11675. to.SetTokenType(ttInt64);
  11676. else
  11677. to.SetTokenType(ttInt);
  11678. // Do the actual conversion (keep sign/unsigned if possible)
  11679. int l = int(reservedVariables.GetLength());
  11680. rctx->bc.GetVarsUsed(reservedVariables);
  11681. if( lctx->type.dataType.IsUnsignedType() )
  11682. to.SetTokenType( to.GetSizeOnStackDWords() == 1 ? ttUInt : ttUInt64 );
  11683. else
  11684. to.SetTokenType( to.GetSizeOnStackDWords() == 1 ? ttInt : ttInt64 );
  11685. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true);
  11686. reservedVariables.SetLength(l);
  11687. // Verify that the conversion was successful
  11688. if( lctx->type.dataType != to )
  11689. {
  11690. asCString str;
  11691. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  11692. Error(str, node);
  11693. }
  11694. // Convert right hand operand to same size as left hand
  11695. l = int(reservedVariables.GetLength());
  11696. lctx->bc.GetVarsUsed(reservedVariables);
  11697. if( rctx->type.dataType.IsUnsignedType() )
  11698. to.SetTokenType( to.GetSizeOnStackDWords() == 1 ? ttUInt : ttUInt64 );
  11699. else
  11700. to.SetTokenType( to.GetSizeOnStackDWords() == 1 ? ttInt : ttInt64 );
  11701. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true);
  11702. reservedVariables.SetLength(l);
  11703. if( rctx->type.dataType != to )
  11704. {
  11705. asCString str;
  11706. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  11707. Error(str, node);
  11708. }
  11709. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  11710. if( !isConstant )
  11711. {
  11712. ConvertToVariableNotIn(lctx, rctx);
  11713. ConvertToVariableNotIn(rctx, lctx);
  11714. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  11715. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  11716. if( op == ttAndAssign || op == ttOrAssign || op == ttXorAssign )
  11717. {
  11718. // Compound assignments execute the right hand value first
  11719. MergeExprBytecode(ctx, rctx);
  11720. MergeExprBytecode(ctx, lctx);
  11721. }
  11722. else
  11723. {
  11724. MergeExprBytecode(ctx, lctx);
  11725. MergeExprBytecode(ctx, rctx);
  11726. }
  11727. ProcessDeferredParams(ctx);
  11728. asEBCInstr instruction = asBC_BAND;
  11729. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  11730. {
  11731. if( op == ttAmp || op == ttAndAssign )
  11732. instruction = asBC_BAND;
  11733. else if( op == ttBitOr || op == ttOrAssign )
  11734. instruction = asBC_BOR;
  11735. else if( op == ttBitXor || op == ttXorAssign )
  11736. instruction = asBC_BXOR;
  11737. }
  11738. else
  11739. {
  11740. if( op == ttAmp || op == ttAndAssign )
  11741. instruction = asBC_BAND64;
  11742. else if( op == ttBitOr || op == ttOrAssign )
  11743. instruction = asBC_BOR64;
  11744. else if( op == ttBitXor || op == ttXorAssign )
  11745. instruction = asBC_BXOR64;
  11746. }
  11747. // Do the operation
  11748. int a = AllocateVariable(lctx->type.dataType, true);
  11749. int b = lctx->type.stackOffset;
  11750. int c = rctx->type.stackOffset;
  11751. ctx->bc.InstrW_W_W(instruction, a, b, c);
  11752. ctx->type.SetVariable(lctx->type.dataType, a, true);
  11753. }
  11754. else
  11755. {
  11756. if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  11757. {
  11758. asQWORD v = 0;
  11759. if( op == ttAmp )
  11760. v = lctx->type.GetConstantQW() & rctx->type.GetConstantQW();
  11761. else if( op == ttBitOr )
  11762. v = lctx->type.GetConstantQW() | rctx->type.GetConstantQW();
  11763. else if( op == ttBitXor )
  11764. v = lctx->type.GetConstantQW() ^ rctx->type.GetConstantQW();
  11765. // Remember the result
  11766. ctx->type.SetConstantQW(lctx->type.dataType, v);
  11767. }
  11768. else
  11769. {
  11770. asDWORD v = 0;
  11771. if( op == ttAmp )
  11772. v = lctx->type.GetConstantDW() & rctx->type.GetConstantDW();
  11773. else if( op == ttBitOr )
  11774. v = lctx->type.GetConstantDW() | rctx->type.GetConstantDW();
  11775. else if( op == ttBitXor )
  11776. v = lctx->type.GetConstantDW() ^ rctx->type.GetConstantDW();
  11777. // Remember the result
  11778. ctx->type.SetConstantDW(lctx->type.dataType, v);
  11779. }
  11780. }
  11781. }
  11782. else if( op == ttBitShiftLeft || op == ttShiftLeftAssign ||
  11783. op == ttBitShiftRight || op == ttShiftRightLAssign ||
  11784. op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  11785. {
  11786. // Don't permit object to primitive conversion, since we don't know which integer type is the correct one
  11787. if( lctx->type.dataType.IsObject() )
  11788. {
  11789. asCString str;
  11790. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  11791. Error(str, node);
  11792. // Set an integer value and allow the compiler to continue
  11793. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), 0);
  11794. return;
  11795. }
  11796. // Convert left hand operand to integer if it's not already one
  11797. asCDataType to = lctx->type.dataType;
  11798. if( lctx->type.dataType.IsUnsignedType() &&
  11799. lctx->type.dataType.GetSizeInMemoryBytes() < 4 )
  11800. {
  11801. // Upgrade to 32bit
  11802. to = asCDataType::CreatePrimitive(ttUInt, false);
  11803. }
  11804. else if( !lctx->type.dataType.IsUnsignedType() )
  11805. {
  11806. if (lctx->type.dataType.GetSizeInMemoryDWords() == 2)
  11807. to = asCDataType::CreatePrimitive(ttInt64, false);
  11808. else
  11809. to = asCDataType::CreatePrimitive(ttInt, false);
  11810. }
  11811. // Do the actual conversion
  11812. int l = int(reservedVariables.GetLength());
  11813. rctx->bc.GetVarsUsed(reservedVariables);
  11814. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true);
  11815. reservedVariables.SetLength(l);
  11816. // Verify that the conversion was successful
  11817. if( lctx->type.dataType != to )
  11818. {
  11819. asCString str;
  11820. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  11821. Error(str, node);
  11822. }
  11823. // Right operand must be 32bit uint
  11824. l = int(reservedVariables.GetLength());
  11825. lctx->bc.GetVarsUsed(reservedVariables);
  11826. ImplicitConversion(rctx, asCDataType::CreatePrimitive(ttUInt, true), node, asIC_IMPLICIT_CONV, true);
  11827. reservedVariables.SetLength(l);
  11828. if( !rctx->type.dataType.IsUnsignedType() )
  11829. {
  11830. asCString str;
  11831. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), "uint");
  11832. Error(str, node);
  11833. }
  11834. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  11835. if( !isConstant )
  11836. {
  11837. ConvertToVariableNotIn(lctx, rctx);
  11838. ConvertToVariableNotIn(rctx, lctx);
  11839. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  11840. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  11841. if( op == ttShiftLeftAssign || op == ttShiftRightLAssign || op == ttShiftRightAAssign )
  11842. {
  11843. // Compound assignments execute the right hand value first
  11844. MergeExprBytecode(ctx, rctx);
  11845. MergeExprBytecode(ctx, lctx);
  11846. }
  11847. else
  11848. {
  11849. MergeExprBytecode(ctx, lctx);
  11850. MergeExprBytecode(ctx, rctx);
  11851. }
  11852. ProcessDeferredParams(ctx);
  11853. asEBCInstr instruction = asBC_BSLL;
  11854. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  11855. {
  11856. if( op == ttBitShiftLeft || op == ttShiftLeftAssign )
  11857. instruction = asBC_BSLL;
  11858. else if( op == ttBitShiftRight || op == ttShiftRightLAssign )
  11859. instruction = asBC_BSRL;
  11860. else if( op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  11861. instruction = asBC_BSRA;
  11862. }
  11863. else
  11864. {
  11865. if( op == ttBitShiftLeft || op == ttShiftLeftAssign )
  11866. instruction = asBC_BSLL64;
  11867. else if( op == ttBitShiftRight || op == ttShiftRightLAssign )
  11868. instruction = asBC_BSRL64;
  11869. else if( op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  11870. instruction = asBC_BSRA64;
  11871. }
  11872. // Do the operation
  11873. int a = AllocateVariable(lctx->type.dataType, true);
  11874. int b = lctx->type.stackOffset;
  11875. int c = rctx->type.stackOffset;
  11876. ctx->bc.InstrW_W_W(instruction, a, b, c);
  11877. ctx->type.SetVariable(lctx->type.dataType, a, true);
  11878. }
  11879. else
  11880. {
  11881. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  11882. {
  11883. asDWORD v = 0;
  11884. if( op == ttBitShiftLeft )
  11885. v = lctx->type.GetConstantDW() << rctx->type.GetConstantDW();
  11886. else if( op == ttBitShiftRight )
  11887. v = lctx->type.GetConstantDW() >> rctx->type.GetConstantDW();
  11888. else if( op == ttBitShiftRightArith )
  11889. v = int(lctx->type.GetConstantDW()) >> rctx->type.GetConstantDW();
  11890. ctx->type.SetConstantDW(lctx->type.dataType, v);
  11891. }
  11892. else
  11893. {
  11894. asQWORD v = 0;
  11895. if( op == ttBitShiftLeft )
  11896. v = lctx->type.GetConstantQW() << rctx->type.GetConstantDW();
  11897. else if( op == ttBitShiftRight )
  11898. v = lctx->type.GetConstantQW() >> rctx->type.GetConstantDW();
  11899. else if( op == ttBitShiftRightArith )
  11900. v = asINT64(lctx->type.GetConstantQW()) >> rctx->type.GetConstantDW();
  11901. ctx->type.SetConstantQW(lctx->type.dataType, v);
  11902. }
  11903. }
  11904. }
  11905. }
  11906. void asCCompiler::CompileComparisonOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType op)
  11907. {
  11908. // Both operands must be of the same type
  11909. // If either operand is a non-primitive then first convert them to the best number type
  11910. if( !lctx->type.dataType.IsPrimitive() )
  11911. {
  11912. int l = int(reservedVariables.GetLength());
  11913. rctx->bc.GetVarsUsed(reservedVariables);
  11914. ImplicitConvObjectToBestMathType(lctx, node);
  11915. reservedVariables.SetLength(l);
  11916. }
  11917. if( !rctx->type.dataType.IsPrimitive() )
  11918. {
  11919. int l = int(reservedVariables.GetLength());
  11920. lctx->bc.GetVarsUsed(reservedVariables);
  11921. ImplicitConvObjectToBestMathType(rctx, node);
  11922. reservedVariables.SetLength(l);
  11923. }
  11924. // Implicitly convert the operands to matching types
  11925. asCDataType to;
  11926. if( lctx->type.dataType.IsDoubleType() || rctx->type.dataType.IsDoubleType() )
  11927. to.SetTokenType(ttDouble);
  11928. else if( lctx->type.dataType.IsFloatType() || rctx->type.dataType.IsFloatType() )
  11929. to.SetTokenType(ttFloat);
  11930. else if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 || rctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  11931. {
  11932. // Convert to int64 if both are signed or if one is non-constant and signed
  11933. if( (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) ||
  11934. (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) )
  11935. to.SetTokenType(ttInt64);
  11936. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  11937. to.SetTokenType(ttUInt64);
  11938. else
  11939. to.SetTokenType(ttInt64);
  11940. }
  11941. else
  11942. {
  11943. // Convert to int32 if both are signed or if one is non-constant and signed
  11944. if( (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) ||
  11945. (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) )
  11946. to.SetTokenType(ttInt);
  11947. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  11948. to.SetTokenType(ttUInt);
  11949. else if( lctx->type.dataType.IsBooleanType() || rctx->type.dataType.IsBooleanType() )
  11950. to.SetTokenType(ttBool);
  11951. else
  11952. to.SetTokenType(ttInt);
  11953. }
  11954. // If doing an operation with double constant and float variable, the constant should be converted to float
  11955. if( (lctx->type.isConstant && lctx->type.dataType.IsDoubleType() && !rctx->type.isConstant && rctx->type.dataType.IsFloatType()) ||
  11956. (rctx->type.isConstant && rctx->type.dataType.IsDoubleType() && !lctx->type.isConstant && lctx->type.dataType.IsFloatType()) )
  11957. to.SetTokenType(ttFloat);
  11958. asASSERT( to.GetTokenType() != ttUnrecognizedToken );
  11959. // Do we have a mismatch between the sign of the operand?
  11960. bool signMismatch = false;
  11961. for( int n = 0; !signMismatch && n < 2; n++ )
  11962. {
  11963. asCExprContext *opCtx = n ? rctx : lctx;
  11964. if( opCtx->type.dataType.IsUnsignedType() != to.IsUnsignedType() )
  11965. {
  11966. // We have a mismatch, unless the value is a literal constant and the conversion won't affect its value
  11967. signMismatch = true;
  11968. if( opCtx->type.isConstant )
  11969. {
  11970. if( opCtx->type.dataType.GetTokenType() == ttUInt64 || opCtx->type.dataType.GetTokenType() == ttInt64 )
  11971. {
  11972. if( !(opCtx->type.GetConstantQW() & (asQWORD(1)<<63)) )
  11973. signMismatch = false;
  11974. }
  11975. else
  11976. {
  11977. if( !(opCtx->type.GetConstantDW() & (1<<31)) )
  11978. signMismatch = false;
  11979. }
  11980. // It's not necessary to check for floats or double, because if
  11981. // it was then the types for the conversion will never be unsigned
  11982. }
  11983. }
  11984. }
  11985. // Check for signed/unsigned mismatch
  11986. if( signMismatch )
  11987. Warning(TXT_SIGNED_UNSIGNED_MISMATCH, node);
  11988. // Attempt to resolve ambiguous enumerations
  11989. if( lctx->type.dataType.IsEnumType() && rctx->enumValue != "" )
  11990. ImplicitConversion(rctx, lctx->type.dataType, node, asIC_IMPLICIT_CONV);
  11991. else if( rctx->type.dataType.IsEnumType() && lctx->enumValue != "" )
  11992. ImplicitConversion(lctx, rctx->type.dataType, node, asIC_IMPLICIT_CONV);
  11993. // Do the actual conversion
  11994. int l = int(reservedVariables.GetLength());
  11995. rctx->bc.GetVarsUsed(reservedVariables);
  11996. if( lctx->type.dataType.IsReference() )
  11997. ConvertToVariable(lctx);
  11998. if( rctx->type.dataType.IsReference() )
  11999. ConvertToVariable(rctx);
  12000. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV);
  12001. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV);
  12002. reservedVariables.SetLength(l);
  12003. // Verify that the conversion was successful
  12004. bool ok = true;
  12005. if( !lctx->type.dataType.IsEqualExceptConst(to) )
  12006. {
  12007. asCString str;
  12008. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  12009. Error(str, node);
  12010. ok = false;
  12011. }
  12012. if( !rctx->type.dataType.IsEqualExceptConst(to) )
  12013. {
  12014. asCString str;
  12015. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  12016. Error(str, node);
  12017. ok = false;
  12018. }
  12019. if( !ok )
  12020. {
  12021. // It wasn't possible to get two valid operands, so we just return
  12022. // a boolean result and let the compiler continue.
  12023. #if AS_SIZEOF_BOOL == 1
  12024. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  12025. #else
  12026. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  12027. #endif
  12028. return;
  12029. }
  12030. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  12031. if( op == ttUnrecognizedToken )
  12032. op = node->tokenType;
  12033. if( !isConstant )
  12034. {
  12035. if( to.IsBooleanType() )
  12036. {
  12037. if( op == ttEqual || op == ttNotEqual )
  12038. {
  12039. // Must convert to temporary variable, because we are changing the value before comparison
  12040. ConvertToTempVariableNotIn(lctx, rctx);
  12041. ConvertToTempVariableNotIn(rctx, lctx);
  12042. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  12043. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  12044. // Make sure they are equal if not false
  12045. lctx->bc.InstrWORD(asBC_NOT, lctx->type.stackOffset);
  12046. rctx->bc.InstrWORD(asBC_NOT, rctx->type.stackOffset);
  12047. MergeExprBytecode(ctx, lctx);
  12048. MergeExprBytecode(ctx, rctx);
  12049. ProcessDeferredParams(ctx);
  12050. int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, true), true);
  12051. int b = lctx->type.stackOffset;
  12052. int c = rctx->type.stackOffset;
  12053. if( op == ttEqual )
  12054. {
  12055. ctx->bc.InstrW_W(asBC_CMPi,b,c);
  12056. ctx->bc.Instr(asBC_TZ);
  12057. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  12058. }
  12059. else if( op == ttNotEqual )
  12060. {
  12061. ctx->bc.InstrW_W(asBC_CMPi,b,c);
  12062. ctx->bc.Instr(asBC_TNZ);
  12063. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  12064. }
  12065. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  12066. }
  12067. else
  12068. {
  12069. // TODO: Use TXT_ILLEGAL_OPERATION_ON
  12070. Error(TXT_ILLEGAL_OPERATION, node);
  12071. #if AS_SIZEOF_BOOL == 1
  12072. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), 0);
  12073. #else
  12074. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), 0);
  12075. #endif
  12076. }
  12077. }
  12078. else
  12079. {
  12080. ConvertToVariableNotIn(lctx, rctx);
  12081. ConvertToVariableNotIn(rctx, lctx);
  12082. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  12083. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  12084. MergeExprBytecode(ctx, lctx);
  12085. MergeExprBytecode(ctx, rctx);
  12086. ProcessDeferredParams(ctx);
  12087. asEBCInstr iCmp = asBC_CMPi, iT = asBC_TZ;
  12088. if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  12089. iCmp = asBC_CMPi;
  12090. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  12091. iCmp = asBC_CMPu;
  12092. else if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  12093. iCmp = asBC_CMPi64;
  12094. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  12095. iCmp = asBC_CMPu64;
  12096. else if( lctx->type.dataType.IsFloatType() )
  12097. iCmp = asBC_CMPf;
  12098. else if( lctx->type.dataType.IsDoubleType() )
  12099. iCmp = asBC_CMPd;
  12100. else
  12101. asASSERT(false);
  12102. if( op == ttEqual )
  12103. iT = asBC_TZ;
  12104. else if( op == ttNotEqual )
  12105. iT = asBC_TNZ;
  12106. else if( op == ttLessThan )
  12107. iT = asBC_TS;
  12108. else if( op == ttLessThanOrEqual )
  12109. iT = asBC_TNP;
  12110. else if( op == ttGreaterThan )
  12111. iT = asBC_TP;
  12112. else if( op == ttGreaterThanOrEqual )
  12113. iT = asBC_TNS;
  12114. int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, true), true);
  12115. int b = lctx->type.stackOffset;
  12116. int c = rctx->type.stackOffset;
  12117. ctx->bc.InstrW_W(iCmp, b, c);
  12118. ctx->bc.Instr(iT);
  12119. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  12120. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  12121. }
  12122. }
  12123. else
  12124. {
  12125. if( to.IsBooleanType() )
  12126. {
  12127. if( op == ttEqual || op == ttNotEqual )
  12128. {
  12129. asDWORD lv, rv;
  12130. #if AS_SIZEOF_BOOL == 1
  12131. lv = lctx->type.GetConstantB();
  12132. rv = rctx->type.GetConstantB();
  12133. #else
  12134. lv = lctx->type.GetConstantDW();
  12135. rv = rctx->type.GetConstantDW();
  12136. #endif
  12137. // Make sure they are equal if not false
  12138. if (lv != 0) lv = VALUE_OF_BOOLEAN_TRUE;
  12139. if (rv != 0) rv = VALUE_OF_BOOLEAN_TRUE;
  12140. asDWORD v = 0;
  12141. if (op == ttEqual)
  12142. v = (lv == rv) ? VALUE_OF_BOOLEAN_TRUE : 0;
  12143. else if (op == ttNotEqual)
  12144. v = (lv != rv) ? VALUE_OF_BOOLEAN_TRUE : 0;
  12145. #if AS_SIZEOF_BOOL == 1
  12146. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), (asBYTE)v);
  12147. #else
  12148. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), v);
  12149. #endif
  12150. }
  12151. else
  12152. {
  12153. // TODO: Use TXT_ILLEGAL_OPERATION_ON
  12154. Error(TXT_ILLEGAL_OPERATION, node);
  12155. }
  12156. }
  12157. else
  12158. {
  12159. int i = 0;
  12160. if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  12161. {
  12162. int v = int(lctx->type.GetConstantDW()) - int(rctx->type.GetConstantDW());
  12163. if( v < 0 ) i = -1;
  12164. if( v > 0 ) i = 1;
  12165. }
  12166. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  12167. {
  12168. asDWORD v1 = lctx->type.GetConstantDW();
  12169. asDWORD v2 = rctx->type.GetConstantDW();
  12170. if( v1 < v2 ) i = -1;
  12171. if( v1 > v2 ) i = 1;
  12172. }
  12173. else if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  12174. {
  12175. asINT64 v = asINT64(lctx->type.GetConstantQW()) - asINT64(rctx->type.GetConstantQW());
  12176. if( v < 0 ) i = -1;
  12177. if( v > 0 ) i = 1;
  12178. }
  12179. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  12180. {
  12181. asQWORD v1 = lctx->type.GetConstantQW();
  12182. asQWORD v2 = rctx->type.GetConstantQW();
  12183. if( v1 < v2 ) i = -1;
  12184. if( v1 > v2 ) i = 1;
  12185. }
  12186. else if( lctx->type.dataType.IsFloatType() )
  12187. {
  12188. float v = lctx->type.GetConstantF() - rctx->type.GetConstantF();
  12189. if( v < 0 ) i = -1;
  12190. if( v > 0 ) i = 1;
  12191. }
  12192. else if( lctx->type.dataType.IsDoubleType() )
  12193. {
  12194. double v = lctx->type.GetConstantD() - rctx->type.GetConstantD();
  12195. if( v < 0 ) i = -1;
  12196. if( v > 0 ) i = 1;
  12197. }
  12198. if( op == ttEqual )
  12199. i = (i == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  12200. else if( op == ttNotEqual )
  12201. i = (i != 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  12202. else if( op == ttLessThan )
  12203. i = (i < 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  12204. else if( op == ttLessThanOrEqual )
  12205. i = (i <= 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  12206. else if( op == ttGreaterThan )
  12207. i = (i > 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  12208. else if( op == ttGreaterThanOrEqual )
  12209. i = (i >= 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  12210. #if AS_SIZEOF_BOOL == 1
  12211. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), (asBYTE)i);
  12212. #else
  12213. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), i);
  12214. #endif
  12215. }
  12216. }
  12217. }
  12218. void asCCompiler::PushVariableOnStack(asCExprContext *ctx, bool asReference)
  12219. {
  12220. // Put the result on the stack
  12221. if( asReference )
  12222. {
  12223. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  12224. ctx->type.dataType.MakeReference(true);
  12225. }
  12226. else
  12227. {
  12228. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  12229. ctx->bc.InstrSHORT(asBC_PshV4, ctx->type.stackOffset);
  12230. else
  12231. ctx->bc.InstrSHORT(asBC_PshV8, ctx->type.stackOffset);
  12232. }
  12233. }
  12234. void asCCompiler::CompileBooleanOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType op)
  12235. {
  12236. // Both operands must be booleans
  12237. asCDataType to;
  12238. to.SetTokenType(ttBool);
  12239. // Do the actual conversion
  12240. int l = int(reservedVariables.GetLength());
  12241. rctx->bc.GetVarsUsed(reservedVariables);
  12242. lctx->bc.GetVarsUsed(reservedVariables);
  12243. // Allow value types to be converted to bool using 'bool opImplConv()'
  12244. if( lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
  12245. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV);
  12246. if( rctx->type.dataType.GetTypeInfo() && (rctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
  12247. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV);
  12248. reservedVariables.SetLength(l);
  12249. // Verify that the conversion was successful
  12250. if( !lctx->type.dataType.IsBooleanType() )
  12251. {
  12252. asCString str;
  12253. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), "bool");
  12254. Error(str, node);
  12255. // Force the conversion to allow compilation to proceed
  12256. lctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  12257. }
  12258. if( !rctx->type.dataType.IsBooleanType() )
  12259. {
  12260. asCString str;
  12261. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), "bool");
  12262. Error(str, node);
  12263. // Force the conversion to allow compilation to proceed
  12264. rctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  12265. }
  12266. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  12267. ctx->type.Set(asCDataType::CreatePrimitive(ttBool, true));
  12268. // What kind of operator is it?
  12269. if( op == ttUnrecognizedToken )
  12270. op = node->tokenType;
  12271. if( op == ttXor )
  12272. {
  12273. if( !isConstant )
  12274. {
  12275. // Must convert to temporary variable, because we are changing the value before comparison
  12276. ConvertToTempVariableNotIn(lctx, rctx);
  12277. ConvertToTempVariableNotIn(rctx, lctx);
  12278. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  12279. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  12280. // Make sure they are equal if not false
  12281. lctx->bc.InstrWORD(asBC_NOT, lctx->type.stackOffset);
  12282. rctx->bc.InstrWORD(asBC_NOT, rctx->type.stackOffset);
  12283. MergeExprBytecode(ctx, lctx);
  12284. MergeExprBytecode(ctx, rctx);
  12285. ProcessDeferredParams(ctx);
  12286. int a = AllocateVariable(ctx->type.dataType, true);
  12287. int b = lctx->type.stackOffset;
  12288. int c = rctx->type.stackOffset;
  12289. ctx->bc.InstrW_W_W(asBC_BXOR,a,b,c);
  12290. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  12291. }
  12292. else
  12293. {
  12294. // Make sure they are equal if not false
  12295. #if AS_SIZEOF_BOOL == 1
  12296. if( lctx->type.GetConstantB() != 0 ) lctx->type.SetConstantB(VALUE_OF_BOOLEAN_TRUE);
  12297. if( rctx->type.GetConstantB() != 0 ) rctx->type.SetConstantB(VALUE_OF_BOOLEAN_TRUE);
  12298. asBYTE v = 0;
  12299. v = lctx->type.GetConstantB() - rctx->type.GetConstantB();
  12300. if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  12301. ctx->type.isConstant = true;
  12302. ctx->type.SetConstantB(v);
  12303. #else
  12304. if( lctx->type.GetConstantDW() != 0 ) lctx->type.SetConstantDW(VALUE_OF_BOOLEAN_TRUE);
  12305. if( rctx->type.GetConstantDW() != 0 ) rctx->type.SetConstantDW(VALUE_OF_BOOLEAN_TRUE);
  12306. asDWORD v = 0;
  12307. v = lctx->type.GetConstantDW() - rctx->type.GetConstantDW();
  12308. if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  12309. ctx->type.isConstant = true;
  12310. ctx->type.SetConstantDW(v);
  12311. #endif
  12312. }
  12313. }
  12314. else if( op == ttAnd ||
  12315. op == ttOr )
  12316. {
  12317. if( !isConstant )
  12318. {
  12319. // If or-operator and first value is 1 the second value shouldn't be calculated
  12320. // if and-operator and first value is 0 the second value shouldn't be calculated
  12321. ConvertToVariable(lctx);
  12322. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  12323. MergeExprBytecode(ctx, lctx);
  12324. int offset = AllocateVariable(asCDataType::CreatePrimitive(ttBool, false), true);
  12325. int label1 = nextLabel++;
  12326. int label2 = nextLabel++;
  12327. ctx->bc.InstrSHORT(asBC_CpyVtoR4, lctx->type.stackOffset);
  12328. ctx->bc.Instr(asBC_ClrHi);
  12329. if( op == ttAnd )
  12330. {
  12331. ctx->bc.InstrDWORD(asBC_JNZ, label1);
  12332. ctx->bc.InstrW_DW(asBC_SetV4, (asWORD)offset, 0);
  12333. ctx->bc.InstrINT(asBC_JMP, label2);
  12334. }
  12335. else if( op == ttOr )
  12336. {
  12337. ctx->bc.InstrDWORD(asBC_JZ, label1);
  12338. #if AS_SIZEOF_BOOL == 1
  12339. ctx->bc.InstrSHORT_B(asBC_SetV1, (short)offset, VALUE_OF_BOOLEAN_TRUE);
  12340. #else
  12341. ctx->bc.InstrSHORT_DW(asBC_SetV4, (short)offset, VALUE_OF_BOOLEAN_TRUE);
  12342. #endif
  12343. ctx->bc.InstrINT(asBC_JMP, label2);
  12344. }
  12345. ctx->bc.Label((short)label1);
  12346. ConvertToVariable(rctx);
  12347. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  12348. rctx->bc.InstrW_W(asBC_CpyVtoV4, offset, rctx->type.stackOffset);
  12349. MergeExprBytecode(ctx, rctx);
  12350. ctx->bc.Label((short)label2);
  12351. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, false), offset, true);
  12352. }
  12353. else
  12354. {
  12355. #if AS_SIZEOF_BOOL == 1
  12356. asBYTE v = 0;
  12357. if( op == ttAnd )
  12358. v = lctx->type.GetConstantB() && rctx->type.GetConstantB();
  12359. else if( op == ttOr )
  12360. v = lctx->type.GetConstantB() || rctx->type.GetConstantB();
  12361. // Remember the result
  12362. ctx->type.isConstant = true;
  12363. ctx->type.SetConstantB(v);
  12364. #else
  12365. asDWORD v = 0;
  12366. if( op == ttAnd )
  12367. v = lctx->type.GetConstantDW() && rctx->type.GetConstantDW();
  12368. else if( op == ttOr )
  12369. v = lctx->type.GetConstantDW() || rctx->type.GetConstantDW();
  12370. // Remember the result
  12371. ctx->type.isConstant = true;
  12372. ctx->type.SetConstantDW(v);
  12373. #endif
  12374. }
  12375. }
  12376. }
  12377. void asCCompiler::CompileOperatorOnHandles(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType opToken)
  12378. {
  12379. // Process the property accessor as get
  12380. ProcessPropertyGetAccessor(lctx, node);
  12381. ProcessPropertyGetAccessor(rctx, node);
  12382. DetermineSingleFunc(lctx, node);
  12383. DetermineSingleFunc(rctx, node);
  12384. // Make sure lctx doesn't end up with a variable used in rctx
  12385. if( lctx->type.isTemporary && rctx->bc.IsVarUsed(lctx->type.stackOffset) )
  12386. {
  12387. asCArray<int> vars;
  12388. rctx->bc.GetVarsUsed(vars);
  12389. int offset = AllocateVariable(lctx->type.dataType, true);
  12390. rctx->bc.ExchangeVar(lctx->type.stackOffset, offset);
  12391. ReleaseTemporaryVariable(offset, 0);
  12392. }
  12393. if( opToken == ttUnrecognizedToken )
  12394. opToken = node->tokenType;
  12395. // Warn if not both operands are explicit handles or null handles
  12396. if( (opToken == ttEqual || opToken == ttNotEqual) &&
  12397. ((!(lctx->type.isExplicitHandle || lctx->type.IsNullConstant()) && !(lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE))) ||
  12398. (!(rctx->type.isExplicitHandle || rctx->type.IsNullConstant()) && !(rctx->type.dataType.GetTypeInfo() && (rctx->type.dataType.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE)))) )
  12399. {
  12400. Warning(TXT_HANDLE_COMPARISON, node);
  12401. }
  12402. // If one of the operands is a value type used as handle, we should look for the opEquals method
  12403. if( ((lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE)) ||
  12404. (rctx->type.dataType.GetTypeInfo() && (rctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE))) &&
  12405. (opToken == ttEqual || opToken == ttIs ||
  12406. opToken == ttNotEqual || opToken == ttNotIs) )
  12407. {
  12408. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  12409. // Find the matching opEquals method
  12410. int r = CompileOverloadedDualOperator2(node, "opEquals", lctx, rctx, true, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  12411. if( r == 0 )
  12412. {
  12413. // Try again by switching the order of the operands
  12414. r = CompileOverloadedDualOperator2(node, "opEquals", rctx, lctx, false, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  12415. }
  12416. if( r == 1 )
  12417. {
  12418. if( opToken == ttNotEqual || opToken == ttNotIs )
  12419. ctx->bc.InstrSHORT(asBC_NOT, ctx->type.stackOffset);
  12420. // Success, don't continue
  12421. return;
  12422. }
  12423. else if( r == 0 )
  12424. {
  12425. // Couldn't find opEquals method
  12426. Error(TXT_NO_APPROPRIATE_OPEQUALS, node);
  12427. }
  12428. // Compiler error, don't continue
  12429. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  12430. return;
  12431. }
  12432. // Implicitly convert null to the other type
  12433. asCDataType to;
  12434. if( lctx->type.IsNullConstant() )
  12435. to = rctx->type.dataType;
  12436. else if( rctx->type.IsNullConstant() )
  12437. to = lctx->type.dataType;
  12438. else
  12439. {
  12440. // Find a common base type
  12441. asCExprContext tmp(engine);
  12442. tmp.type = rctx->type;
  12443. ImplicitConversion(&tmp, lctx->type.dataType, 0, asIC_IMPLICIT_CONV, false);
  12444. if( tmp.type.dataType.GetTypeInfo() == lctx->type.dataType.GetTypeInfo() )
  12445. to = lctx->type.dataType;
  12446. else
  12447. to = rctx->type.dataType;
  12448. // Assume handle-to-const as it is not possible to convert handle-to-const to handle-to-non-const
  12449. to.MakeHandleToConst(true);
  12450. }
  12451. // Need to pop the value if it is a null constant
  12452. if( lctx->type.IsNullConstant() )
  12453. lctx->bc.Instr(asBC_PopPtr);
  12454. if( rctx->type.IsNullConstant() )
  12455. rctx->bc.Instr(asBC_PopPtr);
  12456. // Convert both sides to explicit handles
  12457. to.MakeHandle(true);
  12458. to.MakeReference(false);
  12459. if( !to.IsObjectHandle() )
  12460. {
  12461. // Compiler error, don't continue
  12462. Error(TXT_OPERANDS_MUST_BE_HANDLES, node);
  12463. #if AS_SIZEOF_BOOL == 1
  12464. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  12465. #else
  12466. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  12467. #endif
  12468. return;
  12469. }
  12470. // Do the conversion
  12471. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV);
  12472. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV);
  12473. // Both operands must be of the same type
  12474. // Verify that the conversion was successful
  12475. if( !lctx->type.dataType.IsEqualExceptConst(to) )
  12476. {
  12477. asCString str;
  12478. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  12479. Error(str, node);
  12480. }
  12481. if( !rctx->type.dataType.IsEqualExceptConst(to) )
  12482. {
  12483. asCString str;
  12484. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  12485. Error(str, node);
  12486. }
  12487. // Make sure it really is handles that are being compared
  12488. if( !lctx->type.dataType.IsObjectHandle() )
  12489. {
  12490. Error(TXT_OPERANDS_MUST_BE_HANDLES, node);
  12491. }
  12492. ctx->type.Set(asCDataType::CreatePrimitive(ttBool, true));
  12493. if( opToken == ttEqual || opToken == ttNotEqual || opToken == ttIs || opToken == ttNotIs )
  12494. {
  12495. // Make sure handles received as parameters by reference are copied to a local variable before the
  12496. // asBC_CmpPtr, so we don't end up comparing the reference to the handle instead of the handle itself
  12497. if( lctx->type.isVariable && !lctx->type.isTemporary && lctx->type.stackOffset <= 0 )
  12498. lctx->type.isVariable = false;
  12499. if( rctx->type.isVariable && !rctx->type.isTemporary && rctx->type.stackOffset <= 0 )
  12500. rctx->type.isVariable = false;
  12501. // TODO: runtime optimize: don't do REFCPY if not necessary
  12502. ConvertToVariableNotIn(lctx, rctx);
  12503. ConvertToVariable(rctx);
  12504. // Pop the pointers from the stack as they will not be used
  12505. lctx->bc.Instr(asBC_PopPtr);
  12506. rctx->bc.Instr(asBC_PopPtr);
  12507. MergeExprBytecode(ctx, lctx);
  12508. MergeExprBytecode(ctx, rctx);
  12509. int a = AllocateVariable(ctx->type.dataType, true);
  12510. int b = lctx->type.stackOffset;
  12511. int c = rctx->type.stackOffset;
  12512. ctx->bc.InstrW_W(asBC_CmpPtr, b, c);
  12513. if( opToken == ttEqual || opToken == ttIs )
  12514. ctx->bc.Instr(asBC_TZ);
  12515. else if( opToken == ttNotEqual || opToken == ttNotIs )
  12516. ctx->bc.Instr(asBC_TNZ);
  12517. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  12518. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  12519. ReleaseTemporaryVariable(lctx->type, &ctx->bc);
  12520. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  12521. ProcessDeferredParams(ctx);
  12522. }
  12523. else
  12524. {
  12525. // TODO: Use TXT_ILLEGAL_OPERATION_ON
  12526. Error(TXT_ILLEGAL_OPERATION, node);
  12527. }
  12528. }
  12529. void asCCompiler::PerformFunctionCall(int funcId, asCExprContext *ctx, bool isConstructor, asCArray<asCExprContext*> *args, asCObjectType *objType, bool useVariable, int varOffset, int funcPtrVar)
  12530. {
  12531. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  12532. // A shared object may not call non-shared functions
  12533. if( outFunc->IsShared() && !descr->IsShared() )
  12534. {
  12535. asCString msg;
  12536. msg.Format(TXT_SHARED_CANNOT_CALL_NON_SHARED_FUNC_s, descr->GetDeclarationStr().AddressOf());
  12537. Error(msg, ctx->exprNode);
  12538. }
  12539. // Check if the function is private or protected
  12540. if( descr->isPrivate && descr->GetObjectType() != outFunc->GetObjectType() )
  12541. {
  12542. asCString msg;
  12543. msg.Format(TXT_PRIVATE_METHOD_CALL_s, descr->GetDeclarationStr().AddressOf());
  12544. Error(msg, ctx->exprNode);
  12545. }
  12546. else if( descr->isProtected &&
  12547. !(descr->GetObjectType() == outFunc->GetObjectType() ||
  12548. (outFunc->GetObjectType() && outFunc->GetObjectType()->DerivesFrom(descr->GetObjectType()))) )
  12549. {
  12550. asCString msg;
  12551. msg.Format(TXT_PROTECTED_METHOD_CALL_s, descr->GetDeclarationStr().AddressOf());
  12552. Error(msg, ctx->exprNode);
  12553. }
  12554. int argSize = descr->GetSpaceNeededForArguments();
  12555. // If we're calling a class method we must make sure the object is guaranteed to stay
  12556. // alive throughout the call by holding on to a reference in a local variable. This must
  12557. // be done for any methods that return references, and any calls on script objects.
  12558. // Application registered objects are assumed to know to keep themselves alive even
  12559. // if the method doesn't return a reference.
  12560. if( !ctx->type.isHandleSafe &&
  12561. descr->objectType &&
  12562. (ctx->type.dataType.IsObjectHandle() || ctx->type.dataType.SupportHandles()) &&
  12563. (descr->returnType.IsReference() || (ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_SCRIPT_OBJECT)) &&
  12564. !(ctx->type.isVariable || ctx->type.isTemporary) &&
  12565. !(ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_SCOPED) &&
  12566. !(ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_ASHANDLE) )
  12567. {
  12568. // TODO: runtime optimize: Avoid this for global variables, by storing a reference to the global variable once in a
  12569. // local variable and then refer to the same for each call. An alias for the global variable
  12570. // should be stored in the variable scope so that the compiler can find it. For loops and
  12571. // scopes that will always be executed, i.e. non-if scopes the alias should be stored in the
  12572. // higher scope to increase the probability of re-use.
  12573. int tempRef = AllocateVariable(ctx->type.dataType, true);
  12574. ctx->bc.InstrSHORT(asBC_PSF, (short)tempRef);
  12575. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo());
  12576. // Add the release of this reference as a deferred expression
  12577. asSDeferredParam deferred;
  12578. deferred.origExpr = 0;
  12579. deferred.argInOutFlags = asTM_INREF;
  12580. deferred.argNode = 0;
  12581. deferred.argType.SetVariable(ctx->type.dataType, tempRef, true);
  12582. ctx->deferredParams.PushLast(deferred);
  12583. // Forget the current type
  12584. ctx->type.SetDummy();
  12585. }
  12586. // Check if there is a need to add a hidden pointer for when the function returns an object by value
  12587. if( descr->DoesReturnOnStack() && !useVariable )
  12588. {
  12589. useVariable = true;
  12590. varOffset = AllocateVariable(descr->returnType, true);
  12591. // Push the pointer to the pre-allocated space for the return value
  12592. ctx->bc.InstrSHORT(asBC_PSF, short(varOffset));
  12593. if( descr->objectType )
  12594. {
  12595. // The object pointer is already on the stack, but should be the top
  12596. // one, so we need to swap the pointers in order to get the correct
  12597. ctx->bc.Instr(asBC_SwapPtr);
  12598. }
  12599. }
  12600. if( isConstructor )
  12601. {
  12602. // Sometimes the value types are allocated on the heap,
  12603. // which is when this way of constructing them is used.
  12604. asASSERT(useVariable == false);
  12605. if( (objType->flags & asOBJ_TEMPLATE) )
  12606. {
  12607. asASSERT( descr->funcType == asFUNC_SCRIPT );
  12608. // Find the id of the real constructor and not the generated stub
  12609. asUINT id = 0;
  12610. asDWORD *bc = descr->scriptData->byteCode.AddressOf();
  12611. while( bc )
  12612. {
  12613. if( (*(asBYTE*)bc) == asBC_CALLSYS )
  12614. {
  12615. id = asBC_INTARG(bc);
  12616. break;
  12617. }
  12618. bc += asBCTypeSize[asBCInfo[*(asBYTE*)bc].type];
  12619. }
  12620. asASSERT( id );
  12621. ctx->bc.InstrPTR(asBC_OBJTYPE, objType);
  12622. ctx->bc.Alloc(asBC_ALLOC, objType, id, argSize + AS_PTR_SIZE + AS_PTR_SIZE);
  12623. }
  12624. else
  12625. ctx->bc.Alloc(asBC_ALLOC, objType, descr->id, argSize+AS_PTR_SIZE);
  12626. // The instruction has already moved the returned object to the variable
  12627. ctx->type.Set(asCDataType::CreatePrimitive(ttVoid, false));
  12628. ctx->type.isLValue = false;
  12629. // Clean up arguments
  12630. if( args )
  12631. AfterFunctionCall(funcId, *args, ctx, false);
  12632. ProcessDeferredParams(ctx);
  12633. return;
  12634. }
  12635. else
  12636. {
  12637. if( descr->objectType )
  12638. argSize += AS_PTR_SIZE;
  12639. // If the function returns an object by value the address of the location
  12640. // where the value should be stored is passed as an argument too
  12641. if( descr->DoesReturnOnStack() )
  12642. argSize += AS_PTR_SIZE;
  12643. // TODO: runtime optimize: If it is known that a class method cannot be overridden the call
  12644. // should be made with asBC_CALL as it is faster. Examples where this
  12645. // is known is for example finalled methods where the class doesn't derive
  12646. // from any other, or even non-finalled methods but where it is known
  12647. // at compile time the true type of the object. The first should be
  12648. // quite easy to determine, but the latter will be quite complex and possibly
  12649. // not worth it.
  12650. if( descr->funcType == asFUNC_IMPORTED )
  12651. ctx->bc.Call(asBC_CALLBND , descr->id, argSize);
  12652. // TODO: Maybe we need two different byte codes
  12653. else if( descr->funcType == asFUNC_INTERFACE || descr->funcType == asFUNC_VIRTUAL )
  12654. ctx->bc.Call(asBC_CALLINTF, descr->id, argSize);
  12655. else if( descr->funcType == asFUNC_SCRIPT )
  12656. ctx->bc.Call(asBC_CALL , descr->id, argSize);
  12657. else if( descr->funcType == asFUNC_SYSTEM )
  12658. {
  12659. // Check if we can use the faster asBC_Thiscall1 instruction, i.e. one of
  12660. // type &obj::func(int)
  12661. // type &obj::func(uint)
  12662. if( descr->GetObjectType() && descr->returnType.IsReference() &&
  12663. descr->parameterTypes.GetLength() == 1 &&
  12664. (descr->parameterTypes[0].IsIntegerType() || descr->parameterTypes[0].IsUnsignedType()) &&
  12665. descr->parameterTypes[0].GetSizeInMemoryBytes() == 4 &&
  12666. !descr->parameterTypes[0].IsReference() )
  12667. ctx->bc.Call(asBC_Thiscall1, descr->id, argSize);
  12668. else
  12669. ctx->bc.Call(asBC_CALLSYS , descr->id, argSize);
  12670. }
  12671. else if( descr->funcType == asFUNC_FUNCDEF )
  12672. ctx->bc.CallPtr(asBC_CallPtr, funcPtrVar, argSize);
  12673. }
  12674. if( (descr->returnType.IsObject() || descr->returnType.IsFuncdef()) && !descr->returnType.IsReference() )
  12675. {
  12676. int returnOffset = 0;
  12677. asCExprValue tmpExpr = ctx->type;
  12678. if( descr->DoesReturnOnStack() )
  12679. {
  12680. asASSERT( useVariable );
  12681. // The variable was allocated before the function was called
  12682. returnOffset = varOffset;
  12683. ctx->type.SetVariable(descr->returnType, returnOffset, true);
  12684. // The variable was initialized by the function, so we need to mark it as initialized here
  12685. ctx->bc.ObjInfo(varOffset, asOBJ_INIT);
  12686. }
  12687. else
  12688. {
  12689. if( useVariable )
  12690. {
  12691. // Use the given variable
  12692. returnOffset = varOffset;
  12693. ctx->type.SetVariable(descr->returnType, returnOffset, false);
  12694. }
  12695. else
  12696. {
  12697. // Allocate a temporary variable for the returned object
  12698. // The returned object will actually be allocated on the heap, so
  12699. // we must force the allocation of the variable to do the same
  12700. returnOffset = AllocateVariable(descr->returnType, true, !descr->returnType.IsObjectHandle());
  12701. ctx->type.SetVariable(descr->returnType, returnOffset, true);
  12702. }
  12703. // Move the pointer from the object register to the temporary variable
  12704. ctx->bc.InstrSHORT(asBC_STOREOBJ, (short)returnOffset);
  12705. }
  12706. ReleaseTemporaryVariable(tmpExpr, &ctx->bc);
  12707. ctx->type.dataType.MakeReference(IsVariableOnHeap(returnOffset));
  12708. ctx->type.isLValue = false; // It is a reference, but not an lvalue
  12709. // Clean up arguments
  12710. if( args )
  12711. AfterFunctionCall(funcId, *args, ctx, false);
  12712. ProcessDeferredParams(ctx);
  12713. ctx->bc.InstrSHORT(asBC_PSF, (short)returnOffset);
  12714. }
  12715. else if( descr->returnType.IsReference() )
  12716. {
  12717. asASSERT(useVariable == false);
  12718. // We cannot clean up the arguments yet, because the
  12719. // reference might be pointing to one of them.
  12720. if( args )
  12721. AfterFunctionCall(funcId, *args, ctx, true);
  12722. // Do not process the output parameters yet, because it
  12723. // might invalidate the returned reference
  12724. // If the context holds a variable that needs cleanup
  12725. // store it as a deferred parameter so it will be cleaned up
  12726. // afterwards.
  12727. if( ctx->type.isTemporary )
  12728. {
  12729. asSDeferredParam defer;
  12730. defer.argNode = 0;
  12731. defer.argType = ctx->type;
  12732. defer.argInOutFlags = asTM_INOUTREF;
  12733. defer.origExpr = 0;
  12734. ctx->deferredParams.PushLast(defer);
  12735. }
  12736. ctx->type.Set(descr->returnType);
  12737. if( !descr->returnType.IsPrimitive() )
  12738. {
  12739. ctx->bc.Instr(asBC_PshRPtr);
  12740. if( descr->returnType.IsObject() &&
  12741. !descr->returnType.IsObjectHandle() )
  12742. {
  12743. // We are getting the pointer to the object
  12744. // not a pointer to a object variable
  12745. ctx->type.dataType.MakeReference(false);
  12746. }
  12747. }
  12748. // A returned reference can be used as lvalue
  12749. ctx->type.isLValue = true;
  12750. }
  12751. else
  12752. {
  12753. asASSERT(useVariable == false);
  12754. asCExprValue tmpExpr = ctx->type;
  12755. if( descr->returnType.GetSizeInMemoryBytes() )
  12756. {
  12757. // Allocate a temporary variable to hold the value, but make sure
  12758. // the temporary variable isn't used in any of the deferred arguments
  12759. int l = int(reservedVariables.GetLength());
  12760. for( asUINT n = 0; args && n < args->GetLength(); n++ )
  12761. {
  12762. asCExprContext *expr = (*args)[n]->origExpr;
  12763. if( expr )
  12764. expr->bc.GetVarsUsed(reservedVariables);
  12765. }
  12766. int offset = AllocateVariable(descr->returnType, true);
  12767. reservedVariables.SetLength(l);
  12768. ctx->type.SetVariable(descr->returnType, offset, true);
  12769. // Move the value from the return register to the variable
  12770. if( descr->returnType.GetSizeOnStackDWords() == 1 )
  12771. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)offset);
  12772. else if( descr->returnType.GetSizeOnStackDWords() == 2 )
  12773. ctx->bc.InstrSHORT(asBC_CpyRtoV8, (short)offset);
  12774. }
  12775. else
  12776. ctx->type.Set(descr->returnType);
  12777. ReleaseTemporaryVariable(tmpExpr, &ctx->bc);
  12778. ctx->type.isLValue = false;
  12779. // Clean up arguments
  12780. if( args )
  12781. AfterFunctionCall(funcId, *args, ctx, false);
  12782. ProcessDeferredParams(ctx);
  12783. }
  12784. }
  12785. // This only merges the bytecode, but doesn't modify the type of the final context
  12786. void asCCompiler::MergeExprBytecode(asCExprContext *before, asCExprContext *after)
  12787. {
  12788. before->bc.AddCode(&after->bc);
  12789. for( asUINT n = 0; n < after->deferredParams.GetLength(); n++ )
  12790. {
  12791. before->deferredParams.PushLast(after->deferredParams[n]);
  12792. after->deferredParams[n].origExpr = 0;
  12793. }
  12794. after->deferredParams.SetLength(0);
  12795. }
  12796. // This merges both bytecode and the type of the final context
  12797. void asCCompiler::MergeExprBytecodeAndType(asCExprContext *before, asCExprContext *after)
  12798. {
  12799. MergeExprBytecode(before, after);
  12800. before->Merge(after);
  12801. }
  12802. void asCCompiler::FilterConst(asCArray<int> &funcs, bool removeConst)
  12803. {
  12804. if( funcs.GetLength() == 0 ) return;
  12805. // This is only done for object methods
  12806. asCScriptFunction *desc = builder->GetFunctionDescription(funcs[0]);
  12807. if( desc->objectType == 0 ) return;
  12808. // Check if there are any non-const matches
  12809. asUINT n;
  12810. bool foundNonConst = false;
  12811. for( n = 0; n < funcs.GetLength(); n++ )
  12812. {
  12813. desc = builder->GetFunctionDescription(funcs[n]);
  12814. if( desc->isReadOnly != removeConst )
  12815. {
  12816. foundNonConst = true;
  12817. break;
  12818. }
  12819. }
  12820. if( foundNonConst )
  12821. {
  12822. // Remove all const methods
  12823. for( n = 0; n < funcs.GetLength(); n++ )
  12824. {
  12825. desc = builder->GetFunctionDescription(funcs[n]);
  12826. if( desc->isReadOnly == removeConst )
  12827. {
  12828. if( n == funcs.GetLength() - 1 )
  12829. funcs.PopLast();
  12830. else
  12831. funcs[n] = funcs.PopLast();
  12832. n--;
  12833. }
  12834. }
  12835. }
  12836. }
  12837. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  12838. asCExprValue::asCExprValue()
  12839. {
  12840. isTemporary = false;
  12841. stackOffset = 0;
  12842. isConstant = false;
  12843. isVariable = false;
  12844. isExplicitHandle = false;
  12845. qwordValue = 0;
  12846. isLValue = false;
  12847. isRefToLocal = false;
  12848. isHandleSafe = false;
  12849. }
  12850. void asCExprValue::Set(const asCDataType &dt)
  12851. {
  12852. dataType = dt;
  12853. isTemporary = false;
  12854. stackOffset = 0;
  12855. isConstant = false;
  12856. isVariable = false;
  12857. isExplicitHandle = false;
  12858. qwordValue = 0;
  12859. isLValue = false;
  12860. isRefToLocal = false;
  12861. isHandleSafe = false;
  12862. }
  12863. void asCExprValue::SetVariable(const asCDataType &in_dt, int in_stackOffset, bool in_isTemporary)
  12864. {
  12865. Set(in_dt);
  12866. this->isVariable = true;
  12867. this->isTemporary = in_isTemporary;
  12868. this->stackOffset = (short)in_stackOffset;
  12869. }
  12870. void asCExprValue::SetConstantQW(const asCDataType &dt, asQWORD value)
  12871. {
  12872. Set(dt);
  12873. isConstant = true;
  12874. SetConstantQW(value);
  12875. }
  12876. void asCExprValue::SetConstantDW(const asCDataType &dt, asDWORD value)
  12877. {
  12878. Set(dt);
  12879. isConstant = true;
  12880. SetConstantDW(value);
  12881. }
  12882. void asCExprValue::SetConstantB(const asCDataType &dt, asBYTE value)
  12883. {
  12884. Set(dt);
  12885. isConstant = true;
  12886. SetConstantB(value);
  12887. }
  12888. void asCExprValue::SetConstantW(const asCDataType &dt, asWORD value)
  12889. {
  12890. Set(dt);
  12891. isConstant = true;
  12892. SetConstantW(value);
  12893. }
  12894. void asCExprValue::SetConstantF(const asCDataType &dt, float value)
  12895. {
  12896. Set(dt);
  12897. isConstant = true;
  12898. SetConstantF(value);
  12899. }
  12900. void asCExprValue::SetConstantD(const asCDataType &dt, double value)
  12901. {
  12902. Set(dt);
  12903. isConstant = true;
  12904. SetConstantD(value);
  12905. }
  12906. void asCExprValue::SetConstantQW(asQWORD value)
  12907. {
  12908. asASSERT(dataType.GetSizeInMemoryBytes() == 8);
  12909. qwordValue = value;
  12910. }
  12911. void asCExprValue::SetConstantDW(asDWORD value)
  12912. {
  12913. asASSERT(dataType.GetSizeInMemoryBytes() == 4);
  12914. dwordValue = value;
  12915. }
  12916. void asCExprValue::SetConstantW(asWORD value)
  12917. {
  12918. asASSERT(dataType.GetSizeInMemoryBytes() == 2);
  12919. wordValue = value;
  12920. }
  12921. void asCExprValue::SetConstantB(asBYTE value)
  12922. {
  12923. asASSERT(dataType.GetSizeInMemoryBytes() == 1);
  12924. byteValue = value;
  12925. }
  12926. void asCExprValue::SetConstantF(float value)
  12927. {
  12928. asASSERT(dataType.GetSizeInMemoryBytes() == 4);
  12929. floatValue = value;
  12930. }
  12931. void asCExprValue::SetConstantD(double value)
  12932. {
  12933. asASSERT(dataType.GetSizeInMemoryBytes() == 8);
  12934. doubleValue = value;
  12935. }
  12936. asQWORD asCExprValue::GetConstantQW()
  12937. {
  12938. asASSERT(dataType.GetSizeInMemoryBytes() == 8);
  12939. return qwordValue;
  12940. }
  12941. asDWORD asCExprValue::GetConstantDW()
  12942. {
  12943. asASSERT(dataType.GetSizeInMemoryBytes() == 4);
  12944. return dwordValue;
  12945. }
  12946. asWORD asCExprValue::GetConstantW()
  12947. {
  12948. asASSERT(dataType.GetSizeInMemoryBytes() == 2);
  12949. return wordValue;
  12950. }
  12951. asBYTE asCExprValue::GetConstantB()
  12952. {
  12953. asASSERT(dataType.GetSizeInMemoryBytes() == 1);
  12954. return byteValue;
  12955. }
  12956. float asCExprValue::GetConstantF()
  12957. {
  12958. asASSERT(dataType.GetSizeInMemoryBytes() == 4);
  12959. return floatValue;
  12960. }
  12961. double asCExprValue::GetConstantD()
  12962. {
  12963. asASSERT(dataType.GetSizeInMemoryBytes() == 8);
  12964. return doubleValue;
  12965. }
  12966. void asCExprValue::SetConstantData(const asCDataType &dt, asQWORD qw)
  12967. {
  12968. Set(dt);
  12969. isConstant = true;
  12970. // This code is necessary to guarantee that the code
  12971. // works on both big endian and little endian CPUs.
  12972. if (dataType.GetSizeInMemoryBytes() == 1)
  12973. byteValue = (asBYTE)qw;
  12974. if (dataType.GetSizeInMemoryBytes() == 2)
  12975. wordValue = (asWORD)qw;
  12976. if (dataType.GetSizeInMemoryBytes() == 4)
  12977. dwordValue = (asDWORD)qw;
  12978. else
  12979. qwordValue = qw;
  12980. }
  12981. asQWORD asCExprValue::GetConstantData()
  12982. {
  12983. asQWORD qw = 0;
  12984. // This code is necessary to guarantee that the code
  12985. // works on both big endian and little endian CPUs.
  12986. if (dataType.GetSizeInMemoryBytes() == 1)
  12987. qw = byteValue;
  12988. if (dataType.GetSizeInMemoryBytes() == 2)
  12989. qw = wordValue;
  12990. if (dataType.GetSizeInMemoryBytes() == 4)
  12991. qw = dwordValue;
  12992. else
  12993. qw = qwordValue;
  12994. return qw;
  12995. }
  12996. void asCExprValue::SetUndefinedFuncHandle(asCScriptEngine *engine)
  12997. {
  12998. // This is used for when the expression evaluates to a
  12999. // function, but it is not yet known exactly which. The
  13000. // owner expression will hold the name of the function
  13001. // to determine the exact function when the signature is
  13002. // known.
  13003. Set(asCDataType::CreateObjectHandle(&engine->functionBehaviours, true));
  13004. isConstant = true;
  13005. isExplicitHandle = false;
  13006. qwordValue = 1; // Set to a different value than 0 to differentiate from null constant
  13007. isLValue = false;
  13008. }
  13009. bool asCExprValue::IsUndefinedFuncHandle() const
  13010. {
  13011. if (isConstant == false) return false;
  13012. if (qwordValue == 0) return false;
  13013. if (isLValue) return false;
  13014. if (dataType.GetTypeInfo() == 0) return false;
  13015. if (dataType.GetTypeInfo()->name != "$func") return false;
  13016. if (dataType.IsFuncdef()) return false;
  13017. return true;
  13018. }
  13019. void asCExprValue::SetNullConstant()
  13020. {
  13021. Set(asCDataType::CreateNullHandle());
  13022. isConstant = true;
  13023. isExplicitHandle = false;
  13024. qwordValue = 0;
  13025. isLValue = false;
  13026. }
  13027. bool asCExprValue::IsNullConstant() const
  13028. {
  13029. // We can't check the actual object type, because the null constant may have been cast to another type
  13030. if (isConstant && dataType.IsObjectHandle() && qwordValue == 0)
  13031. return true;
  13032. return false;
  13033. }
  13034. void asCExprValue::SetVoid()
  13035. {
  13036. Set(asCDataType::CreatePrimitive(ttVoid, false));
  13037. isLValue = false;
  13038. isConstant = true;
  13039. }
  13040. bool asCExprValue::IsVoid() const
  13041. {
  13042. if (dataType.GetTokenType() == ttVoid)
  13043. return true;
  13044. return false;
  13045. }
  13046. void asCExprValue::SetDummy()
  13047. {
  13048. SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), 0);
  13049. }
  13050. ////////////////////////////////////////////////////////////////////////////////////////////////
  13051. asCExprContext::asCExprContext(asCScriptEngine *engine) : bc(engine)
  13052. {
  13053. property_arg = 0;
  13054. Clear();
  13055. }
  13056. asCExprContext::~asCExprContext()
  13057. {
  13058. if (property_arg)
  13059. asDELETE(property_arg, asCExprContext);
  13060. }
  13061. void asCExprContext::Clear()
  13062. {
  13063. bc.ClearAll();
  13064. type.Set(asCDataType());
  13065. deferredParams.SetLength(0);
  13066. if (property_arg)
  13067. asDELETE(property_arg, asCExprContext);
  13068. property_arg = 0;
  13069. exprNode = 0;
  13070. origExpr = 0;
  13071. property_get = 0;
  13072. property_set = 0;
  13073. property_const = false;
  13074. property_handle = false;
  13075. property_ref = false;
  13076. methodName = "";
  13077. enumValue = "";
  13078. isVoidExpression = false;
  13079. isCleanArg = false;
  13080. isAnonymousInitList = false;
  13081. }
  13082. bool asCExprContext::IsClassMethod() const
  13083. {
  13084. if (type.dataType.GetTypeInfo() == 0) return false;
  13085. if (methodName == "") return false;
  13086. if (type.dataType.GetTypeInfo() == &type.dataType.GetTypeInfo()->engine->functionBehaviours) return false;
  13087. if (isAnonymousInitList) return false;
  13088. return true;
  13089. }
  13090. bool asCExprContext::IsGlobalFunc() const
  13091. {
  13092. if (type.dataType.GetTypeInfo() == 0) return false;
  13093. if (methodName == "") return false;
  13094. if (type.dataType.GetTypeInfo() != &type.dataType.GetTypeInfo()->engine->functionBehaviours) return false;
  13095. if (isAnonymousInitList) return false;
  13096. return true;
  13097. }
  13098. void asCExprContext::SetLambda(asCScriptNode *funcDecl)
  13099. {
  13100. asASSERT(funcDecl && funcDecl->nodeType == snFunction);
  13101. asASSERT(bc.GetLastInstr() == -1);
  13102. Clear();
  13103. type.SetUndefinedFuncHandle(bc.GetEngine());
  13104. exprNode = funcDecl;
  13105. }
  13106. bool asCExprContext::IsLambda() const
  13107. {
  13108. if (type.IsUndefinedFuncHandle() && exprNode && exprNode->nodeType == snFunction)
  13109. return true;
  13110. return false;
  13111. }
  13112. void asCExprContext::SetVoidExpression()
  13113. {
  13114. Clear();
  13115. type.SetVoid();
  13116. isVoidExpression = true;
  13117. }
  13118. bool asCExprContext::IsVoidExpression() const
  13119. {
  13120. if (isVoidExpression && type.IsVoid() && exprNode == 0)
  13121. return true;
  13122. return false;
  13123. }
  13124. void asCExprContext::SetAnonymousInitList(asCScriptNode *initList)
  13125. {
  13126. Clear();
  13127. exprNode = initList;
  13128. isAnonymousInitList = true;
  13129. }
  13130. bool asCExprContext::IsAnonymousInitList() const
  13131. {
  13132. if (isAnonymousInitList && exprNode && exprNode->nodeType == snInitList)
  13133. return true;
  13134. return false;
  13135. }
  13136. void asCExprContext::Merge(asCExprContext *after)
  13137. {
  13138. type = after->type;
  13139. property_get = after->property_get;
  13140. property_set = after->property_set;
  13141. property_const = after->property_const;
  13142. property_handle = after->property_handle;
  13143. property_ref = after->property_ref;
  13144. property_arg = after->property_arg;
  13145. exprNode = after->exprNode;
  13146. methodName = after->methodName;
  13147. enumValue = after->enumValue;
  13148. isVoidExpression = after->isVoidExpression;
  13149. isCleanArg = after->isCleanArg;
  13150. isAnonymousInitList = after->isAnonymousInitList;
  13151. after->property_arg = 0;
  13152. // Do not copy the origExpr member
  13153. }
  13154. END_AS_NAMESPACE
  13155. #endif // AS_NO_COMPILER