as_compiler.cpp 502 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871987298739874987598769877987898799880988198829883988498859886988798889889989098919892989398949895989698979898989999009901990299039904990599069907990899099910991199129913991499159916991799189919992099219922992399249925992699279928992999309931993299339934993599369937993899399940994199429943994499459946994799489949995099519952995399549955995699579958995999609961996299639964996599669967996899699970997199729973997499759976997799789979998099819982998399849985998699879988998999909991999299939994999599969997999899991000010001100021000310004100051000610007100081000910010100111001210013100141001510016100171001810019100201002110022100231002410025100261002710028100291003010031100321003310034100351003610037100381003910040100411004210043100441004510046100471004810049100501005110052100531005410055100561005710058100591006010061100621006310064100651006610067100681006910070100711007210073100741007510076100771007810079100801008110082100831008410085100861008710088100891009010091100921009310094100951009610097100981009910100101011010210103101041010510106101071010810109101101011110112101131011410115101161011710118101191012010121101221012310124101251012610127101281012910130101311013210133101341013510136101371013810139101401014110142101431014410145101461014710148101491015010151101521015310154101551015610157101581015910160101611016210163101641016510166101671016810169101701017110172101731017410175101761017710178101791018010181101821018310184101851018610187101881018910190101911019210193101941019510196101971019810199102001020110202102031020410205102061020710208102091021010211102121021310214102151021610217102181021910220102211022210223102241022510226102271022810229102301023110232102331023410235102361023710238102391024010241102421024310244102451024610247102481024910250102511025210253102541025510256102571025810259102601026110262102631026410265102661026710268102691027010271102721027310274102751027610277102781027910280102811028210283102841028510286102871028810289102901029110292102931029410295102961029710298102991030010301103021030310304103051030610307103081030910310103111031210313103141031510316103171031810319103201032110322103231032410325103261032710328103291033010331103321033310334103351033610337103381033910340103411034210343103441034510346103471034810349103501035110352103531035410355103561035710358103591036010361103621036310364103651036610367103681036910370103711037210373103741037510376103771037810379103801038110382103831038410385103861038710388103891039010391103921039310394103951039610397103981039910400104011040210403104041040510406104071040810409104101041110412104131041410415104161041710418104191042010421104221042310424104251042610427104281042910430104311043210433104341043510436104371043810439104401044110442104431044410445104461044710448104491045010451104521045310454104551045610457104581045910460104611046210463104641046510466104671046810469104701047110472104731047410475104761047710478104791048010481104821048310484104851048610487104881048910490104911049210493104941049510496104971049810499105001050110502105031050410505105061050710508105091051010511105121051310514105151051610517105181051910520105211052210523105241052510526105271052810529105301053110532105331053410535105361053710538105391054010541105421054310544105451054610547105481054910550105511055210553105541055510556105571055810559105601056110562105631056410565105661056710568105691057010571105721057310574105751057610577105781057910580105811058210583105841058510586105871058810589105901059110592105931059410595105961059710598105991060010601106021060310604106051060610607106081060910610106111061210613106141061510616106171061810619106201062110622106231062410625106261062710628106291063010631106321063310634106351063610637106381063910640106411064210643106441064510646106471064810649106501065110652106531065410655106561065710658106591066010661106621066310664106651066610667106681066910670106711067210673106741067510676106771067810679106801068110682106831068410685106861068710688106891069010691106921069310694106951069610697106981069910700107011070210703107041070510706107071070810709107101071110712107131071410715107161071710718107191072010721107221072310724107251072610727107281072910730107311073210733107341073510736107371073810739107401074110742107431074410745107461074710748107491075010751107521075310754107551075610757107581075910760107611076210763107641076510766107671076810769107701077110772107731077410775107761077710778107791078010781107821078310784107851078610787107881078910790107911079210793107941079510796107971079810799108001080110802108031080410805108061080710808108091081010811108121081310814108151081610817108181081910820108211082210823108241082510826108271082810829108301083110832108331083410835108361083710838108391084010841108421084310844108451084610847108481084910850108511085210853108541085510856108571085810859108601086110862108631086410865108661086710868108691087010871108721087310874108751087610877108781087910880108811088210883108841088510886108871088810889108901089110892108931089410895108961089710898108991090010901109021090310904109051090610907109081090910910109111091210913109141091510916109171091810919109201092110922109231092410925109261092710928109291093010931109321093310934109351093610937109381093910940109411094210943109441094510946109471094810949109501095110952109531095410955109561095710958109591096010961109621096310964109651096610967109681096910970109711097210973109741097510976109771097810979109801098110982109831098410985109861098710988109891099010991109921099310994109951099610997109981099911000110011100211003110041100511006110071100811009110101101111012110131101411015110161101711018110191102011021110221102311024110251102611027110281102911030110311103211033110341103511036110371103811039110401104111042110431104411045110461104711048110491105011051110521105311054110551105611057110581105911060110611106211063110641106511066110671106811069110701107111072110731107411075110761107711078110791108011081110821108311084110851108611087110881108911090110911109211093110941109511096110971109811099111001110111102111031110411105111061110711108111091111011111111121111311114111151111611117111181111911120111211112211123111241112511126111271112811129111301113111132111331113411135111361113711138111391114011141111421114311144111451114611147111481114911150111511115211153111541115511156111571115811159111601116111162111631116411165111661116711168111691117011171111721117311174111751117611177111781117911180111811118211183111841118511186111871118811189111901119111192111931119411195111961119711198111991120011201112021120311204112051120611207112081120911210112111121211213112141121511216112171121811219112201122111222112231122411225112261122711228112291123011231112321123311234112351123611237112381123911240112411124211243112441124511246112471124811249112501125111252112531125411255112561125711258112591126011261112621126311264112651126611267112681126911270112711127211273112741127511276112771127811279112801128111282112831128411285112861128711288112891129011291112921129311294112951129611297112981129911300113011130211303113041130511306113071130811309113101131111312113131131411315113161131711318113191132011321113221132311324113251132611327113281132911330113311133211333113341133511336113371133811339113401134111342113431134411345113461134711348113491135011351113521135311354113551135611357113581135911360113611136211363113641136511366113671136811369113701137111372113731137411375113761137711378113791138011381113821138311384113851138611387113881138911390113911139211393113941139511396113971139811399114001140111402114031140411405114061140711408114091141011411114121141311414114151141611417114181141911420114211142211423114241142511426114271142811429114301143111432114331143411435114361143711438114391144011441114421144311444114451144611447114481144911450114511145211453114541145511456114571145811459114601146111462114631146411465114661146711468114691147011471114721147311474114751147611477114781147911480114811148211483114841148511486114871148811489114901149111492114931149411495114961149711498114991150011501115021150311504115051150611507115081150911510115111151211513115141151511516115171151811519115201152111522115231152411525115261152711528115291153011531115321153311534115351153611537115381153911540115411154211543115441154511546115471154811549115501155111552115531155411555115561155711558115591156011561115621156311564115651156611567115681156911570115711157211573115741157511576115771157811579115801158111582115831158411585115861158711588115891159011591115921159311594115951159611597115981159911600116011160211603116041160511606116071160811609116101161111612116131161411615116161161711618116191162011621116221162311624116251162611627116281162911630116311163211633116341163511636116371163811639116401164111642116431164411645116461164711648116491165011651116521165311654116551165611657116581165911660116611166211663116641166511666116671166811669116701167111672116731167411675116761167711678116791168011681116821168311684116851168611687116881168911690116911169211693116941169511696116971169811699117001170111702117031170411705117061170711708117091171011711117121171311714117151171611717117181171911720117211172211723117241172511726117271172811729117301173111732117331173411735117361173711738117391174011741117421174311744117451174611747117481174911750117511175211753117541175511756117571175811759117601176111762117631176411765117661176711768117691177011771117721177311774117751177611777117781177911780117811178211783117841178511786117871178811789117901179111792117931179411795117961179711798117991180011801118021180311804118051180611807118081180911810118111181211813118141181511816118171181811819118201182111822118231182411825118261182711828118291183011831118321183311834118351183611837118381183911840118411184211843118441184511846118471184811849118501185111852118531185411855118561185711858118591186011861118621186311864118651186611867118681186911870118711187211873118741187511876118771187811879118801188111882118831188411885118861188711888118891189011891118921189311894118951189611897118981189911900119011190211903119041190511906119071190811909119101191111912119131191411915119161191711918119191192011921119221192311924119251192611927119281192911930119311193211933119341193511936119371193811939119401194111942119431194411945119461194711948119491195011951119521195311954119551195611957119581195911960119611196211963119641196511966119671196811969119701197111972119731197411975119761197711978119791198011981119821198311984119851198611987119881198911990119911199211993119941199511996119971199811999120001200112002120031200412005120061200712008120091201012011120121201312014120151201612017120181201912020120211202212023120241202512026120271202812029120301203112032120331203412035120361203712038120391204012041120421204312044120451204612047120481204912050120511205212053120541205512056120571205812059120601206112062120631206412065120661206712068120691207012071120721207312074120751207612077120781207912080120811208212083120841208512086120871208812089120901209112092120931209412095120961209712098120991210012101121021210312104121051210612107121081210912110121111211212113121141211512116121171211812119121201212112122121231212412125121261212712128121291213012131121321213312134121351213612137121381213912140121411214212143121441214512146121471214812149121501215112152121531215412155121561215712158121591216012161121621216312164121651216612167121681216912170121711217212173121741217512176121771217812179121801218112182121831218412185121861218712188121891219012191121921219312194121951219612197121981219912200122011220212203122041220512206122071220812209122101221112212122131221412215122161221712218122191222012221122221222312224122251222612227122281222912230122311223212233122341223512236122371223812239122401224112242122431224412245122461224712248122491225012251122521225312254122551225612257122581225912260122611226212263122641226512266122671226812269122701227112272122731227412275122761227712278122791228012281122821228312284122851228612287122881228912290122911229212293122941229512296122971229812299123001230112302123031230412305123061230712308123091231012311123121231312314123151231612317123181231912320123211232212323123241232512326123271232812329123301233112332123331233412335123361233712338123391234012341123421234312344123451234612347123481234912350123511235212353123541235512356123571235812359123601236112362123631236412365123661236712368123691237012371123721237312374123751237612377123781237912380123811238212383123841238512386123871238812389123901239112392123931239412395123961239712398123991240012401124021240312404124051240612407124081240912410124111241212413124141241512416124171241812419124201242112422124231242412425124261242712428124291243012431124321243312434124351243612437124381243912440124411244212443124441244512446124471244812449124501245112452124531245412455124561245712458124591246012461124621246312464124651246612467124681246912470124711247212473124741247512476124771247812479124801248112482124831248412485124861248712488124891249012491124921249312494124951249612497124981249912500125011250212503125041250512506125071250812509125101251112512125131251412515125161251712518125191252012521125221252312524125251252612527125281252912530125311253212533125341253512536125371253812539125401254112542125431254412545125461254712548125491255012551125521255312554125551255612557125581255912560125611256212563125641256512566125671256812569125701257112572125731257412575125761257712578125791258012581125821258312584125851258612587125881258912590125911259212593125941259512596125971259812599126001260112602126031260412605126061260712608126091261012611126121261312614126151261612617126181261912620126211262212623126241262512626126271262812629126301263112632126331263412635126361263712638126391264012641126421264312644126451264612647126481264912650126511265212653126541265512656126571265812659126601266112662126631266412665126661266712668126691267012671126721267312674126751267612677126781267912680126811268212683126841268512686126871268812689126901269112692126931269412695126961269712698126991270012701127021270312704127051270612707127081270912710127111271212713127141271512716127171271812719127201272112722127231272412725127261272712728127291273012731127321273312734127351273612737127381273912740127411274212743127441274512746127471274812749127501275112752127531275412755127561275712758127591276012761127621276312764127651276612767127681276912770127711277212773127741277512776127771277812779127801278112782127831278412785127861278712788127891279012791127921279312794127951279612797127981279912800128011280212803128041280512806128071280812809128101281112812128131281412815128161281712818128191282012821128221282312824128251282612827128281282912830128311283212833128341283512836128371283812839128401284112842128431284412845128461284712848128491285012851128521285312854128551285612857128581285912860128611286212863128641286512866128671286812869128701287112872128731287412875128761287712878128791288012881128821288312884128851288612887128881288912890128911289212893128941289512896128971289812899129001290112902129031290412905129061290712908129091291012911129121291312914129151291612917129181291912920129211292212923129241292512926129271292812929129301293112932129331293412935129361293712938129391294012941129421294312944129451294612947129481294912950129511295212953129541295512956129571295812959129601296112962129631296412965129661296712968129691297012971129721297312974129751297612977129781297912980129811298212983129841298512986129871298812989129901299112992129931299412995129961299712998129991300013001130021300313004130051300613007130081300913010130111301213013130141301513016130171301813019130201302113022130231302413025130261302713028130291303013031130321303313034130351303613037130381303913040130411304213043130441304513046130471304813049130501305113052130531305413055130561305713058130591306013061130621306313064130651306613067130681306913070130711307213073130741307513076130771307813079130801308113082130831308413085130861308713088130891309013091130921309313094130951309613097130981309913100131011310213103131041310513106131071310813109131101311113112131131311413115131161311713118131191312013121131221312313124131251312613127131281312913130131311313213133131341313513136131371313813139131401314113142131431314413145131461314713148131491315013151131521315313154131551315613157131581315913160131611316213163131641316513166131671316813169131701317113172131731317413175131761317713178131791318013181131821318313184131851318613187131881318913190131911319213193131941319513196131971319813199132001320113202132031320413205132061320713208132091321013211132121321313214132151321613217132181321913220132211322213223132241322513226132271322813229132301323113232132331323413235132361323713238132391324013241132421324313244132451324613247132481324913250132511325213253132541325513256132571325813259132601326113262132631326413265132661326713268132691327013271132721327313274132751327613277132781327913280132811328213283132841328513286132871328813289132901329113292132931329413295132961329713298132991330013301133021330313304133051330613307133081330913310133111331213313133141331513316133171331813319133201332113322133231332413325133261332713328133291333013331133321333313334133351333613337133381333913340133411334213343133441334513346133471334813349133501335113352133531335413355133561335713358133591336013361133621336313364133651336613367133681336913370133711337213373133741337513376133771337813379133801338113382133831338413385133861338713388133891339013391133921339313394133951339613397133981339913400134011340213403134041340513406134071340813409134101341113412134131341413415134161341713418134191342013421134221342313424134251342613427134281342913430134311343213433134341343513436134371343813439134401344113442134431344413445134461344713448134491345013451134521345313454134551345613457134581345913460134611346213463134641346513466134671346813469134701347113472134731347413475134761347713478134791348013481134821348313484134851348613487134881348913490134911349213493134941349513496134971349813499135001350113502135031350413505135061350713508135091351013511135121351313514135151351613517135181351913520135211352213523135241352513526135271352813529135301353113532135331353413535135361353713538135391354013541135421354313544135451354613547135481354913550135511355213553135541355513556135571355813559135601356113562135631356413565135661356713568135691357013571135721357313574135751357613577135781357913580135811358213583135841358513586135871358813589135901359113592135931359413595135961359713598135991360013601136021360313604136051360613607136081360913610136111361213613136141361513616136171361813619136201362113622136231362413625136261362713628136291363013631136321363313634136351363613637136381363913640136411364213643136441364513646136471364813649136501365113652136531365413655136561365713658136591366013661136621366313664136651366613667136681366913670136711367213673136741367513676136771367813679136801368113682136831368413685136861368713688136891369013691136921369313694136951369613697136981369913700137011370213703137041370513706137071370813709137101371113712137131371413715137161371713718137191372013721137221372313724137251372613727137281372913730137311373213733137341373513736137371373813739137401374113742137431374413745137461374713748137491375013751137521375313754137551375613757137581375913760137611376213763137641376513766137671376813769137701377113772137731377413775137761377713778137791378013781137821378313784137851378613787137881378913790137911379213793137941379513796137971379813799138001380113802138031380413805138061380713808138091381013811138121381313814138151381613817138181381913820138211382213823138241382513826138271382813829138301383113832138331383413835138361383713838138391384013841138421384313844138451384613847138481384913850138511385213853138541385513856138571385813859138601386113862138631386413865138661386713868138691387013871138721387313874138751387613877138781387913880138811388213883138841388513886138871388813889138901389113892138931389413895138961389713898138991390013901139021390313904139051390613907139081390913910139111391213913139141391513916139171391813919139201392113922139231392413925139261392713928139291393013931139321393313934139351393613937139381393913940139411394213943139441394513946139471394813949139501395113952139531395413955139561395713958139591396013961139621396313964139651396613967139681396913970139711397213973139741397513976139771397813979139801398113982139831398413985139861398713988139891399013991139921399313994139951399613997139981399914000140011400214003140041400514006140071400814009140101401114012140131401414015140161401714018140191402014021140221402314024140251402614027140281402914030140311403214033140341403514036140371403814039140401404114042140431404414045140461404714048140491405014051140521405314054140551405614057140581405914060140611406214063140641406514066140671406814069140701407114072140731407414075140761407714078140791408014081140821408314084140851408614087140881408914090140911409214093140941409514096140971409814099141001410114102141031410414105141061410714108141091411014111141121411314114141151411614117141181411914120141211412214123141241412514126141271412814129141301413114132141331413414135141361413714138141391414014141141421414314144141451414614147141481414914150141511415214153141541415514156141571415814159141601416114162141631416414165141661416714168141691417014171141721417314174141751417614177141781417914180141811418214183141841418514186141871418814189141901419114192141931419414195141961419714198141991420014201142021420314204142051420614207142081420914210142111421214213142141421514216142171421814219142201422114222142231422414225142261422714228142291423014231142321423314234142351423614237142381423914240142411424214243142441424514246142471424814249142501425114252142531425414255142561425714258142591426014261142621426314264142651426614267142681426914270142711427214273142741427514276142771427814279142801428114282142831428414285142861428714288142891429014291142921429314294142951429614297142981429914300143011430214303143041430514306143071430814309143101431114312143131431414315143161431714318143191432014321143221432314324143251432614327143281432914330143311433214333143341433514336143371433814339143401434114342143431434414345143461434714348143491435014351143521435314354143551435614357143581435914360143611436214363143641436514366143671436814369143701437114372143731437414375143761437714378143791438014381143821438314384143851438614387143881438914390143911439214393143941439514396143971439814399144001440114402144031440414405144061440714408144091441014411144121441314414144151441614417144181441914420144211442214423144241442514426144271442814429144301443114432144331443414435144361443714438144391444014441144421444314444144451444614447144481444914450144511445214453144541445514456144571445814459144601446114462144631446414465144661446714468144691447014471144721447314474144751447614477144781447914480144811448214483144841448514486144871448814489144901449114492144931449414495144961449714498144991450014501145021450314504145051450614507145081450914510145111451214513145141451514516145171451814519145201452114522145231452414525145261452714528145291453014531145321453314534145351453614537145381453914540145411454214543145441454514546145471454814549145501455114552145531455414555145561455714558145591456014561145621456314564145651456614567145681456914570145711457214573145741457514576145771457814579145801458114582145831458414585145861458714588145891459014591145921459314594145951459614597145981459914600146011460214603146041460514606146071460814609146101461114612146131461414615146161461714618146191462014621146221462314624146251462614627146281462914630146311463214633146341463514636146371463814639146401464114642146431464414645146461464714648146491465014651146521465314654146551465614657146581465914660146611466214663146641466514666146671466814669146701467114672146731467414675146761467714678146791468014681146821468314684146851468614687146881468914690146911469214693146941469514696146971469814699147001470114702147031470414705147061470714708147091471014711147121471314714147151471614717147181471914720147211472214723147241472514726147271472814729147301473114732147331473414735147361473714738147391474014741147421474314744147451474614747147481474914750147511475214753147541475514756147571475814759147601476114762147631476414765147661476714768147691477014771147721477314774147751477614777147781477914780147811478214783147841478514786147871478814789147901479114792147931479414795147961479714798147991480014801148021480314804148051480614807148081480914810148111481214813148141481514816148171481814819148201482114822148231482414825148261482714828148291483014831148321483314834148351483614837148381483914840148411484214843148441484514846148471484814849148501485114852148531485414855148561485714858148591486014861148621486314864148651486614867148681486914870148711487214873148741487514876148771487814879148801488114882148831488414885148861488714888148891489014891148921489314894148951489614897148981489914900149011490214903149041490514906149071490814909149101491114912149131491414915149161491714918149191492014921149221492314924149251492614927149281492914930149311493214933149341493514936149371493814939149401494114942149431494414945149461494714948149491495014951149521495314954149551495614957149581495914960149611496214963149641496514966149671496814969149701497114972149731497414975149761497714978149791498014981149821498314984149851498614987149881498914990149911499214993149941499514996149971499814999150001500115002150031500415005150061500715008150091501015011150121501315014150151501615017150181501915020150211502215023150241502515026150271502815029150301503115032150331503415035150361503715038150391504015041150421504315044150451504615047150481504915050150511505215053150541505515056150571505815059150601506115062150631506415065150661506715068150691507015071150721507315074150751507615077150781507915080150811508215083150841508515086150871508815089150901509115092150931509415095150961509715098150991510015101151021510315104151051510615107151081510915110151111511215113151141511515116151171511815119151201512115122151231512415125151261512715128151291513015131151321513315134151351513615137151381513915140151411514215143151441514515146151471514815149151501515115152151531515415155151561515715158151591516015161151621516315164151651516615167151681516915170151711517215173151741517515176151771517815179151801518115182151831518415185151861518715188151891519015191151921519315194151951519615197151981519915200152011520215203152041520515206152071520815209152101521115212152131521415215152161521715218152191522015221152221522315224152251522615227152281522915230152311523215233152341523515236152371523815239152401524115242152431524415245152461524715248152491525015251152521525315254152551525615257152581525915260152611526215263152641526515266152671526815269152701527115272152731527415275152761527715278152791528015281152821528315284152851528615287152881528915290152911529215293152941529515296152971529815299153001530115302153031530415305153061530715308153091531015311153121531315314153151531615317153181531915320153211532215323153241532515326153271532815329153301533115332153331533415335153361533715338153391534015341153421534315344153451534615347153481534915350153511535215353153541535515356153571535815359153601536115362153631536415365153661536715368153691537015371153721537315374153751537615377153781537915380153811538215383153841538515386153871538815389153901539115392153931539415395153961539715398153991540015401154021540315404154051540615407154081540915410154111541215413154141541515416154171541815419154201542115422154231542415425154261542715428154291543015431154321543315434154351543615437154381543915440154411544215443154441544515446154471544815449154501545115452154531545415455154561545715458154591546015461154621546315464154651546615467154681546915470154711547215473154741547515476154771547815479154801548115482154831548415485154861548715488154891549015491154921549315494154951549615497154981549915500155011550215503155041550515506155071550815509155101551115512155131551415515155161551715518155191552015521155221552315524155251552615527155281552915530155311553215533155341553515536155371553815539155401554115542155431554415545155461554715548155491555015551155521555315554155551555615557155581555915560155611556215563155641556515566155671556815569155701557115572155731557415575155761557715578155791558015581155821558315584155851558615587155881558915590155911559215593155941559515596155971559815599156001560115602156031560415605156061560715608156091561015611156121561315614156151561615617156181561915620156211562215623156241562515626156271562815629156301563115632156331563415635156361563715638156391564015641156421564315644156451564615647156481564915650156511565215653156541565515656156571565815659156601566115662156631566415665156661566715668156691567015671156721567315674156751567615677156781567915680156811568215683156841568515686156871568815689156901569115692156931569415695156961569715698156991570015701157021570315704157051570615707157081570915710157111571215713157141571515716157171571815719157201572115722157231572415725157261572715728157291573015731157321573315734157351573615737157381573915740157411574215743157441574515746157471574815749157501575115752157531575415755157561575715758157591576015761157621576315764157651576615767157681576915770157711577215773157741577515776157771577815779157801578115782157831578415785157861578715788157891579015791157921579315794157951579615797157981579915800158011580215803158041580515806158071580815809158101581115812158131581415815158161581715818158191582015821158221582315824158251582615827158281582915830158311583215833158341583515836158371583815839158401584115842158431584415845158461584715848158491585015851158521585315854158551585615857158581585915860158611586215863158641586515866158671586815869158701587115872158731587415875158761587715878158791588015881158821588315884158851588615887158881588915890158911589215893158941589515896158971589815899159001590115902159031590415905159061590715908159091591015911159121591315914159151591615917159181591915920159211592215923159241592515926159271592815929159301593115932159331593415935159361593715938159391594015941159421594315944159451594615947159481594915950159511595215953159541595515956159571595815959159601596115962159631596415965159661596715968159691597015971159721597315974159751597615977159781597915980159811598215983159841598515986159871598815989159901599115992159931599415995159961599715998159991600016001160021600316004160051600616007160081600916010160111601216013160141601516016160171601816019160201602116022160231602416025160261602716028160291603016031160321603316034160351603616037160381603916040160411604216043160441604516046160471604816049160501605116052160531605416055160561605716058160591606016061160621606316064160651606616067160681606916070160711607216073160741607516076160771607816079160801608116082160831608416085160861608716088160891609016091160921609316094160951609616097160981609916100
  1. /*
  2. AngelCode Scripting Library
  3. Copyright (c) 2003-2018 Andreas Jonsson
  4. This software is provided 'as-is', without any express or implied
  5. warranty. In no event will the authors be held liable for any
  6. damages arising from the use of this software.
  7. Permission is granted to anyone to use this software for any
  8. purpose, including commercial applications, and to alter it and
  9. redistribute it freely, subject to the following restrictions:
  10. 1. The origin of this software must not be misrepresented; you
  11. must not claim that you wrote the original software. If you use
  12. this software in a product, an acknowledgment in the product
  13. documentation would be appreciated but is not required.
  14. 2. Altered source versions must be plainly marked as such, and
  15. must not be misrepresented as being the original software.
  16. 3. This notice may not be removed or altered from any source
  17. distribution.
  18. The original version of this library can be located at:
  19. http://www.angelcode.com/angelscript/
  20. Andreas Jonsson
  21. [email protected]
  22. */
  23. // Modified by Lasse Oorni for Urho3D
  24. //
  25. // as_compiler.cpp
  26. //
  27. // The class that does the actual compilation of the functions
  28. //
  29. #include <math.h> // fmodf() pow()
  30. #include "as_config.h"
  31. #ifndef AS_NO_COMPILER
  32. #include "as_compiler.h"
  33. #include "as_tokendef.h"
  34. #include "as_tokenizer.h"
  35. #include "as_string_util.h"
  36. #include "as_texts.h"
  37. #include "as_parser.h"
  38. #include "as_debug.h"
  39. #include "as_context.h" // as_powi()
  40. BEGIN_AS_NAMESPACE
  41. //
  42. // The calling convention rules for script functions:
  43. // - If a class method returns a reference, the caller must guarantee the object pointer stays alive until the function returns, and the reference is no longer going to be used
  44. // - If a class method doesn't return a reference, it must guarantee by itself that the this pointer stays alive during the function call. If no outside access is made, then the function is guaranteed to stay alive and nothing needs to be done
  45. // - The object pointer is always passed as the first argument, position 0
  46. // - If the function returns a value type the caller must reserve the memory for this and pass the pointer as the first argument after the object pointer
  47. //
  48. // TODO: I must correct the interpretation of a reference to objects in the compiler.
  49. // A reference should mean that a pointer to the object is on the stack.
  50. // No expression should end up as non-references to objects, as the actual object is
  51. // never put on the stack.
  52. // Local variables are declared as non-references, but the expression should be a reference to the variable.
  53. // Function parameters of called functions can also be non-references, but in that case it means the
  54. // object will be passed by value (currently on the heap, which will be moved to the application stack).
  55. //
  56. // The compiler shouldn't use the asCDataType::IsReference. The datatype should always be stored as non-references.
  57. // Instead the compiler should keep track of references in TypeInfo, where it should also state how the reference
  58. // is currently stored, i.e. in variable, in register, on stack, etc.
  59. asCCompiler::asCCompiler(asCScriptEngine *engine) : byteCode(engine)
  60. {
  61. builder = 0;
  62. script = 0;
  63. variables = 0;
  64. isProcessingDeferredParams = false;
  65. isCompilingDefaultArg = false;
  66. noCodeOutput = 0;
  67. }
  68. asCCompiler::~asCCompiler()
  69. {
  70. while( variables )
  71. {
  72. asCVariableScope *var = variables;
  73. variables = variables->parent;
  74. asDELETE(var,asCVariableScope);
  75. }
  76. // Clean up all the string constants that were allocated. By now the script
  77. // functions that were compiled successfully already holds their own references
  78. for (asUINT n = 0; n < usedStringConstants.GetLength(); n++)
  79. engine->stringFactory->ReleaseStringConstant(usedStringConstants[n]);
  80. usedStringConstants.SetLength(0);
  81. }
  82. void asCCompiler::Reset(asCBuilder *in_builder, asCScriptCode *in_script, asCScriptFunction *in_outFunc)
  83. {
  84. this->builder = in_builder;
  85. this->engine = in_builder->engine;
  86. this->script = in_script;
  87. this->outFunc = in_outFunc;
  88. hasCompileErrors = false;
  89. m_isConstructor = false;
  90. m_isConstructorCalled = false;
  91. m_classDecl = 0;
  92. m_globalVar = 0;
  93. nextLabel = 0;
  94. breakLabels.SetLength(0);
  95. continueLabels.SetLength(0);
  96. numLambdas = 0;
  97. byteCode.ClearAll();
  98. }
  99. int asCCompiler::CompileDefaultConstructor(asCBuilder *in_builder, asCScriptCode *in_script, asCScriptNode *in_node, asCScriptFunction *in_outFunc, sClassDeclaration *in_classDecl)
  100. {
  101. Reset(in_builder, in_script, in_outFunc);
  102. m_classDecl = in_classDecl;
  103. // Insert a JitEntry at the start of the function for JIT compilers
  104. byteCode.InstrPTR(asBC_JitEntry, 0);
  105. // Add a variable scope that might be needed to declare dummy variables
  106. // in case the member initialization refers to undefined symbols.
  107. AddVariableScope();
  108. // Initialize the class members that have no explicit expression first. This will allow the
  109. // base class' constructor to access these members without worry they will be uninitialized.
  110. // This can happen if the base class' constructor calls a method that is overridden by the derived class
  111. CompileMemberInitialization(&byteCode, true);
  112. // If the class is derived from another, then the base class' default constructor must be called
  113. if( outFunc->objectType->derivedFrom )
  114. {
  115. // Make sure the base class really has a default constructor
  116. if( outFunc->objectType->derivedFrom->beh.construct == 0 )
  117. Error(TEXT_BASE_DOESNT_HAVE_DEF_CONSTR, in_node);
  118. // Call the base class' default constructor
  119. byteCode.InstrSHORT(asBC_PSF, 0);
  120. byteCode.Instr(asBC_RDSPtr);
  121. byteCode.Call(asBC_CALL, outFunc->objectType->derivedFrom->beh.construct, AS_PTR_SIZE);
  122. }
  123. // Initialize the class members that explicit expressions afterwards. This allow the expressions
  124. // to access the base class members without worry they will be uninitialized
  125. CompileMemberInitialization(&byteCode, false);
  126. byteCode.OptimizeLocally(tempVariableOffsets);
  127. // If there are compile errors, there is no reason to build the final code
  128. if( hasCompileErrors )
  129. return -1;
  130. // Pop the object pointer from the stack
  131. byteCode.Ret(AS_PTR_SIZE);
  132. // Count total variable size
  133. int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1;
  134. outFunc->scriptData->variableSpace = varSize;
  135. FinalizeFunction();
  136. #ifdef AS_DEBUG
  137. // DEBUG: output byte code
  138. byteCode.DebugOutput(("__" + outFunc->objectType->name + "_" + outFunc->name + "__defconstr.txt").AddressOf(), in_outFunc);
  139. #endif
  140. return 0;
  141. }
  142. int asCCompiler::CompileFactory(asCBuilder *in_builder, asCScriptCode *in_script, asCScriptFunction *in_outFunc)
  143. {
  144. Reset(in_builder, in_script, in_outFunc);
  145. // Insert a JitEntry at the start of the function for JIT compilers
  146. byteCode.InstrPTR(asBC_JitEntry, 0);
  147. // Find the corresponding constructor
  148. asCDataType dt = asCDataType::CreateType(outFunc->returnType.GetTypeInfo(), false);
  149. int constructor = 0;
  150. for( unsigned int n = 0; n < dt.GetBehaviour()->factories.GetLength(); n++ )
  151. {
  152. if( dt.GetBehaviour()->factories[n] == outFunc->id )
  153. {
  154. constructor = dt.GetBehaviour()->constructors[n];
  155. break;
  156. }
  157. }
  158. // Allocate the class and instantiate it with the constructor
  159. int varOffset = AllocateVariable(dt, true);
  160. outFunc->scriptData->variableSpace = AS_PTR_SIZE;
  161. byteCode.InstrSHORT(asBC_PSF, (short)varOffset);
  162. // Copy all arguments to the top of the stack
  163. // TODO: runtime optimize: Might be interesting to have a specific instruction for copying all arguments
  164. int offset = (int)outFunc->GetSpaceNeededForArguments();
  165. for( int a = int(outFunc->parameterTypes.GetLength()) - 1; a >= 0; a-- )
  166. {
  167. if( !outFunc->parameterTypes[a].IsPrimitive() ||
  168. outFunc->parameterTypes[a].IsReference() )
  169. {
  170. offset -= AS_PTR_SIZE;
  171. byteCode.InstrSHORT(asBC_PshVPtr, short(-offset));
  172. }
  173. else
  174. {
  175. if( outFunc->parameterTypes[a].GetSizeOnStackDWords() == 2 )
  176. {
  177. offset -= 2;
  178. byteCode.InstrSHORT(asBC_PshV8, short(-offset));
  179. }
  180. else
  181. {
  182. offset -= 1;
  183. byteCode.InstrSHORT(asBC_PshV4, short(-offset));
  184. }
  185. }
  186. }
  187. int argDwords = (int)outFunc->GetSpaceNeededForArguments();
  188. byteCode.Alloc(asBC_ALLOC, dt.GetTypeInfo(), constructor, argDwords + AS_PTR_SIZE);
  189. // Return a handle to the newly created object
  190. byteCode.InstrSHORT(asBC_LOADOBJ, (short)varOffset);
  191. byteCode.Ret(argDwords);
  192. FinalizeFunction();
  193. // Tell the virtual machine not to clean up parameters on exception
  194. outFunc->dontCleanUpOnException = true;
  195. /*
  196. #ifdef AS_DEBUG
  197. // DEBUG: output byte code
  198. asCString args;
  199. args.Format("%d", outFunc->parameterTypes.GetLength());
  200. byteCode.DebugOutput(("__" + outFunc->name + "__factory" + args + ".txt").AddressOf(), engine);
  201. #endif
  202. */
  203. return 0;
  204. }
  205. void asCCompiler::FinalizeFunction()
  206. {
  207. TimeIt("asCCompiler::FinalizeFunction");
  208. asASSERT( outFunc->scriptData );
  209. asUINT n;
  210. // Finalize the bytecode
  211. byteCode.Finalize(tempVariableOffsets);
  212. byteCode.ExtractObjectVariableInfo(outFunc);
  213. // Compile the list of object variables for the exception handler
  214. // Start with the variables allocated on the heap, and then the ones allocated on the stack
  215. for( n = 0; n < variableAllocations.GetLength(); n++ )
  216. {
  217. if( (variableAllocations[n].IsObject() || variableAllocations[n].IsFuncdef()) && !variableAllocations[n].IsReference() )
  218. {
  219. if( variableIsOnHeap[n] )
  220. {
  221. outFunc->scriptData->objVariableTypes.PushLast(variableAllocations[n].GetTypeInfo());
  222. outFunc->scriptData->objVariablePos.PushLast(GetVariableOffset(n));
  223. }
  224. }
  225. }
  226. outFunc->scriptData->objVariablesOnHeap = asUINT(outFunc->scriptData->objVariablePos.GetLength());
  227. for( n = 0; n < variableAllocations.GetLength(); n++ )
  228. {
  229. if( (variableAllocations[n].IsObject() || variableAllocations[n].IsFuncdef()) && !variableAllocations[n].IsReference() )
  230. {
  231. if( !variableIsOnHeap[n] )
  232. {
  233. outFunc->scriptData->objVariableTypes.PushLast(variableAllocations[n].GetTypeInfo());
  234. outFunc->scriptData->objVariablePos.PushLast(GetVariableOffset(n));
  235. }
  236. }
  237. }
  238. // Copy byte code to the function
  239. asASSERT( outFunc->scriptData->byteCode.GetLength() == 0 );
  240. outFunc->scriptData->byteCode.SetLength(byteCode.GetSize());
  241. byteCode.Output(outFunc->scriptData->byteCode.AddressOf());
  242. outFunc->AddReferences();
  243. outFunc->scriptData->stackNeeded = byteCode.largestStackUsed + outFunc->scriptData->variableSpace;
  244. outFunc->scriptData->lineNumbers = byteCode.lineNumbers;
  245. // Extract the script section indexes too if there are any entries that are different from the function's script section
  246. int lastIdx = outFunc->scriptData->scriptSectionIdx;
  247. for( n = 0; n < byteCode.sectionIdxs.GetLength(); n++ )
  248. {
  249. if( byteCode.sectionIdxs[n] != lastIdx )
  250. {
  251. lastIdx = byteCode.sectionIdxs[n];
  252. outFunc->scriptData->sectionIdxs.PushLast(byteCode.lineNumbers[n*2]);
  253. outFunc->scriptData->sectionIdxs.PushLast(lastIdx);
  254. }
  255. }
  256. }
  257. // internal
  258. int asCCompiler::SetupParametersAndReturnVariable(asCArray<asCString> &parameterNames, asCScriptNode *func)
  259. {
  260. int stackPos = 0;
  261. if( outFunc->objectType )
  262. stackPos = -AS_PTR_SIZE; // The first parameter is the pointer to the object
  263. // Add the first variable scope, which the parameters and
  264. // variables declared in the outermost statement block is
  265. // part of.
  266. AddVariableScope();
  267. bool isDestructor = false;
  268. asCDataType returnType;
  269. // Examine return type
  270. returnType = outFunc->returnType;
  271. // Check if this is a constructor or destructor
  272. if( returnType.GetTokenType() == ttVoid && outFunc->objectType )
  273. {
  274. if( outFunc->name[0] == '~' )
  275. isDestructor = true;
  276. else if( outFunc->objectType->name == outFunc->name )
  277. m_isConstructor = true;
  278. }
  279. // Is the return type allowed?
  280. if( returnType != asCDataType::CreatePrimitive(ttVoid, false) &&
  281. !returnType.CanBeInstantiated() )
  282. {
  283. // TODO: Hasn't this been validated by the builder already?
  284. asCString str;
  285. str.Format(TXT_RETURN_CANT_BE_s, returnType.Format(outFunc->nameSpace).AddressOf());
  286. Error(str, func);
  287. }
  288. // If the return type is a value type returned by value the address of the
  289. // location where the value will be stored is pushed on the stack before
  290. // the arguments
  291. if( !(isDestructor || m_isConstructor) && outFunc->DoesReturnOnStack() )
  292. stackPos -= AS_PTR_SIZE;
  293. asCVariableScope vs(0);
  294. // Declare parameters
  295. asUINT n;
  296. for( n = 0; n < parameterNames.GetLength(); n++ )
  297. {
  298. // Get the parameter type
  299. asCDataType &type = outFunc->parameterTypes[n];
  300. asETypeModifiers inoutFlag = n < outFunc->inOutFlags.GetLength() ? outFunc->inOutFlags[n] : asTM_NONE;
  301. // Is the data type allowed?
  302. // TODO: Hasn't this been validated by the builder already?
  303. if( (type.IsReference() && inoutFlag != asTM_INOUTREF && !type.CanBeInstantiated()) ||
  304. (!type.IsReference() && !type.CanBeInstantiated()) )
  305. {
  306. asCString parm = type.Format(outFunc->nameSpace);
  307. if( inoutFlag == asTM_INREF )
  308. parm += "in";
  309. else if( inoutFlag == asTM_OUTREF )
  310. parm += "out";
  311. asCString str;
  312. str.Format(TXT_PARAMETER_CANT_BE_s, parm.AddressOf());
  313. Error(str, func);
  314. }
  315. // If the parameter has a name then declare it as variable
  316. if( parameterNames[n] != "" )
  317. {
  318. asCString &name = parameterNames[n];
  319. if( vs.DeclareVariable(name.AddressOf(), type, stackPos, true) < 0 )
  320. {
  321. // TODO: It might be an out-of-memory too
  322. Error(TXT_PARAMETER_ALREADY_DECLARED, func);
  323. }
  324. // Add marker for variable declaration
  325. byteCode.VarDecl((int)outFunc->scriptData->variables.GetLength());
  326. outFunc->AddVariable(name, type, stackPos);
  327. }
  328. else
  329. vs.DeclareVariable("", type, stackPos, true);
  330. // Move to next parameter
  331. stackPos -= type.GetSizeOnStackDWords();
  332. }
  333. for( n = asUINT(vs.variables.GetLength()); n-- > 0; )
  334. variables->DeclareVariable(vs.variables[n]->name.AddressOf(), vs.variables[n]->type, vs.variables[n]->stackOffset, vs.variables[n]->onHeap);
  335. variables->DeclareVariable("return", returnType, stackPos, true);
  336. return stackPos;
  337. }
  338. void asCCompiler::CompileMemberInitialization(asCByteCode *bc, bool onlyDefaults)
  339. {
  340. asASSERT( m_classDecl );
  341. // Initialize each member in the order they were declared
  342. for( asUINT n = 0; n < outFunc->objectType->properties.GetLength(); n++ )
  343. {
  344. asCObjectProperty *prop = outFunc->objectType->properties[n];
  345. // Check if the property has an initialization expression
  346. asCScriptNode *declNode = 0;
  347. asCScriptNode *initNode = 0;
  348. asCScriptCode *initScript = 0;
  349. for( asUINT m = 0; m < m_classDecl->propInits.GetLength(); m++ )
  350. {
  351. if( m_classDecl->propInits[m].name == prop->name )
  352. {
  353. declNode = m_classDecl->propInits[m].declNode;
  354. initNode = m_classDecl->propInits[m].initNode;
  355. initScript = m_classDecl->propInits[m].file;
  356. break;
  357. }
  358. }
  359. // If declNode is null, the property was inherited in which case
  360. // it was already initialized by the base class' constructor
  361. if( declNode )
  362. {
  363. if( initNode )
  364. {
  365. if( onlyDefaults )
  366. continue;
  367. #ifdef AS_NO_MEMBER_INIT
  368. // Give an error as the initialization in the declaration has been disabled
  369. asCScriptCode *origScript = script;
  370. script = initScript;
  371. Error("Initialization of members in declaration is not supported", initNode);
  372. script = origScript;
  373. // Clear the initialization node
  374. initNode = 0;
  375. initScript = script;
  376. #else
  377. // Re-parse the initialization expression as the parser now knows the types, which it didn't earlier
  378. asCParser parser(builder);
  379. int r = parser.ParseVarInit(initScript, initNode);
  380. if( r < 0 )
  381. continue;
  382. initNode = parser.GetScriptNode();
  383. #endif
  384. }
  385. else
  386. {
  387. if( !onlyDefaults )
  388. continue;
  389. }
  390. #ifdef AS_NO_MEMBER_INIT
  391. // The initialization will be done in the asCScriptObject constructor, so
  392. // here we should just validate that the member has a default constructor
  393. if( prop->type.IsObject() &&
  394. !prop->type.IsObjectHandle() &&
  395. (((prop->type.GetTypeInfo()->flags & asOBJ_REF) &&
  396. prop->type.GetBehaviour()->factory == 0) ||
  397. ((prop->type.GetTypeInfo()->flags & asOBJ_VALUE) &&
  398. prop->type.GetBehaviour()->construct == 0 &&
  399. !(prop->type.GetTypeInfo()->flags & asOBJ_POD))) )
  400. {
  401. // Class has no default factory/constructor.
  402. asCString str;
  403. // TODO: funcdef: asCDataType should have a GetTypeName()
  404. if( prop->type.GetFuncDef() )
  405. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, prop->type.GetFuncDef()->GetName());
  406. else
  407. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, prop->type.GetTypeInfo()->GetName());
  408. Error(str, declNode);
  409. }
  410. #else
  411. // Temporarily set the script that is being compiled to where the member initialization is declared.
  412. // The script can be different when including mixin classes from a different script section
  413. asCScriptCode *origScript = script;
  414. script = initScript;
  415. // Add a line instruction with the position of the declaration
  416. LineInstr(bc, declNode->tokenPos);
  417. // Compile the initialization
  418. asQWORD constantValue;
  419. asCByteCode bcInit(engine);
  420. CompileInitialization(initNode, &bcInit, prop->type, declNode, prop->byteOffset, &constantValue, 2);
  421. bcInit.OptimizeLocally(tempVariableOffsets);
  422. bc->AddCode(&bcInit);
  423. script = origScript;
  424. #endif
  425. }
  426. }
  427. }
  428. // Entry
  429. int asCCompiler::CompileFunction(asCBuilder *in_builder, asCScriptCode *in_script, asCArray<asCString> &in_parameterNames, asCScriptNode *in_func, asCScriptFunction *in_outFunc, sClassDeclaration *in_classDecl)
  430. {
  431. TimeIt("asCCompiler::CompileFunction");
  432. Reset(in_builder, in_script, in_outFunc);
  433. int buildErrors = builder->numErrors;
  434. int stackPos = SetupParametersAndReturnVariable(in_parameterNames, in_func);
  435. //--------------------------------------------
  436. // Compile the statement block
  437. if( m_isConstructor )
  438. m_classDecl = in_classDecl;
  439. // We need to parse the statement block now
  440. asCScriptNode *blockBegin;
  441. // If the function signature was implicit, e.g. virtual property accessor or
  442. // lambda function, then the received node already is the statement block
  443. if( in_func->nodeType != snStatementBlock )
  444. blockBegin = in_func->lastChild;
  445. else
  446. blockBegin = in_func;
  447. // TODO: memory: We can parse the statement block one statement at a time, thus save even more memory
  448. // 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
  449. asCParser parser(builder);
  450. int r = parser.ParseStatementBlock(script, blockBegin);
  451. if( r < 0 ) return -1;
  452. asCScriptNode *block = parser.GetScriptNode();
  453. // Reserve a label for the cleanup code
  454. nextLabel++;
  455. bool hasReturn;
  456. asCByteCode bc(engine);
  457. LineInstr(&bc, blockBegin->tokenPos);
  458. CompileStatementBlock(block, false, &hasReturn, &bc);
  459. LineInstr(&bc, blockBegin->tokenPos + blockBegin->tokenLength);
  460. // Make sure there is a return in all paths (if not return type is void)
  461. // Don't bother with this check if there are compiler errors, e.g. Unreachable code
  462. if( !hasCompileErrors && outFunc->returnType != asCDataType::CreatePrimitive(ttVoid, false) )
  463. {
  464. if( hasReturn == false )
  465. Error(TXT_NOT_ALL_PATHS_RETURN, blockBegin);
  466. }
  467. //------------------------------------------------
  468. // Concatenate the bytecode
  469. // Insert a JitEntry at the start of the function for JIT compilers
  470. byteCode.InstrPTR(asBC_JitEntry, 0);
  471. if( outFunc->objectType )
  472. {
  473. if( m_isConstructor )
  474. {
  475. if( outFunc->objectType->derivedFrom )
  476. {
  477. // Call the base class' default constructor unless called manually in the code
  478. if( !m_isConstructorCalled )
  479. {
  480. if( outFunc->objectType->derivedFrom->beh.construct )
  481. {
  482. // Initialize members without explicit expression first
  483. CompileMemberInitialization(&byteCode, true);
  484. // Call base class' constructor
  485. asCByteCode tmpBC(engine);
  486. tmpBC.InstrSHORT(asBC_PSF, 0);
  487. tmpBC.Instr(asBC_RDSPtr);
  488. tmpBC.Call(asBC_CALL, outFunc->objectType->derivedFrom->beh.construct, AS_PTR_SIZE);
  489. tmpBC.OptimizeLocally(tempVariableOffsets);
  490. byteCode.AddCode(&tmpBC);
  491. // Add the initialization of the members with explicit expressions
  492. CompileMemberInitialization(&byteCode, false);
  493. }
  494. else
  495. Error(TEXT_BASE_DOESNT_HAVE_DEF_CONSTR, blockBegin);
  496. }
  497. else
  498. {
  499. // Only initialize members that don't have an explicit expression
  500. // The members that are explicitly initialized will be initialized after the call to base class' constructor
  501. CompileMemberInitialization(&byteCode, true);
  502. }
  503. }
  504. else
  505. {
  506. // Add the initialization of the members
  507. CompileMemberInitialization(&byteCode, true);
  508. CompileMemberInitialization(&byteCode, false);
  509. }
  510. }
  511. }
  512. // Add the code for the statement block
  513. byteCode.AddCode(&bc);
  514. // Count total variable size
  515. int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1;
  516. outFunc->scriptData->variableSpace = varSize;
  517. // Deallocate all local variables
  518. int n;
  519. for( n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  520. {
  521. sVariable *v = variables->variables[n];
  522. if( v->stackOffset > 0 )
  523. {
  524. // Call variables destructors
  525. if( v->name != "return" && v->name != "return address" )
  526. CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode);
  527. DeallocateVariable(v->stackOffset);
  528. }
  529. }
  530. // This is the label that return statements jump to
  531. // in order to exit the function
  532. byteCode.Label(0);
  533. // Call destructors for function parameters
  534. for( n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  535. {
  536. sVariable *v = variables->variables[n];
  537. if( v->stackOffset <= 0 )
  538. {
  539. // Call variable destructors here, for variables not yet destroyed
  540. if( v->name != "return" && v->name != "return address" )
  541. CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode);
  542. }
  543. // Do not deallocate parameters
  544. }
  545. // Check if the number of labels in the functions isn't too many to be handled
  546. if( nextLabel >= (1<<15) )
  547. Error(TXT_TOO_MANY_JUMP_LABELS, in_func);
  548. // If there are compile errors, there is no reason to build the final code
  549. if( hasCompileErrors || builder->numErrors != buildErrors )
  550. return -1;
  551. // At this point there should be no variables allocated
  552. asASSERT(variableAllocations.GetLength() == freeVariables.GetLength());
  553. // Remove the variable scope
  554. RemoveVariableScope();
  555. byteCode.Ret(-stackPos);
  556. FinalizeFunction();
  557. #ifdef AS_DEBUG
  558. // DEBUG: output byte code
  559. if( outFunc->objectType )
  560. byteCode.DebugOutput(("__" + outFunc->objectType->name + "_" + outFunc->name + ".txt").AddressOf(), in_outFunc);
  561. else
  562. byteCode.DebugOutput(("__" + outFunc->name + ".txt").AddressOf(), in_outFunc);
  563. #endif
  564. return 0;
  565. }
  566. int asCCompiler::CallCopyConstructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asCExprContext *arg, asCScriptNode *node, bool isGlobalVar, bool derefDest)
  567. {
  568. if( !type.IsObject() )
  569. return 0;
  570. // CallCopyConstructor should not be called for object handles.
  571. asASSERT( !type.IsObjectHandle() );
  572. asCArray<asCExprContext*> args;
  573. args.PushLast(arg);
  574. // The reference parameter must be pushed on the stack
  575. asASSERT( arg->type.dataType.GetTypeInfo() == type.GetTypeInfo() );
  576. // Since we're calling the copy constructor, we have to trust the function to not do
  577. // anything stupid otherwise we will just enter a loop, as we try to make temporary
  578. // copies of the argument in order to guarantee safety.
  579. if( type.GetTypeInfo()->flags & asOBJ_REF )
  580. {
  581. asCExprContext ctx(engine);
  582. int func = 0;
  583. asSTypeBehaviour *beh = type.GetBehaviour();
  584. if( beh ) func = beh->copyfactory;
  585. if( func > 0 )
  586. {
  587. if( !isGlobalVar )
  588. {
  589. // Call factory and store the handle in the given variable
  590. PerformFunctionCall(func, &ctx, false, &args, CastToObjectType(type.GetTypeInfo()), true, offset);
  591. // Pop the reference left by the function call
  592. ctx.bc.Instr(asBC_PopPtr);
  593. }
  594. else
  595. {
  596. // Call factory
  597. PerformFunctionCall(func, &ctx, false, &args, CastToObjectType(type.GetTypeInfo()));
  598. // Store the returned handle in the global variable
  599. ctx.bc.Instr(asBC_RDSPtr);
  600. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  601. ctx.bc.InstrPTR(asBC_REFCPY, type.GetTypeInfo());
  602. ctx.bc.Instr(asBC_PopPtr);
  603. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  604. }
  605. bc->AddCode(&ctx.bc);
  606. return 0;
  607. }
  608. }
  609. else
  610. {
  611. asSTypeBehaviour *beh = type.GetBehaviour();
  612. int func = beh ? beh->copyconstruct : 0;
  613. if( func > 0 )
  614. {
  615. // Push the address where the object will be stored on the stack, before the argument
  616. // TODO: When the context is serializable this probably has to be changed, since this
  617. // pointer can remain on the stack while the context is suspended. There is no
  618. // risk the pointer becomes invalid though, there is just no easy way to serialize it.
  619. asCByteCode tmp(engine);
  620. if( isGlobalVar )
  621. tmp.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  622. else if( isObjectOnHeap )
  623. tmp.InstrSHORT(asBC_PSF, (short)offset);
  624. tmp.AddCode(bc);
  625. bc->AddCode(&tmp);
  626. // When the object is allocated on the stack the object pointer
  627. // must be pushed on the stack after the arguments
  628. if( !isObjectOnHeap )
  629. {
  630. asASSERT( !isGlobalVar );
  631. bc->InstrSHORT(asBC_PSF, (short)offset);
  632. if( derefDest )
  633. {
  634. // The variable is a reference to the real location, so we need to dereference it
  635. bc->Instr(asBC_RDSPtr);
  636. }
  637. }
  638. asCExprContext ctx(engine);
  639. PerformFunctionCall(func, &ctx, isObjectOnHeap, &args, CastToObjectType(type.GetTypeInfo()));
  640. bc->AddCode(&ctx.bc);
  641. // TODO: value on stack: This probably needs to be done in PerformFunctionCall
  642. // Mark the object as initialized
  643. if( !isObjectOnHeap )
  644. bc->ObjInfo(offset, asOBJ_INIT);
  645. return 0;
  646. }
  647. }
  648. // Class has no copy constructor/factory.
  649. asCString str;
  650. str.Format(TXT_NO_COPY_CONSTRUCTOR_FOR_s, type.GetTypeInfo()->GetName());
  651. Error(str, node);
  652. return -1;
  653. }
  654. int asCCompiler::CallDefaultConstructor(const asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asCScriptNode *node, int isVarGlobOrMem, bool derefDest)
  655. {
  656. if( !type.IsObject() || type.IsObjectHandle() )
  657. return 0;
  658. if( type.GetTypeInfo()->flags & asOBJ_REF )
  659. {
  660. asCExprContext ctx(engine);
  661. ctx.exprNode = node;
  662. int func = 0;
  663. asSTypeBehaviour *beh = type.GetBehaviour();
  664. if( beh )
  665. {
  666. func = beh->factory;
  667. // If no trivial default factory is found, look for a factory where all params have default args
  668. if( func == 0 )
  669. {
  670. for( asUINT n = 0; n < beh->factories.GetLength(); n++ )
  671. {
  672. asCScriptFunction *f = engine->scriptFunctions[beh->factories[n]];
  673. if( f->defaultArgs.GetLength() == f->parameterTypes.GetLength() &&
  674. f->defaultArgs[0] != 0 )
  675. {
  676. func = beh->factories[n];
  677. break;
  678. }
  679. }
  680. }
  681. }
  682. if( func > 0 )
  683. {
  684. asCArray<asCExprContext *> args;
  685. asCScriptFunction *f = engine->scriptFunctions[func];
  686. if( f->parameterTypes.GetLength() )
  687. {
  688. // Add the default values for arguments not explicitly supplied
  689. CompileDefaultAndNamedArgs(node, args, func, CastToObjectType(type.GetTypeInfo()));
  690. PrepareFunctionCall(func, &ctx.bc, args);
  691. MoveArgsToStack(func, &ctx.bc, args, false);
  692. }
  693. if( isVarGlobOrMem == 0 )
  694. {
  695. // Call factory and store the handle in the given variable
  696. PerformFunctionCall(func, &ctx, false, &args, CastToObjectType(type.GetTypeInfo()), true, offset);
  697. // Pop the reference left by the function call
  698. ctx.bc.Instr(asBC_PopPtr);
  699. }
  700. else
  701. {
  702. // Call factory
  703. PerformFunctionCall(func, &ctx, false, &args, CastToObjectType(type.GetTypeInfo()));
  704. // TODO: runtime optimize: Should have a way of storing the object pointer directly to the destination
  705. // instead of first storing it in a local variable and then copying it to the
  706. // destination.
  707. if( !(type.GetTypeInfo()->flags & asOBJ_SCOPED) )
  708. {
  709. // Only dereference the variable if not a scoped type
  710. ctx.bc.Instr(asBC_RDSPtr);
  711. }
  712. if( isVarGlobOrMem == 1 )
  713. {
  714. // Store the returned handle in the global variable
  715. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  716. }
  717. else
  718. {
  719. // Store the returned handle in the class member
  720. ctx.bc.InstrSHORT(asBC_PSF, 0);
  721. ctx.bc.Instr(asBC_RDSPtr);
  722. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  723. }
  724. if( type.GetTypeInfo()->flags & asOBJ_SCOPED )
  725. {
  726. // For scoped typed we must move the reference from the local
  727. // variable rather than copy it as there is no AddRef behaviour
  728. ctx.bc.InstrSHORT_DW(asBC_COPY, AS_PTR_SIZE, asTYPEID_OBJHANDLE | engine->GetTypeIdFromDataType(type));
  729. // Clear the local variable so the reference isn't released
  730. ctx.bc.InstrSHORT(asBC_ClrVPtr, ctx.type.stackOffset);
  731. }
  732. else
  733. {
  734. if( type.IsFuncdef() )
  735. ctx.bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  736. else
  737. ctx.bc.InstrPTR(asBC_REFCPY, type.GetTypeInfo());
  738. }
  739. ctx.bc.Instr(asBC_PopPtr);
  740. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  741. }
  742. bc->AddCode(&ctx.bc);
  743. // Cleanup
  744. for( asUINT n = 0; n < args.GetLength(); n++ )
  745. if( args[n] )
  746. {
  747. asDELETE(args[n], asCExprContext);
  748. }
  749. return 0;
  750. }
  751. }
  752. else
  753. {
  754. asCExprContext ctx(engine);
  755. ctx.exprNode = node;
  756. asSTypeBehaviour *beh = type.GetBehaviour();
  757. int func = 0;
  758. if( beh )
  759. {
  760. func = beh->construct;
  761. // If no trivial default constructor is found, look for a constructor where all params have default args
  762. if( func == 0 )
  763. {
  764. for( asUINT n = 0; n < beh->constructors.GetLength(); n++ )
  765. {
  766. asCScriptFunction *f = engine->scriptFunctions[beh->constructors[n]];
  767. if( f->defaultArgs.GetLength() == f->parameterTypes.GetLength() &&
  768. f->defaultArgs[0] != 0 )
  769. {
  770. func = beh->constructors[n];
  771. break;
  772. }
  773. }
  774. }
  775. }
  776. // Allocate and initialize with the default constructor
  777. if( func != 0 || (type.GetTypeInfo()->flags & asOBJ_POD) )
  778. {
  779. asCArray<asCExprContext *> args;
  780. asCScriptFunction *f = engine->scriptFunctions[func];
  781. if( f && f->parameterTypes.GetLength() )
  782. {
  783. // Add the default values for arguments not explicitly supplied
  784. CompileDefaultAndNamedArgs(node, args, func, CastToObjectType(type.GetTypeInfo()));
  785. PrepareFunctionCall(func, &ctx.bc, args);
  786. MoveArgsToStack(func, &ctx.bc, args, false);
  787. }
  788. if( !isObjectOnHeap )
  789. {
  790. if( isVarGlobOrMem == 0 )
  791. {
  792. // There is nothing to do if there is no function,
  793. // as the memory is already allocated on the stack
  794. if( func )
  795. {
  796. // Call the constructor as a normal function
  797. bc->InstrSHORT(asBC_PSF, (short)offset);
  798. if( derefDest )
  799. bc->Instr(asBC_RDSPtr);
  800. asCExprContext ctxCall(engine);
  801. PerformFunctionCall(func, &ctxCall, false, 0, CastToObjectType(type.GetTypeInfo()));
  802. bc->AddCode(&ctxCall.bc);
  803. // TODO: value on stack: This probably needs to be done in PerformFunctionCall
  804. // Mark the object as initialized
  805. bc->ObjInfo(offset, asOBJ_INIT);
  806. }
  807. }
  808. else if( isVarGlobOrMem == 2 )
  809. {
  810. // Only POD types can be allocated inline in script classes
  811. asASSERT( type.GetTypeInfo()->flags & asOBJ_POD );
  812. if( func )
  813. {
  814. // Call the constructor as a normal function
  815. bc->InstrSHORT(asBC_PSF, 0);
  816. bc->Instr(asBC_RDSPtr);
  817. bc->InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  818. asCExprContext ctxCall(engine);
  819. PerformFunctionCall(func, &ctxCall, false, 0, CastToObjectType(type.GetTypeInfo()));
  820. bc->AddCode(&ctxCall.bc);
  821. }
  822. }
  823. else
  824. {
  825. asASSERT( false );
  826. }
  827. }
  828. else
  829. {
  830. if( isVarGlobOrMem == 0 )
  831. bc->InstrSHORT(asBC_PSF, (short)offset);
  832. else if( isVarGlobOrMem == 1 )
  833. bc->InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  834. else
  835. {
  836. bc->InstrSHORT(asBC_PSF, 0);
  837. bc->Instr(asBC_RDSPtr);
  838. bc->InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  839. }
  840. if( (type.GetTypeInfo()->flags & asOBJ_TEMPLATE) )
  841. {
  842. asCScriptFunction *descr = engine->scriptFunctions[func];
  843. asASSERT( descr->funcType == asFUNC_SCRIPT );
  844. // Find the id of the real constructor and not the generated stub
  845. asUINT id = 0;
  846. asDWORD *funcBc = descr->scriptData->byteCode.AddressOf();
  847. while( funcBc )
  848. {
  849. if( (*(asBYTE*)funcBc) == asBC_CALLSYS )
  850. {
  851. id = asBC_INTARG(funcBc);
  852. break;
  853. }
  854. funcBc += asBCTypeSize[asBCInfo[*(asBYTE*)funcBc].type];
  855. }
  856. asASSERT( id );
  857. bc->InstrPTR(asBC_OBJTYPE, type.GetTypeInfo());
  858. bc->Alloc(asBC_ALLOC, type.GetTypeInfo(), id, AS_PTR_SIZE + AS_PTR_SIZE);
  859. }
  860. else
  861. bc->Alloc(asBC_ALLOC, type.GetTypeInfo(), func, AS_PTR_SIZE);
  862. }
  863. // Cleanup
  864. for( asUINT n = 0; n < args.GetLength(); n++ )
  865. if( args[n] )
  866. {
  867. asDELETE(args[n], asCExprContext);
  868. }
  869. return 0;
  870. }
  871. }
  872. // Class has no default factory/constructor.
  873. asCString str;
  874. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, type.GetTypeInfo()->GetName());
  875. Error(str, node);
  876. return -1;
  877. }
  878. void asCCompiler::CallDestructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc)
  879. {
  880. if( !type.IsReference() )
  881. {
  882. // Call destructor for the data type
  883. if( type.IsObject() || type.IsFuncdef() )
  884. {
  885. // The null pointer doesn't need to be destroyed
  886. if( type.IsNullHandle() )
  887. return;
  888. // Nothing is done for list pattern types, as this is taken care of by the CompileInitList method
  889. if( type.GetTypeInfo()->flags & asOBJ_LIST_PATTERN )
  890. return;
  891. if( isObjectOnHeap || type.IsObjectHandle() )
  892. {
  893. // Free the memory
  894. if (type.IsFuncdef())
  895. bc->InstrW_PTR(asBC_FREE, (short)offset, &engine->functionBehaviours);
  896. else
  897. bc->InstrW_PTR(asBC_FREE, (short)offset, type.GetTypeInfo());
  898. }
  899. else
  900. {
  901. asASSERT( type.GetTypeInfo()->GetFlags() & asOBJ_VALUE );
  902. if( type.GetBehaviour()->destruct )
  903. {
  904. // Call the destructor as a regular function
  905. asCExprContext ctx(engine);
  906. ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
  907. PerformFunctionCall(type.GetBehaviour()->destruct, &ctx);
  908. ctx.bc.OptimizeLocally(tempVariableOffsets);
  909. bc->AddCode(&ctx.bc);
  910. }
  911. // TODO: Value on stack: This probably needs to be done in PerformFunctionCall
  912. // Mark the object as destroyed
  913. bc->ObjInfo(offset, asOBJ_UNINIT);
  914. }
  915. }
  916. }
  917. }
  918. void asCCompiler::LineInstr(asCByteCode *bc, size_t pos)
  919. {
  920. int r, c;
  921. script->ConvertPosToRowCol(pos, &r, &c);
  922. bc->Line(r, c, script->idx);
  923. }
  924. void asCCompiler::CompileStatementBlock(asCScriptNode *block, bool ownVariableScope, bool *hasReturn, asCByteCode *bc)
  925. {
  926. *hasReturn = false;
  927. bool isFinished = false;
  928. bool hasUnreachableCode = false;
  929. bool hasReturnBefore = false;
  930. if( ownVariableScope )
  931. {
  932. bc->Block(true);
  933. AddVariableScope();
  934. }
  935. asCScriptNode *node = block->firstChild;
  936. while( node )
  937. {
  938. #ifdef AS_DEBUG
  939. // Keep the current line in a variable so it will be easier
  940. // to determine where in a script an assert is occurring.
  941. int currentLine = 0;
  942. script->ConvertPosToRowCol(node->tokenPos, &currentLine, 0);
  943. #endif
  944. if( !hasUnreachableCode && (*hasReturn || isFinished) )
  945. {
  946. // Empty statements don't count
  947. if( node->nodeType != snExpressionStatement || node->firstChild )
  948. {
  949. hasUnreachableCode = true;
  950. Warning(TXT_UNREACHABLE_CODE, node);
  951. }
  952. if( *hasReturn )
  953. hasReturnBefore = true;
  954. }
  955. if( node->nodeType == snBreak || node->nodeType == snContinue )
  956. isFinished = true;
  957. asCByteCode statement(engine);
  958. if( node->nodeType == snDeclaration )
  959. CompileDeclaration(node, &statement);
  960. else
  961. CompileStatement(node, hasReturn, &statement);
  962. // Ignore missing returns in unreachable code paths
  963. if( !(*hasReturn) && hasReturnBefore )
  964. *hasReturn = true;
  965. LineInstr(bc, node->tokenPos);
  966. bc->AddCode(&statement);
  967. if( !hasCompileErrors )
  968. {
  969. asASSERT( tempVariables.GetLength() == 0 );
  970. asASSERT( reservedVariables.GetLength() == 0 );
  971. }
  972. node = node->next;
  973. }
  974. if( ownVariableScope )
  975. {
  976. // Deallocate variables in this block, in reverse order
  977. for( int n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  978. {
  979. sVariable *v = variables->variables[n];
  980. // Call variable destructors here, for variables not yet destroyed
  981. // If the block is terminated with a break, continue, or
  982. // return the variables are already destroyed
  983. if( !isFinished && !*hasReturn )
  984. CallDestructor(v->type, v->stackOffset, v->onHeap, bc);
  985. // Don't deallocate function parameters
  986. if( v->stackOffset > 0 )
  987. DeallocateVariable(v->stackOffset);
  988. }
  989. RemoveVariableScope();
  990. bc->Block(false);
  991. }
  992. }
  993. // Entry
  994. int asCCompiler::CompileGlobalVariable(asCBuilder *in_builder, asCScriptCode *in_script, asCScriptNode *in_node, sGlobalVariableDescription *in_gvar, asCScriptFunction *in_outFunc)
  995. {
  996. Reset(in_builder, in_script, in_outFunc);
  997. m_globalVar = in_gvar;
  998. // Add a variable scope (even though variables can't be declared)
  999. AddVariableScope();
  1000. in_gvar->isPureConstant = false;
  1001. // Parse the initialization nodes
  1002. asCParser parser(builder);
  1003. if (in_node)
  1004. {
  1005. int r = parser.ParseVarInit(in_script, in_node);
  1006. if (r < 0)
  1007. return r;
  1008. in_node = parser.GetScriptNode();
  1009. }
  1010. asCExprContext compiledCtx(engine);
  1011. bool preCompiled = false;
  1012. if (in_gvar->datatype.IsAuto())
  1013. {
  1014. preCompiled = CompileAutoType(in_gvar->datatype, compiledCtx, in_node, in_gvar->declaredAtNode);
  1015. if (!preCompiled)
  1016. {
  1017. // If it wasn't possible to determine the type from the expression then there
  1018. // is no need to continue with the initialization. The error was already reported
  1019. // in CompileAutoType.
  1020. return -1;
  1021. }
  1022. }
  1023. if( in_gvar->property == 0 )
  1024. {
  1025. in_gvar->property = builder->module->AllocateGlobalProperty(in_gvar->name.AddressOf(), in_gvar->datatype, in_gvar->ns);
  1026. in_gvar->index = in_gvar->property->id;
  1027. }
  1028. // Compile the expression
  1029. asCExprContext ctx(engine);
  1030. asQWORD constantValue = 0;
  1031. if( CompileInitialization(in_node, &ctx.bc, in_gvar->datatype, in_gvar->declaredAtNode, in_gvar->index, &constantValue, 1, preCompiled ? &compiledCtx : 0) )
  1032. {
  1033. // Should the variable be marked as pure constant?
  1034. if( in_gvar->datatype.IsPrimitive() && in_gvar->datatype.IsReadOnly() )
  1035. {
  1036. in_gvar->isPureConstant = true;
  1037. in_gvar->constantValue = constantValue;
  1038. }
  1039. }
  1040. // Concatenate the bytecode
  1041. int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1;
  1042. // Add information on the line number for the global variable
  1043. size_t pos = 0;
  1044. if( in_gvar->declaredAtNode )
  1045. pos = in_gvar->declaredAtNode->tokenPos;
  1046. else if( in_gvar->initializationNode )
  1047. pos = in_gvar->initializationNode->tokenPos;
  1048. LineInstr(&byteCode, pos);
  1049. // Reserve space for all local variables
  1050. outFunc->scriptData->variableSpace = varSize;
  1051. ctx.bc.OptimizeLocally(tempVariableOffsets);
  1052. byteCode.AddCode(&ctx.bc);
  1053. // Deallocate variables in this block, in reverse order
  1054. for( int n = (int)variables->variables.GetLength() - 1; n >= 0; --n )
  1055. {
  1056. sVariable *v = variables->variables[n];
  1057. // Call variable destructors here, for variables not yet destroyed
  1058. CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode);
  1059. DeallocateVariable(v->stackOffset);
  1060. }
  1061. if( hasCompileErrors ) return -1;
  1062. // At this point there should be no variables allocated
  1063. asASSERT(variableAllocations.GetLength() == freeVariables.GetLength());
  1064. // Remove the variable scope again
  1065. RemoveVariableScope();
  1066. byteCode.Ret(0);
  1067. FinalizeFunction();
  1068. #ifdef AS_DEBUG
  1069. // DEBUG: output byte code
  1070. byteCode.DebugOutput(("___init_" + in_gvar->name + ".txt").AddressOf(), outFunc);
  1071. #endif
  1072. return 0;
  1073. }
  1074. void asCCompiler::DetermineSingleFunc(asCExprContext *ctx, asCScriptNode *node)
  1075. {
  1076. // Don't do anything if this is not a deferred global function
  1077. if( !ctx->IsGlobalFunc() )
  1078. return;
  1079. // Determine the namespace
  1080. asSNameSpace *ns = 0;
  1081. asCString name = "";
  1082. int pos = ctx->methodName.FindLast("::");
  1083. if( pos >= 0 )
  1084. {
  1085. asCString nsName = ctx->methodName.SubString(0, pos+2);
  1086. // Cut off the ::
  1087. if( nsName.GetLength() > 2 )
  1088. nsName.SetLength(nsName.GetLength()-2);
  1089. ns = DetermineNameSpace(nsName);
  1090. name = ctx->methodName.SubString(pos+2);
  1091. }
  1092. else
  1093. {
  1094. DetermineNameSpace("");
  1095. name = ctx->methodName;
  1096. }
  1097. asCArray<int> funcs;
  1098. if( ns )
  1099. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  1100. // CompileVariableAccess should guarantee that at least one function is exists
  1101. asASSERT( funcs.GetLength() > 0 );
  1102. if( funcs.GetLength() > 1 )
  1103. {
  1104. asCString str;
  1105. str.Format(TXT_MULTIPLE_MATCHING_SIGNATURES_TO_s, ctx->methodName.AddressOf());
  1106. Error(str, node);
  1107. // Fall through so the compiler can continue as if only one function was matching
  1108. }
  1109. // A shared object may not access global functions unless they too are shared (e.g. registered functions)
  1110. if( !builder->GetFunctionDescription(funcs[0])->IsShared() &&
  1111. outFunc->IsShared() )
  1112. {
  1113. asCString msg;
  1114. msg.Format(TXT_SHARED_CANNOT_CALL_NON_SHARED_FUNC_s, builder->GetFunctionDescription(funcs[0])->GetDeclaration());
  1115. Error(msg, node);
  1116. // Fall through so the compiler can continue anyway
  1117. }
  1118. // Push the function pointer on the stack
  1119. ctx->bc.InstrPTR(asBC_FuncPtr, builder->GetFunctionDescription(funcs[0]));
  1120. ctx->type.Set(asCDataType::CreateType(engine->FindMatchingFuncdef(builder->GetFunctionDescription(funcs[0]), builder->module), false));
  1121. ctx->type.dataType.MakeHandle(true);
  1122. ctx->type.isExplicitHandle = true;
  1123. ctx->methodName = "";
  1124. }
  1125. void asCCompiler::CompileInitAsCopy(asCDataType &dt, int offset, asCByteCode *bc, asCExprContext *arg, asCScriptNode *node, bool derefDestination)
  1126. {
  1127. bool isObjectOnHeap = derefDestination ? false : IsVariableOnHeap(offset);
  1128. // Use copy constructor if available.
  1129. asCObjectType *ot = CastToObjectType(dt.GetTypeInfo());
  1130. if(!dt.IsObjectHandle() && ot && (ot->beh.copyconstruct || ot->beh.copyfactory))
  1131. {
  1132. PrepareForAssignment(&dt, arg, node, true);
  1133. int r = CallCopyConstructor(dt, offset, isObjectOnHeap, bc, arg, node, 0, derefDestination);
  1134. if( r < 0 && tempVariables.Exists(offset) )
  1135. Error(TXT_FAILED_TO_CREATE_TEMP_OBJ, node);
  1136. }
  1137. else
  1138. {
  1139. // TODO: Need to reserve variables, as the default constructor may need
  1140. // to allocate temporary variables to compute default args
  1141. // Allocate and construct the temporary object before whatever is already in the bytecode
  1142. asCByteCode tmpBC(engine);
  1143. int r = CallDefaultConstructor(dt, offset, isObjectOnHeap, &tmpBC, node, 0, derefDestination);
  1144. if( r < 0 )
  1145. {
  1146. if( tempVariables.Exists(offset) )
  1147. Error(TXT_FAILED_TO_CREATE_TEMP_OBJ, node);
  1148. return;
  1149. }
  1150. tmpBC.AddCode(bc);
  1151. bc->AddCode(&tmpBC);
  1152. // Assign the evaluated expression to the temporary variable
  1153. PrepareForAssignment(&dt, arg, node, true);
  1154. bc->AddCode(&arg->bc);
  1155. // Call the opAssign method to assign the value to the temporary object
  1156. dt.MakeReference(isObjectOnHeap);
  1157. asCExprValue type;
  1158. type.Set(dt);
  1159. type.isTemporary = true;
  1160. type.stackOffset = (short)offset;
  1161. if( dt.IsObjectHandle() )
  1162. type.isExplicitHandle = true;
  1163. bc->InstrSHORT(asBC_PSF, (short)offset);
  1164. if( derefDestination )
  1165. bc->Instr(asBC_RDSPtr);
  1166. r = PerformAssignment(&type, &arg->type, bc, node);
  1167. if( r < 0 )
  1168. {
  1169. if( tempVariables.Exists(offset) )
  1170. Error(TXT_FAILED_TO_CREATE_TEMP_OBJ, node);
  1171. return;
  1172. }
  1173. // Pop the reference that was pushed on the stack if the result is an object
  1174. if( type.dataType.IsObject() || type.dataType.IsFuncdef() )
  1175. bc->Instr(asBC_PopPtr);
  1176. // If the assignment operator returned an object by value it will
  1177. // be in a temporary variable which we need to destroy now
  1178. if( type.isTemporary && type.stackOffset != (short)offset )
  1179. ReleaseTemporaryVariable(type.stackOffset, bc);
  1180. // Release the original value too in case it is a temporary
  1181. ReleaseTemporaryVariable(arg->type, bc);
  1182. }
  1183. }
  1184. int asCCompiler::PrepareArgument(asCDataType *paramType, asCExprContext *ctx, asCScriptNode *node, bool isFunction, int refType, bool isMakingCopy)
  1185. {
  1186. asCDataType param = *paramType;
  1187. if( paramType->GetTokenType() == ttQuestion )
  1188. {
  1189. // The function is expecting a var type. If the argument is a function name, we must now decide which function it is
  1190. DetermineSingleFunc(ctx, node);
  1191. // Since the function is expecting a var type ?, then we don't want to convert the argument to anything else
  1192. param = ctx->type.dataType;
  1193. param.MakeHandle(ctx->type.isExplicitHandle || ctx->type.IsNullConstant());
  1194. // Treat the void expression like a null handle when working with var types
  1195. if( ctx->IsVoidExpression() )
  1196. param = asCDataType::CreateNullHandle();
  1197. // If value assign is disabled for reference types, then make
  1198. // sure to always pass the handle to ? parameters
  1199. if( builder->engine->ep.disallowValueAssignForRefType &&
  1200. ctx->type.dataType.GetTypeInfo() && (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCOPED) )
  1201. {
  1202. param.MakeHandle(true);
  1203. }
  1204. param.MakeReference(paramType->IsReference());
  1205. param.MakeReadOnly(paramType->IsReadOnly());
  1206. }
  1207. else
  1208. param = *paramType;
  1209. asCDataType dt = param;
  1210. // Need to protect arguments by reference
  1211. if( isFunction && dt.IsReference() )
  1212. {
  1213. // Allocate a temporary variable of the same type as the argument
  1214. dt.MakeReference(false);
  1215. int offset;
  1216. if( refType == asTM_INREF )
  1217. {
  1218. ProcessPropertyGetAccessor(ctx, node);
  1219. // Add the type id as hidden arg if the parameter is a ? type
  1220. if( paramType->GetTokenType() == ttQuestion )
  1221. {
  1222. asCByteCode tmpBC(engine);
  1223. // Place the type id on the stack as a hidden parameter
  1224. tmpBC.InstrDWORD(asBC_TYPEID, engine->GetTypeIdFromDataType(param));
  1225. // Insert the code before the expression code
  1226. tmpBC.AddCode(&ctx->bc);
  1227. ctx->bc.AddCode(&tmpBC);
  1228. }
  1229. if( dt.IsPrimitive() )
  1230. {
  1231. // If the reference is const, then it is not necessary to make a copy if the value already is a variable
  1232. // Even if the same variable is passed in another argument as non-const then there is no problem
  1233. IsVariableInitialized(&ctx->type, node);
  1234. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  1235. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true);
  1236. if( !(param.IsReadOnly() && ctx->type.isVariable) )
  1237. ConvertToTempVariable(ctx);
  1238. PushVariableOnStack(ctx, true);
  1239. ctx->type.dataType.MakeReadOnly(param.IsReadOnly());
  1240. }
  1241. else if( ctx->type.dataType.IsNullHandle() )
  1242. {
  1243. // Make sure the argument type can support handles (or is itself a handle)
  1244. if( !dt.SupportHandles() && !dt.IsObjectHandle() )
  1245. {
  1246. asCString str;
  1247. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), param.Format(outFunc->nameSpace).AddressOf());
  1248. Error(str, node);
  1249. ctx->type.Set(param);
  1250. return -1;
  1251. }
  1252. // Need to initialize a local temporary variable to
  1253. // represent the null handle when passed as reference
  1254. asASSERT( ctx->bc.GetLastInstr() == asBC_PshNull );
  1255. ctx->bc.Instr(asBC_PopPtr);
  1256. dt.MakeHandle(true);
  1257. dt.MakeReadOnly(false);
  1258. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1259. // Push the reference to the variable on the stack
  1260. ctx->bc.InstrWORD(asBC_PSF, (short)offset);
  1261. ctx->type.SetVariable(dt, offset, true);
  1262. ctx->type.isExplicitHandle = true;
  1263. }
  1264. else
  1265. {
  1266. IsVariableInitialized(&ctx->type, node);
  1267. if( !isMakingCopy )
  1268. {
  1269. // For parameters expecting a reference to a handle we need to make sure the argument
  1270. // is really a handle, and not just a reference to the object. Do this check before the
  1271. // implicit conversion so it can be treated correctly.
  1272. if (dt.IsObjectHandle() && !ctx->type.dataType.IsObjectHandle())
  1273. {
  1274. // Make a refCopy into a local handle variable
  1275. // Allocate a handle variable
  1276. dt.MakeHandle(true);
  1277. dt.MakeReadOnly(false);
  1278. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1279. // Copy the handle
  1280. Dereference(ctx, true);
  1281. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1282. if (ctx->type.dataType.IsFuncdef())
  1283. ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  1284. else
  1285. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo());
  1286. ctx->bc.Instr(asBC_PopPtr);
  1287. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1288. // Release the original temporary variable
  1289. if( ctx->type.isTemporary )
  1290. ReleaseTemporaryVariable(ctx->type.stackOffset, &ctx->bc);
  1291. ctx->type.SetVariable(dt, offset, true);
  1292. }
  1293. // Even though the parameter expects a reference, it is only meant to be
  1294. // used as input value and doesn't have to refer to the actual object, so it
  1295. // is OK to do an implicit conversion.
  1296. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true);
  1297. if( !ctx->type.dataType.IsEqualExceptRefAndConst(param) )
  1298. {
  1299. asCString str;
  1300. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), param.Format(outFunc->nameSpace).AddressOf());
  1301. Error(str, node);
  1302. ctx->type.Set(param);
  1303. return -1;
  1304. }
  1305. // The compiler must guarantee that the object stays alive during the execution
  1306. // of the function, and it must also guarantee that the value isn't modified by
  1307. // the function.
  1308. // If the argument is a temporary local variable then it is safe to be passed to
  1309. // the function as it is, since the local variable will stay alive, and since it
  1310. // is temporary there is no side effect if the function modifies it.
  1311. // If the parameter is read-only and therefore guaranteed not to be modified by the
  1312. // function, then it is enough that the variable is local to guarantee the lifetime.
  1313. if( !ctx->type.isTemporary && !(param.IsReadOnly() && (ctx->type.isVariable || ctx->type.isRefSafe)) )
  1314. {
  1315. if( ctx->type.dataType.IsFuncdef() || ((ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && param.IsReadOnly() && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCOPED)) )
  1316. {
  1317. // Funcdefs only need an extra handle to guarantee the lifetime.
  1318. // If the object is a reference type (except scoped reference types), and the
  1319. // parameter is a const reference, then it is not necessary to make a copy of the
  1320. // object. The compiler just needs to hold a handle to guarantee the lifetime.
  1321. // Allocate a handle variable
  1322. dt.MakeHandle(true);
  1323. dt.MakeReadOnly(false);
  1324. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1325. // Copy the handle
  1326. Dereference(ctx, true);
  1327. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1328. if (ctx->type.dataType.IsFuncdef())
  1329. ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  1330. else
  1331. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo());
  1332. ctx->bc.Instr(asBC_PopPtr);
  1333. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1334. // The type should be set to the param type instead of dt to guarantee
  1335. // that the expression keeps the correct type for variable ? args. Otherwise
  1336. // MoveArgsToStack will use the wrong bytecode to move the arg to the stack
  1337. bool isExplicitHandle = ctx->type.isExplicitHandle;
  1338. ctx->type.SetVariable(param, offset, true);
  1339. ctx->type.dataType.MakeHandle(true);
  1340. ctx->type.isExplicitHandle = isExplicitHandle;
  1341. }
  1342. else
  1343. {
  1344. // Make a copy of the object to guarantee that the original isn't modified
  1345. asASSERT(!dt.IsFuncdef());
  1346. // Allocate and initialize a temporary local object
  1347. dt.MakeReadOnly(false);
  1348. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1349. CompileInitAsCopy(dt, offset, &ctx->bc, ctx, node, false);
  1350. // Push the object pointer on the stack
  1351. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  1352. if( dt.IsObject() && !dt.IsObjectHandle() )
  1353. ctx->bc.Instr(asBC_RDSPtr);
  1354. // Set the resulting type
  1355. ctx->type.Set(dt);
  1356. ctx->type.isTemporary = true;
  1357. ctx->type.stackOffset = short(offset);
  1358. if( dt.IsObjectHandle() )
  1359. ctx->type.isExplicitHandle = true;
  1360. ctx->type.dataType.MakeReference(false);
  1361. if( paramType->IsReadOnly() )
  1362. ctx->type.dataType.MakeReadOnly(true);
  1363. }
  1364. }
  1365. // When calling a function expecting a var arg with a parameter received as reference to handle
  1366. // then it is necessary to copy the handle to a local variable, otherwise MoveArgsToStack will
  1367. // not be able to do the correct double dereference to put the reference to the object on the stack.
  1368. if (paramType->GetTokenType() == ttQuestion && !param.IsObjectHandle() && ctx->type.isVariable)
  1369. {
  1370. sVariable *var = variables->GetVariableByOffset(ctx->type.stackOffset);
  1371. if (var && var->type.IsReference() && var->type.IsObjectHandle())
  1372. {
  1373. // Copy the handle to local variable
  1374. // Allocate a handle variable
  1375. dt.MakeHandle(true);
  1376. dt.MakeReadOnly(false);
  1377. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1378. // Copy the handle
  1379. Dereference(ctx, true);
  1380. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1381. if (ctx->type.dataType.IsFuncdef())
  1382. ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  1383. else
  1384. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo());
  1385. ctx->bc.Instr(asBC_PopPtr);
  1386. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1387. // The type should be set to the param type instead of dt to guarantee
  1388. // that the expression keeps the correct type for variable ? args. Otherwise
  1389. // MoveArgsToStack will use the wrong bytecode to move the arg to the stack
  1390. ctx->type.SetVariable(param, offset, true);
  1391. }
  1392. }
  1393. }
  1394. else
  1395. {
  1396. // We must guarantee that the address to the value is on the stack
  1397. if( (ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) &&
  1398. !ctx->type.dataType.IsObjectHandle() &&
  1399. ctx->type.dataType.IsReference() )
  1400. Dereference(ctx, true);
  1401. }
  1402. }
  1403. }
  1404. else if( refType == asTM_OUTREF )
  1405. {
  1406. // Add the type id as hidden arg if the parameter is a ? type
  1407. if( paramType->GetTokenType() == ttQuestion )
  1408. {
  1409. asCByteCode tmpBC(engine);
  1410. // Place the type id on the stack as a hidden parameter
  1411. tmpBC.InstrDWORD(asBC_TYPEID, engine->GetTypeIdFromDataType(param));
  1412. // Insert the code before the expression code
  1413. tmpBC.AddCode(&ctx->bc);
  1414. ctx->bc.AddCode(&tmpBC);
  1415. }
  1416. // If the expression is marked as clean, then it can be used directly
  1417. // without the need to allocate another temporary value as it is known
  1418. // that the argument has no other value than the default
  1419. if( ctx->isCleanArg )
  1420. {
  1421. // Must be a local variable
  1422. asASSERT( ctx->type.isVariable );
  1423. }
  1424. else
  1425. {
  1426. // Null handles and void expressions must be marked as explicit
  1427. // handles for correct treatement in MoveArgsToStack
  1428. if (dt.IsNullHandle())
  1429. ctx->type.isExplicitHandle = true;
  1430. // Make sure the variable is not used in the expression
  1431. dt.MakeReadOnly(false);
  1432. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1433. if( dt.IsPrimitive() )
  1434. {
  1435. ctx->type.SetVariable(dt, offset, true);
  1436. PushVariableOnStack(ctx, true);
  1437. }
  1438. else
  1439. {
  1440. // Allocate and construct the temporary object
  1441. asCByteCode tmpBC(engine);
  1442. CallDefaultConstructor(dt, offset, IsVariableOnHeap(offset), &tmpBC, node);
  1443. // Insert the code before the expression code
  1444. tmpBC.AddCode(&ctx->bc);
  1445. ctx->bc.AddCode(&tmpBC);
  1446. dt.MakeReference(!(dt.IsObject() || dt.IsFuncdef()) || dt.IsObjectHandle());
  1447. asCExprValue type;
  1448. type.Set(dt);
  1449. type.isTemporary = true;
  1450. type.stackOffset = (short)offset;
  1451. type.isExplicitHandle = ctx->type.isExplicitHandle;
  1452. ctx->type = type;
  1453. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  1454. if( (dt.IsObject() || dt.IsFuncdef()) && !dt.IsObjectHandle() )
  1455. ctx->bc.Instr(asBC_RDSPtr);
  1456. }
  1457. // After the function returns the temporary variable will
  1458. // be assigned to the expression, if it is a valid lvalue
  1459. }
  1460. }
  1461. else if( refType == asTM_INOUTREF )
  1462. {
  1463. ProcessPropertyGetAccessor(ctx, node);
  1464. // Add the type id as hidden arg if the parameter is a ? type
  1465. if( paramType->GetTokenType() == ttQuestion )
  1466. {
  1467. asCByteCode tmpBC(engine);
  1468. // Place the type id on the stack as a hidden parameter
  1469. tmpBC.InstrDWORD(asBC_TYPEID, engine->GetTypeIdFromDataType(param));
  1470. // Insert the code before the expression code
  1471. tmpBC.AddCode(&ctx->bc);
  1472. ctx->bc.AddCode(&tmpBC);
  1473. }
  1474. // Literal constants cannot be passed to inout ref arguments
  1475. if( !ctx->type.isVariable &&
  1476. ctx->type.isConstant &&
  1477. !ctx->type.dataType.IsEqualExceptRefAndConst(engine->stringType) )
  1478. {
  1479. // Unless unsafe references are turned on and the reference is const
  1480. if( param.IsReadOnly() && engine->ep.allowUnsafeReferences )
  1481. {
  1482. // Since the parameter is a const & make a copy.
  1483. ConvertToTempVariable(ctx);
  1484. ctx->type.dataType.MakeReadOnly(true);
  1485. }
  1486. else
  1487. {
  1488. Error(TXT_NOT_VALID_REFERENCE, node);
  1489. return -1;
  1490. }
  1491. }
  1492. // Perform implicit ref cast if necessary, but don't allow the implicit conversion to create new objects
  1493. if( (ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) && ctx->type.dataType.GetTypeInfo() != dt.GetTypeInfo() )
  1494. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true, false);
  1495. // Only objects that support object handles
  1496. // can be guaranteed to be safe. Local variables are
  1497. // already safe, so there is no need to add an extra
  1498. // references
  1499. if( !engine->ep.allowUnsafeReferences &&
  1500. !ctx->type.isVariable &&
  1501. (ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) &&
  1502. !ctx->type.dataType.IsObjectHandle() &&
  1503. ((ctx->type.dataType.GetBehaviour()->addref &&
  1504. ctx->type.dataType.GetBehaviour()->release) ||
  1505. (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_NOCOUNT) ||
  1506. ctx->type.dataType.IsFuncdef()) )
  1507. {
  1508. // Store a handle to the object as local variable
  1509. asCExprContext tmp(engine);
  1510. dt = ctx->type.dataType;
  1511. dt.MakeHandle(true);
  1512. dt.MakeReference(false);
  1513. dt.MakeReadOnly(false);
  1514. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1515. // Copy the handle
  1516. if( !ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReference() )
  1517. ctx->bc.Instr(asBC_RDSPtr);
  1518. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1519. if( ctx->type.dataType.IsFuncdef() )
  1520. ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  1521. else
  1522. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo());
  1523. ctx->bc.Instr(asBC_PopPtr);
  1524. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1525. dt.MakeHandle(false);
  1526. dt.MakeReference(true);
  1527. // Release previous temporary variable stored in the context (if any)
  1528. if( ctx->type.isTemporary )
  1529. ReleaseTemporaryVariable(ctx->type.stackOffset, &ctx->bc);
  1530. ctx->type.SetVariable(dt, offset, true);
  1531. }
  1532. // Make sure the reference to the value is on the stack
  1533. // For objects, the reference needs to be dereferenced so the pointer on the stack is to the actual object
  1534. // For handles, the reference shouldn't be changed because the pointer on the stack should be to the handle
  1535. if( (ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) && ctx->type.dataType.IsReference() && !param.IsObjectHandle() )
  1536. Dereference(ctx, true);
  1537. else if( ctx->type.isVariable && !(ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) )
  1538. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  1539. else if( ctx->type.dataType.IsPrimitive() )
  1540. ctx->bc.Instr(asBC_PshRPtr);
  1541. else if( ctx->type.dataType.IsObjectHandle() && !ctx->type.dataType.IsReference() )
  1542. ImplicitConversion(ctx, param, node, asIC_IMPLICIT_CONV, true, false);
  1543. }
  1544. }
  1545. else
  1546. {
  1547. ProcessPropertyGetAccessor(ctx, node);
  1548. if( dt.IsPrimitive() )
  1549. {
  1550. IsVariableInitialized(&ctx->type, node);
  1551. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  1552. // Implicitly convert primitives to the parameter type
  1553. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV);
  1554. if( ctx->type.isVariable )
  1555. {
  1556. PushVariableOnStack(ctx, dt.IsReference());
  1557. }
  1558. else if( ctx->type.isConstant )
  1559. {
  1560. ConvertToVariable(ctx);
  1561. PushVariableOnStack(ctx, dt.IsReference());
  1562. }
  1563. }
  1564. else
  1565. {
  1566. IsVariableInitialized(&ctx->type, node);
  1567. // Implicitly convert primitives to the parameter type
  1568. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV);
  1569. // Was the conversion successful?
  1570. if( !ctx->type.dataType.IsEqualExceptRef(dt) )
  1571. {
  1572. asCString str;
  1573. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), dt.Format(outFunc->nameSpace).AddressOf());
  1574. Error(str, node);
  1575. ctx->type.Set(dt);
  1576. return -1;
  1577. }
  1578. if( dt.IsObjectHandle() )
  1579. ctx->type.isExplicitHandle = true;
  1580. if( (dt.IsObject() || dt.IsFuncdef()) && !dt.IsNullHandle() && !dt.IsReference() )
  1581. {
  1582. // Objects passed by value must be placed in temporary variables
  1583. // so that they are guaranteed to not be referenced anywhere else.
  1584. // The object must also be allocated on the heap, as the memory will
  1585. // be deleted by the called function.
  1586. // Handles passed by value must also be placed in a temporary variable
  1587. // to guarantee that the object referred to isn't freed too early.
  1588. // TODO: value on stack: How can we avoid this unnecessary allocation?
  1589. // Don't make temporary copies of handles if it is going to be used
  1590. // for handle assignment anyway, i.e. REFCPY.
  1591. if( !(!isFunction && isMakingCopy && ctx->type.dataType.IsObjectHandle() && ctx->type.isVariable) )
  1592. PrepareTemporaryVariable(node, ctx, true);
  1593. }
  1594. }
  1595. }
  1596. // Don't put any pointer on the stack yet
  1597. if( param.IsReference() || ((param.IsObject() || param.IsFuncdef()) && !param.IsNullHandle()) )
  1598. {
  1599. // &inout parameter may leave the reference on the stack already
  1600. // references considered safe too, i.e. when the life time is known
  1601. if( refType != asTM_INOUTREF && !ctx->type.isRefSafe )
  1602. {
  1603. asASSERT( ctx->type.isVariable || ctx->type.isRefSafe || ctx->type.isTemporary || isMakingCopy );
  1604. if( ctx->type.isVariable || ctx->type.isTemporary )
  1605. {
  1606. ctx->bc.Instr(asBC_PopPtr);
  1607. ctx->bc.InstrSHORT(asBC_VAR, ctx->type.stackOffset);
  1608. ProcessDeferredParams(ctx);
  1609. }
  1610. }
  1611. }
  1612. return 0;
  1613. }
  1614. void asCCompiler::PrepareFunctionCall(int funcId, asCByteCode *bc, asCArray<asCExprContext *> &args)
  1615. {
  1616. // When a match has been found, compile the final byte code using correct parameter types
  1617. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  1618. asASSERT( descr->parameterTypes.GetLength() == args.GetLength() );
  1619. // If the function being called is the opAssign or copy constructor for the same type
  1620. // as the argument, then we should avoid making temporary copy of the argument
  1621. bool makingCopy = false;
  1622. if( descr->parameterTypes.GetLength() == 1 &&
  1623. descr->parameterTypes[0].IsEqualExceptRefAndConst(args[0]->type.dataType) &&
  1624. (((descr->name == "opAssign" || descr->name == "$beh0") && descr->objectType && descr->objectType == args[0]->type.dataType.GetTypeInfo()) ||
  1625. (descr->objectType == 0 && args[0]->type.dataType.GetTypeInfo() && descr->name == args[0]->type.dataType.GetTypeInfo()->name)) )
  1626. makingCopy = true;
  1627. // Add code for arguments
  1628. asCExprContext e(engine);
  1629. for( int n = (int)args.GetLength()-1; n >= 0; n-- )
  1630. {
  1631. // Make sure PrepareArgument doesn't use any variable that is already
  1632. // being used by the argument or any of the following argument expressions
  1633. int l = int(reservedVariables.GetLength());
  1634. for( int m = n; m >= 0; m-- )
  1635. args[m]->bc.GetVarsUsed(reservedVariables);
  1636. PrepareArgument2(&e, args[n], &descr->parameterTypes[n], true, descr->inOutFlags[n], makingCopy);
  1637. reservedVariables.SetLength(l);
  1638. }
  1639. bc->AddCode(&e.bc);
  1640. }
  1641. void asCCompiler::MoveArgsToStack(int funcId, asCByteCode *bc, asCArray<asCExprContext *> &args, bool addOneToOffset)
  1642. {
  1643. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  1644. int offset = 0;
  1645. if( addOneToOffset )
  1646. offset += AS_PTR_SIZE;
  1647. // The address of where the return value should be stored is push on top of the arguments
  1648. if( descr->DoesReturnOnStack() )
  1649. offset += AS_PTR_SIZE;
  1650. #ifdef AS_DEBUG
  1651. // If the function being called is the opAssign or copy constructor for the same type
  1652. // as the argument, then we should avoid making temporary copy of the argument
  1653. bool makingCopy = false;
  1654. if( descr->parameterTypes.GetLength() == 1 &&
  1655. descr->parameterTypes[0].IsEqualExceptRefAndConst(args[0]->type.dataType) &&
  1656. (((descr->name == "opAssign" || descr->name == "$beh0") && descr->objectType && descr->objectType == args[0]->type.dataType.GetTypeInfo()) ||
  1657. (descr->objectType == 0 && args[0]->type.dataType.GetTypeInfo() && descr->name == args[0]->type.dataType.GetTypeInfo()->name)) )
  1658. makingCopy = true;
  1659. #endif
  1660. // Move the objects that are sent by value to the stack just before the call
  1661. for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ )
  1662. {
  1663. if( descr->parameterTypes[n].IsReference() )
  1664. {
  1665. if( (descr->parameterTypes[n].IsObject() || descr->parameterTypes[n].IsFuncdef()) && !descr->parameterTypes[n].IsObjectHandle() )
  1666. {
  1667. if( descr->inOutFlags[n] != asTM_INOUTREF && !args[n]->type.isRefSafe )
  1668. {
  1669. #ifdef AS_DEBUG
  1670. // This assert is inside AS_DEBUG because of the variable makingCopy which is only defined in debug mode
  1671. asASSERT( args[n]->type.isVariable || args[n]->type.isTemporary || makingCopy );
  1672. #endif
  1673. if( (args[n]->type.isVariable || args[n]->type.isTemporary) )
  1674. {
  1675. if( !IsVariableOnHeap(args[n]->type.stackOffset) )
  1676. // TODO: runtime optimize: Actually the reference can be pushed on the stack directly
  1677. // as the value allocated on the stack is guaranteed to be safe
  1678. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1679. else
  1680. bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset);
  1681. }
  1682. }
  1683. if( args[n]->type.dataType.IsObjectHandle() )
  1684. bc->InstrWORD(asBC_ChkNullS, (asWORD)offset);
  1685. }
  1686. else if( descr->inOutFlags[n] != asTM_INOUTREF )
  1687. {
  1688. // If the argument is already known to be safe, i.e. has a guaranteed lifetime,
  1689. // then the address on the stack is already pointing to the correct object so no
  1690. // need to do anything else
  1691. if (!args[n]->type.isRefSafe)
  1692. {
  1693. if (descr->parameterTypes[n].GetTokenType() == ttQuestion &&
  1694. (args[n]->type.dataType.IsObject() || args[n]->type.dataType.IsFuncdef()) &&
  1695. !args[n]->type.dataType.IsObjectHandle())
  1696. {
  1697. // Send the object as a reference to the object,
  1698. // and not to the variable holding the object
  1699. if (!IsVariableOnHeap(args[n]->type.stackOffset))
  1700. // TODO: runtime optimize: Actually the reference can be pushed on the stack directly
  1701. // as the value allocated on the stack is guaranteed to be safe
  1702. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1703. else
  1704. bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset);
  1705. }
  1706. else if (descr->parameterTypes[n].GetTokenType() == ttQuestion &&
  1707. args[n]->type.dataType.IsObjectHandle() && !args[n]->type.isExplicitHandle)
  1708. {
  1709. // The object handle is being passed as an object, so dereference it before
  1710. // the call so the reference will be to the object rather than to the handle
  1711. if (engine->ep.disallowValueAssignForRefType)
  1712. {
  1713. // With disallow value assign all ref type objects are always passed by handle
  1714. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1715. }
  1716. else
  1717. bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset);
  1718. }
  1719. else
  1720. {
  1721. // If the variable is really an argument of @& type, then it is necessary
  1722. // to use asBC_GETOBJREF so the pointer is correctly dereferenced.
  1723. sVariable *var = variables->GetVariableByOffset(args[n]->type.stackOffset);
  1724. if (var == 0 || !var->type.IsReference() || !var->type.IsObjectHandle())
  1725. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1726. else
  1727. bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset);
  1728. }
  1729. }
  1730. }
  1731. }
  1732. else if( descr->parameterTypes[n].IsObject() || descr->parameterTypes[n].IsFuncdef() )
  1733. {
  1734. asASSERT(!args[n]->type.isRefSafe);
  1735. // TODO: value on stack: What can we do to avoid this unnecessary allocation?
  1736. // The object must be allocated on the heap, because this memory will be deleted in as_callfunc_xxx
  1737. asASSERT(IsVariableOnHeap(args[n]->type.stackOffset));
  1738. // The pointer in the variable will be moved to the stack
  1739. bc->InstrWORD(asBC_GETOBJ, (asWORD)offset);
  1740. // Deallocate the variable slot so it can be reused, but do not attempt to
  1741. // free the content of the variable since it was moved to the stack for the call
  1742. DeallocateVariable(args[n]->type.stackOffset);
  1743. args[n]->type.isTemporary = false;
  1744. }
  1745. offset += descr->parameterTypes[n].GetSizeOnStackDWords();
  1746. }
  1747. }
  1748. int asCCompiler::CompileArgumentList(asCScriptNode *node, asCArray<asCExprContext*> &args, asCArray<asSNamedArgument> &namedArgs)
  1749. {
  1750. asASSERT(node->nodeType == snArgList);
  1751. // Count arguments
  1752. asCScriptNode *arg = node->firstChild;
  1753. int argCount = 0;
  1754. while( arg )
  1755. {
  1756. if( arg->nodeType != snNamedArgument )
  1757. argCount++;
  1758. arg = arg->next;
  1759. }
  1760. // Prepare the arrays
  1761. args.SetLength(argCount);
  1762. int n;
  1763. for( n = 0; n < argCount; n++ )
  1764. args[n] = 0;
  1765. n = argCount-1;
  1766. // Compile the arguments in reverse order (as they will be pushed on the stack)
  1767. bool anyErrors = false, inPositionalArguments = false;
  1768. arg = node->lastChild;
  1769. while( arg )
  1770. {
  1771. asCScriptNode *asgNode = arg, *namedNode = 0;
  1772. if( asgNode->nodeType == snNamedArgument )
  1773. {
  1774. if( inPositionalArguments )
  1775. {
  1776. Error(TXT_POS_ARG_AFTER_NAMED_ARG, node);
  1777. return -1;
  1778. }
  1779. asgNode = arg->firstChild->next;
  1780. namedNode = arg->firstChild;
  1781. asASSERT( namedNode->nodeType == snIdentifier );
  1782. }
  1783. else
  1784. inPositionalArguments = true;
  1785. asCExprContext expr(engine);
  1786. int r = CompileAssignment(asgNode, &expr);
  1787. if( r < 0 ) anyErrors = true;
  1788. asCExprContext *ctx = asNEW(asCExprContext)(engine);
  1789. if( ctx == 0 )
  1790. {
  1791. // Out of memory
  1792. return -1;
  1793. }
  1794. MergeExprBytecodeAndType(ctx, &expr);
  1795. if( inPositionalArguments )
  1796. {
  1797. args[n] = ctx;
  1798. n--;
  1799. }
  1800. else
  1801. {
  1802. asSNamedArgument namedArg;
  1803. namedArg.name = asCString(&script->code[namedNode->tokenPos], namedNode->tokenLength);
  1804. namedArg.ctx = ctx;
  1805. // Error out when multiple arguments with the same name are passed
  1806. for( asUINT a = 0; a < namedArgs.GetLength(); ++a )
  1807. {
  1808. if( namedArgs[a].name == namedArg.name )
  1809. {
  1810. Error(TXT_DUPLICATE_NAMED_ARG, asgNode);
  1811. anyErrors = true;
  1812. break;
  1813. }
  1814. }
  1815. namedArgs.PushLast(namedArg);
  1816. }
  1817. arg = arg->prev;
  1818. }
  1819. return anyErrors ? -1 : 0;
  1820. }
  1821. int asCCompiler::CompileDefaultAndNamedArgs(asCScriptNode *node, asCArray<asCExprContext*> &args, int funcId, asCObjectType *objectType, asCArray<asSNamedArgument> *namedArgs)
  1822. {
  1823. asCScriptFunction *func = builder->GetFunctionDescription(funcId);
  1824. if( func == 0 || args.GetLength() >= (asUINT)func->GetParamCount() )
  1825. return 0;
  1826. // Make sure to use the real function for virtual functions
  1827. if( func->funcType == asFUNC_VIRTUAL )
  1828. {
  1829. asASSERT( objectType );
  1830. func = objectType->virtualFunctionTable[func->vfTableIdx];
  1831. }
  1832. // Make sure none of the variables used in the previous arguments are reused in the default arguments
  1833. bool anyErrors = false;
  1834. int prevReservedVars = reservedVariables.GetLength();
  1835. int explicitArgs = (int)args.GetLength();
  1836. for( int p = 0; p < explicitArgs; p++ )
  1837. args[p]->bc.GetVarsUsed(reservedVariables);
  1838. // Make space for all the new arguments
  1839. args.SetLength(func->parameterTypes.GetLength());
  1840. for( asUINT c = explicitArgs; c < args.GetLength(); c++ )
  1841. args[c] = 0;
  1842. // Add the named arguments to the argument list in the right position
  1843. if( namedArgs )
  1844. {
  1845. for( asUINT n = 0; n < namedArgs->GetLength(); ++n )
  1846. {
  1847. asSNamedArgument &named = (*namedArgs)[n];
  1848. named.ctx->bc.GetVarsUsed(reservedVariables);
  1849. // Find the right spot to put it in
  1850. asUINT index = asUINT(-1);
  1851. for( asUINT j = 0; j < func->parameterTypes.GetLength(); ++j )
  1852. {
  1853. if( func->parameterNames[j] == (*namedArgs)[n].name )
  1854. {
  1855. index = j;
  1856. break;
  1857. }
  1858. }
  1859. asASSERT( index < args.GetLength() );
  1860. args[index] = named.ctx;
  1861. named.ctx = 0;
  1862. }
  1863. }
  1864. // Compile the arguments in reverse order (as they will be pushed on the stack)
  1865. for( int n = (int)func->parameterTypes.GetLength() - 1; n >= explicitArgs; n-- )
  1866. {
  1867. if( args[n] != 0 ) continue;
  1868. if( func->defaultArgs[n] == 0 ) { anyErrors = true; continue; }
  1869. // Parse the default arg string
  1870. asCParser parser(builder);
  1871. asCScriptCode code;
  1872. code.SetCode("default arg", func->defaultArgs[n]->AddressOf(), false);
  1873. int r = parser.ParseExpression(&code);
  1874. if( r < 0 )
  1875. {
  1876. asCString msg;
  1877. msg.Format(TXT_FAILED_TO_COMPILE_DEF_ARG_d_IN_FUNC_s, n, func->GetDeclaration());
  1878. Error(msg, node);
  1879. anyErrors = true;
  1880. continue;
  1881. }
  1882. asCScriptNode *arg = parser.GetScriptNode();
  1883. // Temporarily set the script code to the default arg expression
  1884. asCScriptCode *origScript = script;
  1885. script = &code;
  1886. // Don't allow the expression to access local variables
  1887. isCompilingDefaultArg = true;
  1888. // Temporarily set the namespace in the output function to the namespace of the called
  1889. // function so that the default arguments are evaluated in the correct namespace
  1890. asSNameSpace *origNameSpace = outFunc->nameSpace;
  1891. outFunc->nameSpace = func->nameSpace;
  1892. asCExprContext expr(engine);
  1893. r = CompileExpression(arg, &expr);
  1894. // Restore the namespace
  1895. outFunc->nameSpace = origNameSpace;
  1896. // Don't allow address of class method
  1897. if( expr.IsClassMethod() )
  1898. {
  1899. // TODO: Improve error message
  1900. Error(TXT_DEF_ARG_TYPE_DOESNT_MATCH, arg);
  1901. r = -1;
  1902. }
  1903. // Make sure the expression can be implicitly converted to the parameter type
  1904. if( r >= 0 )
  1905. {
  1906. asCArray<int> funcs;
  1907. funcs.PushLast(func->id);
  1908. asCArray<asSOverloadCandidate> matches;
  1909. if( MatchArgument(funcs, matches, &expr, n) == 0 )
  1910. {
  1911. Error(TXT_DEF_ARG_TYPE_DOESNT_MATCH, arg);
  1912. r = -1;
  1913. }
  1914. }
  1915. isCompilingDefaultArg = false;
  1916. script = origScript;
  1917. if( r < 0 )
  1918. {
  1919. asCString msg;
  1920. msg.Format(TXT_FAILED_TO_COMPILE_DEF_ARG_d_IN_FUNC_s, n, func->GetDeclaration());
  1921. Error(msg, node);
  1922. anyErrors = true;
  1923. continue;
  1924. }
  1925. args[n] = asNEW(asCExprContext)(engine);
  1926. if( args[n] == 0 )
  1927. {
  1928. // Out of memory
  1929. reservedVariables.SetLength(prevReservedVars);
  1930. return -1;
  1931. }
  1932. MergeExprBytecodeAndType(args[n], &expr);
  1933. }
  1934. reservedVariables.SetLength(prevReservedVars);
  1935. return anyErrors ? -1 : 0;
  1936. }
  1937. 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)
  1938. {
  1939. asCArray<int> origFuncs = funcs; // Keep the original list for error message
  1940. asUINT cost = 0;
  1941. asUINT n;
  1942. if( funcs.GetLength() > 0 )
  1943. {
  1944. // Check the number of parameters in the found functions
  1945. asUINT totalArgs = (asUINT)args.GetLength();
  1946. if( namedArgs != 0 )
  1947. totalArgs += (asUINT)namedArgs->GetLength();
  1948. for( n = 0; n < funcs.GetLength(); ++n )
  1949. {
  1950. asCScriptFunction *desc = builder->GetFunctionDescription(funcs[n]);
  1951. if( desc->parameterTypes.GetLength() != totalArgs )
  1952. {
  1953. bool noMatch = true;
  1954. if( totalArgs < desc->parameterTypes.GetLength() )
  1955. {
  1956. // For virtual functions, the default args are defined in the real function of the object
  1957. if( desc->funcType == asFUNC_VIRTUAL )
  1958. desc = objectType->virtualFunctionTable[desc->vfTableIdx];
  1959. // Count the number of default args
  1960. asUINT defaultArgs = 0;
  1961. for( asUINT d = 0; d < desc->defaultArgs.GetLength(); d++ )
  1962. if( desc->defaultArgs[d] )
  1963. defaultArgs++;
  1964. if( totalArgs >= desc->parameterTypes.GetLength() - defaultArgs )
  1965. noMatch = false;
  1966. }
  1967. if( noMatch )
  1968. {
  1969. // remove it from the list
  1970. if( n == funcs.GetLength()-1 )
  1971. funcs.PopLast();
  1972. else
  1973. funcs[n] = funcs.PopLast();
  1974. n--;
  1975. }
  1976. }
  1977. }
  1978. // Match functions with the parameters, and discard those that do not match
  1979. asCArray<asSOverloadCandidate> matchingFuncs;
  1980. matchingFuncs.SetLengthNoConstruct( funcs.GetLength() );
  1981. for ( n = 0; n < funcs.GetLength(); ++n )
  1982. {
  1983. matchingFuncs[n].funcId = funcs[n];
  1984. matchingFuncs[n].cost = 0;
  1985. }
  1986. // Match positionally passed arguments
  1987. for( n = 0; n < args.GetLength(); ++n )
  1988. {
  1989. asCArray<asSOverloadCandidate> tempFuncs;
  1990. MatchArgument(funcs, tempFuncs, args[n], n, allowObjectConstruct);
  1991. // Intersect the found functions with the list of matching functions
  1992. for( asUINT f = 0; f < matchingFuncs.GetLength(); f++ )
  1993. {
  1994. asUINT c;
  1995. for( c = 0; c < tempFuncs.GetLength(); c++ )
  1996. {
  1997. if( matchingFuncs[f].funcId == tempFuncs[c].funcId )
  1998. {
  1999. // Sum argument cost
  2000. matchingFuncs[f].cost += tempFuncs[c].cost;
  2001. break;
  2002. } // End if match
  2003. }
  2004. // Was the function a match?
  2005. if( c == tempFuncs.GetLength() )
  2006. {
  2007. // No, remove it from the list
  2008. if( f == matchingFuncs.GetLength()-1 )
  2009. matchingFuncs.PopLast();
  2010. else
  2011. matchingFuncs[f] = matchingFuncs.PopLast();
  2012. f--;
  2013. }
  2014. }
  2015. }
  2016. // Match named arguments
  2017. if( namedArgs != 0 )
  2018. {
  2019. for( asUINT i = 0; i < matchingFuncs.GetLength(); ++i )
  2020. {
  2021. asCScriptFunction *desc = builder->GetFunctionDescription(matchingFuncs[i].funcId);
  2022. if( desc->funcType == asFUNC_VIRTUAL )
  2023. desc = objectType->virtualFunctionTable[desc->vfTableIdx];
  2024. // Match every named argument to an argument in the function
  2025. for( n = 0; n < namedArgs->GetLength(); ++n )
  2026. (*namedArgs)[n].match = asUINT(-1);
  2027. bool matchedAll = true;
  2028. for( asUINT j = 0; j < desc->parameterTypes.GetLength(); ++j )
  2029. {
  2030. asUINT match = asUINT(-1);
  2031. for( n = 0; n < namedArgs->GetLength(); ++n )
  2032. {
  2033. asSNamedArgument &namedArg = (*namedArgs)[n];
  2034. if( desc->parameterNames[j] == namedArg.name )
  2035. {
  2036. namedArg.match = j;
  2037. match = n;
  2038. break;
  2039. }
  2040. }
  2041. // Check that every position is filled somehow
  2042. if( j >= args.GetLength() )
  2043. {
  2044. if( match == asUINT(-1) && !desc->defaultArgs[j] )
  2045. {
  2046. // No argument was found for this, and there is no
  2047. // default, so it doesn't work.
  2048. matchedAll = false;
  2049. break;
  2050. }
  2051. }
  2052. else
  2053. {
  2054. if( match != asUINT(-1) )
  2055. {
  2056. // Can't name an argument that was already passed
  2057. matchedAll = false;
  2058. break;
  2059. }
  2060. }
  2061. }
  2062. // Check that every named argument was matched
  2063. if( matchedAll )
  2064. {
  2065. for( n = 0; n < namedArgs->GetLength(); ++n )
  2066. {
  2067. asSNamedArgument &named = (*namedArgs)[n];
  2068. if( named.match == asUINT(-1) )
  2069. {
  2070. matchedAll = false;
  2071. break;
  2072. }
  2073. // Add to the cost
  2074. cost = MatchArgument(desc, named.ctx, named.match, allowObjectConstruct);
  2075. if( cost == asUINT(-1) )
  2076. {
  2077. matchedAll = false;
  2078. break;
  2079. }
  2080. matchingFuncs[i].cost += cost;
  2081. }
  2082. }
  2083. if( !matchedAll )
  2084. {
  2085. // Remove the function, we didn't match all the arguments.
  2086. if( i == matchingFuncs.GetLength()-1 )
  2087. matchingFuncs.PopLast();
  2088. else
  2089. matchingFuncs[i] = matchingFuncs.PopLast();
  2090. i--;
  2091. }
  2092. }
  2093. }
  2094. // Select the overload(s) with the lowest overall cost
  2095. funcs.SetLength(0);
  2096. asUINT bestCost = asUINT(-1);
  2097. for( n = 0; n < matchingFuncs.GetLength(); ++n )
  2098. {
  2099. cost = matchingFuncs[n].cost;
  2100. if( cost < bestCost )
  2101. {
  2102. funcs.SetLength(0);
  2103. bestCost = cost;
  2104. }
  2105. if( cost == bestCost )
  2106. funcs.PushLast( matchingFuncs[n].funcId );
  2107. }
  2108. // Cost returned is equivalent to the best cost discovered
  2109. cost = bestCost;
  2110. }
  2111. if( !isConstMethod )
  2112. FilterConst(funcs);
  2113. if( funcs.GetLength() != 1 && !silent )
  2114. {
  2115. // Build a readable string of the function with parameter types
  2116. bool attemptsPassingClassMethod = false;
  2117. asCString str;
  2118. if( scope != "" && scope != "::" )
  2119. str = scope + "::";
  2120. str += name;
  2121. str += "(";
  2122. for( n = 0; n < args.GetLength(); n++ )
  2123. {
  2124. if( n > 0 )
  2125. str += ", ";
  2126. if( args[n]->methodName != "" )
  2127. {
  2128. if( args[n]->IsClassMethod() )
  2129. {
  2130. attemptsPassingClassMethod = true;
  2131. str += args[n]->type.dataType.GetTypeInfo()->GetName();
  2132. str += "::";
  2133. }
  2134. str += args[n]->methodName;
  2135. }
  2136. else if (args[n]->IsAnonymousInitList())
  2137. {
  2138. str += "{...}";
  2139. }
  2140. else
  2141. str += args[n]->type.dataType.Format(outFunc->nameSpace);
  2142. }
  2143. if( namedArgs != 0 )
  2144. {
  2145. for( n = 0; n < namedArgs->GetLength(); n++ )
  2146. {
  2147. if( n > 0 || args.GetLength() )
  2148. str += ", ";
  2149. asSNamedArgument &named = (*namedArgs)[n];
  2150. str += named.name;
  2151. str += ": ";
  2152. if( named.ctx->methodName != "" )
  2153. str += named.ctx->methodName;
  2154. else
  2155. str += named.ctx->type.dataType.Format(outFunc->nameSpace);
  2156. }
  2157. }
  2158. str += ")";
  2159. if( isConstMethod )
  2160. str += " const";
  2161. if( objectType && scope == "" )
  2162. str = objectType->name + "::" + str;
  2163. if( funcs.GetLength() == 0 )
  2164. {
  2165. str.Format(TXT_NO_MATCHING_SIGNATURES_TO_s, str.AddressOf());
  2166. Error(str, node);
  2167. if( attemptsPassingClassMethod )
  2168. {
  2169. // Class methods must use delegate objects
  2170. Error(TXT_CANNOT_PASS_CLASS_METHOD_AS_ARG, node);
  2171. }
  2172. else
  2173. {
  2174. // Print the list of candidates
  2175. if( origFuncs.GetLength() > 0 )
  2176. {
  2177. int r = 0, c = 0;
  2178. asASSERT( node );
  2179. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  2180. builder->WriteInfo(script->name.AddressOf(), TXT_CANDIDATES_ARE, r, c, false);
  2181. PrintMatchingFuncs(origFuncs, node, objectType);
  2182. }
  2183. }
  2184. }
  2185. else
  2186. {
  2187. asASSERT( attemptsPassingClassMethod == false );
  2188. str.Format(TXT_MULTIPLE_MATCHING_SIGNATURES_TO_s, str.AddressOf());
  2189. Error(str, node);
  2190. PrintMatchingFuncs(funcs, node, objectType);
  2191. }
  2192. }
  2193. return cost;
  2194. }
  2195. bool asCCompiler::CompileAutoType(asCDataType &type, asCExprContext &compiledCtx, asCScriptNode *node, asCScriptNode *errNode)
  2196. {
  2197. if( node && node->nodeType == snAssignment )
  2198. {
  2199. int r = CompileAssignment(node, &compiledCtx);
  2200. if( r >= 0 )
  2201. {
  2202. // Must not have unused ambiguous names
  2203. if (compiledCtx.IsClassMethod() || compiledCtx.IsGlobalFunc())
  2204. {
  2205. // TODO: Should mention that the problem is the ambiguous name
  2206. Error(TXT_CANNOT_RESOLVE_AUTO, errNode);
  2207. return false;
  2208. }
  2209. // Must not have unused anonymous functions
  2210. if (compiledCtx.IsLambda())
  2211. {
  2212. // TODO: Should mention that the problem is the anonymous function
  2213. Error(TXT_CANNOT_RESOLVE_AUTO, errNode);
  2214. return false;
  2215. }
  2216. // Must not be a null handle
  2217. if (compiledCtx.type.dataType.IsNullHandle())
  2218. {
  2219. // TODO: Should mention that the problem is the null pointer
  2220. Error(TXT_CANNOT_RESOLVE_AUTO, errNode);
  2221. return false;
  2222. }
  2223. asCDataType newType = compiledCtx.type.dataType;
  2224. // Handle const qualifier on auto
  2225. if (type.IsReadOnly())
  2226. newType.MakeReadOnly(true);
  2227. else if (newType.IsPrimitive())
  2228. newType.MakeReadOnly(false);
  2229. // Handle reference/value stuff
  2230. newType.MakeReference(false);
  2231. if (!newType.IsObjectHandle())
  2232. {
  2233. // We got a value object or an object reference.
  2234. // Turn the variable into a handle if specified
  2235. // as auto@, otherwise make it a 'value'.
  2236. if (type.IsHandleToAuto())
  2237. {
  2238. if (newType.MakeHandle(true) < 0)
  2239. {
  2240. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, errNode);
  2241. return false;
  2242. }
  2243. }
  2244. }
  2245. // Implicit handle types should always be handles
  2246. if (newType.GetTypeInfo() &&
  2247. (newType.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE))
  2248. newType.MakeHandle(true);
  2249. type = newType;
  2250. return true;
  2251. }
  2252. return false;
  2253. }
  2254. else
  2255. {
  2256. Error(TXT_CANNOT_RESOLVE_AUTO, errNode);
  2257. type = asCDataType::CreatePrimitive(ttInt, false);
  2258. return false;
  2259. }
  2260. }
  2261. void asCCompiler::CompileDeclaration(asCScriptNode *decl, asCByteCode *bc)
  2262. {
  2263. // Get the data type
  2264. asCDataType type = builder->CreateDataTypeFromNode(decl->firstChild, script, outFunc->nameSpace, false, outFunc->objectType);
  2265. // Declare all variables in this declaration
  2266. asCScriptNode *node = decl->firstChild->next;
  2267. while( node )
  2268. {
  2269. // If this is an auto type, we have to compile the assignment now to figure out the type
  2270. asCExprContext compiledCtx(engine);
  2271. bool preCompiled = false;
  2272. if (type.IsAuto())
  2273. {
  2274. preCompiled = CompileAutoType(type, compiledCtx, node->next, node);
  2275. if (!preCompiled)
  2276. {
  2277. // If it wasn't possible to determine the type from the expression then there
  2278. // is no need to continue with the initialization. The error was already reported
  2279. // in CompileAutoType.
  2280. return;
  2281. }
  2282. }
  2283. // Is the type allowed?
  2284. if( !type.CanBeInstantiated() )
  2285. {
  2286. asCString str;
  2287. if( type.IsAbstractClass() )
  2288. str.Format(TXT_ABSTRACT_CLASS_s_CANNOT_BE_INSTANTIATED, type.Format(outFunc->nameSpace).AddressOf());
  2289. else if( type.IsInterface() )
  2290. str.Format(TXT_INTERFACE_s_CANNOT_BE_INSTANTIATED, type.Format(outFunc->nameSpace).AddressOf());
  2291. else
  2292. // TODO: Improve error message to explain why
  2293. str.Format(TXT_DATA_TYPE_CANT_BE_s, type.Format(outFunc->nameSpace).AddressOf());
  2294. Error(str, node);
  2295. // Don't continue, as it will most likely lead to further
  2296. // errors that may just mislead the script writer
  2297. return;
  2298. }
  2299. // A shared object may not declare variables of non-shared types
  2300. if( outFunc->IsShared() )
  2301. {
  2302. asCTypeInfo *ot = type.GetTypeInfo();
  2303. if( ot && !ot->IsShared() )
  2304. {
  2305. asCString msg;
  2306. msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, ot->name.AddressOf());
  2307. Error(msg, decl);
  2308. }
  2309. }
  2310. // Get the name of the identifier
  2311. asCString name(&script->code[node->tokenPos], node->tokenLength);
  2312. // Verify that the name isn't used by a dynamic data type
  2313. // TODO: Must check against registered funcdefs too
  2314. if( engine->GetRegisteredType(name.AddressOf(), outFunc->nameSpace) != 0 )
  2315. {
  2316. asCString str;
  2317. str.Format(TXT_ILLEGAL_VARIABLE_NAME_s, name.AddressOf());
  2318. Error(str, node);
  2319. }
  2320. int offset = AllocateVariable(type, false);
  2321. if( variables->DeclareVariable(name.AddressOf(), type, offset, IsVariableOnHeap(offset)) < 0 )
  2322. {
  2323. // TODO: It might be an out-of-memory too
  2324. asCString str;
  2325. str.Format(TXT_s_ALREADY_DECLARED, name.AddressOf());
  2326. Error(str, node);
  2327. // Don't continue after this error, as it will just
  2328. // lead to more errors that are likely false
  2329. return;
  2330. }
  2331. else
  2332. {
  2333. // Warn if this variable hides another variable in a higher scope
  2334. if( variables->parent && variables->parent->GetVariable(name.AddressOf()) )
  2335. {
  2336. asCString str;
  2337. str.Format(TXT_s_HIDES_VAR_IN_OUTER_SCOPE, name.AddressOf());
  2338. Warning(str, node);
  2339. }
  2340. }
  2341. // Add marker that the variable has been declared
  2342. bc->VarDecl((int)outFunc->scriptData->variables.GetLength());
  2343. outFunc->AddVariable(name, type, offset);
  2344. // Keep the node for the variable decl
  2345. asCScriptNode *varNode = node;
  2346. node = node->next;
  2347. if( node == 0 || node->nodeType == snIdentifier )
  2348. {
  2349. // Initialize with default constructor
  2350. CompileInitialization(0, bc, type, varNode, offset, 0, 0);
  2351. }
  2352. else
  2353. {
  2354. // Compile the initialization expression
  2355. asQWORD constantValue = 0;
  2356. if( CompileInitialization(node, bc, type, varNode, offset, &constantValue, 0, preCompiled ? &compiledCtx : 0) )
  2357. {
  2358. // Check if the variable should be marked as pure constant
  2359. if( type.IsPrimitive() && type.IsReadOnly() )
  2360. {
  2361. sVariable *v = variables->GetVariable(name.AddressOf());
  2362. v->isPureConstant = true;
  2363. v->constantValue = constantValue;
  2364. }
  2365. }
  2366. node = node->next;
  2367. }
  2368. }
  2369. bc->OptimizeLocally(tempVariableOffsets);
  2370. }
  2371. // Returns true if the initialization expression is a constant expression
  2372. bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, const asCDataType &type, asCScriptNode *errNode, int offset, asQWORD *constantValue, int isVarGlobOrMem, asCExprContext *preCompiled)
  2373. {
  2374. bool isConstantExpression = false;
  2375. if( node && node->nodeType == snArgList )
  2376. {
  2377. // Make sure it is an object and not a handle
  2378. if( type.GetTypeInfo() == 0 || type.IsObjectHandle() )
  2379. {
  2380. Error(TXT_MUST_BE_OBJECT, node);
  2381. }
  2382. else
  2383. {
  2384. // Compile the arguments
  2385. asCArray<asCExprContext *> args;
  2386. asCArray<asSNamedArgument> namedArgs;
  2387. if( CompileArgumentList(node, args, namedArgs) >= 0 )
  2388. {
  2389. // Find all constructors
  2390. asCArray<int> funcs;
  2391. asSTypeBehaviour *beh = type.GetBehaviour();
  2392. if( beh )
  2393. {
  2394. if( type.GetTypeInfo()->flags & asOBJ_REF )
  2395. funcs = beh->factories;
  2396. else
  2397. funcs = beh->constructors;
  2398. }
  2399. asCString str = type.Format(outFunc->nameSpace);
  2400. MatchFunctions(funcs, args, node, str.AddressOf(), &namedArgs);
  2401. if( funcs.GetLength() == 1 )
  2402. {
  2403. // Add the default values for arguments not explicitly supplied
  2404. int r = CompileDefaultAndNamedArgs(node, args, funcs[0], CastToObjectType(type.GetTypeInfo()), &namedArgs);
  2405. if( r == asSUCCESS )
  2406. {
  2407. asCExprContext ctx(engine);
  2408. if( type.GetTypeInfo() && (type.GetTypeInfo()->flags & asOBJ_REF) )
  2409. {
  2410. if( isVarGlobOrMem == 0 )
  2411. MakeFunctionCall(&ctx, funcs[0], 0, args, node, true, offset);
  2412. else
  2413. {
  2414. MakeFunctionCall(&ctx, funcs[0], 0, args, node);
  2415. ctx.bc.Instr(asBC_RDSPtr);
  2416. if( isVarGlobOrMem == 1 )
  2417. {
  2418. // Store the returned handle in the global variable
  2419. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  2420. }
  2421. else
  2422. {
  2423. // Store the returned handle in the member
  2424. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2425. ctx.bc.Instr(asBC_RDSPtr);
  2426. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2427. }
  2428. if( type.IsFuncdef())
  2429. ctx.bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  2430. else
  2431. ctx.bc.InstrPTR(asBC_REFCPY, type.GetTypeInfo());
  2432. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  2433. }
  2434. // Pop the reference left by the function call
  2435. ctx.bc.Instr(asBC_PopPtr);
  2436. }
  2437. else
  2438. {
  2439. bool onHeap = false;
  2440. if( isVarGlobOrMem == 0 )
  2441. {
  2442. // When the object is allocated on the heap, the address where the
  2443. // reference will be stored must be pushed on the stack before the
  2444. // arguments. This reference on the stack is safe, even if the script
  2445. // is suspended during the evaluation of the arguments.
  2446. onHeap = IsVariableOnHeap(offset);
  2447. if( onHeap )
  2448. ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
  2449. }
  2450. else if( isVarGlobOrMem == 1 )
  2451. {
  2452. // Push the address of the location where the variable will be stored on the stack.
  2453. // This reference is safe, because the addresses of the global variables cannot change.
  2454. onHeap = true;
  2455. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  2456. }
  2457. else
  2458. {
  2459. // Value types may be allocated inline if they are POD types
  2460. onHeap = !(type.IsObject() || type.IsFuncdef()) || type.IsReference() || (type.GetTypeInfo()->flags & asOBJ_REF);
  2461. if( onHeap )
  2462. {
  2463. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2464. ctx.bc.Instr(asBC_RDSPtr);
  2465. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2466. }
  2467. }
  2468. PrepareFunctionCall(funcs[0], &ctx.bc, args);
  2469. MoveArgsToStack(funcs[0], &ctx.bc, args, false);
  2470. // When the object is allocated on the stack, the address to the
  2471. // object is pushed on the stack after the arguments as the object pointer
  2472. if( !onHeap )
  2473. {
  2474. if( isVarGlobOrMem == 2 )
  2475. {
  2476. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2477. ctx.bc.Instr(asBC_RDSPtr);
  2478. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2479. }
  2480. else
  2481. {
  2482. ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
  2483. }
  2484. }
  2485. PerformFunctionCall(funcs[0], &ctx, onHeap, &args, CastToObjectType(type.GetTypeInfo()));
  2486. if( isVarGlobOrMem == 0 )
  2487. {
  2488. // Mark the object in the local variable as initialized
  2489. ctx.bc.ObjInfo(offset, asOBJ_INIT);
  2490. }
  2491. }
  2492. bc->AddCode(&ctx.bc);
  2493. }
  2494. }
  2495. }
  2496. // Cleanup
  2497. for( asUINT n = 0; n < args.GetLength(); n++ )
  2498. if( args[n] )
  2499. {
  2500. asDELETE(args[n], asCExprContext);
  2501. }
  2502. for( asUINT n = 0; n < namedArgs.GetLength(); n++ )
  2503. if( namedArgs[n].ctx )
  2504. {
  2505. asDELETE(namedArgs[n].ctx, asCExprContext);
  2506. }
  2507. }
  2508. }
  2509. else if( node && node->nodeType == snInitList )
  2510. {
  2511. asCExprValue ti;
  2512. ti.Set(type);
  2513. ti.isVariable = (isVarGlobOrMem == 0);
  2514. ti.isTemporary = false;
  2515. ti.stackOffset = (short)offset;
  2516. ti.isLValue = true;
  2517. CompileInitList(&ti, node, bc, isVarGlobOrMem);
  2518. }
  2519. else if( node && node->nodeType == snAssignment )
  2520. {
  2521. // Compile the expression
  2522. asCExprContext newExpr(engine);
  2523. asCExprContext* expr;
  2524. int r = 0;
  2525. if( preCompiled )
  2526. {
  2527. expr = preCompiled;
  2528. }
  2529. else
  2530. {
  2531. expr = &newExpr;
  2532. r = CompileAssignment(node, expr);
  2533. }
  2534. // handles initialized with null doesn't need any bytecode
  2535. // since handles will be initialized to null by default anyway
  2536. if (type.IsObjectHandle() && expr->type.IsNullConstant() && expr->bc.IsSimpleExpression() )
  2537. return false;
  2538. // Look for appropriate constructor
  2539. asCArray<int> funcs;
  2540. asCArray<asCExprContext *> args;
  2541. // Handles must use the handle assignment operation.
  2542. // Types that are ASHANDLE must not allow the use of the constructor in this case,
  2543. // because it is ambiguous whether a value assignment or handle assignment will be done.
  2544. // Only do this if the expression is of the same type, as the expression is an assignment
  2545. // and an initialization constructor may not have the same meaning.
  2546. // TODO: Should allow initialization constructor if it is declared as allowed for implicit conversions.
  2547. if( !type.IsObjectHandle() && !expr->type.isExplicitHandle &&
  2548. !(type.GetTypeInfo() && (type.GetTypeInfo()->GetFlags() & asOBJ_ASHANDLE)) &&
  2549. type.IsEqualExceptRefAndConst(expr->type.dataType) )
  2550. {
  2551. asSTypeBehaviour *beh = type.GetBehaviour();
  2552. if( beh )
  2553. {
  2554. if( type.GetTypeInfo()->flags & asOBJ_REF )
  2555. funcs = beh->factories;
  2556. else
  2557. funcs = beh->constructors;
  2558. }
  2559. asCString str = type.Format(outFunc->nameSpace);
  2560. args.PushLast(expr);
  2561. MatchFunctions(funcs, args, node, str.AddressOf(), 0, 0, 0, true);
  2562. // Make sure the argument is of the right type (and not just compatible with the expression)
  2563. if (funcs.GetLength() == 1)
  2564. {
  2565. asCScriptFunction *f = engine->scriptFunctions[funcs[0]];
  2566. if (!f->parameterTypes[0].IsEqualExceptRefAndConst(expr->type.dataType))
  2567. funcs.PopLast();
  2568. }
  2569. }
  2570. if( funcs.GetLength() == 1 )
  2571. {
  2572. // Use the constructor
  2573. // TODO: clean-up: A large part of this is identical to the initalization with argList above
  2574. // Add the default values for arguments not explicitly supplied
  2575. r = CompileDefaultAndNamedArgs(node, args, funcs[0], CastToObjectType(type.GetTypeInfo()));
  2576. if( r == asSUCCESS )
  2577. {
  2578. asCExprContext ctx(engine);
  2579. if( type.GetTypeInfo() && (type.GetTypeInfo()->flags & asOBJ_REF) )
  2580. {
  2581. if( isVarGlobOrMem == 0 )
  2582. MakeFunctionCall(&ctx, funcs[0], 0, args, node, true, offset);
  2583. else
  2584. {
  2585. MakeFunctionCall(&ctx, funcs[0], 0, args, node);
  2586. ctx.bc.Instr(asBC_RDSPtr);
  2587. if( isVarGlobOrMem == 1 )
  2588. {
  2589. // Store the returned handle in the global variable
  2590. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  2591. }
  2592. else
  2593. {
  2594. // Store the returned handle in the member
  2595. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2596. ctx.bc.Instr(asBC_RDSPtr);
  2597. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2598. }
  2599. if( type.IsFuncdef() )
  2600. ctx.bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  2601. else
  2602. ctx.bc.InstrPTR(asBC_REFCPY, type.GetTypeInfo());
  2603. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  2604. }
  2605. // Pop the reference left by the function call
  2606. ctx.bc.Instr(asBC_PopPtr);
  2607. }
  2608. else
  2609. {
  2610. bool onHeap = false;
  2611. if( isVarGlobOrMem == 0 )
  2612. {
  2613. // When the object is allocated on the heap, the address where the
  2614. // reference will be stored must be pushed on the stack before the
  2615. // arguments. This reference on the stack is safe, even if the script
  2616. // is suspended during the evaluation of the arguments.
  2617. onHeap = IsVariableOnHeap(offset);
  2618. if( onHeap )
  2619. ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
  2620. }
  2621. else if( isVarGlobOrMem == 1 )
  2622. {
  2623. // Push the address of the location where the variable will be stored on the stack.
  2624. // This reference is safe, because the addresses of the global variables cannot change.
  2625. onHeap = true;
  2626. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  2627. }
  2628. else
  2629. {
  2630. // Value types may be allocated inline if they are POD types
  2631. onHeap = !(type.IsObject() || type.IsFuncdef()) || type.IsReference() || (type.GetTypeInfo()->flags & asOBJ_REF);
  2632. if( onHeap )
  2633. {
  2634. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2635. ctx.bc.Instr(asBC_RDSPtr);
  2636. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2637. }
  2638. }
  2639. PrepareFunctionCall(funcs[0], &ctx.bc, args);
  2640. MoveArgsToStack(funcs[0], &ctx.bc, args, false);
  2641. // When the object is allocated on the stack, the address to the
  2642. // object is pushed on the stack after the arguments as the object pointer
  2643. if( !onHeap )
  2644. {
  2645. if( isVarGlobOrMem == 2 )
  2646. {
  2647. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2648. ctx.bc.Instr(asBC_RDSPtr);
  2649. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2650. }
  2651. else
  2652. {
  2653. ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
  2654. }
  2655. }
  2656. PerformFunctionCall(funcs[0], &ctx, onHeap, &args, CastToObjectType(type.GetTypeInfo()));
  2657. if( isVarGlobOrMem == 0 )
  2658. {
  2659. // Mark the object in the local variable as initialized
  2660. ctx.bc.ObjInfo(offset, asOBJ_INIT);
  2661. }
  2662. }
  2663. bc->AddCode(&ctx.bc);
  2664. }
  2665. }
  2666. else
  2667. {
  2668. // Call the default constructur, then call the assignment operator
  2669. asCExprContext ctx(engine);
  2670. // Call the default constructor here
  2671. if( isVarGlobOrMem == 0 )
  2672. CallDefaultConstructor(type, offset, IsVariableOnHeap(offset), &ctx.bc, errNode);
  2673. else if( isVarGlobOrMem == 1 )
  2674. CallDefaultConstructor(type, offset, true, &ctx.bc, errNode, isVarGlobOrMem);
  2675. else if( isVarGlobOrMem == 2 )
  2676. CallDefaultConstructor(type, offset, type.IsReference(), &ctx.bc, errNode, isVarGlobOrMem);
  2677. if( r >= 0 )
  2678. {
  2679. if( type.IsPrimitive() )
  2680. {
  2681. if( type.IsReadOnly() && expr->type.isConstant )
  2682. {
  2683. ImplicitConversion(expr, type, node, asIC_IMPLICIT_CONV);
  2684. // Tell caller that the expression is a constant so it can mark the variable as pure constant
  2685. isConstantExpression = true;
  2686. *constantValue = expr->type.GetConstantData();
  2687. }
  2688. asCExprContext lctx(engine);
  2689. if( isVarGlobOrMem == 0 )
  2690. lctx.type.SetVariable(type, offset, false);
  2691. else if( isVarGlobOrMem == 1 )
  2692. {
  2693. lctx.type.Set(type);
  2694. lctx.type.dataType.MakeReference(true);
  2695. // If it is an enum value, i.e. offset is negative, that is being compiled then
  2696. // we skip this as the bytecode won't be used anyway, only the constant value
  2697. if( offset >= 0 )
  2698. lctx.bc.InstrPTR(asBC_LDG, engine->globalProperties[offset]->GetAddressOfValue());
  2699. }
  2700. else
  2701. {
  2702. asASSERT( isVarGlobOrMem == 2 );
  2703. lctx.type.Set(type);
  2704. lctx.type.dataType.MakeReference(true);
  2705. // Load the reference of the primitive member into the register
  2706. lctx.bc.InstrSHORT(asBC_PSF, 0);
  2707. lctx.bc.Instr(asBC_RDSPtr);
  2708. lctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2709. lctx.bc.Instr(asBC_PopRPtr);
  2710. }
  2711. lctx.type.dataType.MakeReadOnly(false);
  2712. lctx.type.isLValue = true;
  2713. DoAssignment(&ctx, &lctx, expr, node, node, ttAssignment, node);
  2714. ProcessDeferredParams(&ctx);
  2715. }
  2716. else
  2717. {
  2718. // TODO: runtime optimize: Here we should look for the best matching constructor, instead of
  2719. // just the copy constructor. Only if no appropriate constructor is
  2720. // available should the assignment operator be used.
  2721. asCExprContext lexpr(engine);
  2722. lexpr.type.Set(type);
  2723. if( isVarGlobOrMem == 0 )
  2724. lexpr.type.dataType.MakeReference(IsVariableOnHeap(offset));
  2725. else if( isVarGlobOrMem == 1 )
  2726. lexpr.type.dataType.MakeReference(true);
  2727. else if( isVarGlobOrMem == 2 )
  2728. {
  2729. if( !lexpr.type.dataType.IsObject() || lexpr.type.dataType.IsFuncdef() || (lexpr.type.dataType.GetTypeInfo()->flags & asOBJ_REF) )
  2730. lexpr.type.dataType.MakeReference(true);
  2731. }
  2732. // Allow initialization of constant variables
  2733. lexpr.type.dataType.MakeReadOnly(false);
  2734. if( type.IsObjectHandle() )
  2735. lexpr.type.isExplicitHandle = true;
  2736. if( isVarGlobOrMem == 0 )
  2737. {
  2738. lexpr.bc.InstrSHORT(asBC_PSF, (short)offset);
  2739. lexpr.type.stackOffset = (short)offset;
  2740. lexpr.type.isVariable = true;
  2741. }
  2742. else if( isVarGlobOrMem == 1 )
  2743. {
  2744. lexpr.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  2745. }
  2746. else
  2747. {
  2748. lexpr.bc.InstrSHORT(asBC_PSF, 0);
  2749. lexpr.bc.Instr(asBC_RDSPtr);
  2750. lexpr.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2751. lexpr.type.stackOffset = -1;
  2752. }
  2753. lexpr.type.isLValue = true;
  2754. // If left expression resolves into a registered type
  2755. // check if the assignment operator is overloaded, and check
  2756. // the type of the right hand expression. If none is found
  2757. // the default action is a direct copy if it is the same type
  2758. // and a simple assignment.
  2759. bool assigned = false;
  2760. // Even though an ASHANDLE can be an explicit handle the overloaded operator needs to be called
  2761. if( (lexpr.type.dataType.IsObject() || lexpr.type.dataType.IsFuncdef()) && (!lexpr.type.isExplicitHandle || (lexpr.type.dataType.GetTypeInfo() && (lexpr.type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE))) )
  2762. {
  2763. bool useHndlAssign = false;
  2764. if (lexpr.type.dataType.IsHandleToAsHandleType())
  2765. {
  2766. useHndlAssign = true;
  2767. // Make sure the right hand expression is treated as a handle
  2768. if (!expr->type.isExplicitHandle && !expr->type.IsNullConstant())
  2769. {
  2770. // TODO: Clean-up: This code is from CompileExpressionPreOp. Create a reusable function
  2771. // Convert the expression to a handle
  2772. if (!expr->type.dataType.IsObjectHandle() && !(expr->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE))
  2773. {
  2774. asCDataType to = expr->type.dataType;
  2775. to.MakeHandle(true);
  2776. to.MakeReference(true);
  2777. to.MakeHandleToConst(expr->type.dataType.IsReadOnly());
  2778. ImplicitConversion(expr, to, node, asIC_IMPLICIT_CONV, true, false);
  2779. asASSERT(expr->type.dataType.IsObjectHandle());
  2780. }
  2781. else if (expr->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE)
  2782. {
  2783. // For the ASHANDLE type we'll simply set the expression as a handle
  2784. expr->type.dataType.MakeHandle(true);
  2785. }
  2786. expr->type.isExplicitHandle = true;
  2787. }
  2788. }
  2789. assigned = CompileOverloadedDualOperator(node, &lexpr, expr, false, &ctx, useHndlAssign);
  2790. if( assigned )
  2791. {
  2792. // Pop the resulting value
  2793. if( !ctx.type.dataType.IsPrimitive() )
  2794. ctx.bc.Instr(asBC_PopPtr);
  2795. // Release the argument
  2796. ProcessDeferredParams(&ctx);
  2797. // Release temporary variable that may be allocated by the overloaded operator
  2798. ReleaseTemporaryVariable(ctx.type, &ctx.bc);
  2799. }
  2800. }
  2801. if( !assigned )
  2802. {
  2803. PrepareForAssignment(&lexpr.type.dataType, expr, node, false);
  2804. // If the expression is constant and the variable also is constant
  2805. // then mark the variable as pure constant. This will allow the compiler
  2806. // to optimize expressions with this variable.
  2807. if( type.IsReadOnly() && expr->type.isConstant )
  2808. {
  2809. isConstantExpression = true;
  2810. *constantValue = expr->type.GetConstantQW();
  2811. }
  2812. // Add expression code to bytecode
  2813. MergeExprBytecode(&ctx, expr);
  2814. // Add byte code for storing value of expression in variable
  2815. ctx.bc.AddCode(&lexpr.bc);
  2816. PerformAssignment(&lexpr.type, &expr->type, &ctx.bc, errNode);
  2817. // Release temporary variables used by expression
  2818. ReleaseTemporaryVariable(expr->type, &ctx.bc);
  2819. ctx.bc.Instr(asBC_PopPtr);
  2820. ProcessDeferredParams(&ctx);
  2821. }
  2822. }
  2823. }
  2824. bc->AddCode(&ctx.bc);
  2825. }
  2826. }
  2827. else
  2828. {
  2829. asASSERT( node == 0 );
  2830. // Call the default constructor here, as no explicit initialization is done
  2831. if( isVarGlobOrMem == 0 )
  2832. CallDefaultConstructor(type, offset, IsVariableOnHeap(offset), bc, errNode);
  2833. else if( isVarGlobOrMem == 1 )
  2834. CallDefaultConstructor(type, offset, true, bc, errNode, isVarGlobOrMem);
  2835. else if( isVarGlobOrMem == 2 )
  2836. {
  2837. if( !(type.IsObject() || type.IsFuncdef()) || type.IsReference() || (type.GetTypeInfo()->flags & asOBJ_REF) )
  2838. CallDefaultConstructor(type, offset, true, bc, errNode, isVarGlobOrMem);
  2839. else
  2840. CallDefaultConstructor(type, offset, false, bc, errNode, isVarGlobOrMem);
  2841. }
  2842. }
  2843. return isConstantExpression;
  2844. }
  2845. void asCCompiler::CompileInitList(asCExprValue *var, asCScriptNode *node, asCByteCode *bc, int isVarGlobOrMem)
  2846. {
  2847. // Check if the type supports initialization lists
  2848. if( var->dataType.GetTypeInfo() == 0 ||
  2849. var->dataType.GetBehaviour()->listFactory == 0 )
  2850. {
  2851. asCString str;
  2852. str.Format(TXT_INIT_LIST_CANNOT_BE_USED_WITH_s, var->dataType.Format(outFunc->nameSpace).AddressOf());
  2853. Error(str, node);
  2854. return;
  2855. }
  2856. // Construct the buffer with the elements
  2857. // Find the list factory
  2858. int funcId = var->dataType.GetBehaviour()->listFactory;
  2859. asASSERT( engine->scriptFunctions[funcId]->listPattern );
  2860. // TODO: runtime optimize: A future optimization should be to use the stack space directly
  2861. // for small buffers so that the dynamic allocation is skipped
  2862. // Create a new special object type for the lists. Both asCRestore and the
  2863. // context exception handler will need this to know how to parse the buffer.
  2864. asCObjectType *listPatternType = engine->GetListPatternType(funcId);
  2865. // Allocate a temporary variable to hold the pointer to the buffer
  2866. int bufferVar = AllocateVariable(asCDataType::CreateType(listPatternType, false), true);
  2867. asUINT bufferSize = 0;
  2868. // Evaluate all elements of the list
  2869. asCExprContext valueExpr(engine);
  2870. asCScriptNode *el = node;
  2871. asSListPatternNode *patternNode = engine->scriptFunctions[listPatternType->templateSubTypes[0].GetBehaviour()->listFactory]->listPattern;
  2872. int elementsInSubList = -1;
  2873. int r = CompileInitListElement(patternNode, el, engine->GetTypeIdFromDataType(asCDataType::CreateType(listPatternType, false)), short(bufferVar), bufferSize, valueExpr.bc, elementsInSubList);
  2874. asASSERT( r || patternNode == 0 );
  2875. if (r < 0)
  2876. {
  2877. asCString msg;
  2878. msg.Format(TXT_PREV_ERROR_WHILE_COMP_LIST_FOR_TYPE_s, var->dataType.Format(outFunc->nameSpace).AddressOf());
  2879. Error(msg, node);
  2880. }
  2881. // After all values have been evaluated we know the final size of the buffer
  2882. asCExprContext allocExpr(engine);
  2883. allocExpr.bc.InstrSHORT_DW(asBC_AllocMem, short(bufferVar), bufferSize);
  2884. // Merge the bytecode into the final sequence
  2885. bc->AddCode(&allocExpr.bc);
  2886. bc->AddCode(&valueExpr.bc);
  2887. // The object itself is the last to be created and will receive the pointer to the buffer
  2888. asCArray<asCExprContext *> args;
  2889. asCExprContext arg1(engine);
  2890. arg1.type.Set(asCDataType::CreatePrimitive(ttUInt, false));
  2891. arg1.type.dataType.MakeReference(true);
  2892. arg1.bc.InstrSHORT(asBC_PshVPtr, short(bufferVar));
  2893. args.PushLast(&arg1);
  2894. asCExprContext ctx(engine);
  2895. if( var->isVariable )
  2896. {
  2897. asASSERT( isVarGlobOrMem == 0 );
  2898. if( var->dataType.GetTypeInfo()->GetFlags() & asOBJ_REF )
  2899. {
  2900. ctx.bc.AddCode(&arg1.bc);
  2901. // Call factory and store the handle in the given variable
  2902. PerformFunctionCall(funcId, &ctx, false, &args, 0, true, var->stackOffset);
  2903. ctx.bc.Instr(asBC_PopPtr);
  2904. }
  2905. else
  2906. {
  2907. // Call the constructor
  2908. // When the object is allocated on the heap, the address where the
  2909. // reference will be stored must be pushed on the stack before the
  2910. // arguments. This reference on the stack is safe, even if the script
  2911. // is suspended during the evaluation of the arguments.
  2912. bool onHeap = IsVariableOnHeap(var->stackOffset);
  2913. if( onHeap )
  2914. ctx.bc.InstrSHORT(asBC_PSF, var->stackOffset);
  2915. ctx.bc.AddCode(&arg1.bc);
  2916. // When the object is allocated on the stack, the address to the
  2917. // object is pushed on the stack after the arguments as the object pointer
  2918. if( !onHeap )
  2919. ctx.bc.InstrSHORT(asBC_PSF, var->stackOffset);
  2920. PerformFunctionCall(funcId, &ctx, onHeap, &args, CastToObjectType(var->dataType.GetTypeInfo()));
  2921. // Mark the object in the local variable as initialized
  2922. ctx.bc.ObjInfo(var->stackOffset, asOBJ_INIT);
  2923. }
  2924. }
  2925. else
  2926. {
  2927. if( var->dataType.GetTypeInfo()->GetFlags() & asOBJ_REF )
  2928. {
  2929. ctx.bc.AddCode(&arg1.bc);
  2930. PerformFunctionCall(funcId, &ctx, false, &args);
  2931. ctx.bc.Instr(asBC_RDSPtr);
  2932. if( isVarGlobOrMem == 1 )
  2933. {
  2934. // Store the returned handle in the global variable
  2935. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[var->stackOffset]->GetAddressOfValue());
  2936. }
  2937. else
  2938. {
  2939. // Store the returned handle in the member
  2940. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2941. ctx.bc.Instr(asBC_RDSPtr);
  2942. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)var->stackOffset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2943. }
  2944. if (var->dataType.IsFuncdef())
  2945. ctx.bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  2946. else
  2947. ctx.bc.InstrPTR(asBC_REFCPY, var->dataType.GetTypeInfo());
  2948. ctx.bc.Instr(asBC_PopPtr);
  2949. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  2950. }
  2951. else
  2952. {
  2953. bool onHeap = true;
  2954. // Put the address where the object pointer will be placed on the stack
  2955. if( isVarGlobOrMem == 1 )
  2956. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[var->stackOffset]->GetAddressOfValue());
  2957. else
  2958. {
  2959. onHeap = !(var->dataType.IsObject() || var->dataType.IsFuncdef()) || var->dataType.IsReference() || (var->dataType.GetTypeInfo()->flags & asOBJ_REF);
  2960. if( onHeap )
  2961. {
  2962. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2963. ctx.bc.Instr(asBC_RDSPtr);
  2964. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)var->stackOffset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2965. }
  2966. }
  2967. // Add the address of the list buffer as the argument
  2968. ctx.bc.AddCode(&arg1.bc);
  2969. if( !onHeap )
  2970. {
  2971. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2972. ctx.bc.Instr(asBC_RDSPtr);
  2973. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)var->stackOffset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false)));
  2974. }
  2975. // Call the ALLOC instruction to allocate memory and invoke constructor
  2976. PerformFunctionCall(funcId, &ctx, onHeap, &args, CastToObjectType(var->dataType.GetTypeInfo()));
  2977. }
  2978. }
  2979. bc->AddCode(&ctx.bc);
  2980. // Free the temporary buffer. The FREE instruction will make sure to destroy
  2981. // each element in the buffer so there is no need to do this manually
  2982. bc->InstrW_PTR(asBC_FREE, short(bufferVar), listPatternType);
  2983. ReleaseTemporaryVariable(bufferVar, bc);
  2984. }
  2985. int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScriptNode *&valueNode, int bufferTypeId, short bufferVar, asUINT &bufferSize, asCByteCode &bcInit, int &elementsInSubList)
  2986. {
  2987. if( patternNode->type == asLPT_START )
  2988. {
  2989. if( valueNode == 0 || valueNode->nodeType != snInitList )
  2990. {
  2991. Error(TXT_EXPECTED_LIST, valueNode);
  2992. return -1;
  2993. }
  2994. // Compile all values until asLPT_END
  2995. patternNode = patternNode->next;
  2996. asCScriptNode *node = valueNode->firstChild;
  2997. while( patternNode->type != asLPT_END )
  2998. {
  2999. // Check for missing value here, else the error reporting will not have a source position to report the error for
  3000. if( node == 0 && patternNode->type == asLPT_TYPE )
  3001. {
  3002. Error(TXT_NOT_ENOUGH_VALUES_FOR_LIST, valueNode);
  3003. return -1;
  3004. }
  3005. asCScriptNode *errNode = node;
  3006. int r = CompileInitListElement(patternNode, node, bufferTypeId, bufferVar, bufferSize, bcInit, elementsInSubList);
  3007. if( r < 0 ) return r;
  3008. if( r == 1 )
  3009. {
  3010. asASSERT( engine->ep.disallowEmptyListElements );
  3011. // Empty elements in the middle are not allowed
  3012. Error(TXT_EMPTY_LIST_ELEMENT_IS_NOT_ALLOWED, errNode);
  3013. }
  3014. asASSERT( patternNode );
  3015. }
  3016. if( node )
  3017. {
  3018. Error(TXT_TOO_MANY_VALUES_FOR_LIST, valueNode);
  3019. return -1;
  3020. }
  3021. // Move to the next node
  3022. valueNode = valueNode->next;
  3023. patternNode = patternNode->next;
  3024. }
  3025. else if( patternNode->type == asLPT_REPEAT || patternNode->type == asLPT_REPEAT_SAME )
  3026. {
  3027. // TODO: list: repeat_inner should make sure the list has the same size as the inner list, i.e. square area
  3028. // TODO: list: repeat_prev should make sure the list is the same size as the previous
  3029. asEListPatternNodeType repeatType = patternNode->type;
  3030. asCScriptNode *firstValue = valueNode;
  3031. // The following values will be repeated N times
  3032. patternNode = patternNode->next;
  3033. // Keep track of the patternNode so it can be reset
  3034. asSListPatternNode *nextNode = patternNode;
  3035. // Align the buffer size to 4 bytes in case previous value was smaller than 4 bytes
  3036. if( bufferSize & 0x3 )
  3037. bufferSize += 4 - (bufferSize & 0x3);
  3038. // The first dword will hold the number of elements in the list
  3039. asDWORD currSize = bufferSize;
  3040. bufferSize += 4;
  3041. asUINT countElements = 0;
  3042. int elementsInSubSubList = -1;
  3043. asCExprContext ctx(engine);
  3044. while( valueNode )
  3045. {
  3046. patternNode = nextNode;
  3047. asCScriptNode *errNode = valueNode;
  3048. int r = CompileInitListElement(patternNode, valueNode, bufferTypeId, bufferVar, bufferSize, ctx.bc, elementsInSubSubList);
  3049. if( r < 0 ) return r;
  3050. if( r == 0 )
  3051. countElements++;
  3052. else
  3053. {
  3054. asASSERT( r == 1 && engine->ep.disallowEmptyListElements );
  3055. if( valueNode )
  3056. {
  3057. // Empty elements in the middle are not allowed
  3058. Error(TXT_EMPTY_LIST_ELEMENT_IS_NOT_ALLOWED, errNode);
  3059. }
  3060. }
  3061. }
  3062. if( countElements == 0 )
  3063. {
  3064. // Skip the sub pattern that was expected to be repeated, otherwise the caller will try to match these when we return
  3065. patternNode = nextNode;
  3066. if( patternNode->type == asLPT_TYPE )
  3067. patternNode = patternNode->next;
  3068. else if( patternNode->type == asLPT_START )
  3069. {
  3070. int subCount = 1;
  3071. do
  3072. {
  3073. patternNode = patternNode->next;
  3074. if( patternNode->type == asLPT_START )
  3075. subCount++;
  3076. else if( patternNode->type == asLPT_END )
  3077. subCount--;
  3078. } while( subCount > 0 );
  3079. patternNode = patternNode->next;
  3080. }
  3081. }
  3082. // For repeat_same each repeated sublist must have the same size to form a rectangular array
  3083. if( repeatType == asLPT_REPEAT_SAME && elementsInSubList != -1 && asUINT(elementsInSubList) != countElements )
  3084. {
  3085. if( countElements < asUINT(elementsInSubList) )
  3086. Error(TXT_NOT_ENOUGH_VALUES_FOR_LIST, firstValue);
  3087. else
  3088. Error(TXT_TOO_MANY_VALUES_FOR_LIST, firstValue);
  3089. return -1;
  3090. }
  3091. else
  3092. {
  3093. // Return to caller the amount of elments in this sublist
  3094. elementsInSubList = countElements;
  3095. }
  3096. // The first dword in the buffer will hold the number of elements
  3097. bcInit.InstrSHORT_DW_DW(asBC_SetListSize, bufferVar, currSize, countElements);
  3098. // Add the values
  3099. bcInit.AddCode(&ctx.bc);
  3100. }
  3101. else if( patternNode->type == asLPT_TYPE )
  3102. {
  3103. bool isEmpty = false;
  3104. // Determine the size of the element
  3105. asUINT size = 0;
  3106. asCDataType dt = reinterpret_cast<asSListPatternDataTypeNode*>(patternNode)->dataType;
  3107. if( valueNode->nodeType == snAssignment || valueNode->nodeType == snInitList )
  3108. {
  3109. asCExprContext lctx(engine);
  3110. asCExprContext rctx(engine);
  3111. if( valueNode->nodeType == snAssignment )
  3112. {
  3113. // Compile the assignment expression
  3114. CompileAssignment(valueNode, &rctx);
  3115. if( dt.GetTokenType() == ttQuestion )
  3116. {
  3117. // Make sure the type is not ambiguous
  3118. DetermineSingleFunc(&rctx, valueNode);
  3119. // We now know the type
  3120. dt = rctx.type.dataType;
  3121. dt.MakeReadOnly(false);
  3122. dt.MakeReference(false);
  3123. // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit.
  3124. if( bufferSize & 0x3 )
  3125. bufferSize += 4 - (bufferSize & 0x3);
  3126. // When value assignment for reference types us disabled, make sure all ref types are passed in as handles
  3127. if (engine->ep.disallowValueAssignForRefType && dt.SupportHandles())
  3128. dt.MakeHandle(true);
  3129. // Place the type id in the buffer
  3130. bcInit.InstrSHORT_DW_DW(asBC_SetListType, bufferVar, bufferSize, engine->GetTypeIdFromDataType(dt));
  3131. bufferSize += 4;
  3132. }
  3133. }
  3134. else if( valueNode->nodeType == snInitList )
  3135. {
  3136. if( dt.GetTokenType() == ttQuestion )
  3137. {
  3138. // Can't use init lists with var type as it is not possible to determine what type should be allocated
  3139. asCString str;
  3140. str.Format(TXT_INIT_LIST_CANNOT_BE_USED_WITH_s, "?");
  3141. Error(str.AddressOf(), valueNode);
  3142. rctx.type.SetDummy();
  3143. dt = rctx.type.dataType;
  3144. }
  3145. else
  3146. {
  3147. // Allocate a temporary variable that will be initialized with the list
  3148. int offset = AllocateVariable(dt, true);
  3149. rctx.type.Set(dt);
  3150. rctx.type.isVariable = true;
  3151. rctx.type.isTemporary = true;
  3152. rctx.type.stackOffset = (short)offset;
  3153. CompileInitList(&rctx.type, valueNode, &rctx.bc, 0);
  3154. // Put the object on the stack
  3155. rctx.bc.InstrSHORT(asBC_PSF, rctx.type.stackOffset);
  3156. // It is a reference that we place on the stack
  3157. rctx.type.dataType.MakeReference(true);
  3158. }
  3159. }
  3160. // Determine size of the element
  3161. if( dt.IsPrimitive() || (!dt.IsNullHandle() && (dt.GetTypeInfo()->flags & asOBJ_VALUE)) )
  3162. size = dt.GetSizeInMemoryBytes();
  3163. else
  3164. size = AS_PTR_SIZE*4;
  3165. // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit.
  3166. if( size >= 4 && (bufferSize & 0x3) )
  3167. bufferSize += 4 - (bufferSize & 0x3);
  3168. // Compile the lvalue
  3169. lctx.bc.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize);
  3170. lctx.type.Set(dt);
  3171. lctx.type.isLValue = true;
  3172. if( dt.IsPrimitive() )
  3173. {
  3174. lctx.bc.Instr(asBC_PopRPtr);
  3175. lctx.type.dataType.MakeReference(true);
  3176. }
  3177. else if( dt.IsObjectHandle() ||
  3178. dt.GetTypeInfo()->flags & asOBJ_REF )
  3179. {
  3180. lctx.type.isExplicitHandle = true;
  3181. lctx.type.dataType.MakeReference(true);
  3182. }
  3183. else
  3184. {
  3185. asASSERT( dt.GetTypeInfo()->flags & asOBJ_VALUE );
  3186. // Make sure the object has been constructed before the assignment
  3187. // TODO: runtime optimize: Use copy constructor instead of assignment to initialize the objects
  3188. asSTypeBehaviour *beh = dt.GetBehaviour();
  3189. int func = 0;
  3190. if( beh ) func = beh->construct;
  3191. if( func == 0 && (dt.GetTypeInfo()->flags & asOBJ_POD) == 0 )
  3192. {
  3193. asCString str;
  3194. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetTypeInfo()->GetName());
  3195. Error(str, valueNode);
  3196. }
  3197. else if( func )
  3198. {
  3199. // Call the constructor as a normal function
  3200. bcInit.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize);
  3201. asCExprContext ctx(engine);
  3202. PerformFunctionCall(func, &ctx, false, 0, CastToObjectType(dt.GetTypeInfo()));
  3203. bcInit.AddCode(&ctx.bc);
  3204. }
  3205. }
  3206. if( lctx.type.dataType.IsNullHandle() )
  3207. {
  3208. // Don't add any code to assign a null handle. RefCpy doesn't work without a known type.
  3209. // The buffer is already initialized to zero in asBC_AllocMem anyway.
  3210. asASSERT( rctx.bc.GetLastInstr() == asBC_PshNull );
  3211. asASSERT( reinterpret_cast<asSListPatternDataTypeNode*>(patternNode)->dataType.GetTokenType() == ttQuestion );
  3212. }
  3213. else
  3214. {
  3215. asCExprContext ctx(engine);
  3216. DoAssignment(&ctx, &lctx, &rctx, valueNode, valueNode, ttAssignment, valueNode);
  3217. if( !lctx.type.dataType.IsPrimitive() )
  3218. ctx.bc.Instr(asBC_PopPtr);
  3219. // Release temporary variables used by expression
  3220. ReleaseTemporaryVariable(ctx.type, &ctx.bc);
  3221. ProcessDeferredParams(&ctx);
  3222. bcInit.AddCode(&ctx.bc);
  3223. }
  3224. }
  3225. else
  3226. {
  3227. if( builder->engine->ep.disallowEmptyListElements )
  3228. {
  3229. // Empty elements are not allowed, except if it is the last in the list
  3230. isEmpty = true;
  3231. }
  3232. else
  3233. {
  3234. // There is no specific value so we need to fill it with a default value
  3235. if( dt.GetTokenType() == ttQuestion )
  3236. {
  3237. // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit.
  3238. if( bufferSize & 0x3 )
  3239. bufferSize += 4 - (bufferSize & 0x3);
  3240. // Place the type id for a null handle in the buffer
  3241. bcInit.InstrSHORT_DW_DW(asBC_SetListType, bufferVar, bufferSize, 0);
  3242. bufferSize += 4;
  3243. dt = asCDataType::CreateNullHandle();
  3244. // No need to initialize the handle as the buffer is already initialized with zeroes
  3245. }
  3246. else if( dt.GetTypeInfo() && dt.GetTypeInfo()->flags & asOBJ_VALUE )
  3247. {
  3248. // For value types with default constructor we need to call the constructor
  3249. asSTypeBehaviour *beh = dt.GetBehaviour();
  3250. int func = 0;
  3251. if( beh ) func = beh->construct;
  3252. if( func == 0 && (dt.GetTypeInfo()->flags & asOBJ_POD) == 0 )
  3253. {
  3254. asCString str;
  3255. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetTypeInfo()->GetName());
  3256. Error(str, valueNode);
  3257. }
  3258. else if( func )
  3259. {
  3260. // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit.
  3261. if( bufferSize & 0x3 )
  3262. bufferSize += 4 - (bufferSize & 0x3);
  3263. // Call the constructor as a normal function
  3264. bcInit.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize);
  3265. asCExprContext ctx(engine);
  3266. PerformFunctionCall(func, &ctx, false, 0, CastToObjectType(dt.GetTypeInfo()));
  3267. bcInit.AddCode(&ctx.bc);
  3268. }
  3269. }
  3270. else if( !dt.IsObjectHandle() && dt.GetTypeInfo() && dt.GetTypeInfo()->flags & asOBJ_REF )
  3271. {
  3272. // For ref types (not handles) we need to call the default factory
  3273. asSTypeBehaviour *beh = dt.GetBehaviour();
  3274. int func = 0;
  3275. if( beh ) func = beh->factory;
  3276. if( func == 0 )
  3277. {
  3278. asCString str;
  3279. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetTypeInfo()->GetName());
  3280. Error(str, valueNode);
  3281. }
  3282. else if( func )
  3283. {
  3284. asCExprContext rctx(engine);
  3285. PerformFunctionCall(func, &rctx, false, 0, CastToObjectType(dt.GetTypeInfo()));
  3286. // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit.
  3287. if( bufferSize & 0x3 )
  3288. bufferSize += 4 - (bufferSize & 0x3);
  3289. asCExprContext lctx(engine);
  3290. lctx.bc.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize);
  3291. lctx.type.Set(dt);
  3292. lctx.type.isLValue = true;
  3293. lctx.type.isExplicitHandle = true;
  3294. lctx.type.dataType.MakeReference(true);
  3295. asCExprContext ctx(engine);
  3296. DoAssignment(&ctx, &lctx, &rctx, valueNode, valueNode, ttAssignment, valueNode);
  3297. if( !lctx.type.dataType.IsPrimitive() )
  3298. ctx.bc.Instr(asBC_PopPtr);
  3299. // Release temporary variables used by expression
  3300. ReleaseTemporaryVariable(ctx.type, &ctx.bc);
  3301. ProcessDeferredParams(&ctx);
  3302. bcInit.AddCode(&ctx.bc);
  3303. }
  3304. }
  3305. }
  3306. }
  3307. if( !isEmpty )
  3308. {
  3309. // Determine size of the element
  3310. if( dt.IsPrimitive() || (!dt.IsNullHandle() && (dt.GetTypeInfo()->flags & asOBJ_VALUE)) )
  3311. size = dt.GetSizeInMemoryBytes();
  3312. else
  3313. size = AS_PTR_SIZE*4;
  3314. asASSERT( size <= 4 || (size & 0x3) == 0 );
  3315. bufferSize += size;
  3316. }
  3317. // Move to the next element
  3318. patternNode = patternNode->next;
  3319. valueNode = valueNode->next;
  3320. if( isEmpty )
  3321. {
  3322. // The caller will determine if the empty element should be ignored or not
  3323. return 1;
  3324. }
  3325. }
  3326. else
  3327. asASSERT( false );
  3328. return 0;
  3329. }
  3330. void asCCompiler::CompileStatement(asCScriptNode *statement, bool *hasReturn, asCByteCode *bc)
  3331. {
  3332. // Don't clear the hasReturn flag if this is an empty statement
  3333. // to avoid false errors of 'not all paths return'
  3334. if( statement->nodeType != snExpressionStatement || statement->firstChild )
  3335. *hasReturn = false;
  3336. if( statement->nodeType == snStatementBlock )
  3337. CompileStatementBlock(statement, true, hasReturn, bc);
  3338. else if( statement->nodeType == snIf )
  3339. CompileIfStatement(statement, hasReturn, bc);
  3340. else if( statement->nodeType == snFor )
  3341. CompileForStatement(statement, bc);
  3342. else if( statement->nodeType == snWhile )
  3343. CompileWhileStatement(statement, bc);
  3344. else if( statement->nodeType == snDoWhile )
  3345. CompileDoWhileStatement(statement, bc);
  3346. else if( statement->nodeType == snExpressionStatement )
  3347. CompileExpressionStatement(statement, bc);
  3348. else if( statement->nodeType == snBreak )
  3349. CompileBreakStatement(statement, bc);
  3350. else if( statement->nodeType == snContinue )
  3351. CompileContinueStatement(statement, bc);
  3352. else if( statement->nodeType == snSwitch )
  3353. CompileSwitchStatement(statement, hasReturn, bc);
  3354. else if( statement->nodeType == snReturn )
  3355. {
  3356. CompileReturnStatement(statement, bc);
  3357. *hasReturn = true;
  3358. }
  3359. else
  3360. asASSERT(false);
  3361. }
  3362. void asCCompiler::CompileSwitchStatement(asCScriptNode *snode, bool *, asCByteCode *bc)
  3363. {
  3364. // TODO: inheritance: Must guarantee that all options in the switch case call a constructor, or that none call it.
  3365. // Reserve label for break statements
  3366. int breakLabel = nextLabel++;
  3367. breakLabels.PushLast(breakLabel);
  3368. // Add a variable scope that will be used by CompileBreak
  3369. // to know where to stop deallocating variables
  3370. AddVariableScope(true, false);
  3371. //---------------------------
  3372. // Compile the switch expression
  3373. //-------------------------------
  3374. // Compile the switch expression
  3375. asCExprContext expr(engine);
  3376. CompileAssignment(snode->firstChild, &expr);
  3377. // Verify that the expression is a primitive type
  3378. if( !expr.type.dataType.IsIntegerType() && !expr.type.dataType.IsUnsignedType() )
  3379. {
  3380. Error(TXT_SWITCH_MUST_BE_INTEGRAL, snode->firstChild);
  3381. return;
  3382. }
  3383. ProcessPropertyGetAccessor(&expr, snode);
  3384. // TODO: Need to support 64bit integers
  3385. // Convert the expression to a 32bit variable
  3386. asCDataType to;
  3387. if( expr.type.dataType.IsIntegerType() )
  3388. to.SetTokenType(ttInt);
  3389. else if( expr.type.dataType.IsUnsignedType() )
  3390. to.SetTokenType(ttUInt);
  3391. // Make sure the value is in a variable
  3392. if( expr.type.dataType.IsReference() )
  3393. ConvertToVariable(&expr);
  3394. ImplicitConversion(&expr, to, snode->firstChild, asIC_IMPLICIT_CONV, true);
  3395. ConvertToVariable(&expr);
  3396. int offset = expr.type.stackOffset;
  3397. ProcessDeferredParams(&expr);
  3398. //-------------------------------
  3399. // Determine case values and labels
  3400. //--------------------------------
  3401. // Remember the first label so that we can later pass the
  3402. // correct label to each CompileCase()
  3403. int firstCaseLabel = nextLabel;
  3404. int defaultLabel = 0;
  3405. asCArray<int> caseValues;
  3406. asCArray<int> caseLabels;
  3407. // Compile all case comparisons and make them jump to the right label
  3408. asCScriptNode *cnode = snode->firstChild->next;
  3409. while( cnode )
  3410. {
  3411. // Each case should have a constant expression
  3412. if( cnode->firstChild && cnode->firstChild->nodeType == snExpression )
  3413. {
  3414. // Compile expression
  3415. asCExprContext c(engine);
  3416. CompileExpression(cnode->firstChild, &c);
  3417. // Verify that the result is a constant
  3418. if( !c.type.isConstant )
  3419. Error(TXT_SWITCH_CASE_MUST_BE_CONSTANT, cnode->firstChild);
  3420. // Verify that the result is an integral number
  3421. if (!c.type.dataType.IsIntegerType() && !c.type.dataType.IsUnsignedType())
  3422. Error(TXT_SWITCH_MUST_BE_INTEGRAL, cnode->firstChild);
  3423. else
  3424. {
  3425. ImplicitConversion(&c, to, cnode->firstChild, asIC_IMPLICIT_CONV, true);
  3426. // Has this case been declared already?
  3427. if (caseValues.IndexOf(c.type.GetConstantDW()) >= 0)
  3428. Error(TXT_DUPLICATE_SWITCH_CASE, cnode->firstChild);
  3429. // TODO: Optimize: We can insert the numbers sorted already
  3430. // Store constant for later use
  3431. caseValues.PushLast(c.type.GetConstantDW());
  3432. // Reserve label for this case
  3433. caseLabels.PushLast(nextLabel++);
  3434. }
  3435. }
  3436. else
  3437. {
  3438. // TODO: It shouldn't be necessary for the default case to be the last one.
  3439. // Is default the last case?
  3440. if( cnode->next )
  3441. {
  3442. Error(TXT_DEFAULT_MUST_BE_LAST, cnode);
  3443. break;
  3444. }
  3445. // Reserve label for this case
  3446. defaultLabel = nextLabel++;
  3447. }
  3448. cnode = cnode->next;
  3449. }
  3450. // check for empty switch
  3451. if (caseValues.GetLength() == 0)
  3452. {
  3453. Error(TXT_EMPTY_SWITCH, snode);
  3454. return;
  3455. }
  3456. if( defaultLabel == 0 )
  3457. defaultLabel = breakLabel;
  3458. //---------------------------------
  3459. // Output the optimized case comparisons
  3460. // with jumps to the case code
  3461. //------------------------------------
  3462. // Sort the case values by increasing value. Do the sort together with the labels
  3463. // A simple bubble sort is sufficient since we don't expect a huge number of values
  3464. for( asUINT fwd = 1; fwd < caseValues.GetLength(); fwd++ )
  3465. {
  3466. for( int bck = fwd - 1; bck >= 0; bck-- )
  3467. {
  3468. int bckp = bck + 1;
  3469. if( caseValues[bck] > caseValues[bckp] )
  3470. {
  3471. // Swap the values in both arrays
  3472. int swap = caseValues[bckp];
  3473. caseValues[bckp] = caseValues[bck];
  3474. caseValues[bck] = swap;
  3475. swap = caseLabels[bckp];
  3476. caseLabels[bckp] = caseLabels[bck];
  3477. caseLabels[bck] = swap;
  3478. }
  3479. else
  3480. break;
  3481. }
  3482. }
  3483. // Find ranges of consecutive numbers
  3484. asCArray<int> ranges;
  3485. ranges.PushLast(0);
  3486. asUINT n;
  3487. for( n = 1; n < caseValues.GetLength(); ++n )
  3488. {
  3489. // We can join numbers that are less than 5 numbers
  3490. // apart since the output code will still be smaller
  3491. if( caseValues[n] > caseValues[n-1] + 5 )
  3492. ranges.PushLast(n);
  3493. }
  3494. // If the value is larger than the largest case value, jump to default
  3495. int tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  3496. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[caseValues.GetLength()-1]);
  3497. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  3498. expr.bc.InstrDWORD(asBC_JP, defaultLabel);
  3499. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  3500. // TODO: runtime optimize: We could possibly optimize this even more by doing a
  3501. // binary search instead of a linear search through the ranges
  3502. // For each range
  3503. int range;
  3504. for( range = 0; range < (int)ranges.GetLength(); range++ )
  3505. {
  3506. // Find the largest value in this range
  3507. int maxRange = caseValues[ranges[range]];
  3508. int index = ranges[range];
  3509. for( ; (index < (int)caseValues.GetLength()) && (caseValues[index] <= maxRange + 5); index++ )
  3510. maxRange = caseValues[index];
  3511. // If there are only 2 numbers then it is better to compare them directly
  3512. if( index - ranges[range] > 2 )
  3513. {
  3514. // If the value is smaller than the smallest case value in the range, jump to default
  3515. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  3516. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[ranges[range]]);
  3517. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  3518. expr.bc.InstrDWORD(asBC_JS, defaultLabel);
  3519. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  3520. int nextRangeLabel = nextLabel++;
  3521. // If this is the last range we don't have to make this test
  3522. if( range < (int)ranges.GetLength() - 1 )
  3523. {
  3524. // If the value is larger than the largest case value in the range, jump to the next range
  3525. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  3526. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, maxRange);
  3527. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  3528. expr.bc.InstrDWORD(asBC_JP, nextRangeLabel);
  3529. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  3530. }
  3531. // Jump forward according to the value
  3532. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  3533. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[ranges[range]]);
  3534. expr.bc.InstrW_W_W(asBC_SUBi, tmpOffset, offset, tmpOffset);
  3535. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  3536. expr.bc.JmpP(tmpOffset, maxRange - caseValues[ranges[range]]);
  3537. // Add the list of jumps to the correct labels (any holes, jump to default)
  3538. index = ranges[range];
  3539. for( int i = caseValues[index]; i <= maxRange; i++ )
  3540. {
  3541. if( caseValues[index] == i )
  3542. expr.bc.InstrINT(asBC_JMP, caseLabels[index++]);
  3543. else
  3544. expr.bc.InstrINT(asBC_JMP, defaultLabel);
  3545. }
  3546. expr.bc.Label((short)nextRangeLabel);
  3547. }
  3548. else
  3549. {
  3550. // Simply make a comparison with each value
  3551. for( int i = ranges[range]; i < index; ++i )
  3552. {
  3553. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  3554. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[i]);
  3555. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  3556. expr.bc.InstrDWORD(asBC_JZ, caseLabels[i]);
  3557. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  3558. }
  3559. }
  3560. }
  3561. // Catch any value that falls trough
  3562. expr.bc.InstrINT(asBC_JMP, defaultLabel);
  3563. // Release the temporary variable previously stored
  3564. ReleaseTemporaryVariable(expr.type, &expr.bc);
  3565. // TODO: optimize: Should optimize each piece individually
  3566. expr.bc.OptimizeLocally(tempVariableOffsets);
  3567. //----------------------------------
  3568. // Output case implementations
  3569. //----------------------------------
  3570. // Compile case implementations, each one with the label before it
  3571. cnode = snode->firstChild->next;
  3572. while( cnode )
  3573. {
  3574. // Each case should have a constant expression
  3575. if( cnode->firstChild && cnode->firstChild->nodeType == snExpression )
  3576. {
  3577. expr.bc.Label((short)firstCaseLabel++);
  3578. CompileCase(cnode->firstChild->next, &expr.bc);
  3579. }
  3580. else
  3581. {
  3582. expr.bc.Label((short)defaultLabel);
  3583. // Is default the last case?
  3584. if( cnode->next )
  3585. {
  3586. // We've already reported this error
  3587. break;
  3588. }
  3589. CompileCase(cnode->firstChild, &expr.bc);
  3590. }
  3591. cnode = cnode->next;
  3592. }
  3593. //--------------------------------
  3594. bc->AddCode(&expr.bc);
  3595. // Add break label
  3596. bc->Label((short)breakLabel);
  3597. breakLabels.PopLast();
  3598. RemoveVariableScope();
  3599. }
  3600. void asCCompiler::CompileCase(asCScriptNode *node, asCByteCode *bc)
  3601. {
  3602. bool isFinished = false;
  3603. bool hasReturn = false;
  3604. bool hasUnreachableCode = false;
  3605. while( node )
  3606. {
  3607. if( !hasUnreachableCode && (hasReturn || isFinished) )
  3608. {
  3609. hasUnreachableCode = true;
  3610. Warning(TXT_UNREACHABLE_CODE, node);
  3611. break;
  3612. }
  3613. if( node->nodeType == snBreak || node->nodeType == snContinue )
  3614. isFinished = true;
  3615. asCByteCode statement(engine);
  3616. if( node->nodeType == snDeclaration )
  3617. {
  3618. Error(TXT_DECL_IN_SWITCH, node);
  3619. // Compile it anyway to avoid further compiler errors
  3620. CompileDeclaration(node, &statement);
  3621. }
  3622. else
  3623. CompileStatement(node, &hasReturn, &statement);
  3624. LineInstr(bc, node->tokenPos);
  3625. bc->AddCode(&statement);
  3626. if( !hasCompileErrors )
  3627. asASSERT( tempVariables.GetLength() == 0 );
  3628. node = node->next;
  3629. }
  3630. }
  3631. void asCCompiler::CompileIfStatement(asCScriptNode *inode, bool *hasReturn, asCByteCode *bc)
  3632. {
  3633. // We will use one label for the if statement
  3634. // and possibly another for the else statement
  3635. int afterLabel = nextLabel++;
  3636. // Compile the expression
  3637. asCExprContext expr(engine);
  3638. int r = CompileAssignment(inode->firstChild, &expr);
  3639. if( r == 0 )
  3640. {
  3641. // Allow value types to be converted to bool using 'bool opImplConv()'
  3642. if( expr.type.dataType.GetTypeInfo() && (expr.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
  3643. ImplicitConversion(&expr, asCDataType::CreatePrimitive(ttBool, false), inode, asIC_IMPLICIT_CONV);
  3644. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  3645. Error(TXT_EXPR_MUST_BE_BOOL, inode->firstChild);
  3646. else
  3647. {
  3648. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  3649. ProcessDeferredParams(&expr);
  3650. if( !expr.type.isConstant )
  3651. {
  3652. ProcessPropertyGetAccessor(&expr, inode);
  3653. ConvertToVariable(&expr);
  3654. // Add a test
  3655. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  3656. expr.bc.Instr(asBC_ClrHi);
  3657. expr.bc.InstrDWORD(asBC_JZ, afterLabel);
  3658. ReleaseTemporaryVariable(expr.type, &expr.bc);
  3659. expr.bc.OptimizeLocally(tempVariableOffsets);
  3660. bc->AddCode(&expr.bc);
  3661. }
  3662. #if AS_SIZEOF_BOOL == 1
  3663. else if( expr.type.GetConstantB() == 0 )
  3664. #else
  3665. else if (expr.type.GetConstantDW() == 0)
  3666. #endif
  3667. {
  3668. // Jump to the else case
  3669. bc->InstrINT(asBC_JMP, afterLabel);
  3670. // TODO: Should we warn that the expression will always go to the else?
  3671. }
  3672. }
  3673. }
  3674. // Compile the if statement
  3675. bool origIsConstructorCalled = m_isConstructorCalled;
  3676. bool hasReturn1;
  3677. asCByteCode ifBC(engine);
  3678. CompileStatement(inode->firstChild->next, &hasReturn1, &ifBC);
  3679. // Add the byte code
  3680. LineInstr(bc, inode->firstChild->next->tokenPos);
  3681. bc->AddCode(&ifBC);
  3682. if( inode->firstChild->next->nodeType == snExpressionStatement && inode->firstChild->next->firstChild == 0 )
  3683. {
  3684. // Don't allow if( expr );
  3685. Error(TXT_IF_WITH_EMPTY_STATEMENT, inode->firstChild->next);
  3686. }
  3687. // If one of the statements call the constructor, the other must as well
  3688. // otherwise it is possible the constructor is never called
  3689. bool constructorCall1 = false;
  3690. bool constructorCall2 = false;
  3691. if( !origIsConstructorCalled && m_isConstructorCalled )
  3692. constructorCall1 = true;
  3693. // Do we have an else statement?
  3694. if( inode->firstChild->next != inode->lastChild )
  3695. {
  3696. // Reset the constructor called flag so the else statement can call the constructor too
  3697. m_isConstructorCalled = origIsConstructorCalled;
  3698. int afterElse = 0;
  3699. if( !hasReturn1 )
  3700. {
  3701. afterElse = nextLabel++;
  3702. // Add jump to after the else statement
  3703. bc->InstrINT(asBC_JMP, afterElse);
  3704. }
  3705. // Add label for the else statement
  3706. bc->Label((short)afterLabel);
  3707. bool hasReturn2;
  3708. asCByteCode elseBC(engine);
  3709. CompileStatement(inode->lastChild, &hasReturn2, &elseBC);
  3710. // Add byte code for the else statement
  3711. LineInstr(bc, inode->lastChild->tokenPos);
  3712. bc->AddCode(&elseBC);
  3713. if( inode->lastChild->nodeType == snExpressionStatement && inode->lastChild->firstChild == 0 )
  3714. {
  3715. // Don't allow if( expr ) {} else;
  3716. Error(TXT_ELSE_WITH_EMPTY_STATEMENT, inode->lastChild);
  3717. }
  3718. if( !hasReturn1 )
  3719. {
  3720. // Add label for the end of else statement
  3721. bc->Label((short)afterElse);
  3722. }
  3723. // The if statement only has return if both alternatives have
  3724. *hasReturn = hasReturn1 && hasReturn2;
  3725. if( !origIsConstructorCalled && m_isConstructorCalled )
  3726. constructorCall2 = true;
  3727. }
  3728. else
  3729. {
  3730. // Add label for the end of if statement
  3731. bc->Label((short)afterLabel);
  3732. *hasReturn = false;
  3733. }
  3734. // Make sure both or neither conditions call a constructor
  3735. if( (constructorCall1 && !constructorCall2) ||
  3736. (constructorCall2 && !constructorCall1) )
  3737. {
  3738. Error(TXT_BOTH_CONDITIONS_MUST_CALL_CONSTRUCTOR, inode);
  3739. }
  3740. m_isConstructorCalled = origIsConstructorCalled || constructorCall1 || constructorCall2;
  3741. }
  3742. void asCCompiler::CompileForStatement(asCScriptNode *fnode, asCByteCode *bc)
  3743. {
  3744. // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables
  3745. AddVariableScope(true, true);
  3746. // We will use three labels for the for loop
  3747. int conditionLabel = nextLabel++;
  3748. int afterLabel = nextLabel++;
  3749. int continueLabel = nextLabel++;
  3750. int insideLabel = nextLabel++;
  3751. continueLabels.PushLast(continueLabel);
  3752. breakLabels.PushLast(afterLabel);
  3753. //---------------------------------------
  3754. // Compile the initialization statement
  3755. asCByteCode initBC(engine);
  3756. LineInstr(&initBC, fnode->firstChild->tokenPos);
  3757. if( fnode->firstChild->nodeType == snDeclaration )
  3758. CompileDeclaration(fnode->firstChild, &initBC);
  3759. else
  3760. CompileExpressionStatement(fnode->firstChild, &initBC);
  3761. //-----------------------------------
  3762. // Compile the condition statement
  3763. asCExprContext expr(engine);
  3764. asCScriptNode *second = fnode->firstChild->next;
  3765. if( second->firstChild )
  3766. {
  3767. int r = CompileAssignment(second->firstChild, &expr);
  3768. if( r >= 0 )
  3769. {
  3770. // Allow value types to be converted to bool using 'bool opImplConv()'
  3771. if( expr.type.dataType.GetTypeInfo() && (expr.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
  3772. ImplicitConversion(&expr, asCDataType::CreatePrimitive(ttBool, false), second->firstChild, asIC_IMPLICIT_CONV);
  3773. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  3774. Error(TXT_EXPR_MUST_BE_BOOL, second);
  3775. else
  3776. {
  3777. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  3778. ProcessDeferredParams(&expr);
  3779. ProcessPropertyGetAccessor(&expr, second);
  3780. // If expression is false exit the loop
  3781. ConvertToVariable(&expr);
  3782. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  3783. expr.bc.Instr(asBC_ClrHi);
  3784. expr.bc.InstrDWORD(asBC_JNZ, insideLabel);
  3785. ReleaseTemporaryVariable(expr.type, &expr.bc);
  3786. expr.bc.OptimizeLocally(tempVariableOffsets);
  3787. // Prepend the line instruction for the condition
  3788. asCByteCode tmp(engine);
  3789. LineInstr(&tmp, second->firstChild->tokenPos);
  3790. tmp.AddCode(&expr.bc);
  3791. expr.bc.AddCode(&tmp);
  3792. }
  3793. }
  3794. }
  3795. //---------------------------
  3796. // Compile the increment statement(s)
  3797. asCByteCode nextBC(engine);
  3798. asCScriptNode *cnode = second->next;
  3799. while( cnode && cnode->nodeType == snExpressionStatement && cnode != fnode->lastChild )
  3800. {
  3801. LineInstr(&nextBC, cnode->tokenPos);
  3802. CompileExpressionStatement(cnode, &nextBC);
  3803. cnode = cnode->next;
  3804. }
  3805. //------------------------------
  3806. // Compile loop statement
  3807. bool hasReturn;
  3808. asCByteCode forBC(engine);
  3809. CompileStatement(fnode->lastChild, &hasReturn, &forBC);
  3810. //-------------------------------
  3811. // Join the code pieces
  3812. bc->AddCode(&initBC);
  3813. bc->InstrDWORD(asBC_JMP, conditionLabel);
  3814. bc->Label((short)insideLabel);
  3815. // Add a suspend bytecode inside the loop to guarantee
  3816. // that the application can suspend the execution
  3817. bc->Instr(asBC_SUSPEND);
  3818. bc->InstrPTR(asBC_JitEntry, 0);
  3819. LineInstr(bc, fnode->lastChild->tokenPos);
  3820. bc->AddCode(&forBC);
  3821. bc->Label((short)continueLabel);
  3822. bc->AddCode(&nextBC);
  3823. bc->Label((short)conditionLabel);
  3824. if( expr.bc.GetLastInstr() == -1 )
  3825. // There is no condition, so we just always jump
  3826. bc->InstrDWORD(asBC_JMP, insideLabel);
  3827. else
  3828. bc->AddCode(&expr.bc);
  3829. bc->Label((short)afterLabel);
  3830. continueLabels.PopLast();
  3831. breakLabels.PopLast();
  3832. // Deallocate variables in this block, in reverse order
  3833. for( int n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  3834. {
  3835. sVariable *v = variables->variables[n];
  3836. // Call variable destructors here, for variables not yet destroyed
  3837. CallDestructor(v->type, v->stackOffset, v->onHeap, bc);
  3838. // Don't deallocate function parameters
  3839. if( v->stackOffset > 0 )
  3840. DeallocateVariable(v->stackOffset);
  3841. }
  3842. RemoveVariableScope();
  3843. }
  3844. void asCCompiler::CompileWhileStatement(asCScriptNode *wnode, asCByteCode *bc)
  3845. {
  3846. // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables
  3847. AddVariableScope(true, true);
  3848. // We will use two labels for the while loop
  3849. int beforeLabel = nextLabel++;
  3850. int afterLabel = nextLabel++;
  3851. continueLabels.PushLast(beforeLabel);
  3852. breakLabels.PushLast(afterLabel);
  3853. // Add label before the expression
  3854. bc->Label((short)beforeLabel);
  3855. // Compile expression
  3856. asCExprContext expr(engine);
  3857. int r = CompileAssignment(wnode->firstChild, &expr);
  3858. if( r == 0 )
  3859. {
  3860. // Allow value types to be converted to bool using 'bool opImplConv()'
  3861. if( expr.type.dataType.GetTypeInfo() && (expr.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
  3862. ImplicitConversion(&expr, asCDataType::CreatePrimitive(ttBool, false), wnode->firstChild, asIC_IMPLICIT_CONV);
  3863. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  3864. Error(TXT_EXPR_MUST_BE_BOOL, wnode->firstChild);
  3865. else
  3866. {
  3867. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  3868. ProcessDeferredParams(&expr);
  3869. ProcessPropertyGetAccessor(&expr, wnode);
  3870. // Add byte code for the expression
  3871. ConvertToVariable(&expr);
  3872. // Jump to end of statement if expression is false
  3873. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  3874. expr.bc.Instr(asBC_ClrHi);
  3875. expr.bc.InstrDWORD(asBC_JZ, afterLabel);
  3876. ReleaseTemporaryVariable(expr.type, &expr.bc);
  3877. expr.bc.OptimizeLocally(tempVariableOffsets);
  3878. bc->AddCode(&expr.bc);
  3879. }
  3880. }
  3881. // Add a suspend bytecode inside the loop to guarantee
  3882. // that the application can suspend the execution
  3883. bc->Instr(asBC_SUSPEND);
  3884. bc->InstrPTR(asBC_JitEntry, 0);
  3885. // Compile statement
  3886. bool hasReturn;
  3887. asCByteCode whileBC(engine);
  3888. CompileStatement(wnode->lastChild, &hasReturn, &whileBC);
  3889. // Add byte code for the statement
  3890. LineInstr(bc, wnode->lastChild->tokenPos);
  3891. bc->AddCode(&whileBC);
  3892. // Jump to the expression
  3893. bc->InstrINT(asBC_JMP, beforeLabel);
  3894. // Add label after the statement
  3895. bc->Label((short)afterLabel);
  3896. continueLabels.PopLast();
  3897. breakLabels.PopLast();
  3898. RemoveVariableScope();
  3899. }
  3900. void asCCompiler::CompileDoWhileStatement(asCScriptNode *wnode, asCByteCode *bc)
  3901. {
  3902. // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables
  3903. AddVariableScope(true, true);
  3904. // We will use two labels for the while loop
  3905. int beforeLabel = nextLabel++;
  3906. int beforeTest = nextLabel++;
  3907. int afterLabel = nextLabel++;
  3908. continueLabels.PushLast(beforeTest);
  3909. breakLabels.PushLast(afterLabel);
  3910. // Add label before the statement
  3911. bc->Label((short)beforeLabel);
  3912. // Compile statement
  3913. bool hasReturn;
  3914. asCByteCode whileBC(engine);
  3915. CompileStatement(wnode->firstChild, &hasReturn, &whileBC);
  3916. // Add byte code for the statement
  3917. LineInstr(bc, wnode->firstChild->tokenPos);
  3918. bc->AddCode(&whileBC);
  3919. // Add label before the expression
  3920. bc->Label((short)beforeTest);
  3921. // Add a suspend bytecode inside the loop to guarantee
  3922. // that the application can suspend the execution
  3923. bc->Instr(asBC_SUSPEND);
  3924. bc->InstrPTR(asBC_JitEntry, 0);
  3925. // Add a line instruction
  3926. LineInstr(bc, wnode->lastChild->tokenPos);
  3927. // Compile expression
  3928. asCExprContext expr(engine);
  3929. CompileAssignment(wnode->lastChild, &expr);
  3930. // Allow value types to be converted to bool using 'bool opImplConv()'
  3931. if( expr.type.dataType.GetTypeInfo() && (expr.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
  3932. ImplicitConversion(&expr, asCDataType::CreatePrimitive(ttBool, false), wnode->lastChild, asIC_IMPLICIT_CONV);
  3933. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  3934. Error(TXT_EXPR_MUST_BE_BOOL, wnode->firstChild);
  3935. else
  3936. {
  3937. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  3938. ProcessDeferredParams(&expr);
  3939. ProcessPropertyGetAccessor(&expr, wnode);
  3940. // Add byte code for the expression
  3941. ConvertToVariable(&expr);
  3942. // Jump to next iteration if expression is true
  3943. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  3944. expr.bc.Instr(asBC_ClrHi);
  3945. expr.bc.InstrDWORD(asBC_JNZ, beforeLabel);
  3946. ReleaseTemporaryVariable(expr.type, &expr.bc);
  3947. expr.bc.OptimizeLocally(tempVariableOffsets);
  3948. bc->AddCode(&expr.bc);
  3949. }
  3950. // Add label after the statement
  3951. bc->Label((short)afterLabel);
  3952. continueLabels.PopLast();
  3953. breakLabels.PopLast();
  3954. RemoveVariableScope();
  3955. }
  3956. void asCCompiler::CompileBreakStatement(asCScriptNode *node, asCByteCode *bc)
  3957. {
  3958. if( breakLabels.GetLength() == 0 )
  3959. {
  3960. Error(TXT_INVALID_BREAK, node);
  3961. return;
  3962. }
  3963. // Add destructor calls for all variables that will go out of scope
  3964. // Put this clean up in a block to allow exception handler to understand them
  3965. bc->Block(true);
  3966. asCVariableScope *vs = variables;
  3967. while( !vs->isBreakScope )
  3968. {
  3969. for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- )
  3970. CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc);
  3971. vs = vs->parent;
  3972. }
  3973. bc->Block(false);
  3974. bc->InstrINT(asBC_JMP, breakLabels[breakLabels.GetLength()-1]);
  3975. }
  3976. void asCCompiler::CompileContinueStatement(asCScriptNode *node, asCByteCode *bc)
  3977. {
  3978. if( continueLabels.GetLength() == 0 )
  3979. {
  3980. Error(TXT_INVALID_CONTINUE, node);
  3981. return;
  3982. }
  3983. // Add destructor calls for all variables that will go out of scope
  3984. // Put this clean up in a block to allow exception handler to understand them
  3985. bc->Block(true);
  3986. asCVariableScope *vs = variables;
  3987. while( !vs->isContinueScope )
  3988. {
  3989. for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- )
  3990. CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc);
  3991. vs = vs->parent;
  3992. }
  3993. bc->Block(false);
  3994. bc->InstrINT(asBC_JMP, continueLabels[continueLabels.GetLength()-1]);
  3995. }
  3996. void asCCompiler::CompileExpressionStatement(asCScriptNode *enode, asCByteCode *bc)
  3997. {
  3998. if( enode->firstChild )
  3999. {
  4000. // Compile the expression
  4001. asCExprContext expr(engine);
  4002. CompileAssignment(enode->firstChild, &expr);
  4003. // Must not have unused ambiguous names
  4004. if( expr.IsClassMethod() || expr.IsGlobalFunc() )
  4005. Error(TXT_INVALID_EXPRESSION_AMBIGUOUS_NAME, enode);
  4006. // Must not have unused anonymous functions
  4007. if( expr.IsLambda() )
  4008. Error(TXT_INVALID_EXPRESSION_LAMBDA, enode);
  4009. // If we get here and there is still an unprocessed property
  4010. // accessor, then process it as a get access. Don't call if there is
  4011. // already a compile error, or we might report an error that is not valid
  4012. if( !hasCompileErrors )
  4013. ProcessPropertyGetAccessor(&expr, enode);
  4014. // Pop the value from the stack
  4015. if( !expr.type.dataType.IsPrimitive() )
  4016. expr.bc.Instr(asBC_PopPtr);
  4017. // Release temporary variables used by expression
  4018. ReleaseTemporaryVariable(expr.type, &expr.bc);
  4019. ProcessDeferredParams(&expr);
  4020. expr.bc.OptimizeLocally(tempVariableOffsets);
  4021. bc->AddCode(&expr.bc);
  4022. }
  4023. }
  4024. void asCCompiler::PrepareTemporaryVariable(asCScriptNode *node, asCExprContext *ctx, bool forceOnHeap)
  4025. {
  4026. // The input can be either an object or funcdef, either as handle or reference
  4027. asASSERT(ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef());
  4028. // If the object already is stored in temporary variable then nothing needs to be done
  4029. // Note, a type can be temporary without being a variable, in which case it is holding off
  4030. // on releasing a previously used object.
  4031. if( ctx->type.isTemporary && ctx->type.isVariable &&
  4032. !(forceOnHeap && !IsVariableOnHeap(ctx->type.stackOffset)) )
  4033. {
  4034. // If the temporary object is currently not a reference
  4035. // the expression needs to be reevaluated to a reference
  4036. if( !ctx->type.dataType.IsReference() )
  4037. {
  4038. ctx->bc.Instr(asBC_PopPtr);
  4039. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  4040. ctx->type.dataType.MakeReference(true);
  4041. }
  4042. return;
  4043. }
  4044. // Allocate temporary variable
  4045. asCDataType dt = ctx->type.dataType;
  4046. dt.MakeReference(false);
  4047. dt.MakeReadOnly(false);
  4048. int offset = AllocateVariable(dt, true, forceOnHeap);
  4049. // Objects stored on the stack are not considered references
  4050. dt.MakeReference(IsVariableOnHeap(offset));
  4051. asCExprValue lvalue;
  4052. lvalue.Set(dt);
  4053. lvalue.isExplicitHandle = ctx->type.isExplicitHandle;
  4054. bool isExplicitHandle = ctx->type.isExplicitHandle;
  4055. bool prevIsTemp = ctx->type.isTemporary;
  4056. int prevStackOffset = ctx->type.stackOffset;
  4057. CompileInitAsCopy(dt, offset, &ctx->bc, ctx, node, false);
  4058. // Release the previous temporary variable if it hasn't already been released
  4059. if( prevIsTemp && tempVariables.Exists(prevStackOffset) )
  4060. ReleaseTemporaryVariable(prevStackOffset, &ctx->bc);
  4061. // Push the reference to the temporary variable on the stack
  4062. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  4063. ctx->type.Set(dt);
  4064. ctx->type.isTemporary = true;
  4065. ctx->type.stackOffset = (short)offset;
  4066. ctx->type.isVariable = true;
  4067. ctx->type.isExplicitHandle = isExplicitHandle;
  4068. ctx->type.dataType.MakeReference(IsVariableOnHeap(offset));
  4069. }
  4070. void asCCompiler::CompileReturnStatement(asCScriptNode *rnode, asCByteCode *bc)
  4071. {
  4072. // Get return type and location
  4073. sVariable *v = variables->GetVariable("return");
  4074. // Basic validations
  4075. if( v->type.GetSizeOnStackDWords() > 0 && !rnode->firstChild )
  4076. {
  4077. Error(TXT_MUST_RETURN_VALUE, rnode);
  4078. return;
  4079. }
  4080. else if( v->type.GetSizeOnStackDWords() == 0 && rnode->firstChild )
  4081. {
  4082. Error(TXT_CANT_RETURN_VALUE, rnode);
  4083. return;
  4084. }
  4085. // Compile the expression
  4086. if( rnode->firstChild )
  4087. {
  4088. // Compile the expression
  4089. asCExprContext expr(engine);
  4090. int r = CompileAssignment(rnode->firstChild, &expr);
  4091. if( r < 0 ) return;
  4092. if( v->type.IsReference() )
  4093. {
  4094. // The expression that gives the reference must not use any of the
  4095. // variables that must be destroyed upon exit, because then it means
  4096. // reference will stay alive while the clean-up is done, which could
  4097. // potentially mean that the reference is invalidated by the clean-up.
  4098. //
  4099. // When the function is returning a reference, the clean-up of the
  4100. // variables must be done before the evaluation of the expression.
  4101. //
  4102. // A reference to a global variable, or a class member for class methods
  4103. // should be allowed to be returned.
  4104. if( !(expr.type.dataType.IsReference() ||
  4105. (expr.type.dataType.IsObject() && !expr.type.dataType.IsObjectHandle())) )
  4106. {
  4107. // Clean up the potential deferred parameters
  4108. ProcessDeferredParams(&expr);
  4109. Error(TXT_NOT_VALID_REFERENCE, rnode);
  4110. return;
  4111. }
  4112. // No references to local variables, temporary variables, or parameters
  4113. // are allowed to be returned, since they go out of scope when the function
  4114. // returns. Even reference parameters are disallowed, since it is not possible
  4115. // to know the scope of them. The exception is the 'this' pointer, which
  4116. // is treated by the compiler as a local variable, but isn't really so.
  4117. if( (expr.type.isVariable && !(expr.type.stackOffset == 0 && outFunc->objectType)) || expr.type.isTemporary )
  4118. {
  4119. // Clean up the potential deferred parameters
  4120. ProcessDeferredParams(&expr);
  4121. Error(TXT_CANNOT_RETURN_REF_TO_LOCAL, rnode);
  4122. return;
  4123. }
  4124. // The type must match exactly as we cannot convert
  4125. // the reference without loosing the original value
  4126. if( !(v->type.IsEqualExceptConst(expr.type.dataType) ||
  4127. ((expr.type.dataType.IsObject() || expr.type.dataType.IsFuncdef()) &&
  4128. !expr.type.dataType.IsObjectHandle() &&
  4129. v->type.IsEqualExceptRefAndConst(expr.type.dataType))) ||
  4130. (!v->type.IsReadOnly() && expr.type.dataType.IsReadOnly()) )
  4131. {
  4132. // Clean up the potential deferred parameters
  4133. ProcessDeferredParams(&expr);
  4134. asCString str;
  4135. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, expr.type.dataType.Format(outFunc->nameSpace).AddressOf(), v->type.Format(outFunc->nameSpace).AddressOf());
  4136. Error(str, rnode);
  4137. return;
  4138. }
  4139. // The expression must not have any deferred expressions, because the evaluation
  4140. // of these cannot be done without keeping the reference which is not safe
  4141. if( expr.deferredParams.GetLength() )
  4142. {
  4143. // Clean up the potential deferred parameters
  4144. ProcessDeferredParams(&expr);
  4145. Error(TXT_REF_CANT_BE_RETURNED_DEFERRED_PARAM, rnode);
  4146. return;
  4147. }
  4148. // Make sure the expression isn't using any local variables that
  4149. // will need to be cleaned up before the function completes
  4150. asCArray<int> usedVars;
  4151. expr.bc.GetVarsUsed(usedVars);
  4152. for( asUINT n = 0; n < usedVars.GetLength(); n++ )
  4153. {
  4154. int var = GetVariableSlot(usedVars[n]);
  4155. if( var != -1 )
  4156. {
  4157. asCDataType dt = variableAllocations[var];
  4158. if( dt.IsObject() )
  4159. {
  4160. ProcessDeferredParams(&expr);
  4161. Error(TXT_REF_CANT_BE_RETURNED_LOCAL_VARS, rnode);
  4162. return;
  4163. }
  4164. }
  4165. }
  4166. // Can't return the reference if could point to a local variable
  4167. if( expr.type.isRefToLocal )
  4168. {
  4169. ProcessDeferredParams(&expr);
  4170. Error(TXT_REF_CANT_BE_TO_LOCAL_VAR, rnode);
  4171. return;
  4172. }
  4173. // All objects in the function must be cleaned up before the expression
  4174. // is evaluated, otherwise there is a possibility that the cleanup will
  4175. // invalidate the reference.
  4176. // Destroy the local variables before loading
  4177. // the reference into the register. This will
  4178. // be done before the expression is evaluated.
  4179. DestroyVariables(bc);
  4180. // For primitives the reference is already in the register,
  4181. // but for non-primitives the reference is on the stack so we
  4182. // need to load it into the register
  4183. if( !expr.type.dataType.IsPrimitive() )
  4184. {
  4185. if( !expr.type.dataType.IsObjectHandle() &&
  4186. expr.type.dataType.IsReference() )
  4187. expr.bc.Instr(asBC_RDSPtr);
  4188. expr.bc.Instr(asBC_PopRPtr);
  4189. }
  4190. // There are no temporaries to release so we're done
  4191. }
  4192. else // if( !v->type.IsReference() )
  4193. {
  4194. ProcessPropertyGetAccessor(&expr, rnode);
  4195. // Prepare the value for assignment
  4196. IsVariableInitialized(&expr.type, rnode->firstChild);
  4197. if( v->type.IsPrimitive() )
  4198. {
  4199. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  4200. // Implicitly convert the value to the return type
  4201. ImplicitConversion(&expr, v->type, rnode->firstChild, asIC_IMPLICIT_CONV);
  4202. // Verify that the conversion was successful
  4203. if( expr.type.dataType != v->type )
  4204. {
  4205. asCString str;
  4206. str.Format(TXT_NO_CONVERSION_s_TO_s, expr.type.dataType.Format(outFunc->nameSpace).AddressOf(), v->type.Format(outFunc->nameSpace).AddressOf());
  4207. Error(str, rnode);
  4208. return;
  4209. }
  4210. else
  4211. {
  4212. ConvertToVariable(&expr);
  4213. // Clean up the local variables and process deferred parameters
  4214. DestroyVariables(&expr.bc);
  4215. ProcessDeferredParams(&expr);
  4216. ReleaseTemporaryVariable(expr.type, &expr.bc);
  4217. // Load the variable in the register
  4218. if( v->type.GetSizeOnStackDWords() == 1 )
  4219. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  4220. else
  4221. expr.bc.InstrSHORT(asBC_CpyVtoR8, expr.type.stackOffset);
  4222. }
  4223. }
  4224. else if( v->type.IsObject() || v->type.IsFuncdef() )
  4225. {
  4226. // Value types are returned on the stack, in a location
  4227. // that has been reserved by the calling function.
  4228. if( outFunc->DoesReturnOnStack() )
  4229. {
  4230. // TODO: runtime optimize: If the return type has a constructor that takes the type of the expression,
  4231. // it should be called directly instead of first converting the expression and
  4232. // then copy the value.
  4233. if( !v->type.IsEqualExceptRefAndConst(expr.type.dataType) )
  4234. {
  4235. ImplicitConversion(&expr, v->type, rnode->firstChild, asIC_IMPLICIT_CONV);
  4236. if( !v->type.IsEqualExceptRefAndConst(expr.type.dataType) )
  4237. {
  4238. asCString str;
  4239. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, expr.type.dataType.Format(outFunc->nameSpace).AddressOf(), v->type.Format(outFunc->nameSpace).AddressOf());
  4240. Error(str, rnode->firstChild);
  4241. return;
  4242. }
  4243. }
  4244. int offset = outFunc->objectType ? -AS_PTR_SIZE : 0;
  4245. CompileInitAsCopy(v->type, offset, &expr.bc, &expr, rnode->firstChild, true);
  4246. // Clean up the local variables and process deferred parameters
  4247. DestroyVariables(&expr.bc);
  4248. ProcessDeferredParams(&expr);
  4249. }
  4250. else
  4251. {
  4252. asASSERT( (v->type.GetTypeInfo()->flags & asOBJ_REF) || v->type.IsFuncdef() );
  4253. // Prepare the expression to be loaded into the object
  4254. // register. This will place the reference in local variable
  4255. PrepareArgument(&v->type, &expr, rnode->firstChild, false, 0);
  4256. // Pop the reference to the temporary variable
  4257. expr.bc.Instr(asBC_PopPtr);
  4258. // Clean up the local variables and process deferred parameters
  4259. DestroyVariables(&expr.bc);
  4260. ProcessDeferredParams(&expr);
  4261. // Load the object pointer into the object register
  4262. // LOADOBJ also clears the address in the variable
  4263. expr.bc.InstrSHORT(asBC_LOADOBJ, expr.type.stackOffset);
  4264. // LOADOBJ cleared the address in the variable so the object will not be freed
  4265. // here, but the temporary variable must still be freed so the slot can be reused
  4266. // By releasing without the bytecode we do just that.
  4267. ReleaseTemporaryVariable(expr.type, 0);
  4268. }
  4269. }
  4270. }
  4271. expr.bc.OptimizeLocally(tempVariableOffsets);
  4272. bc->AddCode(&expr.bc);
  4273. }
  4274. else
  4275. {
  4276. // For functions that don't return anything
  4277. // we just detroy the local variables
  4278. DestroyVariables(bc);
  4279. }
  4280. // Jump to the end of the function
  4281. bc->InstrINT(asBC_JMP, 0);
  4282. }
  4283. void asCCompiler::DestroyVariables(asCByteCode *bc)
  4284. {
  4285. // Call destructor on all variables except for the function parameters
  4286. // Put the clean-up in a block to allow exception handler to understand this
  4287. bc->Block(true);
  4288. asCVariableScope *vs = variables;
  4289. while( vs )
  4290. {
  4291. for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- )
  4292. if( vs->variables[n]->stackOffset > 0 )
  4293. CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc);
  4294. vs = vs->parent;
  4295. }
  4296. bc->Block(false);
  4297. }
  4298. void asCCompiler::AddVariableScope(bool isBreakScope, bool isContinueScope)
  4299. {
  4300. variables = asNEW(asCVariableScope)(variables);
  4301. if( variables == 0 )
  4302. {
  4303. // Out of memory
  4304. return;
  4305. }
  4306. variables->isBreakScope = isBreakScope;
  4307. variables->isContinueScope = isContinueScope;
  4308. }
  4309. void asCCompiler::RemoveVariableScope()
  4310. {
  4311. if( variables )
  4312. {
  4313. asCVariableScope *var = variables;
  4314. variables = variables->parent;
  4315. asDELETE(var,asCVariableScope);
  4316. }
  4317. }
  4318. void asCCompiler::Error(const asCString &msg, asCScriptNode *node)
  4319. {
  4320. asCString str;
  4321. int r = 0, c = 0;
  4322. asASSERT( node );
  4323. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  4324. builder->WriteError(script->name, msg, r, c);
  4325. hasCompileErrors = true;
  4326. }
  4327. void asCCompiler::Warning(const asCString &msg, asCScriptNode *node)
  4328. {
  4329. asCString str;
  4330. int r = 0, c = 0;
  4331. asASSERT( node );
  4332. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  4333. builder->WriteWarning(script->name, msg, r, c);
  4334. }
  4335. void asCCompiler::Information(const asCString &msg, asCScriptNode *node)
  4336. {
  4337. asCString str;
  4338. int r = 0, c = 0;
  4339. asASSERT( node );
  4340. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  4341. builder->WriteInfo(script->name, msg, r, c, false);
  4342. }
  4343. void asCCompiler::PrintMatchingFuncs(asCArray<int> &funcs, asCScriptNode *node, asCObjectType *inType)
  4344. {
  4345. int r = 0, c = 0;
  4346. asASSERT( node );
  4347. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  4348. for( unsigned int n = 0; n < funcs.GetLength(); n++ )
  4349. {
  4350. asCScriptFunction *func = builder->GetFunctionDescription(funcs[n]);
  4351. if( inType && func->funcType == asFUNC_VIRTUAL )
  4352. func = inType->virtualFunctionTable[func->vfTableIdx];
  4353. builder->WriteInfo(script->name, func->GetDeclaration(true, false, true), r, c, false);
  4354. }
  4355. }
  4356. int asCCompiler::AllocateVariableNotIn(const asCDataType &type, bool isTemporary, bool forceOnHeap, asCExprContext *ctx)
  4357. {
  4358. int l = int(reservedVariables.GetLength());
  4359. ctx->bc.GetVarsUsed(reservedVariables);
  4360. int var = AllocateVariable(type, isTemporary, forceOnHeap);
  4361. reservedVariables.SetLength(l);
  4362. return var;
  4363. }
  4364. int asCCompiler::AllocateVariable(const asCDataType &type, bool isTemporary, bool forceOnHeap, bool asReference)
  4365. {
  4366. asCDataType t(type);
  4367. t.MakeReference(asReference);
  4368. if( t.IsPrimitive() && t.GetSizeOnStackDWords() == 1 )
  4369. t.SetTokenType(ttInt);
  4370. if( t.IsPrimitive() && t.GetSizeOnStackDWords() == 2 )
  4371. t.SetTokenType(ttDouble);
  4372. // Only null handles have the token type unrecognized token
  4373. asASSERT( t.IsObjectHandle() || t.GetTokenType() != ttUnrecognizedToken );
  4374. bool isOnHeap = true;
  4375. if( t.IsPrimitive() ||
  4376. (t.GetTypeInfo() && (t.GetTypeInfo()->GetFlags() & asOBJ_VALUE) && !forceOnHeap) )
  4377. {
  4378. // Primitives and value types (unless overridden) are allocated on the stack
  4379. isOnHeap = false;
  4380. }
  4381. // Find a free location with the same type
  4382. for( asUINT n = 0; n < freeVariables.GetLength(); n++ )
  4383. {
  4384. int slot = freeVariables[n];
  4385. if( variableAllocations[slot].IsEqualExceptConst(t) &&
  4386. variableIsTemporary[slot] == isTemporary &&
  4387. variableIsOnHeap[slot] == isOnHeap )
  4388. {
  4389. // We can't return by slot, must count variable sizes
  4390. int offset = GetVariableOffset(slot);
  4391. // Verify that it is not in the list of reserved variables
  4392. bool isUsed = false;
  4393. if( reservedVariables.GetLength() )
  4394. isUsed = reservedVariables.Exists(offset);
  4395. if( !isUsed )
  4396. {
  4397. if( n != freeVariables.GetLength() - 1 )
  4398. freeVariables[n] = freeVariables.PopLast();
  4399. else
  4400. freeVariables.PopLast();
  4401. if( isTemporary )
  4402. tempVariables.PushLast(offset);
  4403. return offset;
  4404. }
  4405. }
  4406. }
  4407. variableAllocations.PushLast(t);
  4408. variableIsTemporary.PushLast(isTemporary);
  4409. variableIsOnHeap.PushLast(isOnHeap);
  4410. int offset = GetVariableOffset((int)variableAllocations.GetLength()-1);
  4411. if( isTemporary )
  4412. {
  4413. // Add offset to the currently allocated temporary variables
  4414. tempVariables.PushLast(offset);
  4415. // Add offset to all known offsets to temporary variables, whether allocated or not
  4416. tempVariableOffsets.PushLast(offset);
  4417. }
  4418. return offset;
  4419. }
  4420. int asCCompiler::GetVariableOffset(int varIndex)
  4421. {
  4422. // Return offset to the last dword on the stack
  4423. // Start at 1 as offset 0 is reserved for the this pointer (or first argument for global functions)
  4424. int varOffset = 1;
  4425. // Skip lower variables
  4426. for( int n = 0; n < varIndex; n++ )
  4427. {
  4428. if( !variableIsOnHeap[n] && variableAllocations[n].IsObject() )
  4429. varOffset += variableAllocations[n].GetSizeInMemoryDWords();
  4430. else
  4431. varOffset += variableAllocations[n].GetSizeOnStackDWords();
  4432. }
  4433. if( varIndex < (int)variableAllocations.GetLength() )
  4434. {
  4435. // For variables larger than 1 dword the returned offset should be to the last dword
  4436. int size;
  4437. if( !variableIsOnHeap[varIndex] && variableAllocations[varIndex].IsObject() )
  4438. size = variableAllocations[varIndex].GetSizeInMemoryDWords();
  4439. else
  4440. size = variableAllocations[varIndex].GetSizeOnStackDWords();
  4441. if( size > 1 )
  4442. varOffset += size-1;
  4443. }
  4444. return varOffset;
  4445. }
  4446. int asCCompiler::GetVariableSlot(int offset)
  4447. {
  4448. int varOffset = 1;
  4449. for( asUINT n = 0; n < variableAllocations.GetLength(); n++ )
  4450. {
  4451. if( !variableIsOnHeap[n] && variableAllocations[n].IsObject() )
  4452. varOffset += -1 + variableAllocations[n].GetSizeInMemoryDWords();
  4453. else
  4454. varOffset += -1 + variableAllocations[n].GetSizeOnStackDWords();
  4455. if( varOffset == offset )
  4456. return n;
  4457. varOffset++;
  4458. }
  4459. return -1;
  4460. }
  4461. bool asCCompiler::IsVariableOnHeap(int offset)
  4462. {
  4463. int varSlot = GetVariableSlot(offset);
  4464. if( varSlot < 0 )
  4465. {
  4466. // This happens for function arguments that are considered as on the heap
  4467. return true;
  4468. }
  4469. return variableIsOnHeap[varSlot];
  4470. }
  4471. void asCCompiler::DeallocateVariable(int offset)
  4472. {
  4473. // Remove temporary variable
  4474. int n;
  4475. for( n = 0; n < (int)tempVariables.GetLength(); n++ )
  4476. {
  4477. if( offset == tempVariables[n] )
  4478. {
  4479. if( n == (int)tempVariables.GetLength()-1 )
  4480. tempVariables.PopLast();
  4481. else
  4482. tempVariables[n] = tempVariables.PopLast();
  4483. break;
  4484. }
  4485. }
  4486. // Mark the variable slot available for new allocations
  4487. n = GetVariableSlot(offset);
  4488. if( n != -1 )
  4489. {
  4490. freeVariables.PushLast(n);
  4491. return;
  4492. }
  4493. // We might get here if the variable was implicitly declared
  4494. // because it was used before a formal declaration, in this case
  4495. // the offset is 0x7FFF
  4496. asASSERT(offset == 0x7FFF);
  4497. }
  4498. void asCCompiler::ReleaseTemporaryVariable(asCExprValue &t, asCByteCode *bc)
  4499. {
  4500. if( t.isTemporary )
  4501. {
  4502. ReleaseTemporaryVariable(t.stackOffset, bc);
  4503. t.isTemporary = false;
  4504. }
  4505. }
  4506. void asCCompiler::ReleaseTemporaryVariable(int offset, asCByteCode *bc)
  4507. {
  4508. asASSERT( tempVariables.Exists(offset) );
  4509. if( bc )
  4510. {
  4511. // We need to call the destructor on the true variable type
  4512. int n = GetVariableSlot(offset);
  4513. asASSERT( n >= 0 );
  4514. if( n >= 0 )
  4515. {
  4516. asCDataType dt = variableAllocations[n];
  4517. bool isOnHeap = variableIsOnHeap[n];
  4518. // Call destructor
  4519. CallDestructor(dt, offset, isOnHeap, bc);
  4520. }
  4521. }
  4522. DeallocateVariable(offset);
  4523. }
  4524. void asCCompiler::Dereference(asCExprContext *ctx, bool generateCode)
  4525. {
  4526. if( ctx->type.dataType.IsReference() )
  4527. {
  4528. if( ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef() )
  4529. {
  4530. ctx->type.dataType.MakeReference(false);
  4531. if( generateCode )
  4532. ctx->bc.Instr(asBC_RDSPtr);
  4533. }
  4534. else
  4535. {
  4536. // This should never happen as primitives are treated differently
  4537. asASSERT(false);
  4538. }
  4539. }
  4540. }
  4541. bool asCCompiler::IsVariableInitialized(asCExprValue *type, asCScriptNode *node)
  4542. {
  4543. // No need to check if there is no variable scope
  4544. if( variables == 0 ) return true;
  4545. // Temporary variables are assumed to be initialized
  4546. if( type->isTemporary ) return true;
  4547. // Verify that it is a variable
  4548. if( !type->isVariable ) return true;
  4549. // Find the variable
  4550. sVariable *v = variables->GetVariableByOffset(type->stackOffset);
  4551. // The variable isn't found if it is a constant, in which case it is guaranteed to be initialized
  4552. if( v == 0 ) return true;
  4553. if( v->isInitialized ) return true;
  4554. // Complex types don't need this test
  4555. if( v->type.IsObject() || v->type.IsFuncdef() ) return true;
  4556. // Mark as initialized so that the user will not be bothered again
  4557. v->isInitialized = true;
  4558. // Write warning
  4559. asCString str;
  4560. str.Format(TXT_s_NOT_INITIALIZED, (const char *)v->name.AddressOf());
  4561. Warning(str, node);
  4562. return false;
  4563. }
  4564. void asCCompiler::PrepareOperand(asCExprContext *ctx, asCScriptNode *node)
  4565. {
  4566. // Check if the variable is initialized (if it indeed is a variable)
  4567. IsVariableInitialized(&ctx->type, node);
  4568. asCDataType to = ctx->type.dataType;
  4569. to.MakeReference(false);
  4570. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV);
  4571. ProcessDeferredParams(ctx);
  4572. }
  4573. void asCCompiler::PrepareForAssignment(asCDataType *lvalue, asCExprContext *rctx, asCScriptNode *node, bool toTemporary, asCExprContext *lvalueExpr)
  4574. {
  4575. // Reserve the temporary variables used in the lvalue expression so they won't end up being used by the rvalue too
  4576. int l = int(reservedVariables.GetLength());
  4577. if( lvalueExpr ) lvalueExpr->bc.GetVarsUsed(reservedVariables);
  4578. ProcessPropertyGetAccessor(rctx, node);
  4579. // Make sure the rvalue is initialized if it is a variable
  4580. IsVariableInitialized(&rctx->type, node);
  4581. if( lvalue->IsPrimitive() )
  4582. {
  4583. if( rctx->type.dataType.IsPrimitive() )
  4584. {
  4585. if( rctx->type.dataType.IsReference() )
  4586. {
  4587. // Cannot do implicit conversion of references so we first convert the reference to a variable
  4588. ConvertToVariableNotIn(rctx, lvalueExpr);
  4589. }
  4590. }
  4591. // Implicitly convert the value to the right type
  4592. ImplicitConversion(rctx, *lvalue, node, asIC_IMPLICIT_CONV);
  4593. // Check data type
  4594. if( !lvalue->IsEqualExceptRefAndConst(rctx->type.dataType) )
  4595. {
  4596. asCString str;
  4597. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lvalue->Format(outFunc->nameSpace).AddressOf());
  4598. Error(str, node);
  4599. rctx->type.SetDummy();
  4600. }
  4601. // Make sure the rvalue is a variable
  4602. if( !rctx->type.isVariable )
  4603. ConvertToVariableNotIn(rctx, lvalueExpr);
  4604. }
  4605. else
  4606. {
  4607. asCDataType to = *lvalue;
  4608. to.MakeReference(false);
  4609. // TODO: ImplicitConversion should know to do this by itself
  4610. // First convert to a handle which will do a reference cast
  4611. if( !lvalue->IsObjectHandle() &&
  4612. (lvalue->GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) )
  4613. to.MakeHandle(true);
  4614. // Don't allow the implicit conversion to create an object
  4615. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true, !toTemporary);
  4616. if( !lvalue->IsObjectHandle() &&
  4617. (lvalue->GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) )
  4618. {
  4619. // Then convert to a reference, which will validate the handle
  4620. to.MakeHandle(false);
  4621. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true, !toTemporary);
  4622. }
  4623. // Check data type
  4624. if( !lvalue->IsEqualExceptRefAndConst(rctx->type.dataType) )
  4625. {
  4626. asCString str;
  4627. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lvalue->Format(outFunc->nameSpace).AddressOf());
  4628. Error(str, node);
  4629. }
  4630. else
  4631. {
  4632. // If the assignment will be made with the copy behaviour then the rvalue must not be a reference
  4633. asASSERT(!lvalue->IsObject() || !rctx->type.dataType.IsReference());
  4634. }
  4635. }
  4636. // Unreserve variables
  4637. reservedVariables.SetLength(l);
  4638. }
  4639. bool asCCompiler::IsLValue(asCExprValue &type)
  4640. {
  4641. if( !type.isLValue ) return false;
  4642. if( type.dataType.IsReadOnly() ) return false;
  4643. if( !type.dataType.IsObject() && !type.isVariable && !type.dataType.IsReference() ) return false;
  4644. return true;
  4645. }
  4646. int asCCompiler::PerformAssignment(asCExprValue *lvalue, asCExprValue *rvalue, asCByteCode *bc, asCScriptNode *node)
  4647. {
  4648. if( lvalue->dataType.IsReadOnly() )
  4649. {
  4650. Error(TXT_REF_IS_READ_ONLY, node);
  4651. return -1;
  4652. }
  4653. if( lvalue->dataType.IsPrimitive() )
  4654. {
  4655. if( lvalue->isVariable )
  4656. {
  4657. // Copy the value between the variables directly
  4658. if( lvalue->dataType.GetSizeInMemoryDWords() == 1 )
  4659. bc->InstrW_W(asBC_CpyVtoV4, lvalue->stackOffset, rvalue->stackOffset);
  4660. else
  4661. bc->InstrW_W(asBC_CpyVtoV8, lvalue->stackOffset, rvalue->stackOffset);
  4662. // Mark variable as initialized
  4663. sVariable *v = variables->GetVariableByOffset(lvalue->stackOffset);
  4664. if( v ) v->isInitialized = true;
  4665. }
  4666. else if( lvalue->dataType.IsReference() )
  4667. {
  4668. // Copy the value of the variable to the reference in the register
  4669. int s = lvalue->dataType.GetSizeInMemoryBytes();
  4670. if( s == 1 )
  4671. bc->InstrSHORT(asBC_WRTV1, rvalue->stackOffset);
  4672. else if( s == 2 )
  4673. bc->InstrSHORT(asBC_WRTV2, rvalue->stackOffset);
  4674. else if( s == 4 )
  4675. bc->InstrSHORT(asBC_WRTV4, rvalue->stackOffset);
  4676. else if( s == 8 )
  4677. bc->InstrSHORT(asBC_WRTV8, rvalue->stackOffset);
  4678. }
  4679. else
  4680. {
  4681. Error(TXT_NOT_VALID_LVALUE, node);
  4682. return -1;
  4683. }
  4684. }
  4685. else if( !lvalue->isExplicitHandle )
  4686. {
  4687. asCExprContext ctx(engine);
  4688. ctx.type = *lvalue;
  4689. Dereference(&ctx, true);
  4690. *lvalue = ctx.type;
  4691. bc->AddCode(&ctx.bc);
  4692. asSTypeBehaviour *beh = lvalue->dataType.GetBehaviour();
  4693. if( beh && beh->copy && beh->copy != engine->scriptTypeBehaviours.beh.copy )
  4694. {
  4695. asCExprContext res(engine);
  4696. PerformFunctionCall(beh->copy, &res, false, 0, CastToObjectType(lvalue->dataType.GetTypeInfo()));
  4697. bc->AddCode(&res.bc);
  4698. *lvalue = res.type;
  4699. }
  4700. else if( beh && beh->copy == engine->scriptTypeBehaviours.beh.copy )
  4701. {
  4702. // Call the default copy operator for script classes
  4703. // This is done differently because the default copy operator
  4704. // is registered as returning int&, but in reality it returns
  4705. // a reference to the object.
  4706. // TODO: Avoid this special case by implementing a copystub for
  4707. // script classes that uses the default copy operator
  4708. bc->Call(asBC_CALLSYS, beh->copy, 2*AS_PTR_SIZE);
  4709. bc->Instr(asBC_PshRPtr);
  4710. }
  4711. else
  4712. {
  4713. // Default copy operator
  4714. if( lvalue->dataType.GetSizeInMemoryDWords() == 0 ||
  4715. !(lvalue->dataType.GetTypeInfo()->flags & asOBJ_POD) )
  4716. {
  4717. asCString msg;
  4718. msg.Format(TXT_NO_DEFAULT_COPY_OP_FOR_s, lvalue->dataType.GetTypeInfo()->name.AddressOf());
  4719. Error(msg, node);
  4720. return -1;
  4721. }
  4722. // Copy larger data types from a reference
  4723. // TODO: runtime optimize: COPY should pop both arguments and store the reference in the register.
  4724. bc->InstrSHORT_DW(asBC_COPY, (short)lvalue->dataType.GetSizeInMemoryDWords(), engine->GetTypeIdFromDataType(lvalue->dataType));
  4725. }
  4726. }
  4727. else
  4728. {
  4729. // TODO: The object handle can be stored in a variable as well
  4730. if( !lvalue->dataType.IsReference() )
  4731. {
  4732. Error(TXT_NOT_VALID_REFERENCE, node);
  4733. return -1;
  4734. }
  4735. if( lvalue->dataType.IsFuncdef() )
  4736. bc->InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  4737. else
  4738. bc->InstrPTR(asBC_REFCPY, lvalue->dataType.GetTypeInfo());
  4739. // Mark variable as initialized
  4740. if( variables )
  4741. {
  4742. sVariable *v = variables->GetVariableByOffset(lvalue->stackOffset);
  4743. if( v ) v->isInitialized = true;
  4744. }
  4745. }
  4746. return 0;
  4747. }
  4748. bool asCCompiler::CompileRefCast(asCExprContext *ctx, const asCDataType &to, bool isExplicit, asCScriptNode *node, bool generateCode)
  4749. {
  4750. bool conversionDone = false;
  4751. asCArray<int> ops;
  4752. // A ref cast must not remove the constness
  4753. bool isConst = ctx->type.dataType.IsObjectConst();
  4754. // Find a suitable opCast or opImplCast method
  4755. asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  4756. for( asUINT n = 0; ot && n < ot->methods.GetLength(); n++ )
  4757. {
  4758. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  4759. if( (isExplicit && func->name == "opCast") ||
  4760. func->name == "opImplCast" )
  4761. {
  4762. // Is the operator for the output type?
  4763. if( func->returnType.GetTypeInfo() != to.GetTypeInfo() )
  4764. continue;
  4765. // Can't call a non-const function on a const object
  4766. if( isConst && !func->IsReadOnly() )
  4767. continue;
  4768. ops.PushLast(func->id);
  4769. }
  4770. }
  4771. // Filter the list by constness to remove const methods if there are matching non-const methods
  4772. FilterConst(ops, !isConst);
  4773. // If there is multiple matches, then pick the most appropriate one
  4774. if (ops.GetLength() > 1)
  4775. {
  4776. // This should only happen if an explicit cast is compiled
  4777. // and the type has both the opCast and opImplCast
  4778. asASSERT(isExplicit);
  4779. asASSERT(ops.GetLength() == 2);
  4780. for (asUINT n = 0; n < ops.GetLength(); n++)
  4781. {
  4782. asCScriptFunction *func = engine->scriptFunctions[ops[n]];
  4783. if (func->name == "opImplCast")
  4784. {
  4785. ops.RemoveIndex(n);
  4786. n--;
  4787. }
  4788. }
  4789. }
  4790. // Should only have one behaviour for each output type
  4791. if( ops.GetLength() == 1 )
  4792. {
  4793. conversionDone = true;
  4794. if( generateCode )
  4795. {
  4796. // TODO: runtime optimize: Instead of producing bytecode for checking if the handle is
  4797. // null, we can create a special CALLSYS instruction that checks
  4798. // if the object pointer is null and if so sets the object register
  4799. // to null directly without executing the function.
  4800. //
  4801. // Alternatively I could force the ref cast behaviours be global
  4802. // functions with 1 parameter, even though they should still be
  4803. // registered with RegisterObjectBehaviour()
  4804. if( (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_NOHANDLE))
  4805. {
  4806. // Add code to avoid calling the cast behaviour if the handle is already null,
  4807. // because that will raise a null pointer exception due to the cast behaviour
  4808. // being a class method, and the this pointer cannot be null.
  4809. if (!ctx->type.isVariable)
  4810. {
  4811. Dereference(ctx, true);
  4812. ConvertToVariable(ctx);
  4813. }
  4814. // The reference on the stack will not be used
  4815. ctx->bc.Instr(asBC_PopPtr);
  4816. // TODO: runtime optimize: should have immediate comparison for null pointer
  4817. int offset = AllocateVariable(asCDataType::CreateNullHandle(), true);
  4818. // 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)
  4819. ctx->bc.InstrSHORT(asBC_ClrVPtr, (asWORD)offset);
  4820. ctx->bc.InstrW_W(asBC_CmpPtr, ctx->type.stackOffset, offset);
  4821. DeallocateVariable(offset);
  4822. int afterLabel = nextLabel++;
  4823. ctx->bc.InstrDWORD(asBC_JZ, afterLabel);
  4824. // Call the cast operator
  4825. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  4826. ctx->bc.Instr(asBC_RDSPtr);
  4827. ctx->type.dataType.MakeReference(false);
  4828. asCArray<asCExprContext *> args;
  4829. MakeFunctionCall(ctx, ops[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
  4830. ctx->bc.Instr(asBC_PopPtr);
  4831. int endLabel = nextLabel++;
  4832. ctx->bc.InstrINT(asBC_JMP, endLabel);
  4833. ctx->bc.Label((short)afterLabel);
  4834. // Make a NULL pointer
  4835. ctx->bc.InstrSHORT(asBC_ClrVPtr, ctx->type.stackOffset);
  4836. ctx->bc.Label((short)endLabel);
  4837. // Push the reference to the handle on the stack
  4838. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  4839. }
  4840. else
  4841. {
  4842. // Value types cannot be null, so there is no need to check for this.
  4843. // Likewise for reference types that are registered with asOBJ_NOHANDLE
  4844. // as those are only expected as registered global properties that cannot
  4845. // be modified anyway.
  4846. // Call the cast operator
  4847. asCArray<asCExprContext *> args;
  4848. MakeFunctionCall(ctx, ops[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
  4849. }
  4850. }
  4851. else
  4852. {
  4853. asCScriptFunction *func = engine->scriptFunctions[ops[0]];
  4854. ctx->type.Set(func->returnType);
  4855. }
  4856. }
  4857. else if( ops.GetLength() == 0 && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) && to.IsObjectHandle() )
  4858. {
  4859. // Check for the generic ref cast method: void opCast(?&out)
  4860. // This option only works if the expected type is a handle
  4861. for( asUINT n = 0; ot && n < ot->methods.GetLength(); n++ )
  4862. {
  4863. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  4864. if( (isExplicit && func->name == "opCast") ||
  4865. func->name == "opImplCast" )
  4866. {
  4867. // Does the operator take the ?&out parameter?
  4868. if( func->returnType.GetTokenType() != ttVoid ||
  4869. func->parameterTypes.GetLength() != 1 ||
  4870. func->parameterTypes[0].GetTokenType() != ttQuestion ||
  4871. func->inOutFlags[0] != asTM_OUTREF )
  4872. continue;
  4873. ops.PushLast(func->id);
  4874. }
  4875. }
  4876. // Filter the list by constness to remove const methods if there are matching non-const methods
  4877. FilterConst(ops, !isConst);
  4878. // If there is multiple matches, then pick the most appropriate one
  4879. if (ops.GetLength() > 1)
  4880. {
  4881. // This should only happen if an explicit cast is compiled
  4882. // and the type has both the opCast and opImplCast
  4883. asASSERT(isExplicit);
  4884. asASSERT(ops.GetLength() == 2);
  4885. for (asUINT n = 0; n < ops.GetLength(); n++)
  4886. {
  4887. asCScriptFunction *func = engine->scriptFunctions[ops[n]];
  4888. if (func->name == "opImplCast")
  4889. {
  4890. ops.RemoveIndex(n);
  4891. n--;
  4892. }
  4893. }
  4894. }
  4895. if( ops.GetLength() == 1 )
  4896. {
  4897. conversionDone = true;
  4898. if( generateCode )
  4899. {
  4900. int afterLabel = 0;
  4901. bool doNullCheck = false;
  4902. bool releaseTempVariable = false;
  4903. asCExprContext tmp(engine);
  4904. if ((ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_NOHANDLE))
  4905. {
  4906. tmp.bc.AddCode(&ctx->bc);
  4907. tmp.Merge(ctx);
  4908. // Add code to avoid calling the cast behaviour if the handle is already null,
  4909. // because that will raise a null pointer exception due to the cast behaviour
  4910. // being a class method, and the this pointer cannot be null.
  4911. doNullCheck = true;
  4912. if (!ctx->type.isVariable)
  4913. {
  4914. Dereference(&tmp, true);
  4915. ConvertToVariable(&tmp);
  4916. releaseTempVariable = true;
  4917. }
  4918. // The reference on the stack will not be used
  4919. tmp.bc.Instr(asBC_PopPtr);
  4920. // TODO: runtime optimize: should have immediate comparison for null pointer
  4921. int offset = AllocateVariable(asCDataType::CreateNullHandle(), true);
  4922. // 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)
  4923. tmp.bc.InstrSHORT(asBC_ClrVPtr, (asWORD)offset);
  4924. tmp.bc.InstrW_W(asBC_CmpPtr, tmp.type.stackOffset, offset);
  4925. DeallocateVariable(offset);
  4926. afterLabel = nextLabel++;
  4927. tmp.bc.InstrDWORD(asBC_JZ, afterLabel);
  4928. // Place the object pointer on the stack
  4929. ctx->bc.InstrSHORT(asBC_PSF, (short)tmp.type.stackOffset);
  4930. }
  4931. // Allocate a temporary variable of the requested handle type
  4932. int stackOffset = AllocateVariableNotIn(to, true, false, ctx);
  4933. // Pass the reference of that variable to the function as output parameter
  4934. asCDataType toRef(to);
  4935. toRef.MakeReference(true);
  4936. asCArray<asCExprContext *> args;
  4937. asCExprContext arg(engine);
  4938. arg.bc.InstrSHORT(asBC_PSF, (short)stackOffset);
  4939. // Don't mark the variable as temporary, so it won't be freed too early
  4940. arg.type.SetVariable(toRef, stackOffset, false);
  4941. arg.type.isLValue = true;
  4942. arg.type.isExplicitHandle = true;
  4943. args.PushLast(&arg);
  4944. // Call the behaviour method
  4945. MakeFunctionCall(ctx, ops[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
  4946. if (doNullCheck)
  4947. {
  4948. // Add the call after the null check
  4949. tmp.bc.AddCode(&ctx->bc);
  4950. ctx->bc.AddCode(&tmp.bc);
  4951. int endLabel = nextLabel++;
  4952. ctx->bc.InstrINT(asBC_JMP, endLabel);
  4953. ctx->bc.Label((short)afterLabel);
  4954. // Make a NULL pointer
  4955. ctx->bc.InstrSHORT(asBC_ClrVPtr, (short)stackOffset);
  4956. ctx->bc.Label((short)endLabel);
  4957. }
  4958. // If a temporary variable was allocated in the tmp to convert
  4959. // the input expression to a variable, it must be released here
  4960. if (releaseTempVariable && tmp.type.isTemporary)
  4961. ReleaseTemporaryVariable(tmp.type.stackOffset, &ctx->bc);
  4962. // Use the reference to the variable as the result of the expression
  4963. // Now we can mark the variable as temporary
  4964. ctx->type.SetVariable(toRef, stackOffset, true);
  4965. ctx->bc.InstrSHORT(asBC_PSF, (short)stackOffset);
  4966. }
  4967. else
  4968. {
  4969. // All casts are legal
  4970. ctx->type.Set(to);
  4971. }
  4972. }
  4973. }
  4974. // If the script object didn't implement a matching opCast or opImplCast
  4975. // then check if the desired type is part of the hierarchy
  4976. if( !conversionDone && (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) )
  4977. {
  4978. // We need it to be a reference
  4979. if( !ctx->type.dataType.IsReference() )
  4980. {
  4981. asCDataType toRef = ctx->type.dataType;
  4982. toRef.MakeReference(true);
  4983. ImplicitConversion(ctx, toRef, 0, isExplicit ? asIC_EXPLICIT_REF_CAST : asIC_IMPLICIT_CONV, generateCode);
  4984. }
  4985. if( isExplicit )
  4986. {
  4987. // Allow dynamic cast between object handles (only for script objects).
  4988. // At run time this may result in a null handle,
  4989. // which when used will throw an exception
  4990. conversionDone = true;
  4991. if( generateCode )
  4992. {
  4993. ctx->bc.InstrDWORD(asBC_Cast, engine->GetTypeIdFromDataType(to));
  4994. // Allocate a temporary variable for the returned object
  4995. int returnOffset = AllocateVariable(to, true);
  4996. // Move the pointer from the object register to the temporary variable
  4997. ctx->bc.InstrSHORT(asBC_STOREOBJ, (short)returnOffset);
  4998. ctx->bc.InstrSHORT(asBC_PSF, (short)returnOffset);
  4999. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5000. ctx->type.SetVariable(to, returnOffset, true);
  5001. ctx->type.dataType.MakeReference(true);
  5002. }
  5003. else
  5004. {
  5005. ctx->type.dataType = to;
  5006. ctx->type.dataType.MakeReference(true);
  5007. }
  5008. }
  5009. else
  5010. {
  5011. if( CastToObjectType(ctx->type.dataType.GetTypeInfo())->DerivesFrom(to.GetTypeInfo()) )
  5012. {
  5013. conversionDone = true;
  5014. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5015. }
  5016. }
  5017. // A ref cast must not remove the constness
  5018. if( isConst )
  5019. ctx->type.dataType.MakeHandleToConst(true);
  5020. }
  5021. return conversionDone;
  5022. }
  5023. asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asCExprContext *ctx, const asCDataType &toOrig, asCScriptNode *node, EImplicitConv convType, bool generateCode)
  5024. {
  5025. asCDataType to = toOrig;
  5026. to.MakeReference(false);
  5027. asASSERT( !ctx->type.dataType.IsReference() );
  5028. // Maybe no conversion is needed
  5029. if( to.IsEqualExceptConst(ctx->type.dataType) )
  5030. {
  5031. // A primitive is const or not
  5032. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  5033. return asCC_NO_CONV;
  5034. }
  5035. // Is the conversion an ambiguous enum value?
  5036. if( ctx->enumValue != "" )
  5037. {
  5038. if( to.IsEnumType() )
  5039. {
  5040. // Attempt to resolve an ambiguous enum value
  5041. asCDataType out;
  5042. asDWORD value;
  5043. if( builder->GetEnumValueFromType(CastToEnumType(to.GetTypeInfo()), ctx->enumValue.AddressOf(), out, value) )
  5044. {
  5045. ctx->type.SetConstantDW(out, value);
  5046. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  5047. // Reset the enum value since we no longer need it
  5048. ctx->enumValue = "";
  5049. // It wasn't really a conversion. The compiler just resolved the ambiguity (or not)
  5050. return asCC_NO_CONV;
  5051. }
  5052. }
  5053. // The enum value is ambiguous
  5054. if( node && generateCode )
  5055. Error(TXT_FOUND_MULTIPLE_ENUM_VALUES, node);
  5056. // Set a dummy to allow the compiler to try to continue the conversion
  5057. ctx->type.SetDummy();
  5058. }
  5059. // Determine the cost of this conversion
  5060. asUINT cost = asCC_NO_CONV;
  5061. if( (to.IsIntegerType() || to.IsUnsignedType()) && (ctx->type.dataType.IsFloatType() || ctx->type.dataType.IsDoubleType()) )
  5062. cost = asCC_INT_FLOAT_CONV;
  5063. else if ((to.IsFloatType() || to.IsDoubleType()) && (ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType()))
  5064. cost = asCC_INT_FLOAT_CONV;
  5065. else if (ctx->type.dataType.IsEnumType() && to.IsIntegerType() && to.GetSizeInMemoryBytes() == ctx->type.dataType.GetSizeInMemoryBytes() )
  5066. cost = asCC_ENUM_SAME_SIZE_CONV;
  5067. else if (ctx->type.dataType.IsEnumType() && to.IsIntegerType() && to.GetSizeInMemoryBytes() != ctx->type.dataType.GetSizeInMemoryBytes())
  5068. cost = asCC_ENUM_DIFF_SIZE_CONV;
  5069. else if( to.IsUnsignedType() && ctx->type.dataType.IsIntegerType() )
  5070. cost = asCC_SIGNED_CONV;
  5071. else if( to.IsIntegerType() && ctx->type.dataType.IsUnsignedType() )
  5072. cost = asCC_SIGNED_CONV;
  5073. else if( to.GetSizeInMemoryBytes() != ctx->type.dataType.GetSizeInMemoryBytes() )
  5074. cost = asCC_PRIMITIVE_SIZE_CONV;
  5075. // Start by implicitly converting constant values
  5076. if( ctx->type.isConstant )
  5077. {
  5078. ImplicitConversionConstant(ctx, to, node, convType);
  5079. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  5080. return cost;
  5081. }
  5082. // Allow implicit conversion between numbers
  5083. if( generateCode )
  5084. {
  5085. // When generating the code the decision has already been made, so we don't bother determining the cost
  5086. // Convert smaller types to 32bit first
  5087. int s = ctx->type.dataType.GetSizeInMemoryBytes();
  5088. if( s < 4 )
  5089. {
  5090. ConvertToTempVariable(ctx);
  5091. if( ctx->type.dataType.IsIntegerType() )
  5092. {
  5093. if( s == 1 )
  5094. ctx->bc.InstrSHORT(asBC_sbTOi, ctx->type.stackOffset);
  5095. else if( s == 2 )
  5096. ctx->bc.InstrSHORT(asBC_swTOi, ctx->type.stackOffset);
  5097. ctx->type.dataType.SetTokenType(ttInt);
  5098. }
  5099. else if( ctx->type.dataType.IsUnsignedType() )
  5100. {
  5101. if( s == 1 )
  5102. ctx->bc.InstrSHORT(asBC_ubTOi, ctx->type.stackOffset);
  5103. else if( s == 2 )
  5104. ctx->bc.InstrSHORT(asBC_uwTOi, ctx->type.stackOffset);
  5105. ctx->type.dataType.SetTokenType(ttUInt);
  5106. }
  5107. }
  5108. if( (to.IsIntegerType() && to.GetSizeInMemoryDWords() == 1 && !to.IsEnumType()) ||
  5109. (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST) )
  5110. {
  5111. if( ctx->type.dataType.IsIntegerType() ||
  5112. ctx->type.dataType.IsUnsignedType() )
  5113. {
  5114. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  5115. {
  5116. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5117. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5118. }
  5119. else
  5120. {
  5121. ConvertToTempVariable(ctx);
  5122. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5123. int offset = AllocateVariable(to, true);
  5124. ctx->bc.InstrW_W(asBC_i64TOi, offset, ctx->type.stackOffset);
  5125. ctx->type.SetVariable(to, offset, true);
  5126. }
  5127. }
  5128. else if( ctx->type.dataType.IsFloatType() )
  5129. {
  5130. ConvertToTempVariable(ctx);
  5131. ctx->bc.InstrSHORT(asBC_fTOi, ctx->type.stackOffset);
  5132. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5133. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5134. if( convType != asIC_EXPLICIT_VAL_CAST )
  5135. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  5136. }
  5137. else if( ctx->type.dataType.IsDoubleType() )
  5138. {
  5139. ConvertToTempVariable(ctx);
  5140. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5141. int offset = AllocateVariable(to, true);
  5142. ctx->bc.InstrW_W(asBC_dTOi, offset, ctx->type.stackOffset);
  5143. ctx->type.SetVariable(to, offset, true);
  5144. if( convType != asIC_EXPLICIT_VAL_CAST )
  5145. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  5146. }
  5147. // Convert to smaller integer if necessary
  5148. s = to.GetSizeInMemoryBytes();
  5149. if( s < 4 )
  5150. {
  5151. ConvertToTempVariable(ctx);
  5152. if( s == 1 )
  5153. ctx->bc.InstrSHORT(asBC_iTOb, ctx->type.stackOffset);
  5154. else if( s == 2 )
  5155. ctx->bc.InstrSHORT(asBC_iTOw, ctx->type.stackOffset);
  5156. }
  5157. }
  5158. else if( to.IsIntegerType() && to.GetSizeInMemoryDWords() == 2 )
  5159. {
  5160. if( ctx->type.dataType.IsIntegerType() ||
  5161. ctx->type.dataType.IsUnsignedType() )
  5162. {
  5163. if( ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  5164. {
  5165. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5166. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5167. }
  5168. else
  5169. {
  5170. ConvertToTempVariable(ctx);
  5171. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5172. int offset = AllocateVariable(to, true);
  5173. if( ctx->type.dataType.IsUnsignedType() )
  5174. ctx->bc.InstrW_W(asBC_uTOi64, offset, ctx->type.stackOffset);
  5175. else
  5176. ctx->bc.InstrW_W(asBC_iTOi64, offset, ctx->type.stackOffset);
  5177. ctx->type.SetVariable(to, offset, true);
  5178. }
  5179. }
  5180. else if( ctx->type.dataType.IsFloatType() )
  5181. {
  5182. ConvertToTempVariable(ctx);
  5183. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5184. int offset = AllocateVariable(to, true);
  5185. ctx->bc.InstrW_W(asBC_fTOi64, offset, ctx->type.stackOffset);
  5186. ctx->type.SetVariable(to, offset, true);
  5187. if( convType != asIC_EXPLICIT_VAL_CAST )
  5188. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  5189. }
  5190. else if( ctx->type.dataType.IsDoubleType() )
  5191. {
  5192. ConvertToTempVariable(ctx);
  5193. ctx->bc.InstrSHORT(asBC_dTOi64, ctx->type.stackOffset);
  5194. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5195. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5196. if( convType != asIC_EXPLICIT_VAL_CAST )
  5197. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  5198. }
  5199. }
  5200. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 1 )
  5201. {
  5202. if( ctx->type.dataType.IsIntegerType() ||
  5203. ctx->type.dataType.IsUnsignedType() )
  5204. {
  5205. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  5206. {
  5207. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5208. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5209. }
  5210. else
  5211. {
  5212. ConvertToTempVariable(ctx);
  5213. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5214. int offset = AllocateVariable(to, true);
  5215. ctx->bc.InstrW_W(asBC_i64TOi, offset, ctx->type.stackOffset);
  5216. ctx->type.SetVariable(to, offset, true);
  5217. }
  5218. }
  5219. else if( ctx->type.dataType.IsFloatType() )
  5220. {
  5221. ConvertToTempVariable(ctx);
  5222. ctx->bc.InstrSHORT(asBC_fTOu, ctx->type.stackOffset);
  5223. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5224. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5225. if( convType != asIC_EXPLICIT_VAL_CAST )
  5226. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  5227. }
  5228. else if( ctx->type.dataType.IsDoubleType() )
  5229. {
  5230. ConvertToTempVariable(ctx);
  5231. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5232. int offset = AllocateVariable(to, true);
  5233. ctx->bc.InstrW_W(asBC_dTOu, offset, ctx->type.stackOffset);
  5234. ctx->type.SetVariable(to, offset, true);
  5235. if( convType != asIC_EXPLICIT_VAL_CAST )
  5236. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  5237. }
  5238. // Convert to smaller integer if necessary
  5239. s = to.GetSizeInMemoryBytes();
  5240. if( s < 4 )
  5241. {
  5242. ConvertToTempVariable(ctx);
  5243. if( s == 1 )
  5244. ctx->bc.InstrSHORT(asBC_iTOb, ctx->type.stackOffset);
  5245. else if( s == 2 )
  5246. ctx->bc.InstrSHORT(asBC_iTOw, ctx->type.stackOffset);
  5247. }
  5248. }
  5249. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 2 )
  5250. {
  5251. if( ctx->type.dataType.IsIntegerType() ||
  5252. ctx->type.dataType.IsUnsignedType() )
  5253. {
  5254. if( ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  5255. {
  5256. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5257. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5258. }
  5259. else
  5260. {
  5261. ConvertToTempVariable(ctx);
  5262. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5263. int offset = AllocateVariable(to, true);
  5264. if( ctx->type.dataType.IsUnsignedType() )
  5265. ctx->bc.InstrW_W(asBC_uTOi64, offset, ctx->type.stackOffset);
  5266. else
  5267. ctx->bc.InstrW_W(asBC_iTOi64, offset, ctx->type.stackOffset);
  5268. ctx->type.SetVariable(to, offset, true);
  5269. }
  5270. }
  5271. else if( ctx->type.dataType.IsFloatType() )
  5272. {
  5273. ConvertToTempVariable(ctx);
  5274. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5275. int offset = AllocateVariable(to, true);
  5276. ctx->bc.InstrW_W(asBC_fTOu64, offset, ctx->type.stackOffset);
  5277. ctx->type.SetVariable(to, offset, true);
  5278. if( convType != asIC_EXPLICIT_VAL_CAST )
  5279. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  5280. }
  5281. else if( ctx->type.dataType.IsDoubleType() )
  5282. {
  5283. ConvertToTempVariable(ctx);
  5284. ctx->bc.InstrSHORT(asBC_dTOu64, ctx->type.stackOffset);
  5285. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5286. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5287. if( convType != asIC_EXPLICIT_VAL_CAST )
  5288. Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node);
  5289. }
  5290. }
  5291. else if( to.IsFloatType() )
  5292. {
  5293. if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  5294. {
  5295. ConvertToTempVariable(ctx);
  5296. ctx->bc.InstrSHORT(asBC_iTOf, ctx->type.stackOffset);
  5297. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5298. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5299. }
  5300. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  5301. {
  5302. ConvertToTempVariable(ctx);
  5303. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5304. int offset = AllocateVariable(to, true);
  5305. ctx->bc.InstrW_W(asBC_i64TOf, offset, ctx->type.stackOffset);
  5306. ctx->type.SetVariable(to, offset, true);
  5307. }
  5308. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  5309. {
  5310. ConvertToTempVariable(ctx);
  5311. ctx->bc.InstrSHORT(asBC_uTOf, ctx->type.stackOffset);
  5312. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5313. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5314. }
  5315. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  5316. {
  5317. ConvertToTempVariable(ctx);
  5318. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5319. int offset = AllocateVariable(to, true);
  5320. ctx->bc.InstrW_W(asBC_u64TOf, offset, ctx->type.stackOffset);
  5321. ctx->type.SetVariable(to, offset, true);
  5322. }
  5323. else if( ctx->type.dataType.IsDoubleType() )
  5324. {
  5325. ConvertToTempVariable(ctx);
  5326. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5327. int offset = AllocateVariable(to, true);
  5328. ctx->bc.InstrW_W(asBC_dTOf, offset, ctx->type.stackOffset);
  5329. ctx->type.SetVariable(to, offset, true);
  5330. }
  5331. }
  5332. else if( to.IsDoubleType() )
  5333. {
  5334. if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  5335. {
  5336. ConvertToTempVariable(ctx);
  5337. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5338. int offset = AllocateVariable(to, true);
  5339. ctx->bc.InstrW_W(asBC_iTOd, offset, ctx->type.stackOffset);
  5340. ctx->type.SetVariable(to, offset, true);
  5341. }
  5342. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  5343. {
  5344. ConvertToTempVariable(ctx);
  5345. ctx->bc.InstrSHORT(asBC_i64TOd, ctx->type.stackOffset);
  5346. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5347. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5348. }
  5349. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  5350. {
  5351. ConvertToTempVariable(ctx);
  5352. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5353. int offset = AllocateVariable(to, true);
  5354. ctx->bc.InstrW_W(asBC_uTOd, offset, ctx->type.stackOffset);
  5355. ctx->type.SetVariable(to, offset, true);
  5356. }
  5357. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  5358. {
  5359. ConvertToTempVariable(ctx);
  5360. ctx->bc.InstrSHORT(asBC_u64TOd, ctx->type.stackOffset);
  5361. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5362. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5363. }
  5364. else if( ctx->type.dataType.IsFloatType() )
  5365. {
  5366. ConvertToTempVariable(ctx);
  5367. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5368. int offset = AllocateVariable(to, true);
  5369. ctx->bc.InstrW_W(asBC_fTOd, offset, ctx->type.stackOffset);
  5370. ctx->type.SetVariable(to, offset, true);
  5371. }
  5372. }
  5373. }
  5374. else
  5375. {
  5376. if( ((to.IsIntegerType() && !to.IsEnumType()) || to.IsUnsignedType() ||
  5377. to.IsFloatType() || to.IsDoubleType() ||
  5378. (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST)) &&
  5379. (ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType() ||
  5380. ctx->type.dataType.IsFloatType() || ctx->type.dataType.IsDoubleType()) )
  5381. {
  5382. ctx->type.dataType.SetTokenType(to.GetTokenType());
  5383. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5384. }
  5385. }
  5386. // Primitive types on the stack, can be const or non-const
  5387. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  5388. return cost;
  5389. }
  5390. asUINT asCCompiler::ImplicitConvLambdaToFunc(asCExprContext *ctx, const asCDataType &to, asCScriptNode * /*node*/, EImplicitConv /*convType*/, bool generateCode)
  5391. {
  5392. asASSERT( to.IsFuncdef() && ctx->IsLambda() );
  5393. asCScriptFunction *funcDef = CastToFuncdefType(to.GetTypeInfo())->funcdef;
  5394. // Check that the lambda has the correct amount of arguments
  5395. asUINT count = 0;
  5396. asCScriptNode *argNode = ctx->exprNode->firstChild;
  5397. while( argNode->nodeType != snStatementBlock )
  5398. {
  5399. // Check if the specified parameter types match the funcdef
  5400. if (argNode->nodeType == snDataType)
  5401. {
  5402. asCDataType dt = builder->CreateDataTypeFromNode(argNode, script, outFunc->nameSpace, false, outFunc->objectType);
  5403. asETypeModifiers inOutFlag;
  5404. dt = builder->ModifyDataTypeFromNode(dt, argNode->next, script, &inOutFlag, 0);
  5405. if (count >= funcDef->parameterTypes.GetLength() ||
  5406. funcDef->parameterTypes[count] != dt ||
  5407. funcDef->inOutFlags[count] != inOutFlag)
  5408. return asCC_NO_CONV;
  5409. argNode = argNode->next;
  5410. }
  5411. if( argNode->nodeType == snIdentifier )
  5412. count++;
  5413. argNode = argNode->next;
  5414. }
  5415. if (funcDef->parameterTypes.GetLength() != count)
  5416. return asCC_NO_CONV;
  5417. asASSERT(argNode->nodeType == snStatementBlock);
  5418. // The Lambda can be used as this funcdef
  5419. ctx->type.dataType = to;
  5420. if( generateCode )
  5421. {
  5422. // Build a unique name for the anonymous function
  5423. asCString name;
  5424. if( m_globalVar )
  5425. name.Format("$%s$%d", m_globalVar->name.AddressOf(), numLambdas++);
  5426. else
  5427. name.Format("$%s$%d", outFunc->GetDeclaration(), numLambdas++);
  5428. // Register the lambda with the builder for later compilation
  5429. asCScriptFunction *func = builder->RegisterLambda(ctx->exprNode, script, funcDef, name, outFunc->nameSpace);
  5430. asASSERT( func == 0 || funcDef->IsSignatureExceptNameEqual(func) );
  5431. ctx->bc.InstrPTR(asBC_FuncPtr, func);
  5432. // Clear the expression node as it is no longer valid
  5433. ctx->exprNode = 0;
  5434. }
  5435. return asCC_CONST_CONV;
  5436. }
  5437. asUINT asCCompiler::ImplicitConversion(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode, bool allowObjectConstruct)
  5438. {
  5439. asASSERT( ctx->type.dataType.GetTokenType() != ttUnrecognizedToken ||
  5440. ctx->type.dataType.IsNullHandle() ||
  5441. ctx->IsAnonymousInitList() );
  5442. if( to.IsFuncdef() && ctx->IsLambda() )
  5443. return ImplicitConvLambdaToFunc(ctx, to, node, convType, generateCode);
  5444. if (ctx->IsAnonymousInitList())
  5445. {
  5446. if (to.GetBehaviour() && to.GetBehaviour()->listFactory)
  5447. {
  5448. if (generateCode)
  5449. CompileAnonymousInitList(ctx->exprNode, ctx, to);
  5450. else
  5451. ctx->type.dataType = to;
  5452. }
  5453. return asCC_NO_CONV;
  5454. }
  5455. // No conversion from void to any other type
  5456. if( ctx->type.dataType.GetTokenType() == ttVoid )
  5457. return asCC_NO_CONV;
  5458. // No conversion from class method to any type (it requires delegate)
  5459. if( ctx->IsClassMethod() )
  5460. return asCC_NO_CONV;
  5461. // Do we want a var type?
  5462. if( to.GetTokenType() == ttQuestion )
  5463. {
  5464. // Any type can be converted to a var type, but only when not generating code
  5465. asASSERT( !generateCode );
  5466. ctx->type.dataType = to;
  5467. return asCC_VARIABLE_CONV;
  5468. }
  5469. // Do we want a primitive?
  5470. else if( to.IsPrimitive() )
  5471. {
  5472. if( !ctx->type.dataType.IsPrimitive() )
  5473. return ImplicitConvObjectToPrimitive(ctx, to, node, convType, generateCode);
  5474. else
  5475. return ImplicitConvPrimitiveToPrimitive(ctx, to, node, convType, generateCode);
  5476. }
  5477. else // The target is a complex type
  5478. {
  5479. if( ctx->type.dataType.IsPrimitive() )
  5480. return ImplicitConvPrimitiveToObject(ctx, to, node, convType, generateCode, allowObjectConstruct);
  5481. else if( ctx->type.IsNullConstant() || ctx->type.dataType.GetTypeInfo() )
  5482. return ImplicitConvObjectToObject(ctx, to, node, convType, generateCode, allowObjectConstruct);
  5483. }
  5484. return asCC_NO_CONV;
  5485. }
  5486. asUINT asCCompiler::ImplicitConvObjectToPrimitive(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode)
  5487. {
  5488. if( ctx->type.isExplicitHandle )
  5489. {
  5490. // An explicit handle cannot be converted to a primitive
  5491. if( convType != asIC_IMPLICIT_CONV && node )
  5492. {
  5493. asCString str;
  5494. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  5495. Error(str, node);
  5496. }
  5497. return asCC_NO_CONV;
  5498. }
  5499. // Find matching value cast behaviours
  5500. // Here we're only interested in those that convert the type to a primitive type
  5501. asCArray<int> funcs;
  5502. asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  5503. if( ot == 0 )
  5504. {
  5505. if( convType != asIC_IMPLICIT_CONV && node )
  5506. {
  5507. asCString str;
  5508. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  5509. Error(str, node);
  5510. }
  5511. return asCC_NO_CONV;
  5512. }
  5513. if( convType == asIC_EXPLICIT_VAL_CAST )
  5514. {
  5515. for( unsigned int n = 0; n < ot->methods.GetLength(); n++ )
  5516. {
  5517. // accept both implicit and explicit cast
  5518. asCScriptFunction *mthd = engine->scriptFunctions[ot->methods[n]];
  5519. if( (mthd->name == "opConv" || mthd->name == "opImplConv") &&
  5520. mthd->parameterTypes.GetLength() == 0 &&
  5521. mthd->returnType.IsPrimitive() )
  5522. funcs.PushLast(ot->methods[n]);
  5523. }
  5524. }
  5525. else
  5526. {
  5527. for( unsigned int n = 0; n < ot->methods.GetLength(); n++ )
  5528. {
  5529. // accept only implicit cast
  5530. asCScriptFunction *mthd = engine->scriptFunctions[ot->methods[n]];
  5531. if( mthd->name == "opImplConv" &&
  5532. mthd->parameterTypes.GetLength() == 0 &&
  5533. mthd->returnType.IsPrimitive() )
  5534. funcs.PushLast(ot->methods[n]);
  5535. }
  5536. }
  5537. FilterConst(funcs, !ctx->type.dataType.IsReadOnly());
  5538. int funcId = 0;
  5539. if( to.IsMathType() )
  5540. {
  5541. // This matrix describes the priorities of the types to search for, for each target type
  5542. // The first column is the target type, the priorities goes from left to right
  5543. eTokenType matchMtx[10][10] =
  5544. {
  5545. {ttDouble, ttFloat, ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8},
  5546. {ttFloat, ttDouble, ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8},
  5547. {ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8, ttDouble, ttFloat},
  5548. {ttUInt64, ttInt64, ttUInt, ttInt, ttUInt16, ttInt16, ttUInt8, ttInt8, ttDouble, ttFloat},
  5549. {ttInt, ttUInt, ttInt64, ttUInt64, ttInt16, ttUInt16, ttInt8, ttUInt8, ttDouble, ttFloat},
  5550. {ttUInt, ttInt, ttUInt64, ttInt64, ttUInt16, ttInt16, ttUInt8, ttInt8, ttDouble, ttFloat},
  5551. {ttInt16, ttUInt16, ttInt, ttUInt, ttInt64, ttUInt64, ttInt8, ttUInt8, ttDouble, ttFloat},
  5552. {ttUInt16, ttInt16, ttUInt, ttInt, ttUInt64, ttInt64, ttUInt8, ttInt8, ttDouble, ttFloat},
  5553. {ttInt8, ttUInt8, ttInt16, ttUInt16, ttInt, ttUInt, ttInt64, ttUInt64, ttDouble, ttFloat},
  5554. {ttUInt8, ttInt8, ttUInt16, ttInt16, ttUInt, ttInt, ttUInt64, ttInt64, ttDouble, ttFloat},
  5555. };
  5556. // Which row to use?
  5557. eTokenType *row = 0;
  5558. for( unsigned int type = 0; type < 10; type++ )
  5559. {
  5560. if( to.GetTokenType() == matchMtx[type][0] )
  5561. {
  5562. row = &matchMtx[type][0];
  5563. break;
  5564. }
  5565. }
  5566. // Find the best matching cast operator
  5567. if( row )
  5568. {
  5569. asCDataType target(to);
  5570. // Priority goes from left to right in the matrix
  5571. for( unsigned int attempt = 0; attempt < 10 && funcId == 0; attempt++ )
  5572. {
  5573. target.SetTokenType(row[attempt]);
  5574. for( unsigned int n = 0; n < funcs.GetLength(); n++ )
  5575. {
  5576. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[n]);
  5577. if( descr->returnType.IsEqualExceptRefAndConst(target) )
  5578. {
  5579. funcId = funcs[n];
  5580. break;
  5581. }
  5582. }
  5583. }
  5584. }
  5585. }
  5586. else
  5587. {
  5588. // Only accept the exact conversion for non-math types
  5589. // Find the matching cast operator
  5590. for( unsigned int n = 0; n < funcs.GetLength(); n++ )
  5591. {
  5592. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[n]);
  5593. if( descr->returnType.IsEqualExceptRefAndConst(to) )
  5594. {
  5595. funcId = funcs[n];
  5596. break;
  5597. }
  5598. }
  5599. }
  5600. // Did we find a suitable function?
  5601. if( funcId != 0 )
  5602. {
  5603. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  5604. if( generateCode )
  5605. {
  5606. Dereference(ctx, true);
  5607. PerformFunctionCall(funcId, ctx);
  5608. }
  5609. else
  5610. ctx->type.Set(descr->returnType);
  5611. // Allow one more implicit conversion to another primitive type
  5612. return asCC_OBJ_TO_PRIMITIVE_CONV + ImplicitConversion(ctx, to, node, convType, generateCode, false);
  5613. }
  5614. // TODO: clean-up: This part is similar to what is in ImplicitConvObjectValue
  5615. // If no direct conversion is found we should look for the generic form 'void opConv(?&out)'
  5616. funcs.SetLength(0);
  5617. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  5618. {
  5619. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  5620. if( ((convType == asIC_EXPLICIT_VAL_CAST) && func->name == "opConv") ||
  5621. func->name == "opImplConv" )
  5622. {
  5623. // Does the operator take the ?&out parameter?
  5624. if( func->returnType != asCDataType::CreatePrimitive(ttVoid, false) ||
  5625. func->parameterTypes.GetLength() != 1 ||
  5626. func->parameterTypes[0].GetTokenType() != ttQuestion ||
  5627. func->inOutFlags[0] != asTM_OUTREF )
  5628. continue;
  5629. funcs.PushLast(ot->methods[n]);
  5630. }
  5631. }
  5632. FilterConst(funcs, !ctx->type.dataType.IsReadOnly());
  5633. // If there are multiple valid value casts, then we must choose the most appropriate one
  5634. if (funcs.GetLength() > 1)
  5635. {
  5636. // This should only happen in case of explicit value cast and
  5637. // the application has registered both opImplConv and opConv
  5638. asASSERT(convType == asIC_EXPLICIT_VAL_CAST);
  5639. asASSERT(funcs.GetLength() == 2);
  5640. for (asUINT n = 0; n < funcs.GetLength(); n++)
  5641. {
  5642. asCScriptFunction *func = engine->scriptFunctions[funcs[n]];
  5643. if (func->name == "opImplConv")
  5644. {
  5645. funcs.RemoveIndex(n);
  5646. n--;
  5647. }
  5648. }
  5649. }
  5650. if( funcs.GetLength() == 1 )
  5651. {
  5652. if( generateCode )
  5653. {
  5654. // Allocate a temporary variable of the requested type
  5655. int stackOffset = AllocateVariableNotIn(to, true, false, ctx);
  5656. CallDefaultConstructor(to, stackOffset, IsVariableOnHeap(stackOffset), &ctx->bc, node);
  5657. // Pass the reference of that variable to the function as output parameter
  5658. asCDataType toRef(to);
  5659. toRef.MakeReference(true);
  5660. toRef.MakeReadOnly(false);
  5661. asCArray<asCExprContext *> args;
  5662. asCExprContext arg(engine);
  5663. // Don't mark the variable as temporary, so it won't be freed too early
  5664. arg.type.SetVariable(toRef, stackOffset, false);
  5665. arg.type.isLValue = true;
  5666. arg.exprNode = node;
  5667. args.PushLast(&arg);
  5668. // Call the behaviour method
  5669. MakeFunctionCall(ctx, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
  5670. // Use the reference to the variable as the result of the expression
  5671. // Now we can mark the variable as temporary
  5672. toRef.MakeReference(false);
  5673. ctx->type.SetVariable(toRef, stackOffset, true);
  5674. }
  5675. else
  5676. ctx->type.Set(to);
  5677. return asCC_OBJ_TO_PRIMITIVE_CONV;
  5678. }
  5679. if( convType != asIC_IMPLICIT_CONV && node )
  5680. {
  5681. asCString str;
  5682. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  5683. Error(str, node);
  5684. }
  5685. return asCC_NO_CONV;
  5686. }
  5687. asUINT asCCompiler::ImplicitConvObjectRef(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode)
  5688. {
  5689. // Convert null to any object type handle, but not to a non-handle type
  5690. if( ctx->type.IsNullConstant() && ctx->methodName == "" )
  5691. {
  5692. if( to.IsObjectHandle() )
  5693. {
  5694. ctx->type.dataType = to;
  5695. return asCC_REF_CONV;
  5696. }
  5697. return asCC_NO_CONV;
  5698. }
  5699. asASSERT(ctx->type.dataType.GetTypeInfo() || ctx->methodName != "");
  5700. // First attempt to convert the base type without instantiating another instance
  5701. if( to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() && ctx->methodName == "" )
  5702. {
  5703. // If the to type is an interface and the from type implements it, then we can convert it immediately
  5704. if( ctx->type.dataType.GetTypeInfo()->Implements(to.GetTypeInfo()) )
  5705. {
  5706. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5707. return asCC_REF_CONV;
  5708. }
  5709. // If the to type is a class and the from type derives from it, then we can convert it immediately
  5710. else if( ctx->type.dataType.GetTypeInfo()->DerivesFrom(to.GetTypeInfo()) )
  5711. {
  5712. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5713. return asCC_REF_CONV;
  5714. }
  5715. // If the types are not equal yet, then we may still be able to find a reference cast
  5716. else if( ctx->type.dataType.GetTypeInfo() != to.GetTypeInfo() )
  5717. {
  5718. // We may still be able to find an implicit ref cast behaviour
  5719. CompileRefCast(ctx, to, convType == asIC_EXPLICIT_REF_CAST, node, generateCode);
  5720. // Was the conversion done?
  5721. if( ctx->type.dataType.GetTypeInfo() == to.GetTypeInfo() )
  5722. return asCC_REF_CONV;
  5723. }
  5724. }
  5725. // Convert matching function types
  5726. if( to.IsFuncdef() )
  5727. {
  5728. // If the input expression is already a funcdef, check if it can be converted
  5729. if( ctx->type.dataType.IsFuncdef() &&
  5730. to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() )
  5731. {
  5732. asCScriptFunction *toFunc = CastToFuncdefType(to.GetTypeInfo())->funcdef;
  5733. asCScriptFunction *fromFunc = CastToFuncdefType(ctx->type.dataType.GetTypeInfo())->funcdef;
  5734. if( toFunc->IsSignatureExceptNameEqual(fromFunc) )
  5735. {
  5736. ctx->type.dataType.SetTypeInfo(to.GetTypeInfo());
  5737. return asCC_REF_CONV;
  5738. }
  5739. }
  5740. // If the input expression is a deferred function ref, check if there is a matching func
  5741. if( ctx->methodName != "" )
  5742. {
  5743. // Determine the namespace
  5744. asSNameSpace *ns = 0;
  5745. asCString name = "";
  5746. int pos = ctx->methodName.FindLast("::");
  5747. if( pos >= 0 )
  5748. {
  5749. asCString nsName = ctx->methodName.SubString(0, pos+2);
  5750. // Trim off the last ::
  5751. if( nsName.GetLength() > 2 )
  5752. nsName.SetLength(nsName.GetLength()-2);
  5753. ns = DetermineNameSpace(nsName);
  5754. name = ctx->methodName.SubString(pos+2);
  5755. }
  5756. else
  5757. {
  5758. DetermineNameSpace("");
  5759. name = ctx->methodName;
  5760. }
  5761. asCArray<int> funcs;
  5762. if( ns )
  5763. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  5764. // Check if any of the functions have perfect match
  5765. asCScriptFunction *toFunc = CastToFuncdefType(to.GetTypeInfo())->funcdef;
  5766. for( asUINT n = 0; n < funcs.GetLength(); n++ )
  5767. {
  5768. asCScriptFunction *func = builder->GetFunctionDescription(funcs[n]);
  5769. if( toFunc->IsSignatureExceptNameEqual(func) )
  5770. {
  5771. if( generateCode )
  5772. {
  5773. ctx->bc.InstrPTR(asBC_FuncPtr, func);
  5774. // Make sure the identified function is shared if we're compiling a shared function
  5775. if( !func->IsShared() && outFunc->IsShared() )
  5776. {
  5777. asCString msg;
  5778. msg.Format(TXT_SHARED_CANNOT_CALL_NON_SHARED_FUNC_s, func->GetDeclaration());
  5779. Error(msg, node);
  5780. }
  5781. }
  5782. ctx->type.dataType = asCDataType::CreateType(to.GetTypeInfo(), false);
  5783. return asCC_REF_CONV;
  5784. }
  5785. }
  5786. }
  5787. }
  5788. return asCC_NO_CONV;
  5789. }
  5790. asUINT asCCompiler::ImplicitConvObjectValue(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode)
  5791. {
  5792. asUINT cost = asCC_NO_CONV;
  5793. // If the base type is still different, and we are allowed to instance
  5794. // another object then we can try an implicit value cast
  5795. if( to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() )
  5796. {
  5797. // TODO: Implement support for implicit constructor/factory
  5798. asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  5799. if( ot == 0 )
  5800. return cost;
  5801. asCArray<int> funcs;
  5802. if( convType == asIC_EXPLICIT_VAL_CAST )
  5803. {
  5804. for( unsigned int n = 0; n < ot->methods.GetLength(); n++ )
  5805. {
  5806. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  5807. // accept both implicit and explicit cast
  5808. if( (func->name == "opConv" ||
  5809. func->name == "opImplConv") &&
  5810. func->returnType.GetTypeInfo() == to.GetTypeInfo() &&
  5811. func->parameterTypes.GetLength() == 0 )
  5812. funcs.PushLast(ot->methods[n]);
  5813. }
  5814. }
  5815. else
  5816. {
  5817. for( unsigned int n = 0; n < ot->methods.GetLength(); n++ )
  5818. {
  5819. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  5820. // accept only implicit cast
  5821. if( func->name == "opImplConv" &&
  5822. func->returnType.GetTypeInfo() == to.GetTypeInfo() &&
  5823. func->parameterTypes.GetLength() == 0 )
  5824. funcs.PushLast(ot->methods[n]);
  5825. }
  5826. }
  5827. FilterConst(funcs, !ctx->type.dataType.IsReadOnly());
  5828. // If there are multiple valid value casts, then we must choose the most appropriate one
  5829. if (funcs.GetLength() > 1)
  5830. {
  5831. // This should only happen in case of explicit value cast and
  5832. // the application has registered both opImplConv and opConv
  5833. asASSERT(convType == asIC_EXPLICIT_VAL_CAST);
  5834. asASSERT(funcs.GetLength() == 2);
  5835. for (asUINT n = 0; n < funcs.GetLength(); n++)
  5836. {
  5837. asCScriptFunction *func = engine->scriptFunctions[funcs[n]];
  5838. if (func->name == "opImplConv")
  5839. {
  5840. funcs.RemoveIndex(n);
  5841. n--;
  5842. }
  5843. }
  5844. }
  5845. if( funcs.GetLength() == 1 )
  5846. {
  5847. asCScriptFunction *f = builder->GetFunctionDescription(funcs[0]);
  5848. if( generateCode )
  5849. {
  5850. Dereference(ctx, true);
  5851. bool useVariable = false;
  5852. int stackOffset = 0;
  5853. if( f->DoesReturnOnStack() )
  5854. {
  5855. useVariable = true;
  5856. stackOffset = AllocateVariable(f->returnType, true);
  5857. // Push the pointer to the pre-allocated space for the return value
  5858. ctx->bc.InstrSHORT(asBC_PSF, short(stackOffset));
  5859. // The object pointer is already on the stack, but should be the top
  5860. // one, so we need to swap the pointers in order to get the correct
  5861. ctx->bc.Instr(asBC_SwapPtr);
  5862. }
  5863. PerformFunctionCall(funcs[0], ctx, false, 0, 0, useVariable, stackOffset);
  5864. }
  5865. else
  5866. ctx->type.Set(f->returnType);
  5867. cost = asCC_TO_OBJECT_CONV;
  5868. }
  5869. else
  5870. {
  5871. // TODO: cleanup: This part is similar to the second half of ImplicitConvObjectToPrimitive
  5872. // Look for a value cast with variable type
  5873. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  5874. {
  5875. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  5876. if( ((convType == asIC_EXPLICIT_VAL_CAST) && func->name == "opConv") ||
  5877. func->name == "opImplConv" )
  5878. {
  5879. // Does the operator take the ?&out parameter?
  5880. if( func->returnType != asCDataType::CreatePrimitive(ttVoid, false) ||
  5881. func->parameterTypes.GetLength() != 1 ||
  5882. func->parameterTypes[0].GetTokenType() != ttQuestion ||
  5883. func->inOutFlags[0] != asTM_OUTREF )
  5884. continue;
  5885. funcs.PushLast(ot->methods[n]);
  5886. }
  5887. }
  5888. FilterConst(funcs, !ctx->type.dataType.IsReadOnly());
  5889. // If there are multiple valid value casts, then we must choose the most appropriate one
  5890. if (funcs.GetLength() > 1)
  5891. {
  5892. // This should only happen in case of explicit value cast and
  5893. // the application has registered both opImplConv and opConv
  5894. asASSERT(convType == asIC_EXPLICIT_VAL_CAST);
  5895. asASSERT(funcs.GetLength() == 2);
  5896. for (asUINT n = 0; n < funcs.GetLength(); n++)
  5897. {
  5898. asCScriptFunction *func = engine->scriptFunctions[funcs[n]];
  5899. if (func->name == "opImplConv")
  5900. {
  5901. funcs.RemoveIndex(n);
  5902. n--;
  5903. }
  5904. }
  5905. }
  5906. if( funcs.GetLength() == 1 )
  5907. {
  5908. cost = asCC_TO_OBJECT_CONV;
  5909. if( generateCode )
  5910. {
  5911. // Allocate a temporary variable of the requested type
  5912. int stackOffset = AllocateVariableNotIn(to, true, false, ctx);
  5913. CallDefaultConstructor(to, stackOffset, IsVariableOnHeap(stackOffset), &ctx->bc, node);
  5914. // Pass the reference of that variable to the function as output parameter
  5915. asCDataType toRef(to);
  5916. toRef.MakeReference(false);
  5917. asCExprContext arg(engine);
  5918. arg.bc.InstrSHORT(asBC_PSF, (short)stackOffset);
  5919. // If this an object on the heap, the pointer must be dereferenced
  5920. if( IsVariableOnHeap(stackOffset) )
  5921. arg.bc.Instr(asBC_RDSPtr);
  5922. // Don't mark the variable as temporary, so it won't be freed too early
  5923. arg.type.SetVariable(toRef, stackOffset, false);
  5924. arg.type.isLValue = true;
  5925. arg.exprNode = node;
  5926. // Mark the argument as clean, so that MakeFunctionCall knows it
  5927. // doesn't have to make a copy of it in order to protect the value
  5928. arg.isCleanArg = true;
  5929. // Call the behaviour method
  5930. asCArray<asCExprContext *> args;
  5931. args.PushLast(&arg);
  5932. MakeFunctionCall(ctx, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
  5933. // Use the reference to the variable as the result of the expression
  5934. // Now we can mark the variable as temporary
  5935. ctx->type.SetVariable(toRef, stackOffset, true);
  5936. ctx->bc.InstrSHORT(asBC_PSF, (short)stackOffset);
  5937. }
  5938. else
  5939. {
  5940. // All casts are legal
  5941. ctx->type.Set(to);
  5942. }
  5943. }
  5944. }
  5945. }
  5946. return cost;
  5947. }
  5948. asUINT asCCompiler::ImplicitConvObjectToObject(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode, bool allowObjectConstruct)
  5949. {
  5950. // First try a ref cast
  5951. asUINT cost = ImplicitConvObjectRef(ctx, to, node, convType, generateCode);
  5952. // If the desired type is an asOBJ_ASHANDLE then we'll assume it is allowed to implicitly
  5953. // construct the object through any of the available constructors
  5954. if( to.GetTypeInfo() && (to.GetTypeInfo()->flags & asOBJ_ASHANDLE) && to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() && allowObjectConstruct )
  5955. {
  5956. asCArray<int> funcs;
  5957. funcs = CastToObjectType(to.GetTypeInfo())->beh.constructors;
  5958. asCArray<asCExprContext *> args;
  5959. args.PushLast(ctx);
  5960. cost = asCC_TO_OBJECT_CONV + MatchFunctions(funcs, args, node, 0, 0, 0, false, true, false);
  5961. // Did we find a matching constructor?
  5962. if( funcs.GetLength() == 1 )
  5963. {
  5964. if( generateCode )
  5965. {
  5966. // If the ASHANDLE receives a variable type parameter, then we need to
  5967. // make sure the expression is treated as a handle and not as a value
  5968. asCScriptFunction *func = engine->scriptFunctions[funcs[0]];
  5969. if( func->parameterTypes[0].GetTokenType() == ttQuestion )
  5970. {
  5971. if( !ctx->type.isExplicitHandle )
  5972. {
  5973. asCDataType toHandle = ctx->type.dataType;
  5974. toHandle.MakeHandle(true);
  5975. toHandle.MakeReference(true);
  5976. toHandle.MakeHandleToConst(ctx->type.dataType.IsReadOnly());
  5977. ImplicitConversion(ctx, toHandle, node, asIC_IMPLICIT_CONV, true, false);
  5978. asASSERT( ctx->type.dataType.IsObjectHandle() );
  5979. }
  5980. ctx->type.isExplicitHandle = true;
  5981. }
  5982. // TODO: This should really reuse the code from CompileConstructCall
  5983. // Allocate the new object
  5984. asCExprValue tempObj;
  5985. tempObj.dataType = to;
  5986. tempObj.dataType.MakeReference(false);
  5987. tempObj.stackOffset = (short)AllocateVariable(tempObj.dataType, true);
  5988. tempObj.dataType.MakeReference(true);
  5989. tempObj.isTemporary = true;
  5990. tempObj.isVariable = true;
  5991. bool onHeap = IsVariableOnHeap(tempObj.stackOffset);
  5992. // Push the address of the object on the stack
  5993. asCExprContext e(engine);
  5994. if( onHeap )
  5995. e.bc.InstrSHORT(asBC_VAR, tempObj.stackOffset);
  5996. PrepareFunctionCall(funcs[0], &e.bc, args);
  5997. MoveArgsToStack(funcs[0], &e.bc, args, false);
  5998. // If the object is allocated on the stack, then call the constructor as a normal function
  5999. if( onHeap )
  6000. {
  6001. int offset = 0;
  6002. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]);
  6003. offset = descr->parameterTypes[0].GetSizeOnStackDWords();
  6004. e.bc.InstrWORD(asBC_GETREF, (asWORD)offset);
  6005. }
  6006. else
  6007. e.bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  6008. PerformFunctionCall(funcs[0], &e, onHeap, &args, CastToObjectType(tempObj.dataType.GetTypeInfo()));
  6009. // Add tag that the object has been initialized
  6010. e.bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT);
  6011. // The constructor doesn't return anything,
  6012. // so we have to manually inform the type of
  6013. // the return value
  6014. e.type = tempObj;
  6015. if( !onHeap )
  6016. e.type.dataType.MakeReference(false);
  6017. // Push the address of the object on the stack again
  6018. e.bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  6019. MergeExprBytecodeAndType(ctx, &e);
  6020. }
  6021. else
  6022. {
  6023. ctx->type.Set(asCDataType::CreateType(to.GetTypeInfo(), false));
  6024. }
  6025. }
  6026. }
  6027. // If the base type is still different, and we are allowed to instance
  6028. // another object then we can try an implicit value cast
  6029. if( to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() && allowObjectConstruct )
  6030. {
  6031. // Attempt implicit value cast
  6032. cost = ImplicitConvObjectValue(ctx, to, node, convType, generateCode);
  6033. }
  6034. // If we still haven't converted the base type to the correct type, then there is
  6035. // no need to continue as it is not possible to do the conversion
  6036. if( to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() )
  6037. return asCC_NO_CONV;
  6038. if( to.IsObjectHandle() )
  6039. {
  6040. // There is no extra cost in converting to a handle
  6041. // reference to handle -> handle
  6042. // reference -> handle
  6043. // object -> handle
  6044. // handle -> reference to handle
  6045. // reference -> reference to handle
  6046. // object -> reference to handle
  6047. if( (!ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReadOnly() && !to.IsHandleToConst()) ||
  6048. (ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsHandleToConst() && !to.IsHandleToConst()) )
  6049. {
  6050. // String literals can be implicitly converted to temporary local variables in order to pass them to functions expecting non-const
  6051. // TODO: NEWSTRING: Should have an engine property to warn or error on this
  6052. if (ctx->type.isConstant && ctx->type.dataType.IsEqualExceptRefAndConst(engine->stringType))
  6053. {
  6054. if (generateCode)
  6055. PrepareTemporaryVariable(node, ctx);
  6056. else
  6057. {
  6058. ctx->type.dataType.MakeReadOnly(false);
  6059. ctx->type.isConstant = false;
  6060. }
  6061. // Add the cost for the copy
  6062. cost += asCC_TO_OBJECT_CONV;
  6063. }
  6064. else if( convType != asIC_IMPLICIT_CONV )
  6065. {
  6066. asASSERT(node);
  6067. asCString str;
  6068. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  6069. Error(str, node);
  6070. }
  6071. }
  6072. if( !ctx->type.dataType.IsObjectHandle() )
  6073. {
  6074. // An object type can be directly converted to a handle of the
  6075. // same type by doing a ref copy to a new variable
  6076. if( ctx->type.dataType.SupportHandles() )
  6077. {
  6078. asCDataType dt = ctx->type.dataType;
  6079. dt.MakeHandle(true);
  6080. dt.MakeReference(false);
  6081. if( generateCode )
  6082. {
  6083. // If the expression is already a local variable, then it is not
  6084. // necessary to do a ref copy, as the ref objects on the stack are
  6085. // really handles, only the handles cannot be modified.
  6086. if( ctx->type.isVariable )
  6087. {
  6088. bool isHandleToConst = ctx->type.dataType.IsReadOnly();
  6089. ctx->type.dataType.MakeReadOnly(false);
  6090. ctx->type.dataType.MakeHandle(true);
  6091. ctx->type.dataType.MakeReadOnly(true);
  6092. ctx->type.dataType.MakeHandleToConst(isHandleToConst);
  6093. if( to.IsReference() && !ctx->type.dataType.IsReference() )
  6094. {
  6095. ctx->bc.Instr(asBC_PopPtr);
  6096. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  6097. ctx->type.dataType.MakeReference(true);
  6098. }
  6099. else if( ctx->type.dataType.IsReference() )
  6100. {
  6101. ctx->bc.Instr(asBC_RDSPtr);
  6102. ctx->type.dataType.MakeReference(false);
  6103. }
  6104. }
  6105. else
  6106. {
  6107. int offset = AllocateVariable(dt, true);
  6108. if( ctx->type.dataType.IsReference() )
  6109. ctx->bc.Instr(asBC_RDSPtr);
  6110. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  6111. if (dt.IsFuncdef())
  6112. ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  6113. else
  6114. ctx->bc.InstrPTR(asBC_REFCPY, dt.GetTypeInfo());
  6115. ctx->bc.Instr(asBC_PopPtr);
  6116. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  6117. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  6118. if( to.IsReference() )
  6119. dt.MakeReference(true);
  6120. else
  6121. ctx->bc.Instr(asBC_RDSPtr);
  6122. ctx->type.SetVariable(dt, offset, true);
  6123. }
  6124. }
  6125. else
  6126. ctx->type.dataType = dt;
  6127. // When this conversion is done the expression is no longer an lvalue
  6128. ctx->type.isLValue = false;
  6129. }
  6130. }
  6131. if( ctx->type.dataType.IsObjectHandle() )
  6132. {
  6133. // A handle to non-const can be converted to a
  6134. // handle to const, but not the other way
  6135. if( to.IsHandleToConst() )
  6136. ctx->type.dataType.MakeHandleToConst(true);
  6137. // A const handle can be converted to a non-const
  6138. // handle and vice versa as the handle is just a value
  6139. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  6140. }
  6141. if( to.IsReference() && !ctx->type.dataType.IsReference() )
  6142. {
  6143. if( generateCode )
  6144. {
  6145. asASSERT( ctx->type.dataType.IsObjectHandle() );
  6146. // If the input type is a handle, then a simple ref copy is enough
  6147. bool isExplicitHandle = ctx->type.isExplicitHandle;
  6148. ctx->type.isExplicitHandle = ctx->type.dataType.IsObjectHandle();
  6149. // If the input type is read-only we'll need to temporarily
  6150. // remove this constness, otherwise the assignment will fail
  6151. bool typeIsReadOnly = ctx->type.dataType.IsReadOnly();
  6152. ctx->type.dataType.MakeReadOnly(false);
  6153. // If the object already is a temporary variable, then the copy
  6154. // doesn't have to be made as it is already a unique object
  6155. PrepareTemporaryVariable(node, ctx);
  6156. ctx->type.dataType.MakeReadOnly(typeIsReadOnly);
  6157. ctx->type.isExplicitHandle = isExplicitHandle;
  6158. }
  6159. // A non-reference can be converted to a reference,
  6160. // by putting the value in a temporary variable
  6161. ctx->type.dataType.MakeReference(true);
  6162. // Since it is a new temporary variable it doesn't have to be const
  6163. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  6164. }
  6165. else if( !to.IsReference() && ctx->type.dataType.IsReference() )
  6166. {
  6167. Dereference(ctx, generateCode);
  6168. }
  6169. }
  6170. else // if( !to.IsObjectHandle() )
  6171. {
  6172. if( !to.IsReference() )
  6173. {
  6174. // reference to handle -> object
  6175. // handle -> object
  6176. // reference -> object
  6177. // An implicit handle can be converted to an object by adding a check for null pointer
  6178. if( ctx->type.dataType.IsObjectHandle() && !ctx->type.isExplicitHandle )
  6179. {
  6180. if( generateCode )
  6181. {
  6182. if( ctx->type.dataType.IsReference() )
  6183. {
  6184. // The pointer on the stack refers to the handle
  6185. ctx->bc.Instr(asBC_ChkRefS);
  6186. }
  6187. else
  6188. {
  6189. // The pointer on the stack refers to the object
  6190. ctx->bc.Instr(asBC_CHKREF);
  6191. }
  6192. }
  6193. ctx->type.dataType.MakeHandle(false);
  6194. }
  6195. // A const object can be converted to a non-const object through a copy
  6196. if( ctx->type.dataType.IsReadOnly() && !to.IsReadOnly() &&
  6197. allowObjectConstruct )
  6198. {
  6199. // Does the object type allow a copy to be made?
  6200. if( ctx->type.dataType.CanBeCopied() )
  6201. {
  6202. if( generateCode )
  6203. {
  6204. // Make a temporary object with the copy
  6205. PrepareTemporaryVariable(node, ctx);
  6206. }
  6207. // In case the object was already in a temporary variable, then the function
  6208. // didn't really do anything so we need to remove the constness here
  6209. ctx->type.dataType.MakeReadOnly(false);
  6210. // Add the cost for the copy
  6211. cost += asCC_TO_OBJECT_CONV;
  6212. }
  6213. }
  6214. if( ctx->type.dataType.IsReference() )
  6215. {
  6216. // This may look strange, but a value type allocated on the stack is already
  6217. // correct, so nothing should be done other than remove the mark as reference.
  6218. // For types allocated on the heap, it is necessary to dereference the pointer
  6219. // that is currently on the stack
  6220. if( IsVariableOnHeap(ctx->type.stackOffset) )
  6221. Dereference(ctx, generateCode);
  6222. else
  6223. ctx->type.dataType.MakeReference(false);
  6224. }
  6225. // A non-const object can be converted to a const object directly
  6226. if( !ctx->type.dataType.IsReadOnly() && to.IsReadOnly() )
  6227. {
  6228. ctx->type.dataType.MakeReadOnly(true);
  6229. }
  6230. }
  6231. else // if( to.IsReference() )
  6232. {
  6233. // reference to handle -> reference
  6234. // handle -> reference
  6235. // object -> reference
  6236. if( ctx->type.dataType.IsReference() )
  6237. {
  6238. if( ctx->type.isExplicitHandle && ctx->type.dataType.GetTypeInfo() && (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) )
  6239. {
  6240. // ASHANDLE objects are really value types, so explicit handle can be removed
  6241. ctx->type.isExplicitHandle = false;
  6242. ctx->type.dataType.MakeHandle(false);
  6243. }
  6244. // A reference to a handle can be converted to a reference to an object
  6245. // by first reading the address, then verifying that it is not null
  6246. if( !to.IsObjectHandle() && ctx->type.dataType.IsObjectHandle() && !ctx->type.isExplicitHandle )
  6247. {
  6248. ctx->type.dataType.MakeHandle(false);
  6249. if( generateCode )
  6250. ctx->bc.Instr(asBC_ChkRefS);
  6251. }
  6252. // A reference to a non-const can be converted to a reference to a const
  6253. if( to.IsReadOnly() )
  6254. ctx->type.dataType.MakeReadOnly(true);
  6255. else if( ctx->type.dataType.IsReadOnly() && allowObjectConstruct )
  6256. {
  6257. // A reference to a const can be converted to a reference to a
  6258. // non-const by copying the object to a temporary variable
  6259. ctx->type.dataType.MakeReadOnly(false);
  6260. if( generateCode )
  6261. {
  6262. // If the object already is a temporary variable, then the copy
  6263. // doesn't have to be made as it is already a unique object
  6264. PrepareTemporaryVariable(node, ctx);
  6265. }
  6266. // Add the cost for the copy
  6267. cost += asCC_TO_OBJECT_CONV;
  6268. }
  6269. }
  6270. else // if( !ctx->type.dataType.IsReference() )
  6271. {
  6272. // A non-reference handle can be converted to a non-handle reference by checking against null handle
  6273. if( ctx->type.dataType.IsObjectHandle() )
  6274. {
  6275. bool readOnly = false;
  6276. if( ctx->type.dataType.IsHandleToConst() )
  6277. readOnly = true;
  6278. if( generateCode )
  6279. {
  6280. if( ctx->type.isVariable )
  6281. ctx->bc.InstrSHORT(asBC_ChkNullV, ctx->type.stackOffset);
  6282. else
  6283. ctx->bc.Instr(asBC_CHKREF);
  6284. }
  6285. ctx->type.dataType.MakeHandle(false);
  6286. ctx->type.dataType.MakeReference(true);
  6287. // Make sure a handle to const isn't converted to non-const reference
  6288. if( readOnly )
  6289. ctx->type.dataType.MakeReadOnly(true);
  6290. }
  6291. else
  6292. {
  6293. // A value type allocated on the stack is differentiated
  6294. // by it not being a reference. But it can be handled as
  6295. // reference by pushing the pointer on the stack
  6296. if( (ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) &&
  6297. (ctx->type.isVariable || ctx->type.isTemporary) &&
  6298. !IsVariableOnHeap(ctx->type.stackOffset) )
  6299. {
  6300. // Actually the pointer is already pushed on the stack in
  6301. // CompileVariableAccess, so we don't need to do anything else
  6302. }
  6303. else if( generateCode )
  6304. {
  6305. // A non-reference can be converted to a reference,
  6306. // by putting the value in a temporary variable
  6307. // If the input type is read-only we'll need to temporarily
  6308. // remove this constness, otherwise the assignment will fail
  6309. bool typeIsReadOnly = ctx->type.dataType.IsReadOnly();
  6310. ctx->type.dataType.MakeReadOnly(false);
  6311. // If the object already is a temporary variable, then the copy
  6312. // doesn't have to be made as it is already a unique object
  6313. PrepareTemporaryVariable(node, ctx);
  6314. ctx->type.dataType.MakeReadOnly(typeIsReadOnly);
  6315. // Add the cost for the copy
  6316. cost += asCC_TO_OBJECT_CONV;
  6317. }
  6318. // This may look strange as the conversion was to make the expression a reference
  6319. // but a value type allocated on the stack is a reference even without the type
  6320. // being marked as such.
  6321. ctx->type.dataType.MakeReference(IsVariableOnHeap(ctx->type.stackOffset));
  6322. }
  6323. if (to.IsReadOnly())
  6324. {
  6325. // This doesn't cost anything
  6326. ctx->type.dataType.MakeReadOnly(true);
  6327. }
  6328. if (!to.IsReadOnly() && ctx->type.dataType.IsReadOnly())
  6329. {
  6330. // A const object can be converted to a non-const object through a copy
  6331. if (allowObjectConstruct || convType == asIC_EXPLICIT_VAL_CAST)
  6332. {
  6333. ctx->type.dataType.MakeReadOnly(false);
  6334. if (generateCode)
  6335. {
  6336. // Make a temporary copy of the object in order to make it non-const
  6337. PrepareTemporaryVariable(node, ctx);
  6338. }
  6339. // Add the cost for the copy
  6340. cost += asCC_TO_OBJECT_CONV;
  6341. }
  6342. // String literals can be implicitly converted to temporary local variables in order to pass them to functions expecting non-const
  6343. // TODO: NEWSTRING: Should have an engine property to warn or error on this
  6344. if (ctx->type.isConstant && ctx->type.dataType.IsEqualExceptRefAndConst(engine->stringType))
  6345. {
  6346. if (generateCode)
  6347. PrepareTemporaryVariable(node, ctx);
  6348. else
  6349. {
  6350. ctx->type.dataType.MakeReadOnly(false);
  6351. ctx->type.isConstant = false;
  6352. }
  6353. // Add the cost for the copy
  6354. cost += asCC_TO_OBJECT_CONV;
  6355. }
  6356. }
  6357. }
  6358. }
  6359. }
  6360. return cost;
  6361. }
  6362. asUINT asCCompiler::ImplicitConvPrimitiveToObject(asCExprContext *ctx, const asCDataType &to, asCScriptNode * /*node*/, EImplicitConv /*isExplicit*/, bool generateCode, bool /*allowObjectConstruct*/)
  6363. {
  6364. // Reference types currently don't allow implicit conversion from primitive to object
  6365. // TODO: Allow implicit conversion to scoped reference types as they are supposed to appear like ordinary value types
  6366. asCObjectType *objType = CastToObjectType(to.GetTypeInfo());
  6367. asASSERT( objType || CastToFuncdefType(to.GetTypeInfo()) );
  6368. if( !objType || (objType->flags & asOBJ_REF) )
  6369. return asCC_NO_CONV;
  6370. // For value types the object must have a constructor that takes a single primitive argument either by value or as input reference
  6371. asCArray<int> funcs;
  6372. for( asUINT n = 0; n < objType->beh.constructors.GetLength(); n++ )
  6373. {
  6374. asCScriptFunction *func = engine->scriptFunctions[objType->beh.constructors[n]];
  6375. if( func->parameterTypes.GetLength() == 1 &&
  6376. func->parameterTypes[0].IsPrimitive() &&
  6377. !(func->inOutFlags[0] & asTM_OUTREF) )
  6378. {
  6379. funcs.PushLast(func->id);
  6380. }
  6381. }
  6382. if( funcs.GetLength() == 0 )
  6383. return asCC_NO_CONV;
  6384. // Check if it is possible to choose a best match
  6385. asCExprContext arg(engine);
  6386. arg.type = ctx->type;
  6387. arg.exprNode = ctx->exprNode; // Use the same node for compiler messages
  6388. asCArray<asCExprContext*> args;
  6389. args.PushLast(&arg);
  6390. asUINT cost = asCC_TO_OBJECT_CONV + MatchFunctions(funcs, args, 0, 0, 0, objType, false, true, false);
  6391. if( funcs.GetLength() != 1 )
  6392. return asCC_NO_CONV;
  6393. if( !generateCode )
  6394. {
  6395. ctx->type.Set(to);
  6396. return cost;
  6397. }
  6398. // TODO: clean up: This part is similar to CompileConstructCall(). It should be put in a common function
  6399. // Clear the type of ctx, as the type is moved to the arg
  6400. ctx->type.SetDummy();
  6401. // Value types and script types are allocated through the constructor
  6402. asCExprValue tempObj;
  6403. tempObj.dataType = to;
  6404. tempObj.stackOffset = (short)AllocateVariable(to, true);
  6405. tempObj.dataType.MakeReference(true);
  6406. tempObj.isTemporary = true;
  6407. tempObj.isVariable = true;
  6408. bool onHeap = IsVariableOnHeap(tempObj.stackOffset);
  6409. // Push the address of the object on the stack
  6410. if( onHeap )
  6411. ctx->bc.InstrSHORT(asBC_VAR, tempObj.stackOffset);
  6412. PrepareFunctionCall(funcs[0], &ctx->bc, args);
  6413. MoveArgsToStack(funcs[0], &ctx->bc, args, false);
  6414. if( !(objType->flags & asOBJ_REF) )
  6415. {
  6416. // If the object is allocated on the stack, then call the constructor as a normal function
  6417. if( onHeap )
  6418. {
  6419. int offset = 0;
  6420. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]);
  6421. for( asUINT n = 0; n < args.GetLength(); n++ )
  6422. offset += descr->parameterTypes[n].GetSizeOnStackDWords();
  6423. ctx->bc.InstrWORD(asBC_GETREF, (asWORD)offset);
  6424. }
  6425. else
  6426. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  6427. PerformFunctionCall(funcs[0], ctx, onHeap, &args, CastToObjectType(tempObj.dataType.GetTypeInfo()));
  6428. // Add tag that the object has been initialized
  6429. ctx->bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT);
  6430. // The constructor doesn't return anything,
  6431. // so we have to manually inform the type of
  6432. // the return value
  6433. ctx->type = tempObj;
  6434. if( !onHeap )
  6435. ctx->type.dataType.MakeReference(false);
  6436. // Push the address of the object on the stack again
  6437. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  6438. }
  6439. else
  6440. {
  6441. asASSERT( objType->flags & asOBJ_SCOPED );
  6442. // Call the factory to create the reference type
  6443. PerformFunctionCall(funcs[0], ctx, false, &args);
  6444. }
  6445. return cost;
  6446. }
  6447. void asCCompiler::ImplicitConversionConstant(asCExprContext *from, const asCDataType &to, asCScriptNode *node, EImplicitConv convType)
  6448. {
  6449. asASSERT(from->type.isConstant);
  6450. // TODO: node should be the node of the value that is
  6451. // converted (not the operator that provokes the implicit
  6452. // conversion)
  6453. // If the base type is correct there is no more to do
  6454. if( to.IsEqualExceptRefAndConst(from->type.dataType) ) return;
  6455. // References cannot be constants
  6456. if( from->type.dataType.IsReference() ) return;
  6457. if( (to.IsIntegerType() && to.GetSizeInMemoryDWords() == 1 && !to.IsEnumType()) ||
  6458. (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST) )
  6459. {
  6460. if( from->type.dataType.IsFloatType() ||
  6461. from->type.dataType.IsDoubleType() ||
  6462. from->type.dataType.IsUnsignedType() ||
  6463. from->type.dataType.IsIntegerType() )
  6464. {
  6465. asCDataType targetDt;
  6466. if (to.IsEnumType())
  6467. targetDt = to;
  6468. else
  6469. targetDt = asCDataType::CreatePrimitive(ttInt, true);
  6470. // Transform the value
  6471. // Float constants can be implicitly converted to int
  6472. if( from->type.dataType.IsFloatType() )
  6473. {
  6474. float fc = from->type.GetConstantF();
  6475. int ic = int(fc);
  6476. if( float(ic) != fc )
  6477. {
  6478. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6479. }
  6480. from->type.SetConstantDW(targetDt, ic);
  6481. }
  6482. // Double constants can be implicitly converted to int
  6483. else if( from->type.dataType.IsDoubleType() )
  6484. {
  6485. double fc = from->type.GetConstantD();
  6486. int ic = int(fc);
  6487. if( double(ic) != fc )
  6488. {
  6489. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6490. }
  6491. from->type.SetConstantDW(targetDt, ic);
  6492. }
  6493. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  6494. {
  6495. // Verify that it is possible to convert to signed without getting negative
  6496. if( from->type.dataType.GetSizeInMemoryBytes() == 4 &&
  6497. int(from->type.GetConstantDW()) < 0 &&
  6498. convType != asIC_EXPLICIT_VAL_CAST &&
  6499. node != 0 )
  6500. Warning(TXT_CHANGE_SIGN, node);
  6501. // Convert to 32bit
  6502. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6503. from->type.SetConstantDW(targetDt, from->type.GetConstantB());
  6504. else if (from->type.dataType.GetSizeInMemoryBytes() == 2)
  6505. from->type.SetConstantDW(targetDt, from->type.GetConstantW());
  6506. else
  6507. from->type.dataType = targetDt;
  6508. }
  6509. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  6510. {
  6511. if (asQWORD(from->type.GetConstantQW()) >> 31)
  6512. if (convType != asIC_EXPLICIT_VAL_CAST && node) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6513. // Convert to 32bit
  6514. from->type.SetConstantDW(targetDt, int(from->type.GetConstantQW()));
  6515. }
  6516. else if (from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2)
  6517. {
  6518. if (int(from->type.GetConstantQW()) != asINT64(from->type.GetConstantQW()))
  6519. if (convType != asIC_EXPLICIT_VAL_CAST && node) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6520. // Convert to 32bit
  6521. from->type.SetConstantDW(targetDt, int(from->type.GetConstantQW()));
  6522. }
  6523. else if (from->type.dataType.IsIntegerType() &&
  6524. from->type.dataType.GetSizeInMemoryBytes() < 4)
  6525. {
  6526. // Convert to 32bit
  6527. if (from->type.dataType.GetSizeInMemoryBytes() == 1)
  6528. from->type.SetConstantDW(targetDt, (asINT8)from->type.GetConstantB());
  6529. else if (from->type.dataType.GetSizeInMemoryBytes() == 2)
  6530. from->type.SetConstantDW(targetDt, (asINT16)from->type.GetConstantW());
  6531. }
  6532. else
  6533. {
  6534. // Only int32 and enums should come here and as these are 32bit
  6535. // already nothing needs to be done except set the target type
  6536. asASSERT((from->type.dataType.GetTokenType() == ttInt ||
  6537. from->type.dataType.IsEnumType()) &&
  6538. from->type.dataType.GetSizeInMemoryBytes() == 4);
  6539. from->type.dataType = targetDt;
  6540. }
  6541. }
  6542. // Check if a downsize is necessary
  6543. if( to.IsIntegerType() &&
  6544. from->type.dataType.IsIntegerType() &&
  6545. from->type.dataType.GetSizeInMemoryBytes() > to.GetSizeInMemoryBytes() )
  6546. {
  6547. // Verify if it is possible
  6548. if( to.GetSizeInMemoryBytes() == 1 )
  6549. {
  6550. if( asINT8(from->type.GetConstantDW()) != int(from->type.GetConstantDW()) )
  6551. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6552. from->type.SetConstantB(asCDataType::CreatePrimitive(to.GetTokenType(), true), asINT8(from->type.GetConstantDW()));
  6553. }
  6554. else if( to.GetSizeInMemoryBytes() == 2 )
  6555. {
  6556. if( asINT16(from->type.GetConstantDW()) != int(from->type.GetConstantDW()) )
  6557. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6558. from->type.SetConstantW(asCDataType::CreatePrimitive(to.GetTokenType(), true), asINT16(from->type.GetConstantDW()));
  6559. }
  6560. }
  6561. }
  6562. else if( to.IsIntegerType() && to.GetSizeInMemoryDWords() == 2 )
  6563. {
  6564. // Float constants can be implicitly converted to int
  6565. if( from->type.dataType.IsFloatType() )
  6566. {
  6567. float fc = from->type.GetConstantF();
  6568. asINT64 ic = asINT64(fc);
  6569. if( float(ic) != fc )
  6570. {
  6571. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6572. }
  6573. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), ic);
  6574. }
  6575. // Double constants can be implicitly converted to int
  6576. else if( from->type.dataType.IsDoubleType() )
  6577. {
  6578. double fc = from->type.GetConstantD();
  6579. asINT64 ic = asINT64(fc);
  6580. if( double(ic) != fc )
  6581. {
  6582. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6583. }
  6584. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), ic);
  6585. }
  6586. else if( from->type.dataType.IsUnsignedType() )
  6587. {
  6588. // Convert to 64bit
  6589. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6590. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), from->type.GetConstantB());
  6591. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6592. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), from->type.GetConstantW());
  6593. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  6594. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), from->type.GetConstantDW());
  6595. else if( from->type.dataType.GetSizeInMemoryBytes() == 8 )
  6596. {
  6597. if( asINT64(from->type.GetConstantQW()) < 0 )
  6598. {
  6599. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  6600. }
  6601. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  6602. }
  6603. }
  6604. else if( from->type.dataType.IsIntegerType() )
  6605. {
  6606. // Convert to 64bit
  6607. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6608. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), (asINT8)from->type.GetConstantB());
  6609. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6610. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), (asINT16)from->type.GetConstantW());
  6611. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  6612. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), (int)from->type.GetConstantDW());
  6613. }
  6614. }
  6615. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 1 )
  6616. {
  6617. if( from->type.dataType.IsFloatType() )
  6618. {
  6619. float fc = from->type.GetConstantF();
  6620. // Some compilers set the value to 0 when converting a negative float to unsigned int.
  6621. // To maintain a consistent behaviour across compilers we convert to int first.
  6622. asUINT uic = asUINT(int(fc));
  6623. if( float(uic) != fc )
  6624. {
  6625. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6626. }
  6627. from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), uic);
  6628. // Try once more, in case of a smaller type
  6629. ImplicitConversionConstant(from, to, node, convType);
  6630. }
  6631. else if( from->type.dataType.IsDoubleType() )
  6632. {
  6633. double fc = from->type.GetConstantD();
  6634. // Some compilers set the value to 0 when converting a negative double to unsigned int.
  6635. // To maintain a consistent behaviour across compilers we convert to int first.
  6636. asUINT uic = asUINT(int(fc));
  6637. if( double(uic) != fc )
  6638. {
  6639. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6640. }
  6641. from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), uic);
  6642. // Try once more, in case of a smaller type
  6643. ImplicitConversionConstant(from, to, node, convType);
  6644. }
  6645. else if( from->type.dataType.IsIntegerType() )
  6646. {
  6647. // Verify that it is possible to convert to unsigned without loosing negative
  6648. if( (from->type.dataType.GetSizeInMemoryBytes() > 4 && asINT64(from->type.GetConstantQW()) < 0) ||
  6649. (from->type.dataType.GetSizeInMemoryBytes() == 4 && int(from->type.GetConstantDW()) < 0) ||
  6650. (from->type.dataType.GetSizeInMemoryBytes() == 2 && asINT16(from->type.GetConstantW()) < 0) ||
  6651. (from->type.dataType.GetSizeInMemoryBytes() == 1 && asINT8(from->type.GetConstantB()) < 0))
  6652. {
  6653. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  6654. }
  6655. // Check if any data is lost
  6656. if( from->type.dataType.GetSizeInMemoryBytes() > 4 && (from->type.GetConstantQW() >> 32) != 0 && (from->type.GetConstantQW() >> 32) != 0xFFFFFFFF )
  6657. {
  6658. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6659. }
  6660. // Convert to 32bit
  6661. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6662. from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), (asINT8)from->type.GetConstantB());
  6663. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6664. from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), (asINT16)from->type.GetConstantW());
  6665. else if (from->type.dataType.GetSizeInMemoryBytes() == 4 )
  6666. from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), (int)from->type.GetConstantDW());
  6667. else
  6668. from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), (int)(asINT64)from->type.GetConstantQW());
  6669. // Try once more, in case of a smaller type
  6670. ImplicitConversionConstant(from, to, node, convType);
  6671. }
  6672. else if( from->type.dataType.IsUnsignedType() &&
  6673. from->type.dataType.GetSizeInMemoryBytes() < 4 )
  6674. {
  6675. // Convert to 32bit
  6676. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6677. from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), from->type.GetConstantB());
  6678. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6679. from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), from->type.GetConstantW());
  6680. // Try once more, in case of a smaller type
  6681. ImplicitConversionConstant(from, to, node, convType);
  6682. }
  6683. else if( from->type.dataType.IsUnsignedType() &&
  6684. from->type.dataType.GetSizeInMemoryBytes() > to.GetSizeInMemoryBytes() )
  6685. {
  6686. // Verify if it is possible
  6687. if( to.GetSizeInMemoryBytes() == 1 )
  6688. {
  6689. if( asBYTE(from->type.GetConstantDW()) != from->type.GetConstantDW() )
  6690. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6691. from->type.SetConstantB(asCDataType::CreatePrimitive(to.GetTokenType(), true), asBYTE(from->type.GetConstantDW()));
  6692. }
  6693. else if( to.GetSizeInMemoryBytes() == 2 )
  6694. {
  6695. if( asWORD(from->type.GetConstantDW()) != from->type.GetConstantDW())
  6696. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6697. from->type.SetConstantW(asCDataType::CreatePrimitive(to.GetTokenType(), true), asWORD(from->type.GetConstantDW()));
  6698. }
  6699. else if (to.GetSizeInMemoryBytes() == 4)
  6700. {
  6701. if( asDWORD(from->type.GetConstantQW()) != from->type.GetConstantQW())
  6702. if (convType != asIC_EXPLICIT_VAL_CAST && node) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  6703. from->type.SetConstantDW(asCDataType::CreatePrimitive(to.GetTokenType(), true), asDWORD(from->type.GetConstantQW()));
  6704. }
  6705. }
  6706. }
  6707. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 2 )
  6708. {
  6709. if( from->type.dataType.IsFloatType() )
  6710. {
  6711. float fc = from->type.GetConstantF();
  6712. // Convert first to int64 then to uint64 to avoid negative float becoming 0 on gnuc base compilers
  6713. asQWORD uic = asQWORD(asINT64(fc));
  6714. #if !defined(_MSC_VER) || _MSC_VER > 1200 // MSVC++ 6
  6715. // MSVC6 doesn't support this conversion
  6716. if( float(uic) != fc )
  6717. {
  6718. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6719. }
  6720. #endif
  6721. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), uic);
  6722. }
  6723. else if( from->type.dataType.IsDoubleType() )
  6724. {
  6725. double fc = from->type.GetConstantD();
  6726. // Convert first to int64 then to uint64 to avoid negative float becoming 0 on gnuc base compilers
  6727. asQWORD uic = asQWORD(asINT64(fc));
  6728. #if !defined(_MSC_VER) || _MSC_VER > 1200 // MSVC++ 6
  6729. // MSVC6 doesn't support this conversion
  6730. if( double(uic) != fc )
  6731. {
  6732. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6733. }
  6734. #endif
  6735. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), uic);
  6736. }
  6737. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  6738. {
  6739. // Convert to 64bit
  6740. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6741. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), (asINT64)(asINT8)from->type.GetConstantB());
  6742. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6743. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), (asINT64)(asINT16)from->type.GetConstantW());
  6744. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  6745. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), (asINT64)(int)from->type.GetConstantDW());
  6746. // Verify that it is possible to convert to unsigned without loosing negative
  6747. if( asINT64(from->type.GetConstantQW()) < 0 )
  6748. {
  6749. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  6750. }
  6751. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  6752. }
  6753. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  6754. {
  6755. // Verify that it is possible to convert to unsigned without loosing negative
  6756. if( asINT64(from->type.GetConstantQW()) < 0 )
  6757. {
  6758. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  6759. }
  6760. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  6761. }
  6762. else if( from->type.dataType.IsUnsignedType() )
  6763. {
  6764. // Convert to 64bit
  6765. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6766. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), from->type.GetConstantB());
  6767. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6768. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), from->type.GetConstantW());
  6769. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  6770. from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), from->type.GetConstantDW());
  6771. }
  6772. }
  6773. else if( to.IsFloatType() )
  6774. {
  6775. if( from->type.dataType.IsDoubleType() )
  6776. {
  6777. double ic = from->type.GetConstantD();
  6778. float fc = float(ic);
  6779. from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  6780. }
  6781. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  6782. {
  6783. // Must properly convert value in case the from value is smaller
  6784. int ic;
  6785. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6786. ic = (asINT8)from->type.GetConstantB();
  6787. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6788. ic = (asINT16)from->type.GetConstantW();
  6789. else
  6790. ic = (int)from->type.GetConstantDW();
  6791. float fc = float(ic);
  6792. if( int(fc) != ic )
  6793. {
  6794. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6795. }
  6796. from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  6797. }
  6798. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  6799. {
  6800. float fc = float(asINT64(from->type.GetConstantQW()));
  6801. if( asINT64(fc) != asINT64(from->type.GetConstantQW()) )
  6802. {
  6803. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6804. }
  6805. from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  6806. }
  6807. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  6808. {
  6809. // Must properly convert value in case the from value is smaller
  6810. unsigned int uic;
  6811. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6812. uic = from->type.GetConstantB();
  6813. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6814. uic = from->type.GetConstantW();
  6815. else
  6816. uic = from->type.GetConstantDW();
  6817. float fc = float(uic);
  6818. if( (unsigned int)(fc) != uic )
  6819. {
  6820. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6821. }
  6822. from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  6823. }
  6824. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  6825. {
  6826. float fc = float((asINT64)from->type.GetConstantQW());
  6827. if( asQWORD(fc) != from->type.GetConstantQW())
  6828. {
  6829. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6830. }
  6831. from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  6832. }
  6833. }
  6834. else if( to.IsDoubleType() )
  6835. {
  6836. if( from->type.dataType.IsFloatType() )
  6837. {
  6838. float ic = from->type.GetConstantF();
  6839. double fc = double(ic);
  6840. from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  6841. }
  6842. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  6843. {
  6844. // Must properly convert value in case the from value is smaller
  6845. int ic;
  6846. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6847. ic = (asINT8)from->type.GetConstantB();
  6848. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6849. ic = (asINT16)from->type.GetConstantW();
  6850. else
  6851. ic = (int)from->type.GetConstantDW();
  6852. double fc = double(ic);
  6853. if( int(fc) != ic )
  6854. {
  6855. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6856. }
  6857. from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  6858. }
  6859. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  6860. {
  6861. double fc = double(asINT64(from->type.GetConstantQW()));
  6862. if( asINT64(fc) != asINT64(from->type.GetConstantQW()) )
  6863. {
  6864. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6865. }
  6866. from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  6867. }
  6868. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  6869. {
  6870. // Must properly convert value in case the from value is smaller
  6871. unsigned int uic;
  6872. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  6873. uic = from->type.GetConstantB();
  6874. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  6875. uic = from->type.GetConstantW();
  6876. else
  6877. uic = from->type.GetConstantDW();
  6878. double fc = double(uic);
  6879. if( (unsigned int)(fc) != uic )
  6880. {
  6881. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6882. }
  6883. from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  6884. }
  6885. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  6886. {
  6887. double fc = double((asINT64)from->type.GetConstantQW());
  6888. if( asQWORD(fc) != from->type.GetConstantQW())
  6889. {
  6890. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  6891. }
  6892. from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc);
  6893. }
  6894. }
  6895. }
  6896. int asCCompiler::DoAssignment(asCExprContext *ctx, asCExprContext *lctx, asCExprContext *rctx, asCScriptNode *lexpr, asCScriptNode *rexpr, eTokenType op, asCScriptNode *opNode)
  6897. {
  6898. // Don't allow any operators on expressions that take address of class method
  6899. // If methodName is set but the type is not an object, then it is a global function
  6900. if( lctx->methodName != "" || rctx->IsClassMethod() )
  6901. {
  6902. Error(TXT_INVALID_OP_ON_METHOD, opNode);
  6903. return -1;
  6904. }
  6905. // Implicit handle types should always be treated as handles in assignments
  6906. if (lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE) )
  6907. {
  6908. lctx->type.dataType.MakeHandle(true);
  6909. lctx->type.isExplicitHandle = true;
  6910. }
  6911. // Urho3D: if there is a handle type, and it does not have an overloaded assignment operator, convert to an explicit handle
  6912. // for scripting convenience. (For the Urho3D handle types, value assignment is not supported)
  6913. if (lctx->type.dataType.IsObjectHandle() && !lctx->type.dataType.IsTemplate() && !lctx->type.isExplicitHandle &&
  6914. (!lctx->type.dataType.GetBehaviour() || !lctx->type.dataType.GetBehaviour()->copy))
  6915. lctx->type.isExplicitHandle = true;
  6916. // If the left hand expression is a property accessor, then that should be used
  6917. // to do the assignment instead of the ordinary operator. The exception is when
  6918. // the property accessor is for a handle property, and the operation is a value
  6919. // assignment.
  6920. if( (lctx->property_get || lctx->property_set) &&
  6921. !(lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle) )
  6922. {
  6923. if( op != ttAssignment )
  6924. {
  6925. // Generate the code for the compound assignment, i.e. get the value, apply operator, then set the value
  6926. return ProcessPropertyGetSetAccessor(ctx, lctx, rctx, op, opNode);
  6927. }
  6928. // It is not allowed to do a handle assignment on a property
  6929. // accessor that doesn't take a handle in the set accessor.
  6930. if( lctx->property_set && lctx->type.isExplicitHandle )
  6931. {
  6932. // set_opIndex has 2 arguments, where as normal setters have only 1
  6933. asCArray<asCDataType>& parameterTypes =
  6934. builder->GetFunctionDescription(lctx->property_set)->parameterTypes;
  6935. if( !parameterTypes[parameterTypes.GetLength() - 1].IsObjectHandle() )
  6936. {
  6937. // Process the property to free the memory
  6938. ProcessPropertySetAccessor(lctx, rctx, opNode);
  6939. Error(TXT_HANDLE_ASSIGN_ON_NON_HANDLE_PROP, opNode);
  6940. return -1;
  6941. }
  6942. }
  6943. MergeExprBytecodeAndType(ctx, lctx);
  6944. return ProcessPropertySetAccessor(ctx, rctx, opNode);
  6945. }
  6946. else if( lctx->property_get && lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle )
  6947. {
  6948. // Get the handle to the object that will be used for the value assignment
  6949. ProcessPropertyGetAccessor(lctx, opNode);
  6950. }
  6951. if( lctx->type.dataType.IsPrimitive() )
  6952. {
  6953. if( !lctx->type.isLValue )
  6954. {
  6955. Error(TXT_NOT_LVALUE, lexpr);
  6956. return -1;
  6957. }
  6958. if( op != ttAssignment )
  6959. {
  6960. // Compute the operator before the assignment
  6961. asCExprValue lvalue = lctx->type;
  6962. if( lctx->type.isTemporary && !lctx->type.isVariable )
  6963. {
  6964. // The temporary variable must not be freed until the
  6965. // assignment has been performed. lvalue still holds
  6966. // the information about the temporary variable
  6967. lctx->type.isTemporary = false;
  6968. }
  6969. asCExprContext o(engine);
  6970. CompileOperator(opNode, lctx, rctx, &o);
  6971. MergeExprBytecode(rctx, &o);
  6972. rctx->type = o.type;
  6973. // Convert the rvalue to the right type and validate it
  6974. PrepareForAssignment(&lvalue.dataType, rctx, rexpr, false);
  6975. MergeExprBytecode(ctx, rctx);
  6976. lctx->type = lvalue;
  6977. // The lvalue continues the same, either it was a variable, or a reference in the register
  6978. }
  6979. else
  6980. {
  6981. // Convert the rvalue to the right type and validate it
  6982. PrepareForAssignment(&lctx->type.dataType, rctx, rexpr, false, lctx);
  6983. MergeExprBytecode(ctx, rctx);
  6984. MergeExprBytecode(ctx, lctx);
  6985. }
  6986. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  6987. PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode);
  6988. ctx->type = lctx->type;
  6989. }
  6990. else if( lctx->type.isExplicitHandle )
  6991. {
  6992. if( !lctx->type.isLValue )
  6993. {
  6994. Error(TXT_NOT_LVALUE, lexpr);
  6995. return -1;
  6996. }
  6997. // Object handles don't have any compound assignment operators
  6998. if( op != ttAssignment )
  6999. {
  7000. asCString str;
  7001. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  7002. Error(str, lexpr);
  7003. return -1;
  7004. }
  7005. if( lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) )
  7006. {
  7007. // The object is a value type but that should be treated as a handle
  7008. // Make sure the right hand value is a handle
  7009. if( !rctx->type.isExplicitHandle &&
  7010. !(rctx->type.dataType.GetTypeInfo() && (rctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE)) )
  7011. {
  7012. // Function names can be considered handles already
  7013. if( rctx->methodName == "" )
  7014. {
  7015. asCDataType dt = rctx->type.dataType;
  7016. dt.MakeHandle(true);
  7017. dt.MakeReference(false);
  7018. PrepareArgument(&dt, rctx, rexpr, true, asTM_INREF);
  7019. if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) )
  7020. {
  7021. asCString str;
  7022. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  7023. Error(str, rexpr);
  7024. return -1;
  7025. }
  7026. }
  7027. // Mark the right hand expression as explicit handle even if the user didn't do it, otherwise
  7028. // the code for moving the argument to the stack may not know to correctly handle the argument type
  7029. // in case of variable parameter type.
  7030. rctx->type.isExplicitHandle = true;
  7031. }
  7032. if( CompileOverloadedDualOperator(opNode, lctx, rctx, false, ctx, true) )
  7033. {
  7034. // An overloaded assignment operator was found (or a compilation error occured)
  7035. return 0;
  7036. }
  7037. // The object must implement the opAssign method
  7038. asCString msg;
  7039. msg.Format(TXT_NO_APPROPRIATE_OPHNDLASSIGN_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  7040. Error(msg.AddressOf(), opNode);
  7041. return -1;
  7042. }
  7043. else
  7044. {
  7045. asCDataType dt = lctx->type.dataType;
  7046. dt.MakeReference(false);
  7047. PrepareArgument(&dt, rctx, rexpr, false, asTM_INREF , true);
  7048. if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) )
  7049. {
  7050. asCString str;
  7051. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  7052. Error(str, rexpr);
  7053. return -1;
  7054. }
  7055. MergeExprBytecode(ctx, rctx);
  7056. MergeExprBytecode(ctx, lctx);
  7057. if(!rctx->type.isRefSafe)
  7058. ctx->bc.InstrWORD(asBC_GETOBJREF, AS_PTR_SIZE);
  7059. PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode);
  7060. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  7061. ctx->type = lctx->type;
  7062. // After the handle assignment the original handle is left on the stack
  7063. ctx->type.dataType.MakeReference(false);
  7064. }
  7065. }
  7066. else // if( lctx->type.dataType.IsObject() )
  7067. {
  7068. // The lvalue reference may be marked as a temporary, if for example
  7069. // it was originated as a handle returned from a function. In such
  7070. // cases it must be possible to assign values to it anyway.
  7071. if( lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle )
  7072. {
  7073. // Convert the handle to a object reference
  7074. asCDataType to;
  7075. to = lctx->type.dataType;
  7076. to.MakeHandle(false);
  7077. ImplicitConversion(lctx, to, lexpr, asIC_IMPLICIT_CONV);
  7078. lctx->type.isLValue = true; // Handle may not have been an lvalue, but the dereferenced object is
  7079. }
  7080. // Check for overloaded assignment operator
  7081. if( CompileOverloadedDualOperator(opNode, lctx, rctx, false, ctx) )
  7082. {
  7083. // An overloaded assignment operator was found (or a compilation error occured)
  7084. return 0;
  7085. }
  7086. // No registered operator was found. In case the operation is a direct
  7087. // assignment and the rvalue is the same type as the lvalue, then we can
  7088. // still use the byte-for-byte copy to do the assignment
  7089. if( op != ttAssignment )
  7090. {
  7091. asCString str;
  7092. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  7093. Error(str, lexpr);
  7094. return -1;
  7095. }
  7096. // If the left hand expression is simple, i.e. without any
  7097. // function calls or allocations of memory, then we can avoid
  7098. // doing a copy of the right hand expression (done by PrepareArgument).
  7099. // Instead the reference to the value can be placed directly on the
  7100. // stack.
  7101. //
  7102. // This optimization should only be done for value types, where
  7103. // the application developer is responsible for making the
  7104. // implementation safe against unwanted destruction of the input
  7105. // reference before the time.
  7106. bool simpleExpr = (lctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) && lctx->bc.IsSimpleExpression();
  7107. // Implicitly convert the rvalue to the type of the lvalue
  7108. bool needConversion = false;
  7109. if( !lctx->type.dataType.IsEqualExceptRefAndConst(rctx->type.dataType) )
  7110. needConversion = true;
  7111. if( !simpleExpr || needConversion )
  7112. {
  7113. asCDataType dt = lctx->type.dataType;
  7114. dt.MakeReference(true);
  7115. dt.MakeReadOnly(true);
  7116. int r = PrepareArgument(&dt, rctx, rexpr, true, 1, !needConversion);
  7117. if( r < 0 )
  7118. return -1;
  7119. if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) )
  7120. {
  7121. asCString str;
  7122. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  7123. Error(str, rexpr);
  7124. return -1;
  7125. }
  7126. }
  7127. else
  7128. {
  7129. // Process any property accessor first, before placing the final reference on the stack
  7130. ProcessPropertyGetAccessor(rctx, rexpr);
  7131. if( rctx->type.dataType.IsReference() && (!(rctx->type.isVariable || rctx->type.isTemporary) || IsVariableOnHeap(rctx->type.stackOffset)) )
  7132. rctx->bc.Instr(asBC_RDSPtr);
  7133. }
  7134. MergeExprBytecode(ctx, rctx);
  7135. MergeExprBytecode(ctx, lctx);
  7136. if( !simpleExpr || needConversion )
  7137. {
  7138. if( !rctx->type.isRefSafe && (rctx->type.isVariable || rctx->type.isTemporary) )
  7139. {
  7140. if( !IsVariableOnHeap(rctx->type.stackOffset) )
  7141. // TODO: runtime optimize: Actually the reference can be pushed on the stack directly
  7142. // as the value allocated on the stack is guaranteed to be safe.
  7143. // The bytecode optimizer should be able to determine this and optimize away the VAR + GETREF
  7144. ctx->bc.InstrWORD(asBC_GETREF, AS_PTR_SIZE);
  7145. else
  7146. ctx->bc.InstrWORD(asBC_GETOBJREF, AS_PTR_SIZE);
  7147. }
  7148. }
  7149. PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode);
  7150. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  7151. ctx->type = lctx->type;
  7152. }
  7153. return 0;
  7154. }
  7155. int asCCompiler::CompileAssignment(asCScriptNode *expr, asCExprContext *ctx)
  7156. {
  7157. asASSERT(expr->nodeType == snAssignment);
  7158. asCScriptNode *lexpr = expr->firstChild;
  7159. if( lexpr->next )
  7160. {
  7161. // Compile the two expression terms
  7162. asCExprContext lctx(engine), rctx(engine);
  7163. int rr = CompileAssignment(lexpr->next->next, &rctx);
  7164. int lr = CompileCondition(lexpr, &lctx);
  7165. if( lr >= 0 && rr >= 0 )
  7166. return DoAssignment(ctx, &lctx, &rctx, lexpr, lexpr->next->next, lexpr->next->tokenType, lexpr->next);
  7167. // Since the operands failed, the assignment was not computed
  7168. ctx->type.SetDummy();
  7169. return -1;
  7170. }
  7171. return CompileCondition(lexpr, ctx);
  7172. }
  7173. int asCCompiler::CompileCondition(asCScriptNode *expr, asCExprContext *ctx)
  7174. {
  7175. asCExprValue ctype;
  7176. // Compile the conditional expression
  7177. asCScriptNode *cexpr = expr->firstChild;
  7178. if( cexpr->next )
  7179. {
  7180. //-------------------------------
  7181. // Compile the condition
  7182. asCExprContext e(engine);
  7183. int r = CompileExpression(cexpr, &e);
  7184. if( r < 0 )
  7185. e.type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  7186. // Allow value types to be converted to bool using 'bool opImplConv()'
  7187. if( e.type.dataType.GetTypeInfo() && (e.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
  7188. ImplicitConversion(&e, asCDataType::CreatePrimitive(ttBool, false), cexpr, asIC_IMPLICIT_CONV);
  7189. if( r >= 0 && !e.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  7190. {
  7191. Error(TXT_EXPR_MUST_BE_BOOL, cexpr);
  7192. e.type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  7193. }
  7194. ctype = e.type;
  7195. ProcessPropertyGetAccessor(&e, cexpr);
  7196. if( e.type.dataType.IsReference() ) ConvertToVariable(&e);
  7197. ProcessDeferredParams(&e);
  7198. //-------------------------------
  7199. // Compile the left expression
  7200. asCExprContext le(engine);
  7201. int lr = CompileAssignment(cexpr->next, &le);
  7202. // Resolve any function names already
  7203. DetermineSingleFunc(&le, cexpr->next);
  7204. //-------------------------------
  7205. // Compile the right expression
  7206. asCExprContext re(engine);
  7207. int rr = CompileAssignment(cexpr->next->next, &re);
  7208. DetermineSingleFunc(&re, cexpr->next->next);
  7209. if( lr >= 0 && rr >= 0 )
  7210. {
  7211. // Don't allow any operators on expressions that take address of class method
  7212. if( le.IsClassMethod() || re.IsClassMethod() )
  7213. {
  7214. Error(TXT_INVALID_OP_ON_METHOD, expr);
  7215. return -1;
  7216. }
  7217. ProcessPropertyGetAccessor(&le, cexpr->next);
  7218. ProcessPropertyGetAccessor(&re, cexpr->next->next);
  7219. bool isExplicitHandle = le.type.isExplicitHandle || re.type.isExplicitHandle;
  7220. // Allow a 0 or null in the first case to be implicitly converted to the second type
  7221. if( le.type.isConstant && le.type.GetConstantData() == 0 && le.type.dataType.IsIntegerType() )
  7222. {
  7223. asCDataType to = re.type.dataType;
  7224. to.MakeReference(false);
  7225. to.MakeReadOnly(true);
  7226. ImplicitConversionConstant(&le, to, cexpr->next, asIC_IMPLICIT_CONV);
  7227. }
  7228. else if( le.type.IsNullConstant() )
  7229. {
  7230. asCDataType to = re.type.dataType;
  7231. to.MakeHandle(true);
  7232. ImplicitConversion(&le, to, cexpr->next, asIC_IMPLICIT_CONV);
  7233. }
  7234. // Allow either case to be converted to const @ if the other is const @
  7235. if( (le.type.dataType.IsHandleToConst() && !le.type.IsNullConstant()) || (re.type.dataType.IsHandleToConst() && !re.type.dataType.IsNullHandle()) )
  7236. {
  7237. le.type.dataType.MakeHandleToConst(true);
  7238. re.type.dataType.MakeHandleToConst(true);
  7239. }
  7240. // Allow an anonymous initialization list to be converted to the type in the other condition
  7241. if (le.IsAnonymousInitList() && re.type.dataType.GetBehaviour() && re.type.dataType.GetBehaviour()->listFactory)
  7242. {
  7243. asCDataType to = re.type.dataType;
  7244. to.MakeReference(false);
  7245. to.MakeReadOnly(false);
  7246. ImplicitConversion(&le, to, cexpr->next, asIC_IMPLICIT_CONV);
  7247. }
  7248. else if (re.IsAnonymousInitList() && le.type.dataType.GetBehaviour() && le.type.dataType.GetBehaviour()->listFactory)
  7249. {
  7250. asCDataType to = le.type.dataType;
  7251. to.MakeReference(false);
  7252. to.MakeReadOnly(false);
  7253. ImplicitConversion(&re, to, cexpr->next->next, asIC_IMPLICIT_CONV);
  7254. }
  7255. if (le.IsAnonymousInitList() )
  7256. {
  7257. Error(TXT_CANNOT_RESOLVE_AUTO, cexpr->next);
  7258. return -1;
  7259. }
  7260. else if (re.IsAnonymousInitList())
  7261. {
  7262. Error(TXT_CANNOT_RESOLVE_AUTO, cexpr->next->next);
  7263. return -1;
  7264. }
  7265. //---------------------------------
  7266. // Output the byte code
  7267. int afterLabel = nextLabel++;
  7268. int elseLabel = nextLabel++;
  7269. // If left expression is void, then we don't need to store the result
  7270. if( le.type.dataType.IsEqualExceptConst(asCDataType::CreatePrimitive(ttVoid, false)) )
  7271. {
  7272. // Put the code for the condition expression on the output
  7273. MergeExprBytecode(ctx, &e);
  7274. // Added the branch decision
  7275. ctx->type = e.type;
  7276. ConvertToVariable(ctx);
  7277. ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset);
  7278. ctx->bc.Instr(asBC_ClrHi);
  7279. ctx->bc.InstrDWORD(asBC_JZ, elseLabel);
  7280. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  7281. // Add the left expression
  7282. MergeExprBytecode(ctx, &le);
  7283. ctx->bc.InstrINT(asBC_JMP, afterLabel);
  7284. // Add the right expression
  7285. ctx->bc.Label((short)elseLabel);
  7286. MergeExprBytecode(ctx, &re);
  7287. ctx->bc.Label((short)afterLabel);
  7288. // Make sure both expressions have the same type
  7289. if( le.type.dataType != re.type.dataType )
  7290. Error(TXT_BOTH_MUST_BE_SAME, expr);
  7291. // Set the type of the result
  7292. ctx->type = le.type;
  7293. }
  7294. else if (le.type.IsNullConstant() && re.type.IsNullConstant())
  7295. {
  7296. // Special case for when both results are 'null'
  7297. // TODO: Other expressions where both results are identical literal constants can probably also be handled this way
  7298. // Put the code for the condition expression on the output
  7299. MergeExprBytecode(ctx, &e);
  7300. // Load the result into the register, but ignore the value since both paths give the same response
  7301. ctx->type = e.type;
  7302. ConvertToVariable(ctx);
  7303. ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset);
  7304. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  7305. // Return a null constant
  7306. ctx->bc.Instr(asBC_PshNull);
  7307. ctx->type.SetNullConstant();
  7308. }
  7309. else
  7310. {
  7311. // Allow "(a ? b : c) = d;" and "return (a ? b : c);" (where the latter returns the reference)
  7312. //
  7313. // Restrictions for the condition to be used as lvalue:
  7314. // 1. both b and c must be of the same type and be lvalue references
  7315. // 2. neither of the expressions can have any deferred arguments
  7316. // that would have to be cleaned up after the reference
  7317. // 3. neither expression can be temporary
  7318. //
  7319. // If either expression is local, the resulting lvalue is not valid
  7320. // for return since it is not allowed to return references to local
  7321. // variables.
  7322. //
  7323. // The reference to the local variable must be loaded into the register,
  7324. // the resulting expression must not be considered as a local variable
  7325. // with a stack offset (i.e. it will not be allowed to use asBC_VAR)
  7326. if( le.type.isLValue && re.type.isLValue &&
  7327. le.deferredParams.GetLength() == 0 && re.deferredParams.GetLength() ==0 &&
  7328. !le.type.isTemporary && !re.type.isTemporary &&
  7329. le.type.dataType == re.type.dataType )
  7330. {
  7331. // Put the code for the condition expression on the output
  7332. MergeExprBytecode(ctx, &e);
  7333. // Add the branch decision
  7334. ctx->type = e.type;
  7335. ConvertToVariable(ctx);
  7336. ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset);
  7337. ctx->bc.Instr(asBC_ClrHi);
  7338. ctx->bc.InstrDWORD(asBC_JZ, elseLabel);
  7339. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  7340. // Start of the left expression
  7341. MergeExprBytecode(ctx, &le);
  7342. if( !le.type.dataType.IsReference() && le.type.isVariable )
  7343. {
  7344. // Load the address of the variable into the register
  7345. ctx->bc.InstrSHORT(asBC_LDV, le.type.stackOffset);
  7346. }
  7347. ctx->bc.InstrINT(asBC_JMP, afterLabel);
  7348. // Start of the right expression
  7349. ctx->bc.Label((short)elseLabel);
  7350. MergeExprBytecode(ctx, &re);
  7351. if( !re.type.dataType.IsReference() && re.type.isVariable )
  7352. {
  7353. // Load the address of the variable into the register
  7354. ctx->bc.InstrSHORT(asBC_LDV, re.type.stackOffset);
  7355. }
  7356. ctx->bc.Label((short)afterLabel);
  7357. // In case the options were to objects, it is necessary to dereference the pointer on
  7358. // the stack so it will point to the actual object, instead of the variable
  7359. if( le.type.dataType.IsReference() && le.type.dataType.IsObject() && !le.type.dataType.IsObjectHandle() )
  7360. {
  7361. asASSERT( re.type.dataType.IsReference() && re.type.dataType.IsObject() && !re.type.dataType.IsObjectHandle() );
  7362. ctx->bc.Instr(asBC_RDSPtr);
  7363. }
  7364. // The result is an lvalue
  7365. ctx->type.isLValue = true;
  7366. ctx->type.dataType = le.type.dataType;
  7367. if( ctx->type.dataType.IsPrimitive() || ctx->type.dataType.IsObjectHandle() )
  7368. ctx->type.dataType.MakeReference(true);
  7369. else
  7370. ctx->type.dataType.MakeReference(false);
  7371. // It can't be a treated as a variable, since we don't know which one was used
  7372. ctx->type.isVariable = false;
  7373. ctx->type.isTemporary = false;
  7374. // Must remember if the reference was to a local variable, since it must not be allowed to be returned
  7375. ctx->type.isRefToLocal = le.type.isVariable || le.type.isRefToLocal || re.type.isVariable || re.type.isRefToLocal;
  7376. }
  7377. else
  7378. {
  7379. // Allocate temporary variable and copy the result to that one
  7380. asCExprValue temp;
  7381. temp = le.type;
  7382. temp.dataType.MakeReference(false);
  7383. temp.dataType.MakeReadOnly(false);
  7384. // Make sure the variable isn't used in any of the expressions,
  7385. // as it would be overwritten which may cause crashes or less visible bugs
  7386. int l = int(reservedVariables.GetLength());
  7387. e.bc.GetVarsUsed(reservedVariables);
  7388. le.bc.GetVarsUsed(reservedVariables);
  7389. re.bc.GetVarsUsed(reservedVariables);
  7390. int offset = AllocateVariable(temp.dataType, true, false);
  7391. reservedVariables.SetLength(l);
  7392. temp.SetVariable(temp.dataType, offset, true);
  7393. // TODO: copy: Use copy constructor if available. See PrepareTemporaryVariable()
  7394. CallDefaultConstructor(temp.dataType, offset, IsVariableOnHeap(offset), &ctx->bc, expr);
  7395. // Put the code for the condition expression on the output
  7396. MergeExprBytecode(ctx, &e);
  7397. // Add the branch decision
  7398. ctx->type = e.type;
  7399. ConvertToVariable(ctx);
  7400. ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset);
  7401. ctx->bc.Instr(asBC_ClrHi);
  7402. ctx->bc.InstrDWORD(asBC_JZ, elseLabel);
  7403. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  7404. // Assign the result of the left expression to the temporary variable
  7405. asCExprValue rtemp;
  7406. rtemp = temp;
  7407. if( rtemp.dataType.IsObjectHandle() )
  7408. rtemp.isExplicitHandle = true;
  7409. PrepareForAssignment(&rtemp.dataType, &le, cexpr->next, true);
  7410. MergeExprBytecode(ctx, &le);
  7411. if( !rtemp.dataType.IsPrimitive() )
  7412. {
  7413. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  7414. rtemp.dataType.MakeReference(IsVariableOnHeap(offset));
  7415. }
  7416. asCExprValue result;
  7417. result = rtemp;
  7418. PerformAssignment(&result, &le.type, &ctx->bc, cexpr->next);
  7419. if( !result.dataType.IsPrimitive() )
  7420. ctx->bc.Instr(asBC_PopPtr); // Pop the original value (always a pointer)
  7421. // Release the old temporary variable
  7422. ReleaseTemporaryVariable(le.type, &ctx->bc);
  7423. ctx->bc.InstrINT(asBC_JMP, afterLabel);
  7424. // Start of the right expression
  7425. ctx->bc.Label((short)elseLabel);
  7426. // Copy the result to the same temporary variable
  7427. PrepareForAssignment(&rtemp.dataType, &re, cexpr->next, true);
  7428. MergeExprBytecode(ctx, &re);
  7429. if( !rtemp.dataType.IsPrimitive() )
  7430. {
  7431. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  7432. rtemp.dataType.MakeReference(IsVariableOnHeap(offset));
  7433. }
  7434. result = rtemp;
  7435. PerformAssignment(&result, &re.type, &ctx->bc, cexpr->next);
  7436. if( !result.dataType.IsPrimitive() )
  7437. ctx->bc.Instr(asBC_PopPtr); // Pop the original value (always a pointer)
  7438. // Release the old temporary variable
  7439. ReleaseTemporaryVariable(re.type, &ctx->bc);
  7440. ctx->bc.Label((short)afterLabel);
  7441. // Make sure both expressions have the same type
  7442. if( !le.type.dataType.IsEqualExceptConst(re.type.dataType) )
  7443. Error(TXT_BOTH_MUST_BE_SAME, expr);
  7444. // Set the temporary variable as output
  7445. ctx->type = rtemp;
  7446. ctx->type.isExplicitHandle = isExplicitHandle;
  7447. if( !ctx->type.dataType.IsPrimitive() )
  7448. {
  7449. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  7450. ctx->type.dataType.MakeReference(IsVariableOnHeap(offset));
  7451. }
  7452. // Make sure the output isn't marked as being a literal constant
  7453. ctx->type.isConstant = false;
  7454. }
  7455. }
  7456. }
  7457. else
  7458. {
  7459. ctx->type.SetDummy();
  7460. return -1;
  7461. }
  7462. }
  7463. else
  7464. return CompileExpression(cexpr, ctx);
  7465. return 0;
  7466. }
  7467. int asCCompiler::CompileExpression(asCScriptNode *expr, asCExprContext *ctx)
  7468. {
  7469. asASSERT(expr->nodeType == snExpression);
  7470. // Convert to polish post fix, i.e: a+b => ab+
  7471. asCArray<asCScriptNode *> postfix;
  7472. ConvertToPostFix(expr, postfix);
  7473. // Compile the postfix formatted expression
  7474. return CompilePostFixExpression(&postfix, ctx);
  7475. }
  7476. void asCCompiler::ConvertToPostFix(asCScriptNode *expr, asCArray<asCScriptNode *> &postfix)
  7477. {
  7478. // The algorithm that I've implemented here is similar to
  7479. // Djikstra's Shunting Yard algorithm, though I didn't know it at the time.
  7480. // ref: http://en.wikipedia.org/wiki/Shunting-yard_algorithm
  7481. // Count the nodes in order to preallocate the buffers
  7482. int count = 0;
  7483. asCScriptNode *node = expr->firstChild;
  7484. while( node )
  7485. {
  7486. count++;
  7487. node = node->next;
  7488. }
  7489. asCArray<asCScriptNode *> stackA(count);
  7490. asCArray<asCScriptNode *> &stackB = postfix;
  7491. stackB.Allocate(count, false);
  7492. node = expr->firstChild;
  7493. while( node )
  7494. {
  7495. int precedence = GetPrecedence(node);
  7496. while( stackA.GetLength() > 0 &&
  7497. precedence <= GetPrecedence(stackA[stackA.GetLength()-1]) )
  7498. stackB.PushLast(stackA.PopLast());
  7499. stackA.PushLast(node);
  7500. node = node->next;
  7501. }
  7502. while( stackA.GetLength() > 0 )
  7503. stackB.PushLast(stackA.PopLast());
  7504. }
  7505. int asCCompiler::CompilePostFixExpression(asCArray<asCScriptNode *> *postfix, asCExprContext *ctx)
  7506. {
  7507. // Shouldn't send any byte code
  7508. asASSERT(ctx->bc.GetLastInstr() == -1);
  7509. // Set the context to a dummy type to avoid further
  7510. // errors in case the expression fails to compile
  7511. ctx->type.SetDummy();
  7512. // Evaluate the operands and operators
  7513. asCArray<asCExprContext*> free;
  7514. asCArray<asCExprContext*> expr;
  7515. int ret = 0;
  7516. for( asUINT n = 0; ret == 0 && n < postfix->GetLength(); n++ )
  7517. {
  7518. asCScriptNode *node = (*postfix)[n];
  7519. if( node->nodeType == snExprTerm )
  7520. {
  7521. asCExprContext *e = free.GetLength() ? free.PopLast() : asNEW(asCExprContext)(engine);
  7522. expr.PushLast(e);
  7523. e->exprNode = node;
  7524. ret = CompileExpressionTerm(node, e);
  7525. }
  7526. else
  7527. {
  7528. asCExprContext *r = expr.PopLast();
  7529. asCExprContext *l = expr.PopLast();
  7530. // Now compile the operator
  7531. asCExprContext *e = free.GetLength() ? free.PopLast() : asNEW(asCExprContext)(engine);
  7532. ret = CompileOperator(node, l, r, e);
  7533. expr.PushLast(e);
  7534. // Free the operands
  7535. l->Clear();
  7536. free.PushLast(l);
  7537. r->Clear();
  7538. free.PushLast(r);
  7539. }
  7540. }
  7541. if( ret == 0 )
  7542. {
  7543. asASSERT(expr.GetLength() == 1);
  7544. // The final result should be moved to the output context
  7545. MergeExprBytecodeAndType(ctx, expr[0]);
  7546. }
  7547. // Clean up
  7548. for( asUINT e = 0; e < expr.GetLength(); e++ )
  7549. asDELETE(expr[e], asCExprContext);
  7550. for( asUINT f = 0; f < free.GetLength(); f++ )
  7551. asDELETE(free[f], asCExprContext);
  7552. return ret;
  7553. }
  7554. int asCCompiler::CompileAnonymousInitList(asCScriptNode *node, asCExprContext *ctx, const asCDataType &dt)
  7555. {
  7556. asASSERT(node->nodeType == snInitList);
  7557. // Do not allow constructing non-shared types in shared functions
  7558. if (outFunc->IsShared() &&
  7559. dt.GetTypeInfo() && !dt.GetTypeInfo()->IsShared())
  7560. {
  7561. asCString msg;
  7562. msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, dt.GetTypeInfo()->name.AddressOf());
  7563. Error(msg, node);
  7564. }
  7565. // Allocate and initialize the temporary object
  7566. int offset = AllocateVariable(dt, true);
  7567. CompileInitialization(node, &ctx->bc, dt, node, offset, 0, 0);
  7568. // Push the reference to the object on the stack
  7569. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  7570. ctx->type.SetVariable(dt, offset, true);
  7571. ctx->type.isLValue = false;
  7572. // If the variable is allocated on the heap we have a reference,
  7573. // otherwise the actual object pointer is pushed on the stack.
  7574. if (IsVariableOnHeap(offset))
  7575. ctx->type.dataType.MakeReference(true);
  7576. // Clear the flag for anonymous initalization list as it is no
  7577. // longer true now that the object has been initialized.
  7578. ctx->isAnonymousInitList = false;
  7579. return 0;
  7580. }
  7581. int asCCompiler::CompileExpressionTerm(asCScriptNode *node, asCExprContext *ctx)
  7582. {
  7583. // Shouldn't send any byte code
  7584. asASSERT(ctx->bc.GetLastInstr() == -1);
  7585. // Check if this is an initialization of a temp object with an initialization list
  7586. if (node->firstChild )
  7587. {
  7588. if (node->firstChild->nodeType == snDataType)
  7589. {
  7590. // Determine the type of the temporary object
  7591. asCDataType dt = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace);
  7592. return CompileAnonymousInitList(node->lastChild, ctx, dt);
  7593. }
  7594. else if (node->firstChild->nodeType == snInitList)
  7595. {
  7596. // As the type is not yet known, the init list will be compiled at a
  7597. // later time when the type can be determined from the destination
  7598. ctx->SetAnonymousInitList(node->firstChild);
  7599. return 0;
  7600. }
  7601. }
  7602. // Set the type as a dummy by default, in case of any compiler errors
  7603. ctx->type.SetDummy();
  7604. // Compile the value node
  7605. asCScriptNode *vnode = node->firstChild;
  7606. while( vnode->nodeType != snExprValue )
  7607. vnode = vnode->next;
  7608. asCExprContext v(engine);
  7609. int r = CompileExpressionValue(vnode, &v); if( r < 0 ) return r;
  7610. // Compile post fix operators
  7611. asCScriptNode *pnode = vnode->next;
  7612. while( pnode )
  7613. {
  7614. r = CompileExpressionPostOp(pnode, &v); if( r < 0 ) return r;
  7615. pnode = pnode->next;
  7616. }
  7617. // Compile pre fix operators
  7618. pnode = vnode->prev;
  7619. while( pnode )
  7620. {
  7621. r = CompileExpressionPreOp(pnode, &v); if( r < 0 ) return r;
  7622. pnode = pnode->prev;
  7623. }
  7624. // Return the byte code and final type description
  7625. MergeExprBytecodeAndType(ctx, &v);
  7626. return 0;
  7627. }
  7628. // returns:
  7629. // SL_LOCALCONST = local constant
  7630. // SL_LOCALVAR = local variable
  7631. // SL_NOMATCH = no match
  7632. asCCompiler::SYMBOLTYPE asCCompiler::SymbolLookupLocalVar(const asCString &name, asCExprContext *outResult)
  7633. {
  7634. sVariable *v = 0;
  7635. if (variables)
  7636. v = variables->GetVariable(name.AddressOf());
  7637. if (v)
  7638. {
  7639. if (v->isPureConstant)
  7640. {
  7641. outResult->type.SetConstantData(v->type, v->constantValue);
  7642. return SL_LOCALCONST;
  7643. }
  7644. outResult->type.SetVariable(v->type, v->stackOffset, false);
  7645. return SL_LOCALVAR;
  7646. }
  7647. return SL_NOMATCH;
  7648. }
  7649. // returns:
  7650. // SL_CLASSPROPACCESS = class property accessor
  7651. // SL_CLASSPROP = class property
  7652. // SL_CLASSMETHOD = class method
  7653. // SL_CLASSTYPE = class child type
  7654. // SL_NOMATCH = no match
  7655. // SL_ERROR = error
  7656. asCCompiler::SYMBOLTYPE asCCompiler::SymbolLookupMember(const asCString &name, asCObjectType *objType, asCExprContext *outResult)
  7657. {
  7658. // See if there are any matching property accessors
  7659. asCExprContext access(engine);
  7660. access.type.Set(asCDataType::CreateType(objType, false));
  7661. access.type.dataType.MakeReference(true);
  7662. int r = 0;
  7663. // Indexed property access
  7664. asCExprContext dummyArg(engine);
  7665. r = FindPropertyAccessor(name, &access, &dummyArg, 0, 0, true);
  7666. if (r == 0)
  7667. {
  7668. // Normal property access
  7669. r = FindPropertyAccessor(name, &access, 0, 0, true);
  7670. }
  7671. if (r < 0) return SL_ERROR;
  7672. if (access.property_get || access.property_set)
  7673. {
  7674. MergeExprBytecodeAndType(outResult, &access);
  7675. outResult->type.dataType.SetTypeInfo(objType);
  7676. return SL_CLASSPROPACCESS;
  7677. }
  7678. // Look for matching properties
  7679. asCDataType dt;
  7680. dt = asCDataType::CreateType(objType, false);
  7681. asCObjectProperty *prop = builder->GetObjectProperty(dt, name.AddressOf());
  7682. if (prop)
  7683. {
  7684. outResult->type.dataType.SetTypeInfo(objType);
  7685. return SL_CLASSPROP;
  7686. }
  7687. // If it is not a property, it may still be the name of a method
  7688. asCObjectType *ot = objType;
  7689. for (asUINT n = 0; n < ot->methods.GetLength(); n++)
  7690. {
  7691. asCScriptFunction *f = engine->scriptFunctions[ot->methods[n]];
  7692. if (f->name == name &&
  7693. (builder->module->accessMask & f->accessMask))
  7694. {
  7695. outResult->type.dataType.SetTypeInfo(objType);
  7696. return SL_CLASSMETHOD;
  7697. }
  7698. }
  7699. // If it is not a method, then it can still be a child type
  7700. for (asUINT n = 0; n < ot->childFuncDefs.GetLength(); n++)
  7701. {
  7702. if (ot->childFuncDefs[n]->name == name)
  7703. {
  7704. outResult->type.dataType.SetTypeInfo(objType);
  7705. return SL_CLASSTYPE;
  7706. }
  7707. }
  7708. return SL_NOMATCH;
  7709. }
  7710. // The purpose of this function is to find the entity that matches the symbol name respecting the scope and visibility hierarchy
  7711. // The 'outResult' will be used to return info on what was identified, but no code will be produced by this function
  7712. // input:
  7713. // name = the name of the symbol to look for
  7714. // scope = explicit scope informed
  7715. // objType = used to look for symbols within object type (e.g. when compiling post op), in this case no local or global symbols will be looked up
  7716. // returns:
  7717. // SL_NOMATCH = no matching symbol
  7718. // SL_LOCALCONST = local constant
  7719. // SL_LOCALVAR = local variable
  7720. // SL_THISPTR = this pointer
  7721. // SL_CLASSPROPACCESS = class property accessor, lookupResult->dataType holds the object type in which the member was found
  7722. // SL_CLASSPROP = class property, lookupResult->dataType holds the object type in which the member was found
  7723. // SL_CLASSMETHOD = class method, lookupResult->dataType holds the object type in which the member was found
  7724. // SL_CLASSTYPE = class child type, lookupResult->dataType holds the object type in which the member was found
  7725. // SL_GLOBALPROPACCESS = global property accessor, lookupResult->symbolNamespace holds the namespace where the symbol was identified
  7726. // SL_GLOBALCONST = global constant, lookupResult->symbolNamespace holds the namespace where the symbol was identified
  7727. // SL_GLOBALVAR = global variable, lookupResult->symbolNamespace holds the namespace where the symbol was identified
  7728. // SL_GLOBALFUNC = global function, lookupResult->symbolNamespace holds the namespace where the symbol was identified
  7729. // SL_GLOBALTYPE = type, lookupResult->dataType holds the type
  7730. // SL_ENUMVAL = enum value, lookupResult->dataType holds the enum type, unless ambigious. lookupResult->symbolNamespace holds the namespace where the symbol was identified
  7731. // SL_ERROR = error
  7732. asCCompiler::SYMBOLTYPE asCCompiler::SymbolLookup(const asCString &name, const asCString &scope, asCObjectType *objType, asCExprContext *outResult)
  7733. {
  7734. asASSERT(outResult);
  7735. // It is a local variable or parameter?
  7736. // This is not accessible by default arg expressions
  7737. if (!isCompilingDefaultArg && scope == "" && !objType )
  7738. {
  7739. SYMBOLTYPE r = SymbolLookupLocalVar(name, outResult);
  7740. if (r != 0)
  7741. return r;
  7742. }
  7743. // Is it a class member?
  7744. // This is not accessible by default arg expressions
  7745. if (!isCompilingDefaultArg && scope == "" && ((objType) || (outFunc && outFunc->objectType)))
  7746. {
  7747. if (name == THIS_TOKEN && !objType)
  7748. {
  7749. asCDataType dt = asCDataType::CreateType(outFunc->objectType, outFunc->IsReadOnly());
  7750. // The object pointer is located at stack position 0
  7751. outResult->type.SetVariable(dt, 0, false);
  7752. return SL_THISPTR;
  7753. }
  7754. if (m_isConstructor && name == SUPER_TOKEN && !objType)
  7755. {
  7756. // If the class is derived from another class, then super can be used to call the base' class constructor
  7757. if (outFunc && outFunc->objectType->derivedFrom)
  7758. {
  7759. outResult->type.dataType.SetTypeInfo(outFunc->objectType->derivedFrom);
  7760. return SL_CLASSMETHOD;
  7761. }
  7762. }
  7763. // Look for members in the type
  7764. SYMBOLTYPE r = SymbolLookupMember(name, objType ? objType : outFunc->objectType, outResult);
  7765. if (r != 0)
  7766. return r;
  7767. }
  7768. // Recursively search parent namespaces for global entities
  7769. asSNameSpace *currNamespace = DetermineNameSpace("");
  7770. while( !objType && currNamespace )
  7771. {
  7772. asCString currScope = scope;
  7773. // If the scope contains ::identifier, then use the last identifier as the class name and the rest of it as the namespace
  7774. // TODO: child funcdef: A scope can include a template type, e.g. array<ns::type>
  7775. int n = currScope.FindLast("::");
  7776. asCString typeName = n >= 0 ? currScope.SubString(n + 2) : currScope;
  7777. asCString nsName = n >= 0 ? currScope.SubString(0, n) : "";
  7778. // If the scope represents a type that the current class inherits
  7779. // from then that should be used instead of going through the namespaces
  7780. if (nsName == "" && (outFunc && outFunc->objectType))
  7781. {
  7782. asCObjectType *ot = outFunc->objectType;
  7783. while (ot)
  7784. {
  7785. if (ot->name == typeName)
  7786. {
  7787. SYMBOLTYPE r = SymbolLookupMember(name, ot, outResult);
  7788. if (r != 0)
  7789. return r;
  7790. }
  7791. ot = ot->derivedFrom;
  7792. }
  7793. }
  7794. // If the scope starts with :: then search from the global scope
  7795. if (currScope.GetLength() < 2 || currScope[0] != ':')
  7796. {
  7797. if (nsName != "")
  7798. {
  7799. if (currNamespace->name != "")
  7800. nsName = currNamespace->name + "::" + nsName;
  7801. }
  7802. else
  7803. nsName = currNamespace->name;
  7804. }
  7805. else
  7806. nsName = nsName.SubString(2);
  7807. // Get the namespace for this scope
  7808. asSNameSpace *ns = engine->FindNameSpace(nsName.AddressOf());
  7809. if (ns)
  7810. {
  7811. // Is there a type with typeName in the namespace?
  7812. asCTypeInfo *scopeType = builder->GetType(typeName.AddressOf(), ns, 0);
  7813. // Check if the symbol is a member of that type
  7814. if (scopeType)
  7815. {
  7816. // Is it an object type?
  7817. if (CastToObjectType(scopeType))
  7818. {
  7819. SYMBOLTYPE r = SymbolLookupMember(name, CastToObjectType(scopeType), outResult);
  7820. if (r != 0)
  7821. return r;
  7822. }
  7823. // Is it an enum type?
  7824. if (CastToEnumType(scopeType))
  7825. {
  7826. asDWORD value = 0;
  7827. asCDataType dt;
  7828. if (builder->GetEnumValueFromType(CastToEnumType(scopeType), name.AddressOf(), dt, value))
  7829. {
  7830. // an enum value was resolved
  7831. outResult->type.SetConstantDW(dt, value);
  7832. outResult->symbolNamespace = ns;
  7833. return SL_ENUMVAL;
  7834. }
  7835. }
  7836. }
  7837. }
  7838. // Get the namespace for this scope. This may return null if the scope is an enum
  7839. nsName = currScope;
  7840. // If the scope starts with :: then search from the global scope
  7841. if (currScope.GetLength() < 2 || currScope[0] != ':')
  7842. {
  7843. if (nsName != "")
  7844. {
  7845. if (currNamespace->name != "")
  7846. nsName = currNamespace->name + "::" + nsName;
  7847. }
  7848. else
  7849. nsName = currNamespace->name;
  7850. }
  7851. else
  7852. nsName = nsName.SubString(2);
  7853. ns = engine->FindNameSpace(nsName.AddressOf());
  7854. // Is it a global property?
  7855. if (ns)
  7856. {
  7857. // See if there are any matching global property accessors
  7858. asCExprContext access(engine);
  7859. int r = 0;
  7860. // Indexed property access
  7861. asCExprContext dummyArg(engine);
  7862. r = FindPropertyAccessor(name, &access, &dummyArg, 0, ns);
  7863. if (r == 0)
  7864. {
  7865. // Normal property access
  7866. r = FindPropertyAccessor(name, &access, 0, ns);
  7867. }
  7868. if (r < 0) return SL_ERROR;
  7869. if (access.property_get || access.property_set)
  7870. {
  7871. MergeExprBytecodeAndType(outResult, &access);
  7872. outResult->symbolNamespace = ns;
  7873. return SL_GLOBALPROPACCESS;
  7874. }
  7875. // See if there is any matching global property
  7876. bool isCompiled = true;
  7877. bool isPureConstant = false;
  7878. bool isAppProp = false;
  7879. asQWORD constantValue = 0;
  7880. asCGlobalProperty *prop = builder->GetGlobalProperty(name.AddressOf(), ns, &isCompiled, &isPureConstant, &constantValue, &isAppProp);
  7881. if (prop)
  7882. {
  7883. // If the global property is a pure constant
  7884. // we can allow the compiler to optimize it. Pure
  7885. // constants are global constant variables that were
  7886. // initialized by literal constants.
  7887. if (isPureConstant)
  7888. {
  7889. outResult->type.SetConstantData(prop->type, constantValue);
  7890. outResult->symbolNamespace = ns;
  7891. return SL_GLOBALCONST;
  7892. }
  7893. else
  7894. {
  7895. outResult->type.Set(prop->type);
  7896. outResult->symbolNamespace = ns;
  7897. return SL_GLOBALVAR;
  7898. }
  7899. }
  7900. }
  7901. // Is it the name of a global function?
  7902. if (ns)
  7903. {
  7904. asCArray<int> funcs;
  7905. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  7906. if (funcs.GetLength() > 0)
  7907. {
  7908. // Defer the evaluation of which function until it is actually used
  7909. // Store the namespace and name of the function for later
  7910. outResult->type.SetUndefinedFuncHandle(engine);
  7911. outResult->methodName = ns ? ns->name + "::" + name : name;
  7912. outResult->symbolNamespace = ns;
  7913. return SL_GLOBALFUNC;
  7914. }
  7915. }
  7916. // Check for type names
  7917. if (ns)
  7918. {
  7919. asCTypeInfo *type = builder->GetType(name.AddressOf(), ns, 0);
  7920. if (type)
  7921. {
  7922. outResult->type.dataType = asCDataType::CreateType(type, false);
  7923. return SL_GLOBALTYPE;
  7924. }
  7925. }
  7926. // Is it an enum value?
  7927. if (ns && !engine->ep.requireEnumScope)
  7928. {
  7929. // Look for the enum value without explicitly informing the enum type
  7930. asDWORD value = 0;
  7931. asCDataType dt;
  7932. int e = builder->GetEnumValue(name.AddressOf(), dt, value, ns);
  7933. if (e)
  7934. {
  7935. if (e == 2)
  7936. {
  7937. // Ambiguous enum value: Save the name for resolution later.
  7938. // The ambiguity could be resolved now, but I hesitate
  7939. // to store too much information in the context.
  7940. outResult->enumValue = name.AddressOf();
  7941. // We cannot set a dummy value because it will pass through
  7942. // cleanly as an integer.
  7943. outResult->type.SetConstantDW(asCDataType::CreatePrimitive(ttIdentifier, true), 0);
  7944. outResult->symbolNamespace = ns;
  7945. return SL_ENUMVAL;
  7946. }
  7947. else
  7948. {
  7949. // an enum value was resolved
  7950. outResult->type.SetConstantDW(dt, value);
  7951. outResult->symbolNamespace = ns;
  7952. return SL_ENUMVAL;
  7953. }
  7954. }
  7955. }
  7956. // If the given scope starts with '::' then the search starts from global scope
  7957. if (scope.GetLength() >= 2 && scope[0] == ':')
  7958. break;
  7959. // Move up to parent namespace
  7960. currNamespace = engine->GetParentNameSpace(currNamespace);
  7961. }
  7962. // The name doesn't match any symbol
  7963. return SL_NOMATCH;
  7964. }
  7965. int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &scope, asCExprContext *ctx, asCScriptNode *errNode, bool isOptional, asCObjectType *objType)
  7966. {
  7967. asCExprContext lookupResult(engine);
  7968. SYMBOLTYPE symbolType = SymbolLookup(name, scope, objType, &lookupResult);
  7969. if (symbolType < 0)
  7970. {
  7971. // Give dummy value
  7972. ctx->type.SetDummy();
  7973. return -1;
  7974. }
  7975. if (symbolType == SL_NOMATCH)
  7976. {
  7977. // Give dummy value
  7978. ctx->type.SetDummy();
  7979. if (!isOptional)
  7980. {
  7981. // No matching symbol
  7982. asCString msg;
  7983. asCString smbl;
  7984. if (scope == "::")
  7985. smbl = scope;
  7986. else if (scope != "")
  7987. smbl = scope + "::";
  7988. smbl += name;
  7989. msg.Format(TXT_NO_MATCHING_SYMBOL_s, smbl.AddressOf());
  7990. Error(msg, errNode);
  7991. }
  7992. return -1;
  7993. }
  7994. // It is a local variable or parameter?
  7995. if( symbolType == SL_LOCALCONST || symbolType == SL_LOCALVAR )
  7996. {
  7997. // This is not accessible by default arg expressions
  7998. asASSERT(!isCompilingDefaultArg && scope == "" && !objType && variables);
  7999. sVariable *v = variables->GetVariable(name.AddressOf());
  8000. asASSERT(v);
  8001. if( v->isPureConstant )
  8002. ctx->type.SetConstantData(v->type, v->constantValue);
  8003. else if( v->type.IsPrimitive() )
  8004. {
  8005. if( v->type.IsReference() )
  8006. {
  8007. // Copy the reference into the register
  8008. ctx->bc.InstrSHORT(asBC_PshVPtr, (short)v->stackOffset);
  8009. ctx->bc.Instr(asBC_PopRPtr);
  8010. ctx->type.Set(v->type);
  8011. }
  8012. else
  8013. ctx->type.SetVariable(v->type, v->stackOffset, false);
  8014. // Set as lvalue unless it is a const variable
  8015. if( !v->type.IsReadOnly() )
  8016. ctx->type.isLValue = true;
  8017. }
  8018. else
  8019. {
  8020. ctx->bc.InstrSHORT(asBC_PSF, (short)v->stackOffset);
  8021. ctx->type.SetVariable(v->type, v->stackOffset, false);
  8022. // If the variable is allocated on the heap we have a reference,
  8023. // otherwise the actual object pointer is pushed on the stack.
  8024. if( v->onHeap || v->type.IsObjectHandle() ) ctx->type.dataType.MakeReference(true);
  8025. // Implicitly dereference handle parameters sent by reference
  8026. if( v->type.IsReference() && (!v->type.IsObject() || v->type.IsObjectHandle()) )
  8027. ctx->bc.Instr(asBC_RDSPtr);
  8028. // Mark the object as safe for access unless it is a handle, as the
  8029. // life time of the object is guaranteed throughout the scope.
  8030. if( !v->type.IsObjectHandle() )
  8031. ctx->type.isRefSafe = true;
  8032. // Set as lvalue unless it is a const variable
  8033. if (!v->type.IsReadOnly())
  8034. ctx->type.isLValue = true;
  8035. }
  8036. return 0;
  8037. }
  8038. // Is it a class member?
  8039. if (symbolType == SL_CLASSPROPACCESS || symbolType == SL_CLASSPROP || symbolType == SL_CLASSMETHOD || symbolType == SL_THISPTR)
  8040. {
  8041. // This is not accessible by default arg expressions
  8042. asASSERT(!isCompilingDefaultArg);
  8043. if (symbolType == SL_THISPTR)
  8044. {
  8045. asASSERT(name == THIS_TOKEN && !objType && scope == "");
  8046. asCDataType dt = asCDataType::CreateType(outFunc->objectType, outFunc->IsReadOnly());
  8047. // The object pointer is located at stack position 0
  8048. ctx->bc.InstrSHORT(asBC_PSF, 0);
  8049. ctx->type.SetVariable(dt, 0, false);
  8050. ctx->type.dataType.MakeReference(true);
  8051. ctx->type.isLValue = true;
  8052. // The 'this' handle is always considered safe (i.e. life time guaranteed)
  8053. ctx->type.isRefSafe = true;
  8054. return 0;
  8055. }
  8056. if (symbolType == SL_CLASSPROPACCESS)
  8057. {
  8058. asASSERT(scope == "");
  8059. // See if there are any matching property accessors
  8060. asCExprContext access(engine);
  8061. if (objType)
  8062. access.type.Set(asCDataType::CreateType(objType, false));
  8063. else
  8064. access.type.Set(asCDataType::CreateType(outFunc->objectType, outFunc->IsReadOnly()));
  8065. access.type.dataType.MakeReference(true);
  8066. int r = 0;
  8067. if (errNode->next && errNode->next->tokenType == ttOpenBracket)
  8068. {
  8069. // This is an index access, check if there is a property accessor that takes an index arg
  8070. asCExprContext dummyArg(engine);
  8071. r = FindPropertyAccessor(name, &access, &dummyArg, errNode, 0, true);
  8072. }
  8073. if (r == 0)
  8074. {
  8075. // Normal property access
  8076. r = FindPropertyAccessor(name, &access, errNode, 0, true);
  8077. }
  8078. if (r < 0) return -1;
  8079. if (access.property_get == 0 && access.property_set == 0)
  8080. {
  8081. // Even though the symbol was identified in SymbolLookup, it doesn't match the arguments
  8082. asCString msg;
  8083. if (errNode->next && errNode->next->tokenType == ttOpenBracket)
  8084. msg.Format(TXT_PROP_ACCESS_s_DOES_NOT_EXPECT_INDEX, name.AddressOf());
  8085. else
  8086. msg.Format(TXT_PROP_ACCESS_s_EXPECTS_INDEX, name.AddressOf());
  8087. Error(msg, errNode);
  8088. return -1;
  8089. }
  8090. if (!objType)
  8091. {
  8092. // Prepare the bytecode for the member access
  8093. // This is only done when accessing through the implicit this pointer
  8094. ctx->bc.InstrSHORT(asBC_PSF, 0);
  8095. }
  8096. MergeExprBytecodeAndType(ctx, &access);
  8097. return 0;
  8098. }
  8099. if (symbolType == SL_CLASSPROP)
  8100. {
  8101. if (scope != "")
  8102. {
  8103. // Cannot access non-static members like this
  8104. asCString msg;
  8105. msg.Format(TXT_CANNOT_ACCESS_NON_STATIC_MEMBER_s, name.AddressOf());
  8106. Error(msg, errNode);
  8107. return -1;
  8108. }
  8109. asCDataType dt;
  8110. if (objType)
  8111. dt = asCDataType::CreateType(objType, false);
  8112. else
  8113. dt = asCDataType::CreateType(outFunc->objectType, false);
  8114. asCObjectProperty *prop = builder->GetObjectProperty(dt, name.AddressOf());
  8115. asASSERT(prop);
  8116. // Is the property access allowed?
  8117. if (prop->isPrivate && prop->isInherited)
  8118. {
  8119. if (engine->ep.privatePropAsProtected)
  8120. {
  8121. // The application is allowing inherited classes to access private properties of the parent
  8122. // class. This option is allowed to provide backwards compatibility with pre-2.30.0 versions
  8123. // as it was how the compiler behaved earlier.
  8124. asCString msg;
  8125. msg.Format(TXT_ACCESSING_PRIVATE_PROP_s, name.AddressOf());
  8126. Warning(msg, errNode);
  8127. }
  8128. else
  8129. {
  8130. asCString msg;
  8131. msg.Format(TXT_INHERITED_PRIVATE_PROP_ACCESS_s, name.AddressOf());
  8132. Error(msg, errNode);
  8133. }
  8134. }
  8135. if (!objType)
  8136. {
  8137. // The object pointer is located at stack position 0
  8138. // This is only done when accessing through the implicit this pointer
  8139. ctx->bc.InstrSHORT(asBC_PSF, 0);
  8140. ctx->type.SetVariable(dt, 0, false);
  8141. ctx->type.dataType.MakeReference(true);
  8142. Dereference(ctx, true);
  8143. }
  8144. // TODO: This is the same as what is in CompileExpressionPostOp
  8145. // Put the offset on the stack
  8146. ctx->bc.InstrSHORT_DW(asBC_ADDSi, (short)prop->byteOffset, engine->GetTypeIdFromDataType(dt));
  8147. if (prop->type.IsReference())
  8148. ctx->bc.Instr(asBC_RDSPtr);
  8149. // Reference to primitive must be stored in the temp register
  8150. if (prop->type.IsPrimitive())
  8151. {
  8152. // TODO: runtime optimize: The ADD offset command should store the reference in the register directly
  8153. ctx->bc.Instr(asBC_PopRPtr);
  8154. }
  8155. // Set the new type (keeping info about temp variable)
  8156. ctx->type.dataType = prop->type;
  8157. ctx->type.dataType.MakeReference(true);
  8158. ctx->type.isVariable = false;
  8159. ctx->type.isLValue = true;
  8160. if (ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle())
  8161. {
  8162. // Objects that are members are not references
  8163. ctx->type.dataType.MakeReference(false);
  8164. // Objects that are members but not handles are safe as long as the parent object is safe
  8165. if (!objType || ctx->type.isRefSafe)
  8166. ctx->type.isRefSafe = true;
  8167. }
  8168. else if (ctx->type.dataType.IsObjectHandle())
  8169. {
  8170. // Objects accessed through handles cannot be considered safe
  8171. // as the handle can be cleared at any time
  8172. ctx->type.isRefSafe = false;
  8173. }
  8174. // If the object reference is const, the property will also be const
  8175. ctx->type.dataType.MakeReadOnly(outFunc->IsReadOnly());
  8176. return 0;
  8177. }
  8178. if (symbolType == SL_CLASSMETHOD)
  8179. {
  8180. asASSERT(objType || outFunc->objectType);
  8181. // If it is not a property, it may still be the name of a method which can be used to create delegates
  8182. asCObjectType *ot = outFunc->objectType;
  8183. asCScriptFunction *func = 0;
  8184. for (asUINT n = 0; n < ot->methods.GetLength(); n++)
  8185. {
  8186. asCScriptFunction *f = engine->scriptFunctions[ot->methods[n]];
  8187. if (f->name == name &&
  8188. (builder->module->accessMask & f->accessMask))
  8189. {
  8190. func = f;
  8191. break;
  8192. }
  8193. }
  8194. asASSERT(func);
  8195. // An object method was found. Keep the name of the method in the expression, but
  8196. // don't actually modify the bytecode at this point since it is not yet known what
  8197. // the method will be used for, or even what overloaded method should be used.
  8198. ctx->methodName = name;
  8199. // Place the object pointer on the stack, as if the expression was this.func
  8200. if (!objType)
  8201. {
  8202. // The object pointer is located at stack position 0
  8203. // This is only done when accessing through the implicit this pointer
  8204. ctx->bc.InstrSHORT(asBC_PSF, 0);
  8205. ctx->type.SetVariable(asCDataType::CreateType(outFunc->objectType, false), 0, false);
  8206. ctx->type.dataType.MakeReference(true);
  8207. Dereference(ctx, true);
  8208. }
  8209. return 0;
  8210. }
  8211. }
  8212. if (symbolType == SL_GLOBALCONST || symbolType == SL_GLOBALPROPACCESS || symbolType == SL_GLOBALVAR || symbolType == SL_GLOBALFUNC || symbolType == SL_ENUMVAL)
  8213. {
  8214. // Get the namespace from SymbolLookup
  8215. asSNameSpace *ns = lookupResult.symbolNamespace;
  8216. if (symbolType == SL_GLOBALPROPACCESS)
  8217. {
  8218. // See if there are any matching global property accessors
  8219. asCExprContext access(engine);
  8220. int r = 0;
  8221. if (errNode->next && errNode->next->tokenType == ttOpenBracket)
  8222. {
  8223. // This is an index access, check if there is a property accessor that takes an index arg
  8224. asCExprContext dummyArg(engine);
  8225. r = FindPropertyAccessor(name, &access, &dummyArg, errNode, ns);
  8226. }
  8227. if (r == 0)
  8228. {
  8229. // Normal property access
  8230. r = FindPropertyAccessor(name, &access, errNode, ns);
  8231. }
  8232. if (r < 0) return -1;
  8233. if (access.property_get == 0 && access.property_set == 0)
  8234. {
  8235. // Even though the symbol was identified in SymbolLookup, it doesn't match the arguments
  8236. asCString msg;
  8237. if (errNode->next && errNode->next->tokenType == ttOpenBracket)
  8238. msg.Format(TXT_PROP_ACCESS_s_DOES_NOT_EXPECT_INDEX, name.AddressOf());
  8239. else
  8240. msg.Format(TXT_PROP_ACCESS_s_EXPECTS_INDEX, name.AddressOf());
  8241. Error(msg, errNode);
  8242. return -1;
  8243. }
  8244. // Prepare the bytecode for the function call
  8245. MergeExprBytecodeAndType(ctx, &access);
  8246. return 0;
  8247. }
  8248. if (symbolType == SL_GLOBALCONST || symbolType == SL_GLOBALVAR)
  8249. {
  8250. bool isCompiled = true;
  8251. bool isPureConstant = false;
  8252. bool isAppProp = false;
  8253. asQWORD constantValue = 0;
  8254. asCGlobalProperty *prop = builder->GetGlobalProperty(name.AddressOf(), ns, &isCompiled, &isPureConstant, &constantValue, &isAppProp);
  8255. asASSERT(prop);
  8256. // Verify that the global property has been compiled already
  8257. if (!isCompiled)
  8258. {
  8259. asCString str;
  8260. str.Format(TXT_UNINITIALIZED_GLOBAL_VAR_s, prop->name.AddressOf());
  8261. Error(str, errNode);
  8262. return -1;
  8263. }
  8264. // If the global property is a pure constant
  8265. // we can allow the compiler to optimize it. Pure
  8266. // constants are global constant variables that were
  8267. // initialized by literal constants.
  8268. if (isPureConstant)
  8269. ctx->type.SetConstantData(prop->type, constantValue);
  8270. else
  8271. {
  8272. // A shared type must not access global vars, unless they
  8273. // too are shared, e.g. application registered vars
  8274. if (outFunc->IsShared())
  8275. {
  8276. if (!isAppProp)
  8277. {
  8278. asCString str;
  8279. str.Format(TXT_SHARED_CANNOT_ACCESS_NON_SHARED_VAR_s, prop->name.AddressOf());
  8280. Error(str, errNode);
  8281. // Allow the compilation to continue to catch other problems
  8282. }
  8283. }
  8284. ctx->type.Set(prop->type);
  8285. ctx->type.isLValue = true;
  8286. if (ctx->type.dataType.IsPrimitive())
  8287. {
  8288. // Load the address of the variable into the register
  8289. ctx->bc.InstrPTR(asBC_LDG, prop->GetAddressOfValue());
  8290. ctx->type.dataType.MakeReference(true);
  8291. }
  8292. else
  8293. {
  8294. // Push the address of the variable on the stack
  8295. ctx->bc.InstrPTR(asBC_PGA, prop->GetAddressOfValue());
  8296. // If the object is a value type or a non-handle variable to a reference type,
  8297. // then we must validate the existance as it could potentially be accessed
  8298. // before it is initialized.
  8299. // This check is not needed for application registered properties, since they
  8300. // are guaranteed to be valid by the application itself.
  8301. if (!isAppProp &&
  8302. ((ctx->type.dataType.GetTypeInfo()->flags & asOBJ_VALUE) ||
  8303. !ctx->type.dataType.IsObjectHandle()))
  8304. {
  8305. ctx->bc.Instr(asBC_ChkRefS);
  8306. }
  8307. // If the address pushed on the stack is to a value type or an object
  8308. // handle, then mark the expression as a reference. Addresses to a reference
  8309. // type aren't marked as references to get correct behaviour
  8310. if ((ctx->type.dataType.GetTypeInfo()->flags & asOBJ_VALUE) ||
  8311. ctx->type.dataType.IsObjectHandle())
  8312. {
  8313. ctx->type.dataType.MakeReference(true);
  8314. }
  8315. else
  8316. {
  8317. asASSERT((ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !ctx->type.dataType.IsObjectHandle());
  8318. // It's necessary to dereference the pointer so the pointer on the stack will point to the actual object
  8319. ctx->bc.Instr(asBC_RDSPtr);
  8320. }
  8321. }
  8322. }
  8323. return 0;
  8324. }
  8325. if (symbolType == SL_GLOBALFUNC)
  8326. {
  8327. asCArray<int> funcs;
  8328. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  8329. asASSERT(funcs.GetLength() > 0);
  8330. if (funcs.GetLength() > 0)
  8331. {
  8332. // Defer the evaluation of which function until it is actually used
  8333. // Store the namespace and name of the function for later
  8334. ctx->type.SetUndefinedFuncHandle(engine);
  8335. ctx->methodName = ns ? ns->name + "::" + name : name;
  8336. }
  8337. return 0;
  8338. }
  8339. if (symbolType == SL_ENUMVAL)
  8340. {
  8341. // The enum type and namespace must be returned from SymbolLookup
  8342. asCDataType dt = lookupResult.type.dataType;
  8343. if (!dt.IsEnumType())
  8344. {
  8345. asASSERT(!engine->ep.requireEnumScope);
  8346. // It is an ambigious enum value. The evaluation needs to be deferred for when the type is known
  8347. ctx->enumValue = name.AddressOf();
  8348. ctx->symbolNamespace = lookupResult.symbolNamespace;
  8349. // We cannot set a dummy value because it will pass through
  8350. // cleanly as an integer.
  8351. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttIdentifier, true), 0);
  8352. return 0;
  8353. }
  8354. asDWORD value = 0;
  8355. int r = builder->GetEnumValueFromType(CastToEnumType(lookupResult.type.dataType.GetTypeInfo()), name.AddressOf(), dt, value);
  8356. asASSERT(r > 0);
  8357. // Even if the enum type is not shared, and we're compiling a shared object,
  8358. // the use of the values are still allowed, since they are treated as constants.
  8359. // an enum value was resolved
  8360. ctx->type.SetConstantDW(dt, value);
  8361. return 0;
  8362. }
  8363. }
  8364. // The result must have been identified above
  8365. if (symbolType == SL_GLOBALTYPE || symbolType == SL_CLASSTYPE)
  8366. {
  8367. // Give dummy value
  8368. ctx->type.SetDummy();
  8369. // The symbol matches a type
  8370. asCString msg;
  8371. asCString smbl;
  8372. if (scope == "::")
  8373. smbl = scope;
  8374. else if (scope != "")
  8375. smbl = scope + "::";
  8376. smbl += name;
  8377. msg.Format(TXT_EXPR_s_IS_DATA_TYPE, smbl.AddressOf());
  8378. Error(msg, errNode);
  8379. return -1;
  8380. }
  8381. // Should not come here
  8382. asASSERT(false);
  8383. return 0;
  8384. }
  8385. int asCCompiler::CompileExpressionValue(asCScriptNode *node, asCExprContext *ctx)
  8386. {
  8387. // Shouldn't receive any byte code
  8388. asASSERT(ctx->bc.GetLastInstr() == -1);
  8389. asCScriptNode *vnode = node->firstChild;
  8390. ctx->exprNode = vnode;
  8391. if( vnode->nodeType == snVariableAccess )
  8392. {
  8393. // Determine the scope resolution of the variable
  8394. asCString scope = builder->GetScopeFromNode(vnode->firstChild, script, &vnode);
  8395. // Determine the name of the variable
  8396. asASSERT(vnode->nodeType == snIdentifier );
  8397. asCString name(&script->code[vnode->tokenPos], vnode->tokenLength);
  8398. return CompileVariableAccess(name, scope, ctx, node);
  8399. }
  8400. else if( vnode->nodeType == snConstant )
  8401. {
  8402. if( vnode->tokenType == ttIntConstant )
  8403. {
  8404. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  8405. bool overflow = false;
  8406. asQWORD val = asStringScanUInt64(value.AddressOf(), 10, 0, &overflow);
  8407. // Is the number bigger than a 64bit word?
  8408. if (overflow)
  8409. {
  8410. Error(TXT_VALUE_TOO_LARGE_FOR_TYPE, vnode);
  8411. // Set the value to zero to avoid further warnings
  8412. val = 0;
  8413. }
  8414. // Do we need 64 bits?
  8415. // If the 31st bit is set we'll treat the value as a signed 64bit number to avoid
  8416. // incorrect warnings about changing signs if the value is assigned to a 64bit variable
  8417. if( val>>31 )
  8418. {
  8419. // Only if the value uses the last bit of a 64bit word do we consider the number unsigned
  8420. if( val>>63 )
  8421. ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), val);
  8422. else
  8423. ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), val);
  8424. }
  8425. else
  8426. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), asDWORD(val));
  8427. }
  8428. else if( vnode->tokenType == ttBitsConstant )
  8429. {
  8430. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  8431. // Let the function determine the radix from the prefix 0x = 16, 0d = 10, 0o = 8, or 0b = 2
  8432. bool overflow = false;
  8433. asQWORD val = asStringScanUInt64(value.AddressOf(), 0, 0, &overflow);
  8434. // Is the number bigger than a 64bit word?
  8435. if (overflow)
  8436. {
  8437. Error(TXT_VALUE_TOO_LARGE_FOR_TYPE, vnode);
  8438. // Set the value to zero to avoid further warnings
  8439. val = 0;
  8440. }
  8441. // Do we need 64 bits?
  8442. if( val>>32 )
  8443. ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), val);
  8444. else
  8445. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), asDWORD(val));
  8446. }
  8447. else if( vnode->tokenType == ttFloatConstant )
  8448. {
  8449. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  8450. // TODO: Check for overflow
  8451. size_t numScanned;
  8452. float v = float(asStringScanDouble(value.AddressOf(), &numScanned));
  8453. ctx->type.SetConstantF(asCDataType::CreatePrimitive(ttFloat, true), v);
  8454. #ifndef AS_USE_DOUBLE_AS_FLOAT
  8455. // Don't check this if we have double as float, because then the whole token would be scanned (i.e. no f suffix)
  8456. asASSERT(numScanned == vnode->tokenLength - 1);
  8457. #endif
  8458. }
  8459. else if( vnode->tokenType == ttDoubleConstant )
  8460. {
  8461. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  8462. // TODO: Check for overflow
  8463. size_t numScanned;
  8464. double v = asStringScanDouble(value.AddressOf(), &numScanned);
  8465. ctx->type.SetConstantD(asCDataType::CreatePrimitive(ttDouble, true), v);
  8466. asASSERT(numScanned == vnode->tokenLength);
  8467. }
  8468. else if( vnode->tokenType == ttTrue ||
  8469. vnode->tokenType == ttFalse )
  8470. {
  8471. #if AS_SIZEOF_BOOL == 1
  8472. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), vnode->tokenType == ttTrue ? VALUE_OF_BOOLEAN_TRUE : 0);
  8473. #else
  8474. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), vnode->tokenType == ttTrue ? VALUE_OF_BOOLEAN_TRUE : 0);
  8475. #endif
  8476. }
  8477. else if( vnode->tokenType == ttStringConstant ||
  8478. vnode->tokenType == ttMultilineStringConstant ||
  8479. vnode->tokenType == ttHeredocStringConstant )
  8480. {
  8481. asCString str;
  8482. asCScriptNode *snode = vnode->firstChild;
  8483. if( script->code[snode->tokenPos] == '\'' && engine->ep.useCharacterLiterals )
  8484. {
  8485. // Treat the single quoted string as a single character literal
  8486. str.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2);
  8487. asDWORD val = 0;
  8488. if( str.GetLength() && (asBYTE)str[0] > 127 && engine->ep.scanner == 1 )
  8489. {
  8490. // This is the start of a UTF8 encoded character. We need to decode it
  8491. val = asStringDecodeUTF8(str.AddressOf(), 0);
  8492. if( val == (asDWORD)-1 )
  8493. Error(TXT_INVALID_CHAR_LITERAL, vnode);
  8494. }
  8495. else
  8496. {
  8497. val = ProcessStringConstant(str, snode);
  8498. if( val == (asDWORD)-1 )
  8499. Error(TXT_INVALID_CHAR_LITERAL, vnode);
  8500. }
  8501. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), val);
  8502. }
  8503. else
  8504. {
  8505. // Process the string constants
  8506. while( snode )
  8507. {
  8508. asCString cat;
  8509. if( snode->tokenType == ttStringConstant )
  8510. {
  8511. cat.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2);
  8512. ProcessStringConstant(cat, snode);
  8513. }
  8514. else if( snode->tokenType == ttMultilineStringConstant )
  8515. {
  8516. if( !engine->ep.allowMultilineStrings )
  8517. Error(TXT_MULTILINE_STRINGS_NOT_ALLOWED, snode);
  8518. cat.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2);
  8519. ProcessStringConstant(cat, snode);
  8520. }
  8521. else if( snode->tokenType == ttHeredocStringConstant )
  8522. {
  8523. cat.Assign(&script->code[snode->tokenPos+3], snode->tokenLength-6);
  8524. ProcessHeredocStringConstant(cat, snode);
  8525. }
  8526. str += cat;
  8527. snode = snode->next;
  8528. }
  8529. // Call the string factory function to create a string object
  8530. if(engine->stringFactory == 0 )
  8531. {
  8532. // Error
  8533. Error(TXT_STRINGS_NOT_RECOGNIZED, vnode);
  8534. // Give dummy value
  8535. ctx->type.SetDummy();
  8536. return -1;
  8537. }
  8538. else
  8539. {
  8540. void *strPtr = const_cast<void*>(engine->stringFactory->GetStringConstant(str.AddressOf(), (asUINT)str.GetLength()));
  8541. if (strPtr == 0)
  8542. {
  8543. // TODO: A better message is needed
  8544. Error(TXT_NULL_POINTER_ACCESS, vnode);
  8545. ctx->type.SetDummy();
  8546. return -1;
  8547. }
  8548. // Keep the pointer in the list for clean up at exit
  8549. usedStringConstants.PushLast(strPtr);
  8550. // Push the pointer on the stack. The string factory already guarantees that the
  8551. // string object is valid throughout the lifetime of the script so no need to add
  8552. // reference count or make local copy.
  8553. ctx->bc.InstrPTR(asBC_PGA, strPtr);
  8554. ctx->type.Set(engine->stringType);
  8555. // Mark the string as literal constant so the compiler knows it is allowed
  8556. // to treat it differently than an ordinary constant string variable
  8557. ctx->type.isConstant = true;
  8558. // Mark the reference to the string constant as safe, so the compiler can
  8559. // avoid making unnecessary temporary copies when passing the reference to
  8560. // functions.
  8561. ctx->type.isRefSafe = true;
  8562. }
  8563. }
  8564. }
  8565. else if( vnode->tokenType == ttNull )
  8566. {
  8567. ctx->bc.Instr(asBC_PshNull);
  8568. ctx->type.SetNullConstant();
  8569. }
  8570. else
  8571. asASSERT(false);
  8572. }
  8573. else if( vnode->nodeType == snFunctionCall )
  8574. {
  8575. // Determine the scope resolution
  8576. asCString scope = builder->GetScopeFromNode(vnode->firstChild, script);
  8577. return CompileFunctionCall(vnode, ctx, 0, false, scope);
  8578. }
  8579. else if( vnode->nodeType == snConstructCall )
  8580. {
  8581. return CompileConstructCall(vnode, ctx);
  8582. }
  8583. else if( vnode->nodeType == snAssignment )
  8584. {
  8585. asCExprContext e(engine);
  8586. int r = CompileAssignment(vnode, &e);
  8587. if( r < 0 )
  8588. {
  8589. ctx->type.SetDummy();
  8590. return r;
  8591. }
  8592. MergeExprBytecodeAndType(ctx, &e);
  8593. }
  8594. else if( vnode->nodeType == snCast )
  8595. {
  8596. // Implement the cast operator
  8597. return CompileConversion(vnode, ctx);
  8598. }
  8599. else if( vnode->nodeType == snUndefined && vnode->tokenType == ttVoid )
  8600. {
  8601. // This is a void expression
  8602. ctx->SetVoidExpression();
  8603. }
  8604. else if( vnode->nodeType == snFunction )
  8605. {
  8606. // This is an anonymous function
  8607. // Defer the evaluation of the function until it is known where it
  8608. // will be used, which is where the signature will be defined
  8609. ctx->SetLambda(vnode);
  8610. }
  8611. else
  8612. asASSERT(false);
  8613. return 0;
  8614. }
  8615. asUINT asCCompiler::ProcessStringConstant(asCString &cstr, asCScriptNode *node, bool processEscapeSequences)
  8616. {
  8617. int charLiteral = -1;
  8618. // Process escape sequences
  8619. asCArray<char> str((int)cstr.GetLength());
  8620. for( asUINT n = 0; n < cstr.GetLength(); n++ )
  8621. {
  8622. #ifdef AS_DOUBLEBYTE_CHARSET
  8623. // Double-byte charset is only allowed for ASCII and not UTF16 encoded strings
  8624. if( (cstr[n] & 0x80) && engine->ep.scanner == 0 && engine->ep.stringEncoding != 1 )
  8625. {
  8626. // This is the lead character of a double byte character
  8627. // include the trail character without checking it's value.
  8628. str.PushLast(cstr[n]);
  8629. n++;
  8630. str.PushLast(cstr[n]);
  8631. continue;
  8632. }
  8633. #endif
  8634. asUINT val;
  8635. if( processEscapeSequences && cstr[n] == '\\' )
  8636. {
  8637. ++n;
  8638. if( n == cstr.GetLength() )
  8639. {
  8640. if( charLiteral == -1 ) charLiteral = 0;
  8641. return charLiteral;
  8642. }
  8643. // Hexadecimal escape sequences will allow the construction of
  8644. // invalid unicode sequences, but the string should also work as
  8645. // a bytearray so we must support this. The code for working with
  8646. // unicode text must be prepared to handle invalid unicode sequences
  8647. if( cstr[n] == 'x' || cstr[n] == 'X' )
  8648. {
  8649. ++n;
  8650. if( n == cstr.GetLength() ) break;
  8651. val = 0;
  8652. int c = engine->ep.stringEncoding == 1 ? 4 : 2;
  8653. for( ; c > 0 && n < cstr.GetLength(); c--, n++ )
  8654. {
  8655. if( cstr[n] >= '0' && cstr[n] <= '9' )
  8656. val = val*16 + cstr[n] - '0';
  8657. else if( cstr[n] >= 'a' && cstr[n] <= 'f' )
  8658. val = val*16 + cstr[n] - 'a' + 10;
  8659. else if( cstr[n] >= 'A' && cstr[n] <= 'F' )
  8660. val = val*16 + cstr[n] - 'A' + 10;
  8661. else
  8662. break;
  8663. }
  8664. // Rewind one, since the loop will increment it again
  8665. n--;
  8666. // Hexadecimal escape sequences produce exact value, even if it is not proper unicode chars
  8667. if( engine->ep.stringEncoding == 0 )
  8668. {
  8669. str.PushLast((asBYTE)val);
  8670. }
  8671. else
  8672. {
  8673. #ifndef AS_BIG_ENDIAN
  8674. str.PushLast((asBYTE)val);
  8675. str.PushLast((asBYTE)(val>>8));
  8676. #else
  8677. str.PushLast((asBYTE)(val>>8));
  8678. str.PushLast((asBYTE)val);
  8679. #endif
  8680. }
  8681. if( charLiteral == -1 ) charLiteral = val;
  8682. continue;
  8683. }
  8684. else if( cstr[n] == 'u' || cstr[n] == 'U' )
  8685. {
  8686. // \u expects 4 hex digits
  8687. // \U expects 8 hex digits
  8688. bool expect2 = cstr[n] == 'u';
  8689. int c = expect2 ? 4 : 8;
  8690. val = 0;
  8691. for( ; c > 0; c-- )
  8692. {
  8693. ++n;
  8694. if( n == cstr.GetLength() ) break;
  8695. if( cstr[n] >= '0' && cstr[n] <= '9' )
  8696. val = val*16 + cstr[n] - '0';
  8697. else if( cstr[n] >= 'a' && cstr[n] <= 'f' )
  8698. val = val*16 + cstr[n] - 'a' + 10;
  8699. else if( cstr[n] >= 'A' && cstr[n] <= 'F' )
  8700. val = val*16 + cstr[n] - 'A' + 10;
  8701. else
  8702. break;
  8703. }
  8704. if( c != 0 )
  8705. {
  8706. // Give warning about invalid code point
  8707. // TODO: Need code position for warning
  8708. asCString msg;
  8709. msg.Format(TXT_INVALID_UNICODE_FORMAT_EXPECTED_d, expect2 ? 4 : 8);
  8710. Warning(msg, node);
  8711. continue;
  8712. }
  8713. }
  8714. else
  8715. {
  8716. if( cstr[n] == '"' )
  8717. val = '"';
  8718. else if( cstr[n] == '\'' )
  8719. val = '\'';
  8720. else if( cstr[n] == 'n' )
  8721. val = '\n';
  8722. else if( cstr[n] == 'r' )
  8723. val = '\r';
  8724. else if( cstr[n] == 't' )
  8725. val = '\t';
  8726. else if( cstr[n] == '0' )
  8727. val = '\0';
  8728. else if( cstr[n] == '\\' )
  8729. val = '\\';
  8730. else
  8731. {
  8732. // Invalid escape sequence
  8733. Warning(TXT_INVALID_ESCAPE_SEQUENCE, node);
  8734. continue;
  8735. }
  8736. }
  8737. }
  8738. else
  8739. {
  8740. if( engine->ep.scanner == 1 && (cstr[n] & 0x80) )
  8741. {
  8742. unsigned int len;
  8743. val = asStringDecodeUTF8(&cstr[n], &len);
  8744. if( val == 0xFFFFFFFF )
  8745. {
  8746. // Incorrect UTF8 encoding. Use only the first byte
  8747. // TODO: Need code position for warning
  8748. Warning(TXT_INVALID_UNICODE_SEQUENCE_IN_SRC, node);
  8749. val = (unsigned char)cstr[n];
  8750. }
  8751. else
  8752. n += len-1;
  8753. }
  8754. else
  8755. val = (unsigned char)cstr[n];
  8756. }
  8757. // Add the character to the final string
  8758. char encodedValue[5];
  8759. int len;
  8760. if( engine->ep.scanner == 1 && engine->ep.stringEncoding == 0 )
  8761. {
  8762. // Convert to UTF8 encoded
  8763. len = asStringEncodeUTF8(val, encodedValue);
  8764. }
  8765. else if( engine->ep.stringEncoding == 1 )
  8766. {
  8767. // Convert to 16bit wide character string (even if the script is scanned as ASCII)
  8768. len = asStringEncodeUTF16(val, encodedValue);
  8769. }
  8770. else
  8771. {
  8772. // Do not convert ASCII characters
  8773. encodedValue[0] = (asBYTE)val;
  8774. len = 1;
  8775. }
  8776. if( len < 0 )
  8777. {
  8778. // Give warning about invalid code point
  8779. // TODO: Need code position for warning
  8780. Warning(TXT_INVALID_UNICODE_VALUE, node);
  8781. }
  8782. else
  8783. {
  8784. // Add the encoded value to the final string
  8785. str.Concatenate(encodedValue, len);
  8786. if( charLiteral == -1 ) charLiteral = val;
  8787. }
  8788. }
  8789. cstr.Assign(str.AddressOf(), str.GetLength());
  8790. return charLiteral;
  8791. }
  8792. void asCCompiler::ProcessHeredocStringConstant(asCString &str, asCScriptNode *node)
  8793. {
  8794. // Remove first line if it only contains whitespace
  8795. bool isMultiline = false;
  8796. int start;
  8797. for( start = 0; start < (int)str.GetLength(); start++ )
  8798. {
  8799. if( str[start] == '\n' )
  8800. {
  8801. isMultiline = true;
  8802. // Remove the linebreak as well
  8803. start++;
  8804. break;
  8805. }
  8806. if( str[start] != ' ' &&
  8807. str[start] != '\t' &&
  8808. str[start] != '\r' )
  8809. {
  8810. // Don't remove anything
  8811. start = 0;
  8812. break;
  8813. }
  8814. }
  8815. // Remove the line after the last line break if it only contains whitespaces
  8816. int end;
  8817. for( end = (int)str.GetLength() - 1; end >= 0; end-- )
  8818. {
  8819. if( str[end] == '\n' )
  8820. {
  8821. // Don't remove the last line break
  8822. end++;
  8823. break;
  8824. }
  8825. if( str[end] != ' ' &&
  8826. str[end] != '\t' &&
  8827. str[end] != '\r' )
  8828. {
  8829. // Don't remove anything
  8830. end = (int)str.GetLength();
  8831. break;
  8832. }
  8833. }
  8834. if( end < 0 ) end = 0;
  8835. asCString tmp;
  8836. if (end > start || engine->ep.heredocTrimMode != 2 )
  8837. {
  8838. // if heredocTrimMode == 0 the string shouldn't be trimmed
  8839. // if heredocTrimMode == 1 the string should only be trimmed if it is multiline
  8840. // if heredocTrimMode == 2 the string should always be trimmed
  8841. if (engine->ep.heredocTrimMode == 2 || (isMultiline && engine->ep.heredocTrimMode == 1))
  8842. tmp.Assign(&str[start], end - start);
  8843. else
  8844. tmp = str;
  8845. }
  8846. ProcessStringConstant(tmp, node, false);
  8847. str = tmp;
  8848. }
  8849. int asCCompiler::CompileConversion(asCScriptNode *node, asCExprContext *ctx)
  8850. {
  8851. asCExprContext expr(engine);
  8852. asCDataType to;
  8853. bool anyErrors = false;
  8854. EImplicitConv convType;
  8855. if( node->nodeType == snConstructCall || node->nodeType == snFunctionCall )
  8856. {
  8857. convType = asIC_EXPLICIT_VAL_CAST;
  8858. // Verify that there is only one argument
  8859. if( node->lastChild->firstChild == 0 ||
  8860. node->lastChild->firstChild != node->lastChild->lastChild )
  8861. {
  8862. Error(TXT_ONLY_ONE_ARGUMENT_IN_CAST, node->lastChild);
  8863. expr.type.SetDummy();
  8864. anyErrors = true;
  8865. }
  8866. else if (node->lastChild->firstChild &&
  8867. node->lastChild->firstChild->nodeType == snNamedArgument)
  8868. {
  8869. Error(TXT_INVALID_USE_OF_NAMED_ARGS, node->lastChild);
  8870. expr.type.SetDummy();
  8871. anyErrors = true;
  8872. }
  8873. else
  8874. {
  8875. // Compile the expression
  8876. int r = CompileAssignment(node->lastChild->firstChild, &expr);
  8877. if( r < 0 )
  8878. anyErrors = true;
  8879. }
  8880. // Determine the requested type
  8881. to = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace);
  8882. to.MakeReadOnly(true); // Default to const
  8883. asASSERT(to.IsPrimitive());
  8884. }
  8885. else
  8886. {
  8887. convType = asIC_EXPLICIT_REF_CAST;
  8888. // Compile the expression
  8889. int r = CompileAssignment(node->lastChild, &expr);
  8890. if( r < 0 )
  8891. anyErrors = true;
  8892. // Determine the requested type
  8893. to = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace);
  8894. // If the type support object handles, then use it
  8895. if( to.SupportHandles() )
  8896. {
  8897. to.MakeHandle(true);
  8898. if( expr.type.dataType.IsObjectConst() )
  8899. to.MakeHandleToConst(true);
  8900. }
  8901. else if( !to.IsObjectHandle() )
  8902. {
  8903. // The cast<type> operator can only be used for reference casts
  8904. Error(TXT_ILLEGAL_TARGET_TYPE_FOR_REF_CAST, node->firstChild);
  8905. anyErrors = true;
  8906. }
  8907. }
  8908. // Do not allow casting to non shared type if we're compiling a shared method
  8909. if( outFunc->IsShared() &&
  8910. to.GetTypeInfo() && !to.GetTypeInfo()->IsShared() )
  8911. {
  8912. asCString msg;
  8913. msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, to.GetTypeInfo()->name.AddressOf());
  8914. Error(msg, node);
  8915. anyErrors = true;
  8916. }
  8917. if( anyErrors )
  8918. {
  8919. // Assume that the error can be fixed and allow the compilation to continue
  8920. ctx->type.Set(to);
  8921. return -1;
  8922. }
  8923. ProcessPropertyGetAccessor(&expr, node);
  8924. // Don't allow any operators on expressions that take address of class method
  8925. if( expr.IsClassMethod() )
  8926. {
  8927. Error(TXT_INVALID_OP_ON_METHOD, node);
  8928. return -1;
  8929. }
  8930. // We don't want a reference for conversion casts
  8931. if( convType == asIC_EXPLICIT_VAL_CAST && expr.type.dataType.IsReference() )
  8932. {
  8933. if( expr.type.dataType.IsObject() )
  8934. Dereference(&expr, true);
  8935. else
  8936. ConvertToVariable(&expr);
  8937. }
  8938. ImplicitConversion(&expr, to, node, convType);
  8939. IsVariableInitialized(&expr.type, node);
  8940. // If no type conversion is really tried ignore it
  8941. if( to == expr.type.dataType )
  8942. {
  8943. // This will keep information about constant type
  8944. MergeExprBytecode(ctx, &expr);
  8945. ctx->type = expr.type;
  8946. return 0;
  8947. }
  8948. if( to.IsEqualExceptRefAndConst(expr.type.dataType) && to.IsPrimitive() )
  8949. {
  8950. MergeExprBytecode(ctx, &expr);
  8951. ctx->type = expr.type;
  8952. ctx->type.dataType.MakeReadOnly(true);
  8953. return 0;
  8954. }
  8955. // The implicit conversion already does most of the conversions permitted,
  8956. // here we'll only treat those conversions that require an explicit cast.
  8957. bool conversionOK = false;
  8958. if( !expr.type.isConstant && expr.type.dataType != asCDataType::CreatePrimitive(ttVoid, false) )
  8959. {
  8960. if( !expr.type.dataType.IsObject() )
  8961. ConvertToTempVariable(&expr);
  8962. if( to.IsObjectHandle() &&
  8963. expr.type.dataType.IsObjectHandle() &&
  8964. !(!to.IsHandleToConst() && expr.type.dataType.IsHandleToConst()) )
  8965. {
  8966. conversionOK = CompileRefCast(&expr, to, true, node);
  8967. MergeExprBytecode(ctx, &expr);
  8968. ctx->type = expr.type;
  8969. }
  8970. }
  8971. if( conversionOK )
  8972. return 0;
  8973. // Conversion not available
  8974. ctx->type.SetDummy();
  8975. asCString strTo, strFrom;
  8976. strTo = to.Format(outFunc->nameSpace);
  8977. strFrom = expr.type.dataType.Format(outFunc->nameSpace);
  8978. asCString msg;
  8979. msg.Format(TXT_NO_CONVERSION_s_TO_s, strFrom.AddressOf(), strTo.AddressOf());
  8980. Error(msg, node);
  8981. return -1;
  8982. }
  8983. void asCCompiler::AfterFunctionCall(int funcID, asCArray<asCExprContext*> &args, asCExprContext *ctx, bool deferAll)
  8984. {
  8985. // deferAll is set to true if for example the function returns a reference, since in
  8986. // this case the function might be returning a reference to one of the arguments.
  8987. asCScriptFunction *descr = builder->GetFunctionDescription(funcID);
  8988. // Parameters that are sent by reference should be assigned
  8989. // to the evaluated expression if it is an lvalue
  8990. // Evaluate the arguments from last to first
  8991. int n = (int)descr->parameterTypes.GetLength() - 1;
  8992. for( ; n >= 0; n-- )
  8993. {
  8994. // All &out arguments must be deferred, except if the argument is clean, in which case the actual reference was passed in to the function
  8995. // If deferAll is set all objects passed by reference or handle must be deferred
  8996. if( (descr->parameterTypes[n].IsReference() && (descr->inOutFlags[n] & asTM_OUTREF) && !args[n]->isCleanArg) ||
  8997. (descr->parameterTypes[n].IsObject() && deferAll && (descr->parameterTypes[n].IsReference() || descr->parameterTypes[n].IsObjectHandle())) )
  8998. {
  8999. asASSERT( !(descr->parameterTypes[n].IsReference() && (descr->inOutFlags[n] == asTM_OUTREF) && !args[n]->isCleanArg) || args[n]->origExpr );
  9000. // For &inout, only store the argument if it is for a temporary variable
  9001. if( engine->ep.allowUnsafeReferences ||
  9002. descr->inOutFlags[n] != asTM_INOUTREF || args[n]->type.isTemporary )
  9003. {
  9004. // Store the argument for later processing
  9005. asSDeferredParam outParam;
  9006. outParam.argNode = args[n]->exprNode;
  9007. outParam.argType = args[n]->type;
  9008. outParam.argInOutFlags = descr->inOutFlags[n];
  9009. outParam.origExpr = args[n]->origExpr;
  9010. ctx->deferredParams.PushLast(outParam);
  9011. }
  9012. }
  9013. else
  9014. {
  9015. // Release the temporary variable now
  9016. ReleaseTemporaryVariable(args[n]->type, &ctx->bc);
  9017. }
  9018. // Move the argument's deferred expressions over to the final expression
  9019. for( asUINT m = 0; m < args[n]->deferredParams.GetLength(); m++ )
  9020. {
  9021. ctx->deferredParams.PushLast(args[n]->deferredParams[m]);
  9022. args[n]->deferredParams[m].origExpr = 0;
  9023. }
  9024. args[n]->deferredParams.SetLength(0);
  9025. }
  9026. }
  9027. void asCCompiler::ProcessDeferredParams(asCExprContext *ctx)
  9028. {
  9029. if( isProcessingDeferredParams ) return;
  9030. isProcessingDeferredParams = true;
  9031. for( asUINT n = 0; n < ctx->deferredParams.GetLength(); n++ )
  9032. {
  9033. asSDeferredParam outParam = ctx->deferredParams[n];
  9034. if( outParam.argInOutFlags < asTM_OUTREF ) // &in, or not reference
  9035. {
  9036. // Just release the variable
  9037. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  9038. }
  9039. else if( outParam.argInOutFlags == asTM_OUTREF )
  9040. {
  9041. asCExprContext *expr = outParam.origExpr;
  9042. outParam.origExpr = 0;
  9043. if( outParam.argType.dataType.IsObjectHandle() )
  9044. {
  9045. // Implicitly convert the value to a handle
  9046. if( expr->type.dataType.IsObjectHandle() )
  9047. expr->type.isExplicitHandle = true;
  9048. }
  9049. // Verify that the expression result in a lvalue, or a property accessor
  9050. if( IsLValue(expr->type) || expr->property_get || expr->property_set )
  9051. {
  9052. asCExprContext rctx(engine);
  9053. rctx.type = outParam.argType;
  9054. if( rctx.type.dataType.IsPrimitive() )
  9055. rctx.type.dataType.MakeReference(false);
  9056. else
  9057. {
  9058. rctx.bc.InstrSHORT(asBC_PSF, outParam.argType.stackOffset);
  9059. rctx.type.dataType.MakeReference(IsVariableOnHeap(outParam.argType.stackOffset));
  9060. if( expr->type.isExplicitHandle )
  9061. rctx.type.isExplicitHandle = true;
  9062. }
  9063. asCExprContext o(engine);
  9064. DoAssignment(&o, expr, &rctx, outParam.argNode, outParam.argNode, ttAssignment, outParam.argNode);
  9065. if( !o.type.dataType.IsPrimitive() ) o.bc.Instr(asBC_PopPtr);
  9066. // The assignment may itself have resulted in a new temporary variable, e.g. if
  9067. // the opAssign returns a non-reference. We must release this temporary variable
  9068. // since it won't be used
  9069. ReleaseTemporaryVariable(o.type, &o.bc);
  9070. MergeExprBytecode(ctx, &o);
  9071. }
  9072. else
  9073. {
  9074. // We must still evaluate the expression
  9075. MergeExprBytecode(ctx, expr);
  9076. if( !expr->IsVoidExpression() && (!expr->type.isConstant || expr->type.IsNullConstant()) )
  9077. ctx->bc.Instr(asBC_PopPtr);
  9078. // Give an error, except if the argument is void, null or 0 which indicate the argument is explicitly to be ignored
  9079. if( !expr->IsVoidExpression() && !expr->type.IsNullConstant() &&
  9080. !(expr->type.isConstant && expr->type.dataType.IsPrimitive() && expr->type.GetConstantData() == 0) )
  9081. Error(TXT_ARG_NOT_LVALUE, outParam.argNode);
  9082. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  9083. }
  9084. ReleaseTemporaryVariable(expr->type, &ctx->bc);
  9085. // Delete the original expression context
  9086. asDELETE(expr, asCExprContext);
  9087. }
  9088. else // &inout
  9089. {
  9090. if( outParam.argType.isTemporary )
  9091. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  9092. else if( !outParam.argType.isVariable )
  9093. {
  9094. if( outParam.argType.dataType.IsObject() &&
  9095. ((outParam.argType.dataType.GetBehaviour()->addref &&
  9096. outParam.argType.dataType.GetBehaviour()->release) ||
  9097. (outParam.argType.dataType.GetTypeInfo()->flags & asOBJ_NOCOUNT)) )
  9098. {
  9099. // Release the object handle that was taken to guarantee the reference
  9100. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  9101. }
  9102. }
  9103. }
  9104. }
  9105. ctx->deferredParams.SetLength(0);
  9106. isProcessingDeferredParams = false;
  9107. }
  9108. int asCCompiler::CompileConstructCall(asCScriptNode *node, asCExprContext *ctx)
  9109. {
  9110. // The first node is a datatype node
  9111. asCString name;
  9112. asCExprValue tempObj;
  9113. bool onHeap = true;
  9114. asCArray<int> funcs;
  9115. bool error = false;
  9116. // It is possible that the name is really a constructor
  9117. asCDataType dt;
  9118. dt = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace);
  9119. if( dt.IsPrimitive() )
  9120. {
  9121. // This is a cast to a primitive type
  9122. return CompileConversion(node, ctx);
  9123. }
  9124. if( dt.GetTypeInfo() && (dt.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE) )
  9125. {
  9126. // Types declared as implicit handle must not attempt to construct a handle
  9127. dt.MakeHandle(false);
  9128. }
  9129. // Don't accept syntax like object@(expr)
  9130. if( dt.IsObjectHandle() )
  9131. {
  9132. asCString str;
  9133. str.Format(TXT_CANT_CONSTRUCT_s_USE_REF_CAST, dt.Format(outFunc->nameSpace).AddressOf());
  9134. Error(str, node);
  9135. ctx->type.SetDummy();
  9136. return -1;
  9137. }
  9138. // Make sure the desired type can actually be instantiated
  9139. // Delegates are allowed to be created through construct calls,
  9140. // even though they cannot be instantiated as variables
  9141. if( !dt.CanBeInstantiated() && !dt.IsFuncdef() )
  9142. {
  9143. asCString str;
  9144. if( dt.IsAbstractClass() )
  9145. str.Format(TXT_ABSTRACT_CLASS_s_CANNOT_BE_INSTANTIATED, dt.Format(outFunc->nameSpace).AddressOf());
  9146. else if( dt.IsInterface() )
  9147. str.Format(TXT_INTERFACE_s_CANNOT_BE_INSTANTIATED, dt.Format(outFunc->nameSpace).AddressOf());
  9148. else
  9149. // TODO: Improve error message to explain why
  9150. str.Format(TXT_DATA_TYPE_CANT_BE_s, dt.Format(outFunc->nameSpace).AddressOf());
  9151. Error(str, node);
  9152. ctx->type.SetDummy();
  9153. return -1;
  9154. }
  9155. // Do not allow constructing non-shared types in shared functions
  9156. if( outFunc->IsShared() &&
  9157. dt.GetTypeInfo() && !dt.GetTypeInfo()->IsShared() )
  9158. {
  9159. asCString msg;
  9160. msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, dt.GetTypeInfo()->name.AddressOf());
  9161. Error(msg, node);
  9162. return -1;
  9163. }
  9164. // Compile the arguments
  9165. asCArray<asCExprContext *> args;
  9166. asCArray<asSNamedArgument> namedArgs;
  9167. asCArray<asCExprValue> temporaryVariables;
  9168. if( CompileArgumentList(node->lastChild, args, namedArgs) >= 0 )
  9169. {
  9170. // Check for a value cast behaviour
  9171. if( args.GetLength() == 1 && args[0]->type.dataType.GetTypeInfo() )
  9172. {
  9173. asCExprContext conv(engine);
  9174. conv.type = args[0]->type;
  9175. asUINT cost = ImplicitConversion(&conv, dt, node->lastChild, asIC_EXPLICIT_VAL_CAST, false);
  9176. // Don't use this if the cost is 0 because it would mean that nothing
  9177. // is done and the script wants a new value to be constructed
  9178. if( conv.type.dataType.IsEqualExceptRef(dt) && cost > 0 )
  9179. {
  9180. // Make sure the result is a reference, just as if to a local variable
  9181. dt.MakeReference(true);
  9182. // Make sure any property accessor is already evaluated
  9183. ProcessPropertyGetAccessor(args[0], args[0]->exprNode);
  9184. ImplicitConversion(args[0], dt, node->lastChild, asIC_EXPLICIT_VAL_CAST);
  9185. ctx->bc.AddCode(&args[0]->bc);
  9186. ctx->type = args[0]->type;
  9187. asDELETE(args[0], asCExprContext);
  9188. return 0;
  9189. }
  9190. }
  9191. // Check for possible constructor/factory
  9192. name = dt.Format(outFunc->nameSpace);
  9193. asSTypeBehaviour *beh = dt.GetBehaviour();
  9194. if( !(dt.GetTypeInfo()->flags & asOBJ_REF) && !dt.IsFuncdef() )
  9195. {
  9196. funcs = beh->constructors;
  9197. // Value types and script types are allocated through the constructor
  9198. tempObj.dataType = dt;
  9199. tempObj.stackOffset = (short)AllocateVariable(dt, true);
  9200. tempObj.dataType.MakeReference(true);
  9201. tempObj.isTemporary = true;
  9202. tempObj.isVariable = true;
  9203. onHeap = IsVariableOnHeap(tempObj.stackOffset);
  9204. // Push the address of the object on the stack
  9205. if( onHeap )
  9206. ctx->bc.InstrSHORT(asBC_VAR, tempObj.stackOffset);
  9207. }
  9208. else if( beh )
  9209. funcs = beh->factories;
  9210. // Special case: Allow calling func(void) with a void expression.
  9211. if( args.GetLength() == 1 && args[0]->type.dataType == asCDataType::CreatePrimitive(ttVoid, false) )
  9212. {
  9213. // Evaluate the expression before the function call
  9214. MergeExprBytecode(ctx, args[0]);
  9215. asDELETE(args[0], asCExprContext);
  9216. args.SetLength(0);
  9217. }
  9218. // Special case: If this is an object constructor and there are no arguments use the default constructor.
  9219. // If none has been registered, just allocate the variable and push it on the stack.
  9220. if( args.GetLength() == 0 )
  9221. {
  9222. beh = tempObj.dataType.GetBehaviour();
  9223. if( beh && beh->construct == 0 && !(dt.GetTypeInfo()->flags & asOBJ_REF) )
  9224. {
  9225. // Call the default constructor
  9226. ctx->type = tempObj;
  9227. if( onHeap )
  9228. {
  9229. asASSERT(ctx->bc.GetLastInstr() == asBC_VAR);
  9230. ctx->bc.RemoveLastInstr();
  9231. }
  9232. CallDefaultConstructor(tempObj.dataType, tempObj.stackOffset, IsVariableOnHeap(tempObj.stackOffset), &ctx->bc, node);
  9233. // Push the reference on the stack
  9234. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  9235. return 0;
  9236. }
  9237. }
  9238. // Special case: If this is a construction of a delegate and the expression names an object method
  9239. if( dt.IsFuncdef() && args.GetLength() == 1 && args[0]->methodName != "" )
  9240. {
  9241. // TODO: delegate: It is possible that the argument returns a function pointer already, in which
  9242. // case no object delegate will be created, but instead a delegate for a function pointer
  9243. // In theory a simple cast would be good in this case, but this is a construct call so it
  9244. // is expected that a new object is created.
  9245. dt.MakeHandle(true);
  9246. ctx->type.Set(dt);
  9247. // The delegate must be able to hold on to a reference to the object
  9248. if( !args[0]->type.dataType.SupportHandles() )
  9249. {
  9250. Error(TXT_CANNOT_CREATE_DELEGATE_FOR_NOREF_TYPES, node);
  9251. error = true;
  9252. }
  9253. else
  9254. {
  9255. // Filter the available object methods to find the one that matches the func def
  9256. asCObjectType *type = CastToObjectType(args[0]->type.dataType.GetTypeInfo());
  9257. asCScriptFunction *bestMethod = 0;
  9258. for( asUINT n = 0; n < type->methods.GetLength(); n++ )
  9259. {
  9260. asCScriptFunction *func = engine->scriptFunctions[type->methods[n]];
  9261. if( func->name != args[0]->methodName )
  9262. continue;
  9263. // If the expression is for a const object, then only const methods should be accepted
  9264. if( args[0]->type.dataType.IsReadOnly() && !func->IsReadOnly() )
  9265. continue;
  9266. if( func->IsSignatureExceptNameAndObjectTypeEqual(CastToFuncdefType(dt.GetTypeInfo())->funcdef) )
  9267. {
  9268. bestMethod = func;
  9269. // If the expression is non-const the non-const overloaded method has priority
  9270. if( args[0]->type.dataType.IsReadOnly() == func->IsReadOnly() )
  9271. break;
  9272. }
  9273. }
  9274. if( bestMethod )
  9275. {
  9276. // The object pointer is already on the stack
  9277. MergeExprBytecode(ctx, args[0]);
  9278. // Push the function pointer as an additional argument
  9279. ctx->bc.InstrPTR(asBC_FuncPtr, bestMethod);
  9280. // Call the factory function for the delegate
  9281. asCArray<int> delegateFuncs;
  9282. builder->GetFunctionDescriptions(DELEGATE_FACTORY, delegateFuncs, engine->nameSpaces[0]);
  9283. asASSERT(delegateFuncs.GetLength() == 1 );
  9284. ctx->bc.Call(asBC_CALLSYS , delegateFuncs[0], 2*AS_PTR_SIZE);
  9285. // Store the returned delegate in a temporary variable
  9286. int returnOffset = AllocateVariable(dt, true, false);
  9287. dt.MakeReference(true);
  9288. ctx->type.SetVariable(dt, returnOffset, true);
  9289. ctx->bc.InstrSHORT(asBC_STOREOBJ, (short)returnOffset);
  9290. // Push a reference to the temporary variable on the stack
  9291. ctx->bc.InstrSHORT(asBC_PSF, (short)returnOffset);
  9292. // Clean up arguments
  9293. ReleaseTemporaryVariable(args[0]->type, &ctx->bc);
  9294. }
  9295. else
  9296. {
  9297. asCString msg;
  9298. msg.Format(TXT_NO_MATCHING_SIGNATURES_TO_s, CastToFuncdefType(dt.GetTypeInfo())->funcdef->GetDeclaration());
  9299. Error(msg.AddressOf(), node);
  9300. error = true;
  9301. }
  9302. }
  9303. // Clean-up arg
  9304. asDELETE(args[0], asCExprContext);
  9305. return error ? -1 : 0;
  9306. }
  9307. MatchFunctions(funcs, args, node, name.AddressOf(), &namedArgs, 0, false);
  9308. if( funcs.GetLength() != 1 )
  9309. {
  9310. // The error was reported by MatchFunctions()
  9311. error = true;
  9312. // Dummy value
  9313. ctx->type.SetDummy();
  9314. }
  9315. else
  9316. {
  9317. // TODO: Clean up: Merge this with MakeFunctionCall
  9318. // Add the default values for arguments not explicitly supplied
  9319. int r = CompileDefaultAndNamedArgs(node, args, funcs[0], CastToObjectType(dt.GetTypeInfo()), &namedArgs);
  9320. if( r == asSUCCESS )
  9321. {
  9322. asCByteCode objBC(engine);
  9323. PrepareFunctionCall(funcs[0], &ctx->bc, args);
  9324. MoveArgsToStack(funcs[0], &ctx->bc, args, false);
  9325. if( !(dt.GetTypeInfo()->flags & asOBJ_REF) )
  9326. {
  9327. // If the object is allocated on the stack, then call the constructor as a normal function
  9328. if( onHeap )
  9329. {
  9330. int offset = 0;
  9331. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]);
  9332. for( asUINT n = 0; n < args.GetLength(); n++ )
  9333. offset += descr->parameterTypes[n].GetSizeOnStackDWords();
  9334. ctx->bc.InstrWORD(asBC_GETREF, (asWORD)offset);
  9335. }
  9336. else
  9337. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  9338. PerformFunctionCall(funcs[0], ctx, onHeap, &args, CastToObjectType(tempObj.dataType.GetTypeInfo()));
  9339. // Add tag that the object has been initialized
  9340. ctx->bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT);
  9341. // The constructor doesn't return anything,
  9342. // so we have to manually inform the type of
  9343. // the return value
  9344. ctx->type = tempObj;
  9345. if( !onHeap )
  9346. ctx->type.dataType.MakeReference(false);
  9347. // Push the address of the object on the stack again
  9348. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  9349. }
  9350. else
  9351. {
  9352. // Call the factory to create the reference type
  9353. PerformFunctionCall(funcs[0], ctx, false, &args);
  9354. }
  9355. }
  9356. else
  9357. error = true;
  9358. }
  9359. }
  9360. else
  9361. {
  9362. // Failed to compile the argument list, set the result to the dummy type
  9363. ctx->type.SetDummy();
  9364. error = true;
  9365. }
  9366. // Cleanup
  9367. for( asUINT n = 0; n < args.GetLength(); n++ )
  9368. if( args[n] )
  9369. {
  9370. asDELETE(args[n], asCExprContext);
  9371. }
  9372. for( asUINT n = 0; n < namedArgs.GetLength(); n++ )
  9373. if( namedArgs[n].ctx )
  9374. {
  9375. asDELETE(namedArgs[n].ctx, asCExprContext);
  9376. }
  9377. return error ? -1 : 0;
  9378. }
  9379. int asCCompiler::CompileFunctionCall(asCScriptNode *node, asCExprContext *ctx, asCObjectType *objectType, bool objIsConst, const asCString &scope)
  9380. {
  9381. asCExprValue tempObj;
  9382. asCArray<int> funcs;
  9383. int localVar = -1;
  9384. bool initializeMembers = false;
  9385. asCExprContext funcExpr(engine);
  9386. asCScriptNode *nm = node->lastChild->prev;
  9387. asCString name(&script->code[nm->tokenPos], nm->tokenLength);
  9388. // Find the matching entities
  9389. // If objectType is set then this is a post op expression and we shouldn't look for local variables
  9390. asCExprContext lookupResult(engine);
  9391. SYMBOLTYPE symbolType = SymbolLookup(name, scope, objectType, &lookupResult);
  9392. if (symbolType < 0)
  9393. return -1;
  9394. if (symbolType == SL_NOMATCH)
  9395. {
  9396. // No matching symbol
  9397. asCString msg;
  9398. asCString smbl;
  9399. if (scope == "::")
  9400. smbl = scope;
  9401. else if (scope != "")
  9402. smbl = scope + "::";
  9403. smbl += name;
  9404. msg.Format(TXT_NO_MATCHING_SYMBOL_s, smbl.AddressOf());
  9405. Error(msg, node);
  9406. return -1;
  9407. }
  9408. // Is the symbol matching a variable/property?
  9409. if (symbolType == SL_LOCALCONST || symbolType == SL_LOCALVAR ||
  9410. symbolType == SL_THISPTR || symbolType == SL_CLASSPROPACCESS || symbolType == SL_CLASSPROP ||
  9411. symbolType == SL_GLOBALPROPACCESS || symbolType == SL_GLOBALCONST || symbolType == SL_GLOBALVAR || symbolType == SL_ENUMVAL)
  9412. {
  9413. // Variables/properties can be used as functions if they have the opCall
  9414. if (!(lookupResult.type.dataType.IsFuncdef() || lookupResult.type.dataType.IsObject()))
  9415. {
  9416. // The variable is not a function or object with opCall
  9417. asCString msg;
  9418. msg.Format(TXT_NOT_A_FUNC_s_IS_TYPE_s, name.AddressOf(), lookupResult.type.dataType.Format(outFunc->nameSpace).AddressOf());
  9419. Error(msg, node);
  9420. return -1;
  9421. }
  9422. // Compile the variable
  9423. // TODO: Take advantage of the known symbol, so it doesn't have to be looked up again
  9424. localVar = CompileVariableAccess(name, scope, &funcExpr, node, false, objectType);
  9425. asASSERT(localVar >= 0);
  9426. if (funcExpr.type.dataType.IsFuncdef())
  9427. {
  9428. funcs.PushLast(CastToFuncdefType(funcExpr.type.dataType.GetTypeInfo())->funcdef->id);
  9429. }
  9430. else if (funcExpr.type.dataType.IsObject())
  9431. {
  9432. // Keep information about temporary variables as deferred expression so it can be properly cleaned up after the call
  9433. if (ctx->type.isTemporary)
  9434. {
  9435. asASSERT(objectType);
  9436. asSDeferredParam deferred;
  9437. deferred.origExpr = 0;
  9438. deferred.argInOutFlags = asTM_INREF;
  9439. deferred.argNode = 0;
  9440. deferred.argType.SetVariable(ctx->type.dataType, ctx->type.stackOffset, true);
  9441. ctx->deferredParams.PushLast(deferred);
  9442. }
  9443. if (funcExpr.property_get == 0)
  9444. Dereference(ctx, true);
  9445. // Add the bytecode for accessing the object on which opCall will be called
  9446. if (ctx->type.dataType.IsObject())
  9447. {
  9448. // Make sure the ProcessPropertyGetAccess knows whether or not to
  9449. // dereference the original object before calling the get accessor
  9450. funcExpr.property_ref = ctx->type.dataType.IsReference();
  9451. }
  9452. MergeExprBytecodeAndType(ctx, &funcExpr);
  9453. ProcessPropertyGetAccessor(ctx, node);
  9454. Dereference(ctx, true);
  9455. objectType = CastToObjectType(funcExpr.type.dataType.GetTypeInfo());
  9456. // Get the opCall methods from the object type
  9457. if (funcExpr.type.dataType.IsObjectHandle())
  9458. objIsConst = funcExpr.type.dataType.IsHandleToConst();
  9459. else
  9460. objIsConst = funcExpr.type.dataType.IsReadOnly();
  9461. builder->GetObjectMethodDescriptions("opCall", CastToObjectType(funcExpr.type.dataType.GetTypeInfo()), funcs, objIsConst);
  9462. }
  9463. }
  9464. // Is the symbol matching a class method?
  9465. if (symbolType == SL_CLASSMETHOD)
  9466. {
  9467. // If we're compiling a constructor and the name of the function is super then
  9468. // the constructor of the base class is being called.
  9469. // super cannot be prefixed with a scope operator
  9470. if (scope == "" && m_isConstructor && name == SUPER_TOKEN)
  9471. {
  9472. // If the class is not derived from anyone else, calling super should give an error
  9473. if (outFunc && outFunc->objectType->derivedFrom)
  9474. funcs = outFunc->objectType->derivedFrom->beh.constructors;
  9475. // Must not allow calling base class' constructor multiple times
  9476. if (continueLabels.GetLength() > 0)
  9477. {
  9478. // If a continue label is set we are in a loop
  9479. Error(TXT_CANNOT_CALL_CONSTRUCTOR_IN_LOOPS, node);
  9480. }
  9481. else if (breakLabels.GetLength() > 0)
  9482. {
  9483. // TODO: inheritance: Should eventually allow constructors in switch statements
  9484. // If a break label is set we are either in a loop or a switch statements
  9485. Error(TXT_CANNOT_CALL_CONSTRUCTOR_IN_SWITCH, node);
  9486. }
  9487. else if (m_isConstructorCalled)
  9488. {
  9489. Error(TXT_CANNOT_CALL_CONSTRUCTOR_TWICE, node);
  9490. }
  9491. m_isConstructorCalled = true;
  9492. // We need to initialize the class members, but only after all the deferred arguments have been completed
  9493. initializeMembers = true;
  9494. }
  9495. else
  9496. {
  9497. // The scope can be used to specify the base class
  9498. builder->GetObjectMethodDescriptions(name.AddressOf(), CastToObjectType(lookupResult.type.dataType.GetTypeInfo()), funcs, objIsConst, scope, node, script);
  9499. }
  9500. // If a class method is being called implicitly, then add the this pointer for the call
  9501. if (funcs.GetLength() && !objectType)
  9502. {
  9503. // Verify that the identified function is actually part of the class hierarchy
  9504. if (!outFunc->objectType->DerivesFrom(lookupResult.type.dataType.GetTypeInfo()))
  9505. {
  9506. asCString msg;
  9507. asCString mthd;
  9508. if (scope == "")
  9509. mthd = name;
  9510. else if (scope == "::")
  9511. mthd = scope + name;
  9512. else
  9513. mthd = scope + "::" + name;
  9514. msg.Format(TXT_METHOD_s_NOT_PART_OF_OBJECT_s, mthd.AddressOf(), outFunc->objectType->name.AddressOf());
  9515. Error(msg, node);
  9516. return -1;
  9517. }
  9518. objectType = outFunc->objectType;
  9519. asCDataType dt = asCDataType::CreateType(objectType, false);
  9520. // The object pointer is located at stack position 0
  9521. ctx->bc.InstrSHORT(asBC_PSF, 0);
  9522. ctx->type.SetVariable(dt, 0, false);
  9523. ctx->type.dataType.MakeReference(true);
  9524. Dereference(ctx, true);
  9525. }
  9526. }
  9527. // Is it a global function?
  9528. if (symbolType == SL_GLOBALFUNC)
  9529. {
  9530. // The symbol lookup identified the namespace to use
  9531. int n = lookupResult.methodName.FindLast("::");
  9532. asSNameSpace *ns = engine->FindNameSpace(lookupResult.methodName.SubString(0, n).AddressOf());
  9533. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  9534. }
  9535. // Is it a type?
  9536. if (symbolType == SL_CLASSTYPE || symbolType == SL_GLOBALTYPE)
  9537. {
  9538. bool isValid = false;
  9539. asCDataType dt = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace, false, 0, false, &isValid);
  9540. if (isValid)
  9541. return CompileConstructCall(node, ctx);
  9542. }
  9543. // Compile the arguments
  9544. asCArray<asCExprContext *> args;
  9545. asCArray<asSNamedArgument> namedArgs;
  9546. bool isOK = true;
  9547. if( CompileArgumentList(node->lastChild, args, namedArgs) >= 0 )
  9548. {
  9549. // Special case: Allow calling func(void) with an expression that evaluates to no datatype, but isn't exactly 'void'
  9550. if( args.GetLength() == 1 && args[0]->type.IsVoid() && !args[0]->IsVoidExpression() )
  9551. {
  9552. // Evaluate the expression before the function call
  9553. MergeExprBytecode(ctx, args[0]);
  9554. asDELETE(args[0], asCExprContext);
  9555. args.SetLength(0);
  9556. }
  9557. MatchFunctions(funcs, args, node, name.AddressOf(), &namedArgs, objectType, objIsConst, false, true, scope);
  9558. if( funcs.GetLength() != 1 )
  9559. {
  9560. // The error was reported by MatchFunctions()
  9561. // Dummy value
  9562. ctx->type.SetDummy();
  9563. isOK = false;
  9564. }
  9565. else
  9566. {
  9567. // Add the default values for arguments not explicitly supplied
  9568. int r = CompileDefaultAndNamedArgs(node, args, funcs[0], objectType, &namedArgs);
  9569. // TODO: funcdef: Do we have to make sure the handle is stored in a temporary variable, or
  9570. // is it enough to make sure it is in a local variable?
  9571. // For function pointer we must guarantee that the function is safe, i.e.
  9572. // by first storing the function pointer in a local variable (if it isn't already in one)
  9573. if( r == asSUCCESS )
  9574. {
  9575. asCScriptFunction *func = builder->GetFunctionDescription(funcs[0]);
  9576. if( func->funcType == asFUNC_FUNCDEF )
  9577. {
  9578. if( objectType && funcExpr.property_get <= 0 )
  9579. {
  9580. // Dereference the object pointer to access the member
  9581. Dereference(ctx, true);
  9582. }
  9583. if( funcExpr.property_get > 0 )
  9584. {
  9585. ProcessPropertyGetAccessor(&funcExpr, node);
  9586. Dereference(&funcExpr, true);
  9587. }
  9588. else
  9589. {
  9590. Dereference(&funcExpr, true);
  9591. ConvertToVariable(&funcExpr);
  9592. }
  9593. // The actual function should be called as if a global function
  9594. objectType = 0;
  9595. // The function call will be made directly from the local variable so the function pointer shouldn't be on the stack
  9596. funcExpr.bc.Instr(asBC_PopPtr);
  9597. asCExprValue tmp = ctx->type;
  9598. MergeExprBytecodeAndType(ctx, &funcExpr);
  9599. ReleaseTemporaryVariable(tmp, &ctx->bc);
  9600. }
  9601. MakeFunctionCall(ctx, funcs[0], objectType, args, node, false, 0, funcExpr.type.stackOffset);
  9602. }
  9603. else
  9604. isOK = false;
  9605. }
  9606. }
  9607. else
  9608. {
  9609. // Failed to compile the argument list, set the dummy type and continue compilation
  9610. ctx->type.SetDummy();
  9611. isOK = false;
  9612. }
  9613. // Cleanup
  9614. for( asUINT n = 0; n < args.GetLength(); n++ )
  9615. if( args[n] )
  9616. {
  9617. asDELETE(args[n], asCExprContext);
  9618. }
  9619. for( asUINT n = 0; n < namedArgs.GetLength(); n++ )
  9620. if( namedArgs[n].ctx )
  9621. {
  9622. asDELETE(namedArgs[n].ctx, asCExprContext);
  9623. }
  9624. if( initializeMembers )
  9625. {
  9626. asASSERT( m_isConstructor );
  9627. // Need to initialize members here, as they may use the properties of the base class
  9628. // If there are multiple paths that call super(), then there will also be multiple
  9629. // locations with initializations of the members. It is not possible to consolidate
  9630. // these in one place, as the expressions for the initialization are evaluated where
  9631. // they are compiled, which means that they may access different variables depending
  9632. // on the scope where super() is called.
  9633. // Members that don't have an explicit initialization expression will be initialized
  9634. // beginning of the constructor as they are guaranteed not to use at the any
  9635. // members of the base class.
  9636. CompileMemberInitialization(&ctx->bc, false);
  9637. }
  9638. return isOK ? 0 : -1;
  9639. }
  9640. asSNameSpace *asCCompiler::DetermineNameSpace(const asCString &scope)
  9641. {
  9642. asSNameSpace *ns;
  9643. if( scope == "" )
  9644. {
  9645. // When compiling default argument expression the correct namespace is stored in the outFunc even for objects
  9646. if( outFunc->nameSpace->name != "" || isCompilingDefaultArg )
  9647. ns = outFunc->nameSpace;
  9648. else if( outFunc->objectType && outFunc->objectType->nameSpace->name != "" )
  9649. ns = outFunc->objectType->nameSpace;
  9650. else
  9651. ns = engine->nameSpaces[0];
  9652. }
  9653. else if( scope == "::" )
  9654. ns = engine->nameSpaces[0];
  9655. else
  9656. ns = engine->FindNameSpace(scope.AddressOf());
  9657. return ns;
  9658. }
  9659. int asCCompiler::CompileExpressionPreOp(asCScriptNode *node, asCExprContext *ctx)
  9660. {
  9661. int op = node->tokenType;
  9662. // Don't allow any prefix operators except handle on expressions that take address of class method
  9663. if( ctx->IsClassMethod() && op != ttHandle )
  9664. {
  9665. Error(TXT_INVALID_OP_ON_METHOD, node);
  9666. return -1;
  9667. }
  9668. // Don't allow any operators on void expressions
  9669. if( ctx->IsVoidExpression() )
  9670. {
  9671. Error(TXT_VOID_CANT_BE_OPERAND, node);
  9672. return -1;
  9673. }
  9674. IsVariableInitialized(&ctx->type, node);
  9675. if( op == ttHandle )
  9676. {
  9677. if( ctx->methodName != "" )
  9678. {
  9679. // Don't allow taking the handle of a handle
  9680. if( ctx->type.isExplicitHandle )
  9681. {
  9682. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node);
  9683. return -1;
  9684. }
  9685. }
  9686. else
  9687. {
  9688. // Don't allow taking handle of a handle, i.e. @@
  9689. if( ctx->type.isExplicitHandle )
  9690. {
  9691. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node);
  9692. return -1;
  9693. }
  9694. // @null is allowed even though it is implicit
  9695. if( !ctx->type.IsNullConstant() )
  9696. {
  9697. // Verify that the type allow its handle to be taken
  9698. if( !ctx->type.dataType.SupportHandles() && !ctx->type.dataType.IsObjectHandle() )
  9699. {
  9700. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node);
  9701. return -1;
  9702. }
  9703. // Objects that are not local variables are not references
  9704. // Objects allocated on the stack are also not marked as references
  9705. if( !ctx->type.dataType.IsReference() &&
  9706. !((ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) && !ctx->type.isVariable) &&
  9707. !(ctx->type.isVariable && !IsVariableOnHeap(ctx->type.stackOffset)) )
  9708. {
  9709. Error(TXT_NOT_VALID_REFERENCE, node);
  9710. return -1;
  9711. }
  9712. // Convert the expression to a handle
  9713. if( !ctx->type.dataType.IsObjectHandle() && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) )
  9714. {
  9715. asCDataType to = ctx->type.dataType;
  9716. to.MakeHandle(true);
  9717. to.MakeReference(true);
  9718. to.MakeHandleToConst(ctx->type.dataType.IsReadOnly());
  9719. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV, true, false);
  9720. asASSERT( ctx->type.dataType.IsObjectHandle() );
  9721. }
  9722. else if( ctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE )
  9723. {
  9724. // For the ASHANDLE type we'll simply set the expression as a handle
  9725. ctx->type.dataType.MakeHandle(true);
  9726. }
  9727. }
  9728. }
  9729. // Mark the expression as an explicit handle to avoid implicit conversions to non-handle expressions
  9730. ctx->type.isExplicitHandle = true;
  9731. }
  9732. else if( (op == ttMinus || op == ttPlus || op == ttBitNot || op == ttInc || op == ttDec) && ctx->type.dataType.IsObject() )
  9733. {
  9734. // Look for the appropriate method
  9735. // There is no overloadable operator for unary plus
  9736. const char *opName = 0;
  9737. switch( op )
  9738. {
  9739. case ttMinus: opName = "opNeg"; break;
  9740. case ttBitNot: opName = "opCom"; break;
  9741. case ttInc: opName = "opPreInc"; break;
  9742. case ttDec: opName = "opPreDec"; break;
  9743. }
  9744. if( opName )
  9745. {
  9746. // TODO: Should convert this to something similar to CompileOverloadedDualOperator2
  9747. ProcessPropertyGetAccessor(ctx, node);
  9748. // 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
  9749. // Find the correct method
  9750. bool isConst = ctx->type.dataType.IsObjectConst();
  9751. asCArray<int> funcs;
  9752. asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  9753. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  9754. {
  9755. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  9756. if( func->name == opName &&
  9757. func->parameterTypes.GetLength() == 0 &&
  9758. (!isConst || func->IsReadOnly()) )
  9759. {
  9760. funcs.PushLast(func->id);
  9761. }
  9762. }
  9763. // Did we find the method?
  9764. if( funcs.GetLength() == 1 )
  9765. {
  9766. asCArray<asCExprContext *> args;
  9767. MakeFunctionCall(ctx, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
  9768. return 0;
  9769. }
  9770. else if( funcs.GetLength() == 0 )
  9771. {
  9772. asCString str;
  9773. str = asCString(opName) + "()";
  9774. if( isConst )
  9775. str += " const";
  9776. str.Format(TXT_FUNCTION_s_NOT_FOUND, str.AddressOf());
  9777. Error(str, node);
  9778. ctx->type.SetDummy();
  9779. return -1;
  9780. }
  9781. else if( funcs.GetLength() > 1 )
  9782. {
  9783. Error(TXT_MORE_THAN_ONE_MATCHING_OP, node);
  9784. PrintMatchingFuncs(funcs, node);
  9785. ctx->type.SetDummy();
  9786. return -1;
  9787. }
  9788. }
  9789. else if( op == ttPlus )
  9790. {
  9791. Error(TXT_ILLEGAL_OPERATION, node);
  9792. ctx->type.SetDummy();
  9793. return -1;
  9794. }
  9795. }
  9796. else if( op == ttPlus || op == ttMinus )
  9797. {
  9798. // This is only for primitives. Objects are treated in the above block
  9799. // Make sure the type is a math type
  9800. if( !(ctx->type.dataType.IsIntegerType() ||
  9801. ctx->type.dataType.IsUnsignedType() ||
  9802. ctx->type.dataType.IsFloatType() ||
  9803. ctx->type.dataType.IsDoubleType() ) )
  9804. {
  9805. Error(TXT_ILLEGAL_OPERATION, node);
  9806. return -1;
  9807. }
  9808. ProcessPropertyGetAccessor(ctx, node);
  9809. asCDataType to = ctx->type.dataType;
  9810. if( ctx->type.dataType.IsUnsignedType() )
  9811. {
  9812. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  9813. to = asCDataType::CreatePrimitive(ttInt8, false);
  9814. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  9815. to = asCDataType::CreatePrimitive(ttInt16, false);
  9816. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 )
  9817. to = asCDataType::CreatePrimitive(ttInt, false);
  9818. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 8 )
  9819. to = asCDataType::CreatePrimitive(ttInt64, false);
  9820. else
  9821. {
  9822. Error(TXT_INVALID_TYPE, node);
  9823. return -1;
  9824. }
  9825. }
  9826. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  9827. // Use an explicit conversion in case of constants to avoid unnecessary warning about change of sign
  9828. ImplicitConversion(ctx, to, node, ctx->type.isConstant ? asIC_EXPLICIT_VAL_CAST : asIC_IMPLICIT_CONV);
  9829. if( !ctx->type.isConstant )
  9830. {
  9831. ConvertToTempVariable(ctx);
  9832. asASSERT(!ctx->type.isLValue);
  9833. if( op == ttMinus )
  9834. {
  9835. if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  9836. ctx->bc.InstrSHORT(asBC_NEGi, ctx->type.stackOffset);
  9837. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  9838. ctx->bc.InstrSHORT(asBC_NEGi64, ctx->type.stackOffset);
  9839. else if( ctx->type.dataType.IsFloatType() )
  9840. ctx->bc.InstrSHORT(asBC_NEGf, ctx->type.stackOffset);
  9841. else if( ctx->type.dataType.IsDoubleType() )
  9842. ctx->bc.InstrSHORT(asBC_NEGd, ctx->type.stackOffset);
  9843. else
  9844. {
  9845. Error(TXT_ILLEGAL_OPERATION, node);
  9846. return -1;
  9847. }
  9848. return 0;
  9849. }
  9850. }
  9851. else
  9852. {
  9853. if( op == ttMinus )
  9854. {
  9855. if (ctx->type.dataType.IsIntegerType())
  9856. {
  9857. if (ctx->type.dataType.GetSizeInMemoryBytes() == 4)
  9858. ctx->type.SetConstantDW(-(int)ctx->type.GetConstantDW());
  9859. else if (ctx->type.dataType.GetSizeInMemoryBytes() == 2)
  9860. ctx->type.SetConstantW(-(asINT16)ctx->type.GetConstantW());
  9861. else if (ctx->type.dataType.GetSizeInMemoryBytes() == 1)
  9862. ctx->type.SetConstantB(-(asINT8)ctx->type.GetConstantB());
  9863. else if (ctx->type.dataType.GetSizeInMemoryBytes() == 8)
  9864. ctx->type.SetConstantQW(-(asINT64)ctx->type.GetConstantQW());
  9865. }
  9866. else if( ctx->type.dataType.IsFloatType() )
  9867. ctx->type.SetConstantF(-ctx->type.GetConstantF());
  9868. else if( ctx->type.dataType.IsDoubleType() )
  9869. ctx->type.SetConstantD(-ctx->type.GetConstantD());
  9870. else
  9871. {
  9872. Error(TXT_ILLEGAL_OPERATION, node);
  9873. return -1;
  9874. }
  9875. return 0;
  9876. }
  9877. }
  9878. }
  9879. else if( op == ttNot )
  9880. {
  9881. // Allow value types to be converted to bool using 'bool opImplConv()'
  9882. if( ctx->type.dataType.GetTypeInfo() && (ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
  9883. ImplicitConversion(ctx, asCDataType::CreatePrimitive(ttBool, false), node, asIC_IMPLICIT_CONV);
  9884. if( ctx->type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  9885. {
  9886. if( ctx->type.isConstant )
  9887. {
  9888. #if AS_SIZEOF_BOOL == 1
  9889. ctx->type.SetConstantB(ctx->type.GetConstantB() == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  9890. #else
  9891. ctx->type.SetConstantDW(ctx->type.GetConstantDW() == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  9892. #endif
  9893. return 0;
  9894. }
  9895. ProcessPropertyGetAccessor(ctx, node);
  9896. ConvertToTempVariable(ctx);
  9897. asASSERT(!ctx->type.isLValue);
  9898. ctx->bc.InstrSHORT(asBC_NOT, ctx->type.stackOffset);
  9899. }
  9900. else
  9901. {
  9902. Error(TXT_ILLEGAL_OPERATION, node);
  9903. return -1;
  9904. }
  9905. }
  9906. else if( op == ttBitNot )
  9907. {
  9908. ProcessPropertyGetAccessor(ctx, node);
  9909. asCDataType to = ctx->type.dataType;
  9910. if( ctx->type.dataType.IsIntegerType() )
  9911. {
  9912. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  9913. to = asCDataType::CreatePrimitive(ttUInt8, false);
  9914. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  9915. to = asCDataType::CreatePrimitive(ttUInt16, false);
  9916. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 )
  9917. to = asCDataType::CreatePrimitive(ttUInt, false);
  9918. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 8 )
  9919. to = asCDataType::CreatePrimitive(ttUInt64, false);
  9920. else
  9921. {
  9922. Error(TXT_INVALID_TYPE, node);
  9923. return -1;
  9924. }
  9925. }
  9926. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  9927. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV);
  9928. if( ctx->type.dataType.IsUnsignedType() )
  9929. {
  9930. if( ctx->type.isConstant )
  9931. {
  9932. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  9933. ctx->type.SetConstantB(~ctx->type.GetConstantB());
  9934. else if (ctx->type.dataType.GetSizeInMemoryBytes() == 2)
  9935. ctx->type.SetConstantW(~ctx->type.GetConstantW());
  9936. else if (ctx->type.dataType.GetSizeInMemoryBytes() == 4)
  9937. ctx->type.SetConstantDW(~ctx->type.GetConstantDW());
  9938. else
  9939. ctx->type.SetConstantQW(~ctx->type.GetConstantQW());
  9940. return 0;
  9941. }
  9942. ConvertToTempVariable(ctx);
  9943. asASSERT(!ctx->type.isLValue);
  9944. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  9945. ctx->bc.InstrSHORT(asBC_BNOT, ctx->type.stackOffset);
  9946. else
  9947. ctx->bc.InstrSHORT(asBC_BNOT64, ctx->type.stackOffset);
  9948. }
  9949. else
  9950. {
  9951. Error(TXT_ILLEGAL_OPERATION, node);
  9952. return -1;
  9953. }
  9954. }
  9955. else if( op == ttInc || op == ttDec )
  9956. {
  9957. // Need a reference to the primitive that will be updated
  9958. // The result of this expression is the same reference as before
  9959. // Make sure the reference isn't a temporary variable
  9960. if( ctx->type.isTemporary )
  9961. {
  9962. Error(TXT_REF_IS_TEMP, node);
  9963. return -1;
  9964. }
  9965. if( ctx->type.dataType.IsReadOnly() )
  9966. {
  9967. Error(TXT_REF_IS_READ_ONLY, node);
  9968. return -1;
  9969. }
  9970. if( ctx->property_get || ctx->property_set )
  9971. {
  9972. Error(TXT_INVALID_REF_PROP_ACCESS, node);
  9973. return -1;
  9974. }
  9975. if( !ctx->type.isLValue )
  9976. {
  9977. Error(TXT_NOT_LVALUE, node);
  9978. return -1;
  9979. }
  9980. if( ctx->type.isVariable && !ctx->type.dataType.IsReference() )
  9981. ConvertToReference(ctx);
  9982. else if( !ctx->type.dataType.IsReference() )
  9983. {
  9984. Error(TXT_NOT_VALID_REFERENCE, node);
  9985. return -1;
  9986. }
  9987. if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt64, false)) ||
  9988. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt64, false)) )
  9989. {
  9990. if( op == ttInc )
  9991. ctx->bc.Instr(asBC_INCi64);
  9992. else
  9993. ctx->bc.Instr(asBC_DECi64);
  9994. }
  9995. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt, false)) ||
  9996. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt, false)) )
  9997. {
  9998. if( op == ttInc )
  9999. ctx->bc.Instr(asBC_INCi);
  10000. else
  10001. ctx->bc.Instr(asBC_DECi);
  10002. }
  10003. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt16, false)) ||
  10004. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt16, false)) )
  10005. {
  10006. if( op == ttInc )
  10007. ctx->bc.Instr(asBC_INCi16);
  10008. else
  10009. ctx->bc.Instr(asBC_DECi16);
  10010. }
  10011. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt8, false)) ||
  10012. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt8, false)) )
  10013. {
  10014. if( op == ttInc )
  10015. ctx->bc.Instr(asBC_INCi8);
  10016. else
  10017. ctx->bc.Instr(asBC_DECi8);
  10018. }
  10019. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttFloat, false)) )
  10020. {
  10021. if( op == ttInc )
  10022. ctx->bc.Instr(asBC_INCf);
  10023. else
  10024. ctx->bc.Instr(asBC_DECf);
  10025. }
  10026. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttDouble, false)) )
  10027. {
  10028. if( op == ttInc )
  10029. ctx->bc.Instr(asBC_INCd);
  10030. else
  10031. ctx->bc.Instr(asBC_DECd);
  10032. }
  10033. else
  10034. {
  10035. Error(TXT_ILLEGAL_OPERATION, node);
  10036. return -1;
  10037. }
  10038. }
  10039. else
  10040. {
  10041. // Unknown operator
  10042. asASSERT(false);
  10043. return -1;
  10044. }
  10045. return 0;
  10046. }
  10047. void asCCompiler::ConvertToReference(asCExprContext *ctx)
  10048. {
  10049. if( ctx->type.isVariable && !ctx->type.dataType.IsReference() )
  10050. {
  10051. ctx->bc.InstrSHORT(asBC_LDV, ctx->type.stackOffset);
  10052. ctx->type.dataType.MakeReference(true);
  10053. ctx->type.SetVariable(ctx->type.dataType, ctx->type.stackOffset, ctx->type.isTemporary);
  10054. }
  10055. }
  10056. int asCCompiler::FindPropertyAccessor(const asCString &name, asCExprContext *ctx, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess)
  10057. {
  10058. return FindPropertyAccessor(name, ctx, 0, node, ns, isThisAccess);
  10059. }
  10060. int asCCompiler::FindPropertyAccessor(const asCString &name, asCExprContext *ctx, asCExprContext *arg, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess)
  10061. {
  10062. if( engine->ep.propertyAccessorMode == 0 )
  10063. {
  10064. // Property accessors have been disabled by the application
  10065. return 0;
  10066. }
  10067. int getId = 0, setId = 0;
  10068. asCString getName = "get_" + name;
  10069. asCString setName = "set_" + name;
  10070. asCArray<int> multipleGetFuncs, multipleSetFuncs;
  10071. if( ctx->type.dataType.IsObject() )
  10072. {
  10073. asASSERT( ns == 0 );
  10074. // Don't look for property accessors in script classes if the script
  10075. // property accessors have been disabled by the application
  10076. if( !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) ||
  10077. engine->ep.propertyAccessorMode == 2 )
  10078. {
  10079. // Check if the object has any methods with the corresponding accessor name(s)
  10080. asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  10081. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  10082. {
  10083. asCScriptFunction *f = engine->scriptFunctions[ot->methods[n]];
  10084. // TODO: The type of the parameter should match the argument (unless the arg is a dummy)
  10085. if( f->name == getName && (int)f->parameterTypes.GetLength() == (arg?1:0) )
  10086. {
  10087. if( getId == 0 )
  10088. getId = ot->methods[n];
  10089. else
  10090. {
  10091. if( multipleGetFuncs.GetLength() == 0 )
  10092. multipleGetFuncs.PushLast(getId);
  10093. multipleGetFuncs.PushLast(ot->methods[n]);
  10094. }
  10095. }
  10096. // TODO: getset: If the parameter is a reference, it must not be an out reference. Should we allow inout ref?
  10097. if( f->name == setName && (int)f->parameterTypes.GetLength() == (arg?2:1) )
  10098. {
  10099. if( setId == 0 )
  10100. setId = ot->methods[n];
  10101. else
  10102. {
  10103. if( multipleSetFuncs.GetLength() == 0 )
  10104. multipleSetFuncs.PushLast(setId);
  10105. multipleSetFuncs.PushLast(ot->methods[n]);
  10106. }
  10107. }
  10108. }
  10109. }
  10110. }
  10111. else
  10112. {
  10113. asASSERT( ns != 0 );
  10114. // Look for appropriate global functions.
  10115. asCArray<int> funcs;
  10116. asUINT n;
  10117. builder->GetFunctionDescriptions(getName.AddressOf(), funcs, ns);
  10118. for( n = 0; n < funcs.GetLength(); n++ )
  10119. {
  10120. asCScriptFunction *f = builder->GetFunctionDescription(funcs[n]);
  10121. // TODO: The type of the parameter should match the argument (unless the arg is a dummy)
  10122. if( (int)f->parameterTypes.GetLength() == (arg?1:0) )
  10123. {
  10124. if( getId == 0 )
  10125. getId = funcs[n];
  10126. else
  10127. {
  10128. if( multipleGetFuncs.GetLength() == 0 )
  10129. multipleGetFuncs.PushLast(getId);
  10130. multipleGetFuncs.PushLast(funcs[n]);
  10131. }
  10132. }
  10133. }
  10134. funcs.SetLength(0);
  10135. builder->GetFunctionDescriptions(setName.AddressOf(), funcs, ns);
  10136. for( n = 0; n < funcs.GetLength(); n++ )
  10137. {
  10138. asCScriptFunction *f = builder->GetFunctionDescription(funcs[n]);
  10139. // TODO: getset: If the parameter is a reference, it must not be an out reference. Should we allow inout ref?
  10140. if( (int)f->parameterTypes.GetLength() == (arg?2:1) )
  10141. {
  10142. if( setId == 0 )
  10143. setId = funcs[n];
  10144. else
  10145. {
  10146. if( multipleSetFuncs.GetLength() == 0 )
  10147. multipleSetFuncs.PushLast(getId);
  10148. multipleSetFuncs.PushLast(funcs[n]);
  10149. }
  10150. }
  10151. }
  10152. }
  10153. bool isConst = ctx->type.dataType.IsObjectConst();
  10154. // Check for multiple matches
  10155. if( multipleGetFuncs.GetLength() > 0 )
  10156. {
  10157. // Filter the list by constness
  10158. FilterConst(multipleGetFuncs, !isConst);
  10159. if( multipleGetFuncs.GetLength() > 1 )
  10160. {
  10161. if (node)
  10162. {
  10163. asCString str;
  10164. str.Format(TXT_MULTIPLE_PROP_GET_ACCESSOR_FOR_s, name.AddressOf());
  10165. Error(str, node);
  10166. PrintMatchingFuncs(multipleGetFuncs, node);
  10167. }
  10168. return -1;
  10169. }
  10170. else
  10171. {
  10172. // The id may have changed
  10173. getId = multipleGetFuncs[0];
  10174. }
  10175. }
  10176. if( multipleSetFuncs.GetLength() > 0 )
  10177. {
  10178. // Filter the list by constness
  10179. FilterConst(multipleSetFuncs, !isConst);
  10180. if( multipleSetFuncs.GetLength() > 1 )
  10181. {
  10182. if (node)
  10183. {
  10184. asCString str;
  10185. str.Format(TXT_MULTIPLE_PROP_SET_ACCESSOR_FOR_s, name.AddressOf());
  10186. Error(str, node);
  10187. PrintMatchingFuncs(multipleSetFuncs, node);
  10188. }
  10189. return -1;
  10190. }
  10191. else
  10192. {
  10193. // The id may have changed
  10194. setId = multipleSetFuncs[0];
  10195. }
  10196. }
  10197. // Check for type compatibility between get and set accessor
  10198. if( getId && setId )
  10199. {
  10200. asCScriptFunction *getFunc = builder->GetFunctionDescription(getId);
  10201. asCScriptFunction *setFunc = builder->GetFunctionDescription(setId);
  10202. // It is permitted for a getter to return a handle and the setter to take a reference
  10203. int idx = (arg?1:0);
  10204. if( !getFunc->returnType.IsEqualExceptRefAndConst(setFunc->parameterTypes[idx]) &&
  10205. !((getFunc->returnType.IsObjectHandle() && !setFunc->parameterTypes[idx].IsObjectHandle()) &&
  10206. (getFunc->returnType.GetTypeInfo() == setFunc->parameterTypes[idx].GetTypeInfo())) )
  10207. {
  10208. if (node)
  10209. {
  10210. asCString str;
  10211. str.Format(TXT_GET_SET_ACCESSOR_TYPE_MISMATCH_FOR_s, name.AddressOf());
  10212. Error(str, node);
  10213. asCArray<int> funcs;
  10214. funcs.PushLast(getId);
  10215. funcs.PushLast(setId);
  10216. PrintMatchingFuncs(funcs, node);
  10217. }
  10218. return -1;
  10219. }
  10220. }
  10221. // Check if we are within one of the accessors
  10222. int realGetId = getId;
  10223. int realSetId = setId;
  10224. if( outFunc->objectType && isThisAccess )
  10225. {
  10226. // The property accessors would be virtual functions, so we need to find the real implementation
  10227. asCScriptFunction *getFunc = getId ? builder->GetFunctionDescription(getId) : 0;
  10228. if( getFunc &&
  10229. getFunc->funcType == asFUNC_VIRTUAL &&
  10230. outFunc->objectType->DerivesFrom(getFunc->objectType) )
  10231. realGetId = outFunc->objectType->virtualFunctionTable[getFunc->vfTableIdx]->id;
  10232. asCScriptFunction *setFunc = setId ? builder->GetFunctionDescription(setId) : 0;
  10233. if( setFunc &&
  10234. setFunc->funcType == asFUNC_VIRTUAL &&
  10235. outFunc->objectType->DerivesFrom(setFunc->objectType) )
  10236. realSetId = outFunc->objectType->virtualFunctionTable[setFunc->vfTableIdx]->id;
  10237. }
  10238. // Avoid recursive call, by not treating this as a property accessor call.
  10239. // This will also allow having the real property with the same name as the accessors.
  10240. if( (isThisAccess || outFunc->objectType == 0) &&
  10241. ((realGetId && realGetId == outFunc->id) ||
  10242. (realSetId && realSetId == outFunc->id)) )
  10243. {
  10244. getId = 0;
  10245. setId = 0;
  10246. }
  10247. // Check if the application has disabled script written property accessors
  10248. if( engine->ep.propertyAccessorMode == 1 )
  10249. {
  10250. if( getId && builder->GetFunctionDescription(getId)->funcType != asFUNC_SYSTEM )
  10251. getId = 0;
  10252. if( setId && builder->GetFunctionDescription(setId)->funcType != asFUNC_SYSTEM )
  10253. setId = 0;
  10254. }
  10255. if( getId || setId )
  10256. {
  10257. // Property accessors were found, but we don't know which is to be used yet, so
  10258. // we just prepare the bytecode for the method call, and then store the function ids
  10259. // so that the right one can be used when we get there.
  10260. ctx->property_get = getId;
  10261. ctx->property_set = setId;
  10262. bool isRefSafe = ctx->type.isRefSafe;
  10263. if( ctx->type.dataType.IsObject() )
  10264. {
  10265. // If the object is read-only then we need to remember that
  10266. if( (!ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReadOnly()) ||
  10267. (ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsHandleToConst()) )
  10268. ctx->property_const = true;
  10269. else
  10270. ctx->property_const = false;
  10271. // If the object is a handle then we need to remember that
  10272. ctx->property_handle = ctx->type.dataType.IsObjectHandle();
  10273. ctx->property_ref = ctx->type.dataType.IsReference();
  10274. }
  10275. // The setter's parameter type is used as the property type,
  10276. // unless only the getter is available
  10277. asCDataType dt;
  10278. if( setId )
  10279. dt = builder->GetFunctionDescription(setId)->parameterTypes[(arg?1:0)];
  10280. else
  10281. dt = builder->GetFunctionDescription(getId)->returnType;
  10282. // Just change the type, the context must still maintain information
  10283. // about previous variable offset and the indicator of temporary variable.
  10284. int offset = ctx->type.stackOffset;
  10285. bool isTemp = ctx->type.isTemporary;
  10286. ctx->type.Set(dt);
  10287. ctx->type.stackOffset = (short)offset;
  10288. ctx->type.isTemporary = isTemp;
  10289. ctx->exprNode = node;
  10290. // Remember if the object is safe, so the invocation of the property
  10291. // accessor doesn't needlessly make a safe copy of the handle
  10292. ctx->type.isRefSafe = isRefSafe;
  10293. // Store the argument for later use
  10294. if( arg )
  10295. {
  10296. ctx->property_arg = asNEW(asCExprContext)(engine);
  10297. if( ctx->property_arg == 0 )
  10298. {
  10299. // Out of memory
  10300. return -1;
  10301. }
  10302. MergeExprBytecodeAndType(ctx->property_arg, arg);
  10303. }
  10304. return 1;
  10305. }
  10306. // No accessor was found
  10307. return 0;
  10308. }
  10309. int asCCompiler::ProcessPropertySetAccessor(asCExprContext *ctx, asCExprContext *arg, asCScriptNode *node)
  10310. {
  10311. // TODO: A lot of this code is similar to ProcessPropertyGetAccessor. Can we unify them?
  10312. if( !ctx->property_set )
  10313. {
  10314. Error(TXT_PROPERTY_HAS_NO_SET_ACCESSOR, node);
  10315. return -1;
  10316. }
  10317. asCScriptFunction *func = builder->GetFunctionDescription(ctx->property_set);
  10318. // Make sure the arg match the property
  10319. asCArray<int> funcs;
  10320. funcs.PushLast(ctx->property_set);
  10321. asCArray<asCExprContext *> args;
  10322. if( ctx->property_arg )
  10323. args.PushLast(ctx->property_arg);
  10324. args.PushLast(arg);
  10325. MatchFunctions(funcs, args, node, func->GetName(), 0, func->objectType, ctx->property_const);
  10326. if( funcs.GetLength() == 0 )
  10327. {
  10328. // MatchFunctions already reported the error
  10329. if( ctx->property_arg )
  10330. {
  10331. asDELETE(ctx->property_arg, asCExprContext);
  10332. ctx->property_arg = 0;
  10333. }
  10334. return -1;
  10335. }
  10336. if( func->objectType )
  10337. {
  10338. // Setup the context with the original type so the method call gets built correctly
  10339. ctx->type.dataType = asCDataType::CreateType(func->objectType, ctx->property_const);
  10340. if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
  10341. if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
  10342. // Don't allow the call if the object is read-only and the property accessor is not const
  10343. if( ctx->property_const && !func->IsReadOnly() )
  10344. {
  10345. Error(TXT_NON_CONST_METHOD_ON_CONST_OBJ, node);
  10346. asCArray<int> funcCandidates;
  10347. funcCandidates.PushLast(ctx->property_set);
  10348. PrintMatchingFuncs(funcCandidates, node);
  10349. }
  10350. }
  10351. // Call the accessor
  10352. MakeFunctionCall(ctx, ctx->property_set, func->objectType, args, node);
  10353. ctx->property_get = 0;
  10354. ctx->property_set = 0;
  10355. if( ctx->property_arg )
  10356. {
  10357. asDELETE(ctx->property_arg, asCExprContext);
  10358. ctx->property_arg = 0;
  10359. }
  10360. return 0;
  10361. }
  10362. int asCCompiler::ProcessPropertyGetSetAccessor(asCExprContext *ctx, asCExprContext *lctx, asCExprContext *rctx, eTokenType op, asCScriptNode *errNode)
  10363. {
  10364. // TODO: Perhaps it might be interesting to allow the definition of compound setters for better
  10365. // performance, e.g. set_add_prop, set_mul_prop, etc. With these it would also be possible
  10366. // to support value types, since it would be a single call
  10367. // Compound assignment for indexed property accessors is not supported yet
  10368. if( lctx->property_arg != 0 )
  10369. {
  10370. // Process the property to free the memory
  10371. ProcessPropertySetAccessor(lctx, rctx, errNode);
  10372. Error(TXT_COMPOUND_ASGN_WITH_IDX_PROP, errNode);
  10373. return -1;
  10374. }
  10375. // Compound assignments require both get and set accessors
  10376. if( lctx->property_set == 0 || lctx->property_get == 0 )
  10377. {
  10378. // Process the property to free the memory
  10379. ProcessPropertySetAccessor(lctx, rctx, errNode);
  10380. Error(TXT_COMPOUND_ASGN_REQUIRE_GET_SET, errNode);
  10381. return -1;
  10382. }
  10383. // Property accessors on value types (or scoped references types) are not supported since
  10384. // it is not possible to guarantee that the object will stay alive between the two calls
  10385. asCScriptFunction *func = engine->scriptFunctions[lctx->property_set];
  10386. if( func->objectType && (func->objectType->flags & (asOBJ_VALUE | asOBJ_SCOPED)) )
  10387. {
  10388. // Process the property to free the memory
  10389. ProcessPropertySetAccessor(lctx, rctx, errNode);
  10390. Error(TXT_COMPOUND_ASGN_ON_VALUE_TYPE, errNode);
  10391. return -1;
  10392. }
  10393. // Translate the compound assignment to the corresponding dual operator
  10394. switch( op )
  10395. {
  10396. case ttAddAssign: op = ttPlus; break;
  10397. case ttSubAssign: op = ttMinus; break;
  10398. case ttMulAssign: op = ttStar; break;
  10399. case ttDivAssign: op = ttSlash; break;
  10400. case ttModAssign: op = ttPercent; break;
  10401. case ttPowAssign: op = ttStarStar; break;
  10402. case ttAndAssign: op = ttAmp; break;
  10403. case ttOrAssign: op = ttBitOr; break;
  10404. case ttXorAssign: op = ttBitXor; break;
  10405. case ttShiftLeftAssign: op = ttBitShiftLeft; break;
  10406. case ttShiftRightAAssign: op = ttBitShiftRightArith; break;
  10407. case ttShiftRightLAssign: op = ttBitShiftRight; break;
  10408. default: op = ttUnrecognizedToken; break;
  10409. }
  10410. if( op == ttUnrecognizedToken )
  10411. {
  10412. // Shouldn't happen
  10413. asASSERT(false);
  10414. // Process the property to free the memory
  10415. ProcessPropertySetAccessor(lctx, rctx, errNode);
  10416. return -1;
  10417. }
  10418. asCExprContext before(engine);
  10419. if( func->objectType && (func->objectType->flags & (asOBJ_REF|asOBJ_SCOPED)) == asOBJ_REF )
  10420. {
  10421. // Keep a reference to the object in a local variable
  10422. before.bc.AddCode(&lctx->bc);
  10423. asUINT len = reservedVariables.GetLength();
  10424. rctx->bc.GetVarsUsed(reservedVariables);
  10425. before.bc.GetVarsUsed(reservedVariables);
  10426. asCDataType dt = asCDataType::CreateObjectHandle(func->objectType, false);
  10427. int offset = AllocateVariable(dt, true);
  10428. reservedVariables.SetLength(len);
  10429. before.type.SetVariable(dt, offset, true);
  10430. if( lctx->property_ref )
  10431. before.bc.Instr(asBC_RDSPtr);
  10432. before.bc.InstrSHORT(asBC_PSF, (short)offset);
  10433. before.bc.InstrPTR(asBC_REFCPY, func->objectType);
  10434. before.bc.Instr(asBC_PopPtr);
  10435. if( lctx->type.isTemporary )
  10436. {
  10437. // Add the release of the temporary variable as a deferred expression
  10438. asSDeferredParam deferred;
  10439. deferred.origExpr = 0;
  10440. deferred.argInOutFlags = asTM_INREF;
  10441. deferred.argNode = 0;
  10442. deferred.argType.SetVariable(ctx->type.dataType, lctx->type.stackOffset, true);
  10443. before.deferredParams.PushLast(deferred);
  10444. }
  10445. // Update the left expression to use the local variable
  10446. lctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  10447. lctx->type.stackOffset = (short)offset;
  10448. lctx->property_ref = true;
  10449. // Don't release the temporary variable too early
  10450. lctx->type.isTemporary = false;
  10451. ctx->bc.AddCode(&before.bc);
  10452. }
  10453. // Keep the original information on the property
  10454. asCExprContext llctx(engine);
  10455. llctx.type = lctx->type;
  10456. llctx.property_arg = lctx->property_arg;
  10457. llctx.property_const = lctx->property_const;
  10458. llctx.property_get = lctx->property_get;
  10459. llctx.property_handle = lctx->property_handle;
  10460. llctx.property_ref = lctx->property_ref;
  10461. llctx.property_set = lctx->property_set;
  10462. // Compile the dual operator using the get accessor
  10463. CompileOperator(errNode, lctx, rctx, ctx, op, false);
  10464. // If we made a local variable to hold the reference it must be reused
  10465. if( before.type.stackOffset )
  10466. llctx.bc.InstrSHORT(asBC_PSF, before.type.stackOffset);
  10467. // Compile the assignment using the set accessor
  10468. ProcessPropertySetAccessor(&llctx, ctx, errNode);
  10469. MergeExprBytecodeAndType(ctx, &llctx);
  10470. if( before.type.stackOffset )
  10471. ReleaseTemporaryVariable(before.type.stackOffset, &ctx->bc);
  10472. asASSERT( ctx->deferredParams.GetLength() == 0 );
  10473. ctx->deferredParams = before.deferredParams;
  10474. ProcessDeferredParams(ctx);
  10475. return 0;
  10476. }
  10477. void asCCompiler::ProcessPropertyGetAccessor(asCExprContext *ctx, asCScriptNode *node)
  10478. {
  10479. // If no property accessor has been prepared then don't do anything
  10480. if( !ctx->property_get && !ctx->property_set )
  10481. return;
  10482. if( !ctx->property_get )
  10483. {
  10484. // Raise error on missing accessor
  10485. Error(TXT_PROPERTY_HAS_NO_GET_ACCESSOR, node);
  10486. ctx->type.SetDummy();
  10487. return;
  10488. }
  10489. asCExprValue objType = ctx->type;
  10490. asCScriptFunction *func = builder->GetFunctionDescription(ctx->property_get);
  10491. // Make sure the arg match the property
  10492. asCArray<int> funcs;
  10493. funcs.PushLast(ctx->property_get);
  10494. asCArray<asCExprContext *> args;
  10495. if( ctx->property_arg )
  10496. args.PushLast(ctx->property_arg);
  10497. MatchFunctions(funcs, args, node, func->GetName(), 0, func->objectType, ctx->property_const);
  10498. if( funcs.GetLength() == 0 )
  10499. {
  10500. // MatchFunctions already reported the error
  10501. if( ctx->property_arg )
  10502. {
  10503. asDELETE(ctx->property_arg, asCExprContext);
  10504. ctx->property_arg = 0;
  10505. }
  10506. ctx->type.SetDummy();
  10507. return;
  10508. }
  10509. if( func->objectType )
  10510. {
  10511. // Setup the context with the original type so the method call gets built correctly
  10512. ctx->type.dataType = asCDataType::CreateType(func->objectType, ctx->property_const);
  10513. if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
  10514. if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
  10515. // Don't allow the call if the object is read-only and the property accessor is not const
  10516. if( ctx->property_const && !func->IsReadOnly() )
  10517. {
  10518. Error(TXT_NON_CONST_METHOD_ON_CONST_OBJ, node);
  10519. asCArray<int> funcCandidates;
  10520. funcCandidates.PushLast(ctx->property_get);
  10521. PrintMatchingFuncs(funcCandidates, node);
  10522. }
  10523. }
  10524. // The explicit handle flag must be remembered
  10525. bool isExplicitHandle = ctx->type.isExplicitHandle;
  10526. // Call the accessor
  10527. MakeFunctionCall(ctx, ctx->property_get, func->objectType, args, node);
  10528. if( isExplicitHandle )
  10529. ctx->type.isExplicitHandle = true;
  10530. // Clear the property get/set ids
  10531. ctx->property_get = 0;
  10532. ctx->property_set = 0;
  10533. if( ctx->property_arg )
  10534. {
  10535. asDELETE(ctx->property_arg, asCExprContext);
  10536. ctx->property_arg = 0;
  10537. }
  10538. }
  10539. int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asCExprContext *ctx)
  10540. {
  10541. // Don't allow any postfix operators on expressions that take address of class method
  10542. if( ctx->IsClassMethod() )
  10543. {
  10544. Error(TXT_INVALID_OP_ON_METHOD, node);
  10545. return -1;
  10546. }
  10547. // Don't allow any operators on void expressions
  10548. if( ctx->IsVoidExpression() )
  10549. {
  10550. Error(TXT_VOID_CANT_BE_OPERAND, node);
  10551. return -1;
  10552. }
  10553. // Check if the variable is initialized (if it indeed is a variable)
  10554. IsVariableInitialized(&ctx->type, node);
  10555. int op = node->tokenType;
  10556. if( (op == ttInc || op == ttDec) && ctx->type.dataType.IsObject() )
  10557. {
  10558. const char *opName = 0;
  10559. switch( op )
  10560. {
  10561. case ttInc: opName = "opPostInc"; break;
  10562. case ttDec: opName = "opPostDec"; break;
  10563. }
  10564. if( opName )
  10565. {
  10566. // TODO: Should convert this to something similar to CompileOverloadedDualOperator2
  10567. ProcessPropertyGetAccessor(ctx, node);
  10568. // 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
  10569. // Find the correct method
  10570. bool isConst = ctx->type.dataType.IsObjectConst();
  10571. asCArray<int> funcs;
  10572. asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  10573. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  10574. {
  10575. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  10576. if( func->name == opName &&
  10577. func->parameterTypes.GetLength() == 0 &&
  10578. (!isConst || func->IsReadOnly()) )
  10579. {
  10580. funcs.PushLast(func->id);
  10581. }
  10582. }
  10583. // Did we find the method?
  10584. if( funcs.GetLength() == 1 )
  10585. {
  10586. asCArray<asCExprContext *> args;
  10587. MakeFunctionCall(ctx, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
  10588. return 0;
  10589. }
  10590. else if( funcs.GetLength() == 0 )
  10591. {
  10592. asCString str;
  10593. str = asCString(opName) + "()";
  10594. if( isConst )
  10595. str += " const";
  10596. str.Format(TXT_FUNCTION_s_NOT_FOUND, str.AddressOf());
  10597. Error(str, node);
  10598. ctx->type.SetDummy();
  10599. return -1;
  10600. }
  10601. else if( funcs.GetLength() > 1 )
  10602. {
  10603. Error(TXT_MORE_THAN_ONE_MATCHING_OP, node);
  10604. PrintMatchingFuncs(funcs, node);
  10605. ctx->type.SetDummy();
  10606. return -1;
  10607. }
  10608. }
  10609. }
  10610. else if( op == ttInc || op == ttDec )
  10611. {
  10612. // Make sure the reference isn't a temporary variable
  10613. if( ctx->type.isTemporary )
  10614. {
  10615. Error(TXT_REF_IS_TEMP, node);
  10616. return -1;
  10617. }
  10618. if( ctx->type.dataType.IsReadOnly() )
  10619. {
  10620. Error(TXT_REF_IS_READ_ONLY, node);
  10621. return -1;
  10622. }
  10623. if( ctx->property_get || ctx->property_set )
  10624. {
  10625. Error(TXT_INVALID_REF_PROP_ACCESS, node);
  10626. return -1;
  10627. }
  10628. if( !ctx->type.isLValue )
  10629. {
  10630. Error(TXT_NOT_LVALUE, node);
  10631. return -1;
  10632. }
  10633. if( ctx->type.isVariable && !ctx->type.dataType.IsReference() )
  10634. ConvertToReference(ctx);
  10635. else if( !ctx->type.dataType.IsReference() )
  10636. {
  10637. Error(TXT_NOT_VALID_REFERENCE, node);
  10638. return -1;
  10639. }
  10640. // Copy the value to a temp before changing it
  10641. ConvertToTempVariable(ctx);
  10642. asASSERT(!ctx->type.isLValue);
  10643. // Increment the value pointed to by the reference still in the register
  10644. asEBCInstr iInc = asBC_INCi, iDec = asBC_DECi;
  10645. if( ctx->type.dataType.IsDoubleType() )
  10646. {
  10647. iInc = asBC_INCd;
  10648. iDec = asBC_DECd;
  10649. }
  10650. else if( ctx->type.dataType.IsFloatType() )
  10651. {
  10652. iInc = asBC_INCf;
  10653. iDec = asBC_DECf;
  10654. }
  10655. else if( ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType() )
  10656. {
  10657. if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt16, false)) ||
  10658. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt16, false)) )
  10659. {
  10660. iInc = asBC_INCi16;
  10661. iDec = asBC_DECi16;
  10662. }
  10663. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt8, false)) ||
  10664. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt8, false)) )
  10665. {
  10666. iInc = asBC_INCi8;
  10667. iDec = asBC_DECi8;
  10668. }
  10669. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt64, false)) ||
  10670. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt64, false)) )
  10671. {
  10672. iInc = asBC_INCi64;
  10673. iDec = asBC_DECi64;
  10674. }
  10675. }
  10676. else
  10677. {
  10678. Error(TXT_ILLEGAL_OPERATION, node);
  10679. return -1;
  10680. }
  10681. if( op == ttInc ) ctx->bc.Instr(iInc); else ctx->bc.Instr(iDec);
  10682. }
  10683. else if( op == ttDot )
  10684. {
  10685. if( node->firstChild->nodeType == snIdentifier )
  10686. {
  10687. ProcessPropertyGetAccessor(ctx, node);
  10688. // Get the property name
  10689. asCString name(&script->code[node->firstChild->tokenPos], node->firstChild->tokenLength);
  10690. if( ctx->type.dataType.IsObject() )
  10691. {
  10692. // We need to look for get/set property accessors.
  10693. // If found, the context stores information on the get/set accessors
  10694. // until it is known which is to be used.
  10695. int r = 0;
  10696. if( node->next && node->next->tokenType == ttOpenBracket )
  10697. {
  10698. // The property accessor should take an index arg
  10699. asCExprContext dummyArg(engine);
  10700. r = FindPropertyAccessor(name, ctx, &dummyArg, node, 0);
  10701. }
  10702. if( r == 0 )
  10703. r = FindPropertyAccessor(name, ctx, node, 0);
  10704. if( r != 0 )
  10705. return r;
  10706. if( !ctx->type.dataType.IsPrimitive() )
  10707. Dereference(ctx, true);
  10708. if( ctx->type.dataType.IsObjectHandle() )
  10709. {
  10710. // Convert the handle to a normal object
  10711. asCDataType dt = ctx->type.dataType;
  10712. dt.MakeHandle(false);
  10713. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV);
  10714. // The handle may not have been an lvalue, but the dereferenced object is
  10715. ctx->type.isLValue = true;
  10716. }
  10717. bool isConst = ctx->type.dataType.IsObjectConst();
  10718. asCObjectProperty *prop = builder->GetObjectProperty(ctx->type.dataType, name.AddressOf());
  10719. if( prop )
  10720. {
  10721. // Is the property access allowed?
  10722. if( (prop->isPrivate || prop->isProtected) && (!outFunc || outFunc->objectType != ctx->type.dataType.GetTypeInfo()) )
  10723. {
  10724. asCString msg;
  10725. if( prop->isPrivate )
  10726. msg.Format(TXT_PRIVATE_PROP_ACCESS_s, name.AddressOf());
  10727. else
  10728. msg.Format(TXT_PROTECTED_PROP_ACCESS_s, name.AddressOf());
  10729. Error(msg, node);
  10730. }
  10731. // Adjust the pointer for composite member
  10732. // This must always be done even if the offset is 0 because the asCWriter needs the meta data in ADDSi to identify the composite property
  10733. if( prop->compositeOffset || prop->isCompositeIndirect )
  10734. ctx->bc.InstrSHORT_DW(asBC_ADDSi, (short)prop->compositeOffset, engine->GetTypeIdFromDataType(asCDataType::CreateType(ctx->type.dataType.GetTypeInfo(), false)));
  10735. if (prop->isCompositeIndirect)
  10736. ctx->bc.Instr(asBC_RDSPtr);
  10737. // Put the offset on the stack
  10738. // This must always be done even if the offset is 0 so the type info is stored
  10739. ctx->bc.InstrSHORT_DW(asBC_ADDSi, (short)prop->byteOffset, engine->GetTypeIdFromDataType(asCDataType::CreateType(ctx->type.dataType.GetTypeInfo(), false)));
  10740. if( prop->type.IsReference() )
  10741. ctx->bc.Instr(asBC_RDSPtr);
  10742. // Reference to primitive must be stored in the temp register
  10743. if( prop->type.IsPrimitive() )
  10744. {
  10745. ctx->bc.Instr(asBC_PopRPtr);
  10746. }
  10747. // Keep information about temporary variables as deferred expression
  10748. if( ctx->type.isTemporary )
  10749. {
  10750. // Add the release of this reference, as a deferred expression
  10751. asSDeferredParam deferred;
  10752. deferred.origExpr = 0;
  10753. deferred.argInOutFlags = asTM_INREF;
  10754. deferred.argNode = 0;
  10755. deferred.argType.SetVariable(ctx->type.dataType, ctx->type.stackOffset, true);
  10756. ctx->deferredParams.PushLast(deferred);
  10757. }
  10758. // Set the new type and make sure it is not treated as a variable anymore
  10759. ctx->type.dataType = prop->type;
  10760. ctx->type.dataType.MakeReference(true);
  10761. ctx->type.isVariable = false;
  10762. ctx->type.isTemporary = false;
  10763. if( (ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) && !ctx->type.dataType.IsObjectHandle() )
  10764. {
  10765. // Objects that are members are not references
  10766. ctx->type.dataType.MakeReference(false);
  10767. // The object is safe (life time guaranteed) if the parent object is also safe
  10768. }
  10769. else if (ctx->type.dataType.IsObjectHandle())
  10770. {
  10771. // A object accessed through a handle cannot be considered safe,
  10772. // as it can be cleared at any time
  10773. ctx->type.isRefSafe = false;
  10774. }
  10775. ctx->type.dataType.MakeReadOnly(isConst ? true : prop->type.IsReadOnly());
  10776. }
  10777. else
  10778. {
  10779. // If the name is not a property, the compiler must check if the name matches
  10780. // a method, which can be used for constructing delegates
  10781. asIScriptFunction *func = 0;
  10782. asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  10783. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  10784. {
  10785. if( engine->scriptFunctions[ot->methods[n]]->name == name )
  10786. {
  10787. func = engine->scriptFunctions[ot->methods[n]];
  10788. break;
  10789. }
  10790. }
  10791. if( func )
  10792. {
  10793. // An object method was found. Keep the name of the method in the expression, but
  10794. // don't actually modify the bytecode at this point since it is not yet known what
  10795. // the method will be used for, or even what overloaded method should be used.
  10796. ctx->methodName = name;
  10797. }
  10798. else
  10799. {
  10800. asCString str;
  10801. str.Format(TXT_s_NOT_MEMBER_OF_s, name.AddressOf(), ctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  10802. Error(str, node);
  10803. return -1;
  10804. }
  10805. }
  10806. }
  10807. else
  10808. {
  10809. asCString str;
  10810. str.Format(TXT_s_NOT_MEMBER_OF_s, name.AddressOf(), ctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  10811. Error(str, node);
  10812. return -1;
  10813. }
  10814. }
  10815. else
  10816. {
  10817. // Make sure it is an object we are accessing
  10818. if( !ctx->type.dataType.IsObject() )
  10819. {
  10820. asCString str;
  10821. str.Format(TXT_ILLEGAL_OPERATION_ON_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  10822. Error(str, node);
  10823. return -1;
  10824. }
  10825. // Process the get property accessor
  10826. ProcessPropertyGetAccessor(ctx, node);
  10827. // Compile function call
  10828. int r = CompileFunctionCall(node->firstChild, ctx, CastToObjectType(ctx->type.dataType.GetTypeInfo()), ctx->type.dataType.IsObjectConst());
  10829. if( r < 0 ) return r;
  10830. }
  10831. }
  10832. else if( op == ttOpenBracket )
  10833. {
  10834. // If the property access takes an index arg and the argument hasn't been evaluated yet,
  10835. // then we should use that instead of processing it now. If the argument has already been
  10836. // evaluated, then we should process the property accessor as a get access now as the new
  10837. // index operator is on the result of that accessor.
  10838. asCString propertyName;
  10839. asSNameSpace *ns = 0;
  10840. if( ((ctx->property_get && builder->GetFunctionDescription(ctx->property_get)->GetParamCount() == 1) ||
  10841. (ctx->property_set && builder->GetFunctionDescription(ctx->property_set)->GetParamCount() == 2)) &&
  10842. (ctx->property_arg && ctx->property_arg->type.dataType.GetTokenType() == ttUnrecognizedToken) )
  10843. {
  10844. // Determine the name of the property accessor
  10845. asCScriptFunction *func = 0;
  10846. if( ctx->property_get )
  10847. func = builder->GetFunctionDescription(ctx->property_get);
  10848. else
  10849. func = builder->GetFunctionDescription(ctx->property_set);
  10850. propertyName = func->GetName();
  10851. propertyName = propertyName.SubString(4);
  10852. // Set the original type of the expression so we can re-evaluate the property accessor
  10853. if( func->objectType )
  10854. {
  10855. ctx->type.dataType = asCDataType::CreateType(func->objectType, ctx->property_const);
  10856. if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
  10857. if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
  10858. }
  10859. else
  10860. {
  10861. // Store the namespace where the function is declared
  10862. // so the same function can be found later
  10863. ctx->type.SetDummy();
  10864. ns = func->nameSpace;
  10865. }
  10866. ctx->property_get = ctx->property_set = 0;
  10867. if( ctx->property_arg )
  10868. {
  10869. asDELETE(ctx->property_arg, asCExprContext);
  10870. ctx->property_arg = 0;
  10871. }
  10872. }
  10873. else
  10874. {
  10875. if( !ctx->type.dataType.IsObject() )
  10876. {
  10877. asCString str;
  10878. str.Format(TXT_OBJECT_DOESNT_SUPPORT_INDEX_OP, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  10879. Error(str, node);
  10880. return -1;
  10881. }
  10882. ProcessPropertyGetAccessor(ctx, node);
  10883. }
  10884. // Compile the expression
  10885. bool isOK = true;
  10886. asCArray<asCExprContext *> args;
  10887. asCArray<asSNamedArgument> namedArgs;
  10888. asASSERT( node->firstChild->nodeType == snArgList );
  10889. if( CompileArgumentList(node->firstChild, args, namedArgs) >= 0 )
  10890. {
  10891. // Check for the existence of the opIndex method
  10892. bool lookForProperty = true;
  10893. if( propertyName == "" )
  10894. {
  10895. bool isConst = ctx->type.dataType.IsObjectConst();
  10896. asCObjectType *objectType = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  10897. asCArray<int> funcs;
  10898. builder->GetObjectMethodDescriptions("opIndex", objectType, funcs, isConst);
  10899. if( funcs.GetLength() > 0 )
  10900. {
  10901. // Since there are opIndex methods, the compiler should not look for get/set_opIndex accessors
  10902. lookForProperty = false;
  10903. // Determine which of opIndex methods that match
  10904. MatchFunctions(funcs, args, node, "opIndex", 0, objectType, isConst);
  10905. if( funcs.GetLength() != 1 )
  10906. {
  10907. // The error has already been reported by MatchFunctions
  10908. isOK = false;
  10909. }
  10910. else
  10911. {
  10912. // Add the default values for arguments not explicitly supplied
  10913. int r = CompileDefaultAndNamedArgs(node, args, funcs[0], objectType);
  10914. if( r == 0 )
  10915. MakeFunctionCall(ctx, funcs[0], objectType, args, node, false, 0, ctx->type.stackOffset);
  10916. else
  10917. isOK = false;
  10918. }
  10919. }
  10920. }
  10921. if( lookForProperty && isOK )
  10922. {
  10923. if( args.GetLength() != 1 )
  10924. {
  10925. // TODO: opIndex: Implement support for multiple index arguments in set_opIndex too
  10926. Error(TXT_PROP_ACCESS_WITH_INDEX_ONE_ARG, node);
  10927. isOK = false;
  10928. }
  10929. else
  10930. {
  10931. Dereference(ctx, true);
  10932. asCExprContext lctx(engine);
  10933. MergeExprBytecodeAndType(&lctx, ctx);
  10934. // Check for accessors methods for the opIndex, either as get/set_opIndex or as get/set with the property name
  10935. int r = FindPropertyAccessor(propertyName == "" ? "opIndex" : propertyName.AddressOf(), &lctx, args[0], node, ns);
  10936. if (r == 0)
  10937. {
  10938. asCString str;
  10939. str.Format(TXT_OBJECT_DOESNT_SUPPORT_INDEX_OP, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  10940. Error(str, node);
  10941. isOK = false;
  10942. }
  10943. else if (r < 0)
  10944. isOK = false;
  10945. if (isOK)
  10946. MergeExprBytecodeAndType(ctx, &lctx);
  10947. }
  10948. }
  10949. }
  10950. else
  10951. isOK = false;
  10952. // Cleanup
  10953. for( asUINT n = 0; n < args.GetLength(); n++ )
  10954. if( args[n] )
  10955. {
  10956. asDELETE(args[n], asCExprContext);
  10957. }
  10958. if( !isOK )
  10959. return -1;
  10960. }
  10961. else if( op == ttOpenParanthesis )
  10962. {
  10963. // TODO: Most of this is already done by CompileFunctionCall(). Can we share the code?
  10964. // Make sure the expression is a funcdef or an object that may have opCall methods
  10965. if( !ctx->type.dataType.GetTypeInfo() || (!ctx->type.dataType.IsFuncdef() && !ctx->type.dataType.IsObject()) )
  10966. {
  10967. Error(TXT_EXPR_DOESNT_EVAL_TO_FUNC, node);
  10968. return -1;
  10969. }
  10970. // Compile arguments
  10971. asCArray<asCExprContext *> args;
  10972. asCArray<asSNamedArgument> namedArgs;
  10973. if( CompileArgumentList(node->lastChild, args, namedArgs) >= 0 )
  10974. {
  10975. // Match arguments with the funcdef
  10976. asCArray<int> funcs;
  10977. if( ctx->type.dataType.IsFuncdef() )
  10978. {
  10979. funcs.PushLast(CastToFuncdefType(ctx->type.dataType.GetTypeInfo())->funcdef->id);
  10980. MatchFunctions(funcs, args, node, ctx->type.dataType.GetTypeInfo()->name.AddressOf(), &namedArgs);
  10981. }
  10982. else
  10983. {
  10984. bool isConst = ctx->type.dataType.IsObjectConst();
  10985. builder->GetObjectMethodDescriptions("opCall", CastToObjectType(ctx->type.dataType.GetTypeInfo()), funcs, isConst);
  10986. MatchFunctions(funcs, args, node, "opCall", &namedArgs, CastToObjectType(ctx->type.dataType.GetTypeInfo()), isConst);
  10987. }
  10988. if( funcs.GetLength() != 1 )
  10989. {
  10990. // The error was reported by MatchFunctions()
  10991. // Dummy value
  10992. ctx->type.SetDummy();
  10993. }
  10994. else
  10995. {
  10996. // Add the default values for arguments not explicitly supplied
  10997. int r = CompileDefaultAndNamedArgs(node, args, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), &namedArgs);
  10998. // TODO: funcdef: Do we have to make sure the handle is stored in a temporary variable, or
  10999. // is it enough to make sure it is in a local variable?
  11000. // For function pointer we must guarantee that the function is safe, i.e.
  11001. // by first storing the function pointer in a local variable (if it isn't already in one)
  11002. if( r == asSUCCESS )
  11003. {
  11004. Dereference(ctx, true);
  11005. if( ctx->type.dataType.IsFuncdef() )
  11006. {
  11007. if( !ctx->type.isVariable )
  11008. ConvertToVariable(ctx);
  11009. // Remove the reference from the stack as the asBC_CALLPTR instruction takes the variable as argument
  11010. ctx->bc.Instr(asBC_PopPtr);
  11011. }
  11012. MakeFunctionCall(ctx, funcs[0], ctx->type.dataType.IsFuncdef() ? 0 : CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node, false, 0, ctx->type.stackOffset);
  11013. }
  11014. }
  11015. }
  11016. else
  11017. ctx->type.SetDummy();
  11018. // Cleanup
  11019. for( asUINT n = 0; n < args.GetLength(); n++ )
  11020. if( args[n] )
  11021. {
  11022. asDELETE(args[n], asCExprContext);
  11023. }
  11024. for( asUINT n = 0; n < namedArgs.GetLength(); n++ )
  11025. if( namedArgs[n].ctx )
  11026. {
  11027. asDELETE(namedArgs[n].ctx, asCExprContext);
  11028. }
  11029. }
  11030. return 0;
  11031. }
  11032. int asCCompiler::GetPrecedence(asCScriptNode *op)
  11033. {
  11034. // x ** y
  11035. // x * y, x / y, x % y
  11036. // x + y, x - y
  11037. // x <= y, x < y, x >= y, x > y
  11038. // x = =y, x != y, x xor y, x is y, x !is y
  11039. // x and y
  11040. // x or y
  11041. // The following are not used in this function,
  11042. // but should have lower precedence than the above
  11043. // x ? y : z
  11044. // x = y
  11045. // The expression term have the highest precedence
  11046. if( op->nodeType == snExprTerm )
  11047. return 1;
  11048. // Evaluate operators by token
  11049. int tokenType = op->tokenType;
  11050. if( tokenType == ttStarStar )
  11051. return 0;
  11052. if( tokenType == ttStar || tokenType == ttSlash || tokenType == ttPercent )
  11053. return -1;
  11054. if( tokenType == ttPlus || tokenType == ttMinus )
  11055. return -2;
  11056. if( tokenType == ttBitShiftLeft ||
  11057. tokenType == ttBitShiftRight ||
  11058. tokenType == ttBitShiftRightArith )
  11059. return -3;
  11060. if( tokenType == ttAmp )
  11061. return -4;
  11062. if( tokenType == ttBitXor )
  11063. return -5;
  11064. if( tokenType == ttBitOr )
  11065. return -6;
  11066. if( tokenType == ttLessThanOrEqual ||
  11067. tokenType == ttLessThan ||
  11068. tokenType == ttGreaterThanOrEqual ||
  11069. tokenType == ttGreaterThan )
  11070. return -7;
  11071. if( tokenType == ttEqual || tokenType == ttNotEqual || tokenType == ttXor || tokenType == ttIs || tokenType == ttNotIs )
  11072. return -8;
  11073. if( tokenType == ttAnd )
  11074. return -9;
  11075. if( tokenType == ttOr )
  11076. return -10;
  11077. // Unknown operator
  11078. asASSERT(false);
  11079. return 0;
  11080. }
  11081. asUINT asCCompiler::MatchArgument(asCArray<int> &funcs, asCArray<asSOverloadCandidate> &matches, const asCExprContext *argExpr, int paramNum, bool allowObjectConstruct)
  11082. {
  11083. matches.SetLength(0);
  11084. for( asUINT n = 0; n < funcs.GetLength(); n++ )
  11085. {
  11086. asCScriptFunction *desc = builder->GetFunctionDescription(funcs[n]);
  11087. // Does the function have arguments enough?
  11088. if( (int)desc->parameterTypes.GetLength() <= paramNum )
  11089. continue;
  11090. int cost = MatchArgument(desc, argExpr, paramNum, allowObjectConstruct);
  11091. if( cost != -1 )
  11092. matches.PushLast(asSOverloadCandidate(funcs[n], asUINT(cost)));
  11093. }
  11094. return (asUINT)matches.GetLength();
  11095. }
  11096. int asCCompiler::MatchArgument(asCScriptFunction *desc, const asCExprContext *argExpr, int paramNum, bool allowObjectConstruct)
  11097. {
  11098. // void expressions can match any out parameter, but nothing else
  11099. if( argExpr->IsVoidExpression() )
  11100. {
  11101. if( desc->inOutFlags[paramNum] == asTM_OUTREF )
  11102. return 0;
  11103. return -1;
  11104. }
  11105. // Anonymous init lists can only match parameters that can be initialized with a list
  11106. if (argExpr->IsAnonymousInitList())
  11107. {
  11108. if ((desc->parameterTypes[paramNum].IsReference() && desc->inOutFlags[paramNum] != asTM_INREF) ||
  11109. desc->parameterTypes[paramNum].GetTypeInfo() == 0 ||
  11110. desc->parameterTypes[paramNum].GetBehaviour()->listFactory == 0)
  11111. {
  11112. return -1;
  11113. }
  11114. return 0;
  11115. }
  11116. // Can we make the match by implicit conversion?
  11117. asCExprContext ti(engine);
  11118. ti.type = argExpr->type;
  11119. ti.methodName = argExpr->methodName;
  11120. ti.enumValue = argExpr->enumValue;
  11121. ti.exprNode = argExpr->exprNode;
  11122. if( argExpr->type.dataType.IsPrimitive() )
  11123. ti.type.dataType.MakeReference(false);
  11124. // Don't allow the implicit conversion to make a copy in case the argument is expecting a reference to the true value
  11125. if (desc->parameterTypes[paramNum].IsReference() && desc->inOutFlags[paramNum] == asTM_INOUTREF)
  11126. allowObjectConstruct = false;
  11127. int cost = ImplicitConversion(&ti, desc->parameterTypes[paramNum], 0, asIC_IMPLICIT_CONV, false, allowObjectConstruct);
  11128. // If the function parameter is an inout-reference then it must not be possible to call the
  11129. // function with an incorrect argument type, even though the type can normally be converted.
  11130. if( desc->parameterTypes[paramNum].IsReference() &&
  11131. desc->inOutFlags[paramNum] == asTM_INOUTREF &&
  11132. desc->parameterTypes[paramNum].GetTokenType() != ttQuestion )
  11133. {
  11134. // Observe, that the below checks are only necessary for when unsafe references have been
  11135. // enabled by the application. Without this the &inout reference form wouldn't be allowed
  11136. // for these value types.
  11137. // Don't allow a primitive to be converted to a reference of another primitive type
  11138. if( desc->parameterTypes[paramNum].IsPrimitive() &&
  11139. desc->parameterTypes[paramNum].GetTokenType() != argExpr->type.dataType.GetTokenType() )
  11140. {
  11141. asASSERT( engine->ep.allowUnsafeReferences );
  11142. return -1;
  11143. }
  11144. // Don't allow an enum to be converted to a reference of another enum type
  11145. if( desc->parameterTypes[paramNum].IsEnumType() &&
  11146. desc->parameterTypes[paramNum].GetTypeInfo() != argExpr->type.dataType.GetTypeInfo() )
  11147. {
  11148. asASSERT( engine->ep.allowUnsafeReferences );
  11149. return -1;
  11150. }
  11151. // Don't allow a non-handle expression to be converted to a reference to a handle
  11152. if( desc->parameterTypes[paramNum].IsObjectHandle() &&
  11153. !argExpr->type.dataType.IsObjectHandle() )
  11154. {
  11155. asASSERT( engine->ep.allowUnsafeReferences );
  11156. return -1;
  11157. }
  11158. // Don't allow a value type to be converted
  11159. if( (desc->parameterTypes[paramNum].GetTypeInfo() && (desc->parameterTypes[paramNum].GetTypeInfo()->GetFlags() & asOBJ_VALUE)) &&
  11160. (desc->parameterTypes[paramNum].GetTypeInfo() != argExpr->type.dataType.GetTypeInfo()) )
  11161. {
  11162. asASSERT( engine->ep.allowUnsafeReferences );
  11163. return -1;
  11164. }
  11165. }
  11166. // How well does the argument match the function parameter?
  11167. if( desc->parameterTypes[paramNum].IsEqualExceptRef(ti.type.dataType) )
  11168. return cost;
  11169. // No match is available
  11170. return -1;
  11171. }
  11172. void asCCompiler::PrepareArgument2(asCExprContext *ctx, asCExprContext *arg, asCDataType *paramType, bool isFunction, int refType, bool isMakingCopy)
  11173. {
  11174. // Reference parameters whose value won't be used don't evaluate the expression
  11175. // Clean arguments (i.e. default value) will be passed in directly as there is nothing to protect
  11176. if( paramType->IsReference() && !(refType & asTM_INREF) && !arg->isCleanArg )
  11177. {
  11178. // Store the original bytecode so that it can be reused when processing the deferred output parameter
  11179. asCExprContext *orig = asNEW(asCExprContext)(engine);
  11180. if( orig == 0 )
  11181. {
  11182. // Out of memory
  11183. return;
  11184. }
  11185. MergeExprBytecodeAndType(orig, arg);
  11186. arg->origExpr = orig;
  11187. }
  11188. PrepareArgument(paramType, arg, arg->exprNode, isFunction, refType, isMakingCopy);
  11189. // arg still holds the original expression for output parameters
  11190. ctx->bc.AddCode(&arg->bc);
  11191. }
  11192. bool asCCompiler::CompileOverloadedDualOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, bool leftToRight, asCExprContext *ctx, bool isHandle, eTokenType token)
  11193. {
  11194. DetermineSingleFunc(lctx, node);
  11195. DetermineSingleFunc(rctx, node);
  11196. ctx->exprNode = node;
  11197. // What type of operator is it?
  11198. if( token == ttUnrecognizedToken )
  11199. token = node->tokenType;
  11200. if( token == ttUnrecognizedToken )
  11201. {
  11202. // This happens when the compiler is inferring an assignment
  11203. // operation from another action, for example in preparing a value
  11204. // as a function argument
  11205. token = ttAssignment;
  11206. }
  11207. // boolean operators are not overloadable
  11208. if( token == ttAnd ||
  11209. token == ttOr ||
  11210. token == ttXor )
  11211. return false;
  11212. // Dual operators can also be implemented as class methods
  11213. if( token == ttEqual ||
  11214. token == ttNotEqual )
  11215. {
  11216. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  11217. // Find the matching opEquals method
  11218. int r = CompileOverloadedDualOperator2(node, "opEquals", lctx, rctx, leftToRight, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  11219. if( r == 0 )
  11220. {
  11221. // Try again by switching the order of the operands
  11222. r = CompileOverloadedDualOperator2(node, "opEquals", rctx, lctx, !leftToRight, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  11223. }
  11224. if( r == 1 )
  11225. {
  11226. if( token == ttNotEqual )
  11227. ctx->bc.InstrSHORT(asBC_NOT, ctx->type.stackOffset);
  11228. // Success, don't continue
  11229. return true;
  11230. }
  11231. else if( r < 0 )
  11232. {
  11233. // Compiler error, don't continue
  11234. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  11235. return true;
  11236. }
  11237. }
  11238. if( token == ttEqual ||
  11239. token == ttNotEqual ||
  11240. token == ttLessThan ||
  11241. token == ttLessThanOrEqual ||
  11242. token == ttGreaterThan ||
  11243. token == ttGreaterThanOrEqual )
  11244. {
  11245. bool swappedOrder = false;
  11246. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  11247. // Find the matching opCmp method
  11248. int r = CompileOverloadedDualOperator2(node, "opCmp", lctx, rctx, leftToRight, ctx, true, asCDataType::CreatePrimitive(ttInt, false));
  11249. if( r == 0 )
  11250. {
  11251. // Try again by switching the order of the operands
  11252. swappedOrder = true;
  11253. r = CompileOverloadedDualOperator2(node, "opCmp", rctx, lctx, !leftToRight, ctx, true, asCDataType::CreatePrimitive(ttInt, false));
  11254. }
  11255. if( r == 1 )
  11256. {
  11257. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  11258. int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, false), true);
  11259. ctx->bc.InstrW_DW(asBC_CMPIi, ctx->type.stackOffset, 0);
  11260. if( token == ttEqual )
  11261. ctx->bc.Instr(asBC_TZ);
  11262. else if( token == ttNotEqual )
  11263. ctx->bc.Instr(asBC_TNZ);
  11264. else if( (token == ttLessThan && !swappedOrder) ||
  11265. (token == ttGreaterThan && swappedOrder) )
  11266. ctx->bc.Instr(asBC_TS);
  11267. else if( (token == ttLessThanOrEqual && !swappedOrder) ||
  11268. (token == ttGreaterThanOrEqual && swappedOrder) )
  11269. ctx->bc.Instr(asBC_TNP);
  11270. else if( (token == ttGreaterThan && !swappedOrder) ||
  11271. (token == ttLessThan && swappedOrder) )
  11272. ctx->bc.Instr(asBC_TP);
  11273. else if( (token == ttGreaterThanOrEqual && !swappedOrder) ||
  11274. (token == ttLessThanOrEqual && swappedOrder) )
  11275. ctx->bc.Instr(asBC_TNS);
  11276. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  11277. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, false), a, true);
  11278. // Success, don't continue
  11279. return true;
  11280. }
  11281. else if( r < 0 )
  11282. {
  11283. // Compiler error, don't continue
  11284. #if AS_SIZEOF_BOOL == 1
  11285. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  11286. #else
  11287. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  11288. #endif
  11289. return true;
  11290. }
  11291. }
  11292. // The rest of the operators are not commutative, and doesn't require specific return type
  11293. const char *op = 0, *op_r = 0;
  11294. switch( int(token) ) // convert to int to avoid warning in gnuc that not all values are tested
  11295. {
  11296. case ttPlus: op = "opAdd"; op_r = "opAdd_r"; break;
  11297. case ttMinus: op = "opSub"; op_r = "opSub_r"; break;
  11298. case ttStar: op = "opMul"; op_r = "opMul_r"; break;
  11299. case ttSlash: op = "opDiv"; op_r = "opDiv_r"; break;
  11300. case ttPercent: op = "opMod"; op_r = "opMod_r"; break;
  11301. case ttStarStar: op = "opPow"; op_r = "opPow_r"; break;
  11302. case ttBitOr: op = "opOr"; op_r = "opOr_r"; break;
  11303. case ttAmp: op = "opAnd"; op_r = "opAnd_r"; break;
  11304. case ttBitXor: op = "opXor"; op_r = "opXor_r"; break;
  11305. case ttBitShiftLeft: op = "opShl"; op_r = "opShl_r"; break;
  11306. case ttBitShiftRight: op = "opShr"; op_r = "opShr_r"; break;
  11307. case ttBitShiftRightArith: op = "opUShr"; op_r = "opUShr_r"; break;
  11308. }
  11309. // TODO: Might be interesting to support a concatenation operator, e.g. ~
  11310. if( op && op_r )
  11311. {
  11312. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  11313. // Find the matching operator method
  11314. int r = CompileOverloadedDualOperator2(node, op, lctx, rctx, leftToRight, ctx);
  11315. if( r == 0 )
  11316. {
  11317. // Try again by switching the order of the operands, and using the reversed operator
  11318. r = CompileOverloadedDualOperator2(node, op_r, rctx, lctx, !leftToRight, ctx);
  11319. }
  11320. if( r == 1 )
  11321. {
  11322. // Success, don't continue
  11323. return true;
  11324. }
  11325. else if( r < 0 )
  11326. {
  11327. // Compiler error, don't continue
  11328. ctx->type.SetDummy();
  11329. return true;
  11330. }
  11331. }
  11332. // Assignment operators
  11333. op = 0;
  11334. if( isHandle )
  11335. {
  11336. // Only asOBJ_ASHANDLE types can get here
  11337. asASSERT( lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) );
  11338. asASSERT( token == ttAssignment );
  11339. if( token == ttAssignment )
  11340. op = "opHndlAssign";
  11341. }
  11342. else
  11343. {
  11344. switch( int(token) ) // convert to int to avoid warning in gnuc that not all values are tested
  11345. {
  11346. case ttAssignment: op = "opAssign"; break;
  11347. case ttAddAssign: op = "opAddAssign"; break;
  11348. case ttSubAssign: op = "opSubAssign"; break;
  11349. case ttMulAssign: op = "opMulAssign"; break;
  11350. case ttDivAssign: op = "opDivAssign"; break;
  11351. case ttModAssign: op = "opModAssign"; break;
  11352. case ttPowAssign: op = "opPowAssign"; break;
  11353. case ttOrAssign: op = "opOrAssign"; break;
  11354. case ttAndAssign: op = "opAndAssign"; break;
  11355. case ttXorAssign: op = "opXorAssign"; break;
  11356. case ttShiftLeftAssign: op = "opShlAssign"; break;
  11357. case ttShiftRightLAssign: op = "opShrAssign"; break;
  11358. case ttShiftRightAAssign: op = "opUShrAssign"; break;
  11359. }
  11360. }
  11361. if( op )
  11362. {
  11363. if( builder->engine->ep.disallowValueAssignForRefType &&
  11364. lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !(lctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCOPED) )
  11365. {
  11366. if( token == ttAssignment )
  11367. Error(TXT_DISALLOW_ASSIGN_ON_REF_TYPE, node);
  11368. else
  11369. Error(TXT_DISALLOW_COMPOUND_ASSIGN_ON_REF_TYPE, node);
  11370. // Set a dummy output
  11371. ctx->type.Set(lctx->type.dataType);
  11372. return true;
  11373. }
  11374. // TODO: Shouldn't accept const lvalue with the assignment operators
  11375. // Find the matching operator method
  11376. int r = CompileOverloadedDualOperator2(node, op, lctx, rctx, false, ctx);
  11377. if( r == 1 )
  11378. {
  11379. // Success, don't continue
  11380. return true;
  11381. }
  11382. else if( r < 0 )
  11383. {
  11384. // Compiler error, don't continue
  11385. ctx->type.SetDummy();
  11386. return true;
  11387. }
  11388. }
  11389. // No suitable operator was found
  11390. return false;
  11391. }
  11392. // Returns negative on compile error
  11393. // zero on no matching operator
  11394. // one on matching operator
  11395. int asCCompiler::CompileOverloadedDualOperator2(asCScriptNode *node, const char *methodName, asCExprContext *lctx, asCExprContext *rctx, bool leftToRight, asCExprContext *ctx, bool specificReturn, const asCDataType &returnType)
  11396. {
  11397. // Find the matching method
  11398. if( lctx->type.dataType.IsObject() &&
  11399. (!lctx->type.isExplicitHandle ||
  11400. lctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) &&
  11401. !lctx->type.IsNullConstant() )
  11402. {
  11403. asUINT n;
  11404. // Is the left value a const?
  11405. bool isConst = lctx->type.dataType.IsObjectConst();
  11406. asCArray<int> funcs;
  11407. asCObjectType *ot = CastToObjectType(lctx->type.dataType.GetTypeInfo());
  11408. asASSERT(ot);
  11409. for( n = 0; ot && n < ot->methods.GetLength(); n++ )
  11410. {
  11411. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  11412. asASSERT( func );
  11413. if( func && func->name == methodName &&
  11414. (!specificReturn || func->returnType == returnType) &&
  11415. func->parameterTypes.GetLength() == 1 &&
  11416. (!isConst || func->IsReadOnly()) )
  11417. {
  11418. // Make sure the method is accessible by the module
  11419. if( builder->module->accessMask & func->accessMask )
  11420. {
  11421. funcs.PushLast(func->id);
  11422. }
  11423. }
  11424. }
  11425. // Which is the best matching function?
  11426. asCArray<asSOverloadCandidate> tempFuncs;
  11427. MatchArgument(funcs, tempFuncs, rctx, 0);
  11428. // Find the lowest cost operator(s)
  11429. asCArray<int> ops;
  11430. asUINT bestCost = asUINT(-1);
  11431. for( n = 0; n < tempFuncs.GetLength(); ++n )
  11432. {
  11433. asUINT cost = tempFuncs[n].cost;
  11434. if( cost < bestCost )
  11435. {
  11436. ops.SetLength(0);
  11437. bestCost = cost;
  11438. }
  11439. if( cost == bestCost )
  11440. ops.PushLast(tempFuncs[n].funcId);
  11441. }
  11442. // If the object is not const, then we need to prioritize non-const methods
  11443. if( !isConst )
  11444. FilterConst(ops);
  11445. // Did we find an operator?
  11446. if( ops.GetLength() == 1 )
  11447. {
  11448. // Reserve the variables used in the right expression so the new temporary
  11449. // variable allocated for the left operand isn't accidentally overwritten.
  11450. int l = int(reservedVariables.GetLength());
  11451. rctx->bc.GetVarsUsed(reservedVariables);
  11452. // Process the lctx expression as get accessor
  11453. ProcessPropertyGetAccessor(lctx, node);
  11454. reservedVariables.SetLength(l);
  11455. asCExprContext tmpCtx(engine);
  11456. if (leftToRight)
  11457. {
  11458. // Make sure lctx is in fact a variable. If it is a reference there is no
  11459. // guarantee that the reference will stay alive throughout the evaluation of rctx
  11460. if (!lctx->type.isVariable)
  11461. {
  11462. // Reserve the variables used in the right expression so the new temporary
  11463. // variable allocated for the left operand isn't accidentally overwritten.
  11464. l = int(reservedVariables.GetLength());
  11465. rctx->bc.GetVarsUsed(reservedVariables);
  11466. if (engine->ep.allowUnsafeReferences && lctx->type.dataType.IsObject() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_VALUE))
  11467. {
  11468. // If the application allows unsafe references, then it is not necessary to
  11469. // make a copy of the object, just store the reference as a local variable
  11470. // Allocate a temporary variable as reference to the type
  11471. asCDataType dt = lctx->type.dataType;
  11472. dt.MakeReference(true);
  11473. int offset = AllocateVariable(dt, true, false, true);
  11474. Dereference(lctx, true);
  11475. // Copy the pointer to the temporary variable
  11476. lctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  11477. if (lctx->type.dataType.IsFuncdef())
  11478. lctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  11479. else
  11480. lctx->bc.InstrPTR(asBC_REFCPY, lctx->type.dataType.GetTypeInfo());
  11481. lctx->type.SetVariable(dt, offset, true);
  11482. }
  11483. else
  11484. {
  11485. if (lctx->type.dataType.SupportHandles())
  11486. lctx->type.dataType.MakeHandle(true);
  11487. PrepareTemporaryVariable(node, lctx);
  11488. }
  11489. reservedVariables.SetLength(l);
  11490. }
  11491. // Move the bytecode for the left operand to a temporary context
  11492. // so we can later make sure this is computed first
  11493. tmpCtx.bc.AddCode(&lctx->bc);
  11494. tmpCtx.bc.Instr(asBC_PopPtr);
  11495. // Add bytecode to push the object pointer computed in the left operand on the stack as the this pointer
  11496. // This will be placed after rctx by MakeFunctionCall below
  11497. lctx->bc.InstrWORD(asBC_PSF, lctx->type.stackOffset);
  11498. // Implicitly dereference handle parameters sent by reference
  11499. sVariable *v = variables->GetVariableByOffset(lctx->type.stackOffset);
  11500. if (v && v->type.IsReference() && (!v->type.IsObject() || v->type.IsObjectHandle()))
  11501. lctx->bc.Instr(asBC_RDSPtr);
  11502. }
  11503. else
  11504. {
  11505. // Make sure the rvalue doesn't have deferred temporary variables that are also used in the lvalue,
  11506. // since that would cause the VM to overwrite the variable while executing the bytecode for the lvalue.
  11507. asCArray<int> usedVars;
  11508. lctx->bc.GetVarsUsed(usedVars);
  11509. asUINT oldReservedVars = reservedVariables.GetLength();
  11510. for (n = 0; n < rctx->deferredParams.GetLength(); n++)
  11511. {
  11512. if (rctx->deferredParams[n].argType.isTemporary &&
  11513. usedVars.Exists(rctx->deferredParams[n].argType.stackOffset))
  11514. {
  11515. if (reservedVariables.GetLength() == oldReservedVars)
  11516. reservedVariables.Concatenate(usedVars);
  11517. // Allocate a new variable for the deferred argument
  11518. int offset = AllocateVariableNotIn(rctx->deferredParams[n].argType.dataType, true, false, rctx);
  11519. int oldVar = rctx->deferredParams[n].argType.stackOffset;
  11520. rctx->deferredParams[n].argType.stackOffset = short(offset);
  11521. rctx->bc.ExchangeVar(oldVar, offset);
  11522. ReleaseTemporaryVariable(oldVar, 0);
  11523. }
  11524. }
  11525. reservedVariables.SetLength(oldReservedVars);
  11526. }
  11527. // Merge the bytecode so that it forms lvalue.methodName(rvalue)
  11528. asCArray<asCExprContext *> args;
  11529. args.PushLast(rctx);
  11530. MergeExprBytecode(ctx, lctx);
  11531. ctx->type = lctx->type;
  11532. MakeFunctionCall(ctx, ops[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node);
  11533. // Rearrange the bytecode so the left argument is computed first
  11534. if (leftToRight)
  11535. {
  11536. tmpCtx.bc.AddCode(&ctx->bc);
  11537. ctx->bc.AddCode(&tmpCtx.bc);
  11538. }
  11539. // Found matching operator
  11540. return 1;
  11541. }
  11542. else if( ops.GetLength() > 1 )
  11543. {
  11544. Error(TXT_MORE_THAN_ONE_MATCHING_OP, node);
  11545. PrintMatchingFuncs(ops, node);
  11546. ctx->type.SetDummy();
  11547. // Compiler error
  11548. return -1;
  11549. }
  11550. }
  11551. // No matching operator
  11552. return 0;
  11553. }
  11554. void asCCompiler::MakeFunctionCall(asCExprContext *ctx, int funcId, asCObjectType *objectType, asCArray<asCExprContext*> &args, asCScriptNode *node, bool useVariable, int stackOffset, int funcPtrVar)
  11555. {
  11556. if( objectType )
  11557. Dereference(ctx, true);
  11558. // Store the expression node for error reporting
  11559. if( ctx->exprNode == 0 )
  11560. ctx->exprNode = node;
  11561. asCByteCode objBC(engine);
  11562. objBC.AddCode(&ctx->bc);
  11563. PrepareFunctionCall(funcId, &ctx->bc, args);
  11564. // Verify if any of the args variable offsets are used in the other code.
  11565. // If they are exchange the offset for a new one
  11566. asUINT n;
  11567. for( n = 0; n < args.GetLength(); n++ )
  11568. {
  11569. if( args[n]->type.isTemporary && objBC.IsVarUsed(args[n]->type.stackOffset) )
  11570. {
  11571. // Release the current temporary variable
  11572. ReleaseTemporaryVariable(args[n]->type, 0);
  11573. asCDataType dt = args[n]->type.dataType;
  11574. dt.MakeReference(false);
  11575. int l = int(reservedVariables.GetLength());
  11576. objBC.GetVarsUsed(reservedVariables);
  11577. ctx->bc.GetVarsUsed(reservedVariables);
  11578. int newOffset = AllocateVariable(dt, true, IsVariableOnHeap(args[n]->type.stackOffset));
  11579. reservedVariables.SetLength(l);
  11580. asASSERT( IsVariableOnHeap(args[n]->type.stackOffset) == IsVariableOnHeap(newOffset) );
  11581. ctx->bc.ExchangeVar(args[n]->type.stackOffset, newOffset);
  11582. args[n]->type.stackOffset = (short)newOffset;
  11583. args[n]->type.isTemporary = true;
  11584. args[n]->type.isVariable = true;
  11585. }
  11586. }
  11587. // If the function will return a value type on the stack, then we must allocate space
  11588. // for that here and push the address on the stack as a hidden argument to the function
  11589. asCScriptFunction *func = builder->GetFunctionDescription(funcId);
  11590. if( func->DoesReturnOnStack() )
  11591. {
  11592. asASSERT(!useVariable);
  11593. useVariable = true;
  11594. stackOffset = AllocateVariable(func->returnType, true);
  11595. ctx->bc.InstrSHORT(asBC_PSF, short(stackOffset));
  11596. }
  11597. ctx->bc.AddCode(&objBC);
  11598. MoveArgsToStack(funcId, &ctx->bc, args, objectType ? true : false);
  11599. PerformFunctionCall(funcId, ctx, false, &args, 0, useVariable, stackOffset, funcPtrVar);
  11600. }
  11601. int asCCompiler::CompileOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType op, bool leftToRight)
  11602. {
  11603. // Don't allow any operators on expressions that take address of class method, but allow it on global functions
  11604. if( (lctx->IsClassMethod()) || (rctx->IsClassMethod()) )
  11605. {
  11606. Error(TXT_INVALID_OP_ON_METHOD, node);
  11607. return -1;
  11608. }
  11609. // Don't allow any operators on void expressions
  11610. if( lctx->IsVoidExpression() || rctx->IsVoidExpression() )
  11611. {
  11612. Error(TXT_VOID_CANT_BE_OPERAND, node);
  11613. return -1;
  11614. }
  11615. if( op == ttUnrecognizedToken )
  11616. op = node->tokenType;
  11617. IsVariableInitialized(&lctx->type, node);
  11618. IsVariableInitialized(&rctx->type, node);
  11619. if( lctx->type.isExplicitHandle || rctx->type.isExplicitHandle ||
  11620. lctx->type.IsNullConstant() || rctx->type.IsNullConstant() ||
  11621. op == ttIs || op == ttNotIs )
  11622. {
  11623. CompileOperatorOnHandles(node, lctx, rctx, ctx, op);
  11624. return 0;
  11625. }
  11626. else
  11627. {
  11628. // Compile an overloaded operator for the two operands
  11629. if( CompileOverloadedDualOperator(node, lctx, rctx, leftToRight, ctx, false, op) )
  11630. return 0;
  11631. // If both operands are objects, then we shouldn't continue
  11632. if( lctx->type.dataType.IsObject() && rctx->type.dataType.IsObject() )
  11633. {
  11634. asCString str;
  11635. 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());
  11636. Error(str, node);
  11637. ctx->type.SetDummy();
  11638. return -1;
  11639. }
  11640. // Process the property get accessors (if any)
  11641. ProcessPropertyGetAccessor(lctx, node);
  11642. ProcessPropertyGetAccessor(rctx, node);
  11643. // Make sure we have two variables or constants
  11644. if( lctx->type.dataType.IsReference() ) ConvertToVariableNotIn(lctx, rctx);
  11645. if( rctx->type.dataType.IsReference() ) ConvertToVariableNotIn(rctx, lctx);
  11646. // Make sure lctx doesn't end up with a variable used in rctx
  11647. if( lctx->type.isTemporary && rctx->bc.IsVarUsed(lctx->type.stackOffset) )
  11648. {
  11649. int offset = AllocateVariableNotIn(lctx->type.dataType, true, false, rctx);
  11650. rctx->bc.ExchangeVar(lctx->type.stackOffset, offset);
  11651. ReleaseTemporaryVariable(offset, 0);
  11652. }
  11653. // Math operators
  11654. // + - * / % ** += -= *= /= %= **=
  11655. if( op == ttPlus || op == ttAddAssign ||
  11656. op == ttMinus || op == ttSubAssign ||
  11657. op == ttStar || op == ttMulAssign ||
  11658. op == ttSlash || op == ttDivAssign ||
  11659. op == ttPercent || op == ttModAssign ||
  11660. op == ttStarStar || op == ttPowAssign )
  11661. {
  11662. CompileMathOperator(node, lctx, rctx, ctx, op);
  11663. return 0;
  11664. }
  11665. // Bitwise operators
  11666. // << >> >>> & | ^ <<= >>= >>>= &= |= ^=
  11667. if( op == ttAmp || op == ttAndAssign ||
  11668. op == ttBitOr || op == ttOrAssign ||
  11669. op == ttBitXor || op == ttXorAssign ||
  11670. op == ttBitShiftLeft || op == ttShiftLeftAssign ||
  11671. op == ttBitShiftRight || op == ttShiftRightLAssign ||
  11672. op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  11673. {
  11674. CompileBitwiseOperator(node, lctx, rctx, ctx, op);
  11675. return 0;
  11676. }
  11677. // Comparison operators
  11678. // == != < > <= >=
  11679. if( op == ttEqual || op == ttNotEqual ||
  11680. op == ttLessThan || op == ttLessThanOrEqual ||
  11681. op == ttGreaterThan || op == ttGreaterThanOrEqual )
  11682. {
  11683. CompileComparisonOperator(node, lctx, rctx, ctx, op);
  11684. return 0;
  11685. }
  11686. // Boolean operators
  11687. // && || ^^
  11688. if( op == ttAnd || op == ttOr || op == ttXor )
  11689. {
  11690. CompileBooleanOperator(node, lctx, rctx, ctx, op);
  11691. return 0;
  11692. }
  11693. }
  11694. asASSERT(false);
  11695. return -1;
  11696. }
  11697. void asCCompiler::ConvertToTempVariableNotIn(asCExprContext *ctx, asCExprContext *exclude)
  11698. {
  11699. int l = int(reservedVariables.GetLength());
  11700. if( exclude ) exclude->bc.GetVarsUsed(reservedVariables);
  11701. ConvertToTempVariable(ctx);
  11702. reservedVariables.SetLength(l);
  11703. }
  11704. void asCCompiler::ConvertToTempVariable(asCExprContext *ctx)
  11705. {
  11706. // This is only used for primitive types and null handles
  11707. asASSERT( ctx->type.dataType.IsPrimitive() || ctx->type.dataType.IsNullHandle() );
  11708. ConvertToVariable(ctx);
  11709. if( !ctx->type.isTemporary )
  11710. {
  11711. if( ctx->type.dataType.IsPrimitive() )
  11712. {
  11713. // Copy the variable to a temporary variable
  11714. int offset = AllocateVariable(ctx->type.dataType, true);
  11715. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  11716. ctx->bc.InstrW_W(asBC_CpyVtoV4, offset, ctx->type.stackOffset);
  11717. else
  11718. ctx->bc.InstrW_W(asBC_CpyVtoV8, offset, ctx->type.stackOffset);
  11719. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  11720. }
  11721. else
  11722. {
  11723. // We should never get here
  11724. asASSERT(false);
  11725. }
  11726. }
  11727. }
  11728. void asCCompiler::ConvertToVariable(asCExprContext *ctx)
  11729. {
  11730. // We should never get here while the context is still an unprocessed property accessor
  11731. asASSERT(ctx->property_get == 0 && ctx->property_set == 0);
  11732. int offset;
  11733. if( !ctx->type.isVariable &&
  11734. (ctx->type.dataType.IsObjectHandle() ||
  11735. (ctx->type.dataType.IsObject() && ctx->type.dataType.SupportHandles())) )
  11736. {
  11737. offset = AllocateVariable(ctx->type.dataType, true);
  11738. if( ctx->type.IsNullConstant() )
  11739. {
  11740. if( ctx->bc.GetLastInstr() == asBC_PshNull )
  11741. ctx->bc.Instr(asBC_PopPtr); // Pop the null constant pushed onto the stack
  11742. ctx->bc.InstrSHORT(asBC_ClrVPtr, (short)offset);
  11743. }
  11744. else
  11745. {
  11746. Dereference(ctx, true);
  11747. // Copy the object handle to a variable
  11748. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  11749. if( ctx->type.dataType.IsFuncdef() )
  11750. ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours);
  11751. else
  11752. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo());
  11753. ctx->bc.Instr(asBC_PopPtr);
  11754. }
  11755. // As this is an object the reference must be placed on the stack
  11756. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  11757. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  11758. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  11759. ctx->type.dataType.MakeHandle(true);
  11760. ctx->type.dataType.MakeReference(true);
  11761. }
  11762. else if( (!ctx->type.isVariable || ctx->type.dataType.IsReference()) &&
  11763. ctx->type.dataType.IsPrimitive() )
  11764. {
  11765. if( ctx->type.isConstant )
  11766. {
  11767. offset = AllocateVariable(ctx->type.dataType, true);
  11768. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  11769. ctx->bc.InstrSHORT_B(asBC_SetV1, (short)offset, ctx->type.GetConstantB());
  11770. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  11771. ctx->bc.InstrSHORT_W(asBC_SetV2, (short)offset, ctx->type.GetConstantW());
  11772. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 )
  11773. ctx->bc.InstrSHORT_DW(asBC_SetV4, (short)offset, ctx->type.GetConstantDW());
  11774. else
  11775. ctx->bc.InstrSHORT_QW(asBC_SetV8, (short)offset, ctx->type.GetConstantQW());
  11776. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  11777. return;
  11778. }
  11779. else
  11780. {
  11781. asASSERT(ctx->type.dataType.IsPrimitive());
  11782. asASSERT(ctx->type.dataType.IsReference());
  11783. ctx->type.dataType.MakeReference(false);
  11784. offset = AllocateVariable(ctx->type.dataType, true);
  11785. // Read the value from the address in the register directly into the variable
  11786. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  11787. ctx->bc.InstrSHORT(asBC_RDR1, (short)offset);
  11788. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  11789. ctx->bc.InstrSHORT(asBC_RDR2, (short)offset);
  11790. else if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  11791. ctx->bc.InstrSHORT(asBC_RDR4, (short)offset);
  11792. else
  11793. ctx->bc.InstrSHORT(asBC_RDR8, (short)offset);
  11794. }
  11795. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  11796. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  11797. }
  11798. }
  11799. void asCCompiler::ConvertToVariableNotIn(asCExprContext *ctx, asCExprContext *exclude)
  11800. {
  11801. int l = int(reservedVariables.GetLength());
  11802. if( exclude ) exclude->bc.GetVarsUsed(reservedVariables);
  11803. ConvertToVariable(ctx);
  11804. reservedVariables.SetLength(l);
  11805. }
  11806. void asCCompiler::ImplicitConvObjectToBestMathType(asCExprContext *ctx, asCScriptNode *node)
  11807. {
  11808. asCArray<int> funcs;
  11809. asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo());
  11810. if( ot )
  11811. {
  11812. for( unsigned int n = 0; n < ot->methods.GetLength(); n++ )
  11813. {
  11814. // Consider only implicit casts
  11815. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  11816. if( func->name == "opImplConv" &&
  11817. func->returnType.IsPrimitive() &&
  11818. func->parameterTypes.GetLength() == 0 )
  11819. funcs.PushLast(ot->methods[n]);
  11820. }
  11821. // Use the one with the highest precision
  11822. const eTokenType match[10] = {ttDouble, ttFloat, ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8};
  11823. while( funcs.GetLength() > 1 )
  11824. {
  11825. eTokenType returnType = builder->GetFunctionDescription(funcs[0])->returnType.GetTokenType();
  11826. int value1 = 11, value2 = 11;
  11827. for( asUINT i = 0; i < 10; i++ )
  11828. {
  11829. if( returnType == match[i] )
  11830. {
  11831. value1 = i;
  11832. break;
  11833. }
  11834. }
  11835. for( asUINT n = 1; n < funcs.GetLength(); n++ )
  11836. {
  11837. returnType = builder->GetFunctionDescription(funcs[n])->returnType.GetTokenType();
  11838. for( asUINT i = 0; i < 10; i++ )
  11839. {
  11840. if( returnType == match[i] )
  11841. {
  11842. value2 = i;
  11843. break;
  11844. }
  11845. }
  11846. if( value2 >= value1 )
  11847. {
  11848. // Remove this and continue searching
  11849. funcs.RemoveIndexUnordered(n--);
  11850. }
  11851. else
  11852. {
  11853. // Remove the first, and start over
  11854. funcs.RemoveIndexUnordered(0);
  11855. break;
  11856. }
  11857. }
  11858. }
  11859. // Do the conversion
  11860. if( funcs.GetLength() )
  11861. ImplicitConvObjectToPrimitive(ctx, builder->GetFunctionDescription(funcs[0])->returnType, node, asIC_IMPLICIT_CONV);
  11862. }
  11863. }
  11864. void asCCompiler::CompileMathOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType op)
  11865. {
  11866. // TODO: If a constant is only using 32bits, then a 32bit operation is preferred
  11867. // TODO: clean up: This initial part is identical to CompileComparisonOperator. Make a common function out of it
  11868. // If either operand is a non-primitive then use the primitive type
  11869. if( !lctx->type.dataType.IsPrimitive() )
  11870. {
  11871. int l = int(reservedVariables.GetLength());
  11872. rctx->bc.GetVarsUsed(reservedVariables);
  11873. ImplicitConvObjectToBestMathType(lctx, node);
  11874. reservedVariables.SetLength(l);
  11875. }
  11876. if( !rctx->type.dataType.IsPrimitive() )
  11877. {
  11878. int l = int(reservedVariables.GetLength());
  11879. lctx->bc.GetVarsUsed(reservedVariables);
  11880. ImplicitConvObjectToBestMathType(rctx, node);
  11881. reservedVariables.SetLength(l);
  11882. }
  11883. // Both types must now be primitives. Implicitly convert them so they match
  11884. asCDataType to;
  11885. if( lctx->type.dataType.IsDoubleType() || rctx->type.dataType.IsDoubleType() )
  11886. to.SetTokenType(ttDouble);
  11887. else if( lctx->type.dataType.IsFloatType() || rctx->type.dataType.IsFloatType() )
  11888. to.SetTokenType(ttFloat);
  11889. else if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 || rctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  11890. {
  11891. // Convert to int64 if both are signed or if one is non-constant and signed
  11892. if( (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) ||
  11893. (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) )
  11894. to.SetTokenType(ttInt64);
  11895. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  11896. to.SetTokenType(ttUInt64);
  11897. else
  11898. to.SetTokenType(ttInt64);
  11899. }
  11900. else
  11901. {
  11902. // Convert to int32 if both are signed or if one is non-constant and signed
  11903. if( (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) ||
  11904. (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) )
  11905. to.SetTokenType(ttInt);
  11906. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  11907. to.SetTokenType(ttUInt);
  11908. else
  11909. to.SetTokenType(ttInt);
  11910. }
  11911. // If doing an operation with double constant and float variable, the constant should be converted to float
  11912. if( (lctx->type.isConstant && lctx->type.dataType.IsDoubleType() && !rctx->type.isConstant && rctx->type.dataType.IsFloatType()) ||
  11913. (rctx->type.isConstant && rctx->type.dataType.IsDoubleType() && !lctx->type.isConstant && lctx->type.dataType.IsFloatType()) )
  11914. to.SetTokenType(ttFloat);
  11915. if( op == ttUnrecognizedToken )
  11916. op = node->tokenType;
  11917. // If integer division is disabled, convert to floating-point
  11918. if( engine->ep.disableIntegerDivision &&
  11919. (op == ttSlash || op == ttDivAssign) &&
  11920. (to.IsIntegerType() || to.IsUnsignedType()) )
  11921. {
  11922. // Use double to avoid losing precision when dividing with 32bit ints
  11923. // For 64bit ints there is unfortunately no greater type so with those
  11924. // there is still a risk of loosing precision
  11925. to.SetTokenType(ttDouble);
  11926. }
  11927. // Do the actual conversion
  11928. int l = int(reservedVariables.GetLength());
  11929. rctx->bc.GetVarsUsed(reservedVariables);
  11930. lctx->bc.GetVarsUsed(reservedVariables);
  11931. if( lctx->type.dataType.IsReference() )
  11932. ConvertToVariable(lctx);
  11933. if( rctx->type.dataType.IsReference() )
  11934. ConvertToVariable(rctx);
  11935. if( to.IsPrimitive() )
  11936. {
  11937. // ttStarStar allows an integer, right-hand operand and a double
  11938. // left-hand operand.
  11939. if( (op == ttStarStar || op == ttPowAssign) &&
  11940. lctx->type.dataType.IsDoubleType() &&
  11941. (rctx->type.dataType.IsIntegerType() ||
  11942. rctx->type.dataType.IsUnsignedType()) )
  11943. {
  11944. to.SetTokenType(ttInt);
  11945. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true);
  11946. to.SetTokenType(ttDouble);
  11947. }
  11948. else
  11949. {
  11950. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true);
  11951. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true);
  11952. }
  11953. }
  11954. reservedVariables.SetLength(l);
  11955. // Verify that the conversion was successful
  11956. if( !lctx->type.dataType.IsIntegerType() &&
  11957. !lctx->type.dataType.IsUnsignedType() &&
  11958. !lctx->type.dataType.IsFloatType() &&
  11959. !lctx->type.dataType.IsDoubleType() )
  11960. {
  11961. asCString str;
  11962. str.Format(TXT_NO_CONVERSION_s_TO_MATH_TYPE, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  11963. Error(str, node);
  11964. ctx->type.SetDummy();
  11965. return;
  11966. }
  11967. if( !rctx->type.dataType.IsIntegerType() &&
  11968. !rctx->type.dataType.IsUnsignedType() &&
  11969. !rctx->type.dataType.IsFloatType() &&
  11970. !rctx->type.dataType.IsDoubleType() )
  11971. {
  11972. asCString str;
  11973. str.Format(TXT_NO_CONVERSION_s_TO_MATH_TYPE, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  11974. Error(str, node);
  11975. ctx->type.SetDummy();
  11976. return;
  11977. }
  11978. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  11979. // Verify if we are dividing with a constant zero
  11980. if( rctx->type.isConstant &&
  11981. (op == ttSlash || op == ttDivAssign ||
  11982. op == ttPercent || op == ttModAssign) &&
  11983. ((rctx->type.dataType.GetSizeInMemoryBytes() == 4 && rctx->type.GetConstantDW() == 0) ||
  11984. (rctx->type.dataType.GetSizeInMemoryBytes() == 8 && rctx->type.GetConstantQW() == 0) ||
  11985. (rctx->type.dataType.GetSizeInMemoryBytes() == 1 && rctx->type.GetConstantB() == 0) ||
  11986. (rctx->type.dataType.GetSizeInMemoryBytes() == 2 && rctx->type.GetConstantW() == 0)) )
  11987. {
  11988. Error(TXT_DIVIDE_BY_ZERO, node);
  11989. }
  11990. if( !isConstant )
  11991. {
  11992. ConvertToVariableNotIn(lctx, rctx);
  11993. ConvertToVariableNotIn(rctx, lctx);
  11994. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  11995. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  11996. if( op == ttAddAssign || op == ttSubAssign ||
  11997. op == ttMulAssign || op == ttDivAssign ||
  11998. op == ttModAssign || op == ttPowAssign )
  11999. {
  12000. // Merge the operands in the different order so that they are evaluated correctly
  12001. MergeExprBytecode(ctx, rctx);
  12002. MergeExprBytecode(ctx, lctx);
  12003. // We must not process the deferred parameters yet, as
  12004. // it may overwrite the lvalue kept in the register
  12005. }
  12006. else
  12007. {
  12008. MergeExprBytecode(ctx, lctx);
  12009. MergeExprBytecode(ctx, rctx);
  12010. ProcessDeferredParams(ctx);
  12011. }
  12012. asEBCInstr instruction = asBC_ADDi;
  12013. if( lctx->type.dataType.IsIntegerType() ||
  12014. lctx->type.dataType.IsUnsignedType() )
  12015. {
  12016. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  12017. {
  12018. if( op == ttPlus || op == ttAddAssign )
  12019. instruction = asBC_ADDi;
  12020. else if( op == ttMinus || op == ttSubAssign )
  12021. instruction = asBC_SUBi;
  12022. else if( op == ttStar || op == ttMulAssign )
  12023. instruction = asBC_MULi;
  12024. else if( op == ttSlash || op == ttDivAssign )
  12025. {
  12026. if( lctx->type.dataType.IsIntegerType() )
  12027. instruction = asBC_DIVi;
  12028. else
  12029. instruction = asBC_DIVu;
  12030. }
  12031. else if( op == ttPercent || op == ttModAssign )
  12032. {
  12033. if( lctx->type.dataType.IsIntegerType() )
  12034. instruction = asBC_MODi;
  12035. else
  12036. instruction = asBC_MODu;
  12037. }
  12038. else if( op == ttStarStar || op == ttPowAssign )
  12039. {
  12040. if( lctx->type.dataType.IsIntegerType() )
  12041. instruction = asBC_POWi;
  12042. else
  12043. instruction = asBC_POWu;
  12044. }
  12045. }
  12046. else
  12047. {
  12048. if( op == ttPlus || op == ttAddAssign )
  12049. instruction = asBC_ADDi64;
  12050. else if( op == ttMinus || op == ttSubAssign )
  12051. instruction = asBC_SUBi64;
  12052. else if( op == ttStar || op == ttMulAssign )
  12053. instruction = asBC_MULi64;
  12054. else if( op == ttSlash || op == ttDivAssign )
  12055. {
  12056. if( lctx->type.dataType.IsIntegerType() )
  12057. instruction = asBC_DIVi64;
  12058. else
  12059. instruction = asBC_DIVu64;
  12060. }
  12061. else if( op == ttPercent || op == ttModAssign )
  12062. {
  12063. if( lctx->type.dataType.IsIntegerType() )
  12064. instruction = asBC_MODi64;
  12065. else
  12066. instruction = asBC_MODu64;
  12067. }
  12068. else if( op == ttStarStar || op == ttPowAssign )
  12069. {
  12070. if( lctx->type.dataType.IsIntegerType() )
  12071. instruction = asBC_POWi64;
  12072. else
  12073. instruction = asBC_POWu64;
  12074. }
  12075. }
  12076. }
  12077. else if( lctx->type.dataType.IsFloatType() )
  12078. {
  12079. if( op == ttPlus || op == ttAddAssign )
  12080. instruction = asBC_ADDf;
  12081. else if( op == ttMinus || op == ttSubAssign )
  12082. instruction = asBC_SUBf;
  12083. else if( op == ttStar || op == ttMulAssign )
  12084. instruction = asBC_MULf;
  12085. else if( op == ttSlash || op == ttDivAssign )
  12086. instruction = asBC_DIVf;
  12087. else if( op == ttPercent || op == ttModAssign )
  12088. instruction = asBC_MODf;
  12089. else if( op == ttStarStar || op == ttPowAssign )
  12090. instruction = asBC_POWf;
  12091. }
  12092. else if( lctx->type.dataType.IsDoubleType() )
  12093. {
  12094. if( rctx->type.dataType.IsIntegerType() )
  12095. {
  12096. asASSERT(rctx->type.dataType.GetSizeInMemoryDWords() == 1);
  12097. if( op == ttStarStar || op == ttPowAssign )
  12098. instruction = asBC_POWdi;
  12099. else
  12100. asASSERT(false); // Should not be possible
  12101. }
  12102. else
  12103. {
  12104. if( op == ttPlus || op == ttAddAssign )
  12105. instruction = asBC_ADDd;
  12106. else if( op == ttMinus || op == ttSubAssign )
  12107. instruction = asBC_SUBd;
  12108. else if( op == ttStar || op == ttMulAssign )
  12109. instruction = asBC_MULd;
  12110. else if( op == ttSlash || op == ttDivAssign )
  12111. instruction = asBC_DIVd;
  12112. else if( op == ttPercent || op == ttModAssign )
  12113. instruction = asBC_MODd;
  12114. else if( op == ttStarStar || op == ttPowAssign )
  12115. instruction = asBC_POWd;
  12116. }
  12117. }
  12118. else
  12119. {
  12120. // Shouldn't be possible
  12121. asASSERT(false);
  12122. }
  12123. // Do the operation
  12124. int a = AllocateVariable(lctx->type.dataType, true);
  12125. int b = lctx->type.stackOffset;
  12126. int c = rctx->type.stackOffset;
  12127. ctx->bc.InstrW_W_W(instruction, a, b, c);
  12128. ctx->type.SetVariable(lctx->type.dataType, a, true);
  12129. }
  12130. else
  12131. {
  12132. // Both values are constants
  12133. if( lctx->type.dataType.IsIntegerType() ||
  12134. lctx->type.dataType.IsUnsignedType() )
  12135. {
  12136. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  12137. {
  12138. int v = 0;
  12139. if( op == ttPlus )
  12140. v = int(lctx->type.GetConstantDW()) + int(rctx->type.GetConstantDW());
  12141. else if( op == ttMinus )
  12142. v = int(lctx->type.GetConstantDW()) - int(rctx->type.GetConstantDW());
  12143. else if( op == ttStar )
  12144. v = int(lctx->type.GetConstantDW()) * int(rctx->type.GetConstantDW());
  12145. else if( op == ttSlash )
  12146. {
  12147. // TODO: Should probably report an error, rather than silently convert the value to 0
  12148. if( rctx->type.GetConstantDW() == 0 || (int(rctx->type.GetConstantDW()) == -1 && lctx->type.GetConstantDW() == 0x80000000) )
  12149. v = 0;
  12150. else
  12151. if( lctx->type.dataType.IsIntegerType() )
  12152. v = int(lctx->type.GetConstantDW()) / int(rctx->type.GetConstantDW());
  12153. else
  12154. v = lctx->type.GetConstantDW() / rctx->type.GetConstantDW();
  12155. }
  12156. else if( op == ttPercent )
  12157. {
  12158. // TODO: Should probably report an error, rather than silently convert the value to 0
  12159. if( rctx->type.GetConstantDW() == 0 || (int(rctx->type.GetConstantDW()) == -1 && lctx->type.GetConstantDW() == 0x80000000) )
  12160. v = 0;
  12161. else
  12162. if( lctx->type.dataType.IsIntegerType() )
  12163. v = int(lctx->type.GetConstantDW()) % int(rctx->type.GetConstantDW());
  12164. else
  12165. v = lctx->type.GetConstantDW() % rctx->type.GetConstantDW();
  12166. }
  12167. else if( op == ttStarStar )
  12168. {
  12169. bool isOverflow;
  12170. if( lctx->type.dataType.IsIntegerType() )
  12171. v = as_powi(int(lctx->type.GetConstantDW()), int(rctx->type.GetConstantDW()), isOverflow);
  12172. else
  12173. v = as_powu(lctx->type.GetConstantDW(), rctx->type.GetConstantDW(), isOverflow);
  12174. if( isOverflow )
  12175. Error(TXT_POW_OVERFLOW, node);
  12176. }
  12177. ctx->type.SetConstantDW(lctx->type.dataType, v);
  12178. // If the right value is greater than the left value in a minus operation, then we need to convert the type to int
  12179. if( lctx->type.dataType.GetTokenType() == ttUInt && op == ttMinus && lctx->type.GetConstantDW() < rctx->type.GetConstantDW())
  12180. ctx->type.dataType.SetTokenType(ttInt);
  12181. }
  12182. else
  12183. {
  12184. asQWORD v = 0;
  12185. if( op == ttPlus )
  12186. v = asINT64(lctx->type.GetConstantQW()) + asINT64(rctx->type.GetConstantQW());
  12187. else if( op == ttMinus )
  12188. v = asINT64(lctx->type.GetConstantQW()) - asINT64(rctx->type.GetConstantQW());
  12189. else if( op == ttStar )
  12190. v = asINT64(lctx->type.GetConstantQW()) * asINT64(rctx->type.GetConstantQW());
  12191. else if( op == ttSlash )
  12192. {
  12193. // TODO: Should probably report an error, rather than silently convert the value to 0
  12194. if( rctx->type.GetConstantQW() == 0 || (rctx->type.GetConstantQW() == asQWORD(-1) && lctx->type.GetConstantQW() == (asQWORD(1)<<63)) )
  12195. v = 0;
  12196. else
  12197. if( lctx->type.dataType.IsIntegerType() )
  12198. v = asINT64(lctx->type.GetConstantQW()) / asINT64(rctx->type.GetConstantQW());
  12199. else
  12200. v = lctx->type.GetConstantQW() / rctx->type.GetConstantQW();
  12201. }
  12202. else if( op == ttPercent )
  12203. {
  12204. // TODO: Should probably report an error, rather than silently convert the value to 0
  12205. if( rctx->type.GetConstantQW() == 0 || (rctx->type.GetConstantQW() == asQWORD(-1) && lctx->type.GetConstantQW() == (asQWORD(1)<<63)) )
  12206. v = 0;
  12207. else
  12208. if( lctx->type.dataType.IsIntegerType() )
  12209. v = asINT64(lctx->type.GetConstantQW()) % asINT64(rctx->type.GetConstantQW());
  12210. else
  12211. v = lctx->type.GetConstantQW() % rctx->type.GetConstantQW();
  12212. }
  12213. else if( op == ttStarStar )
  12214. {
  12215. bool isOverflow;
  12216. if( lctx->type.dataType.IsIntegerType() )
  12217. v = as_powi64(asINT64(lctx->type.GetConstantQW()), asINT64(rctx->type.GetConstantQW()), isOverflow);
  12218. else
  12219. v = as_powu64(lctx->type.GetConstantQW(), rctx->type.GetConstantQW(), isOverflow);
  12220. if( isOverflow )
  12221. Error(TXT_POW_OVERFLOW, node);
  12222. }
  12223. ctx->type.SetConstantQW(lctx->type.dataType, v);
  12224. // If the right value is greater than the left value in a minus operation, then we need to convert the type to int
  12225. if( lctx->type.dataType.GetTokenType() == ttUInt64 && op == ttMinus && lctx->type.GetConstantQW() < rctx->type.GetConstantQW())
  12226. ctx->type.dataType.SetTokenType(ttInt64);
  12227. }
  12228. }
  12229. else if( lctx->type.dataType.IsFloatType() )
  12230. {
  12231. float v = 0.0f;
  12232. if( op == ttPlus )
  12233. v = lctx->type.GetConstantF() + rctx->type.GetConstantF();
  12234. else if( op == ttMinus )
  12235. v = lctx->type.GetConstantF() - rctx->type.GetConstantF();
  12236. else if( op == ttStar )
  12237. v = lctx->type.GetConstantF() * rctx->type.GetConstantF();
  12238. else if( op == ttSlash )
  12239. {
  12240. if( rctx->type.GetConstantF() == 0 )
  12241. v = 0;
  12242. else
  12243. v = lctx->type.GetConstantF() / rctx->type.GetConstantF();
  12244. }
  12245. else if( op == ttPercent )
  12246. {
  12247. if( rctx->type.GetConstantF() == 0 )
  12248. v = 0;
  12249. else
  12250. v = fmodf(lctx->type.GetConstantF(), rctx->type.GetConstantF());
  12251. }
  12252. else if( op == ttStarStar )
  12253. {
  12254. v = powf(lctx->type.GetConstantF(), rctx->type.GetConstantF());
  12255. if( v == HUGE_VAL )
  12256. Error(TXT_POW_OVERFLOW, node);
  12257. }
  12258. ctx->type.SetConstantF(lctx->type.dataType, v);
  12259. }
  12260. else if( lctx->type.dataType.IsDoubleType() )
  12261. {
  12262. double v = 0.0;
  12263. if( rctx->type.dataType.IsIntegerType() )
  12264. {
  12265. asASSERT(rctx->type.dataType.GetSizeInMemoryDWords() == 1);
  12266. if( op == ttStarStar || op == ttPowAssign )
  12267. {
  12268. v = pow(lctx->type.GetConstantD(), int(rctx->type.GetConstantDW()));
  12269. if( v == HUGE_VAL )
  12270. Error(TXT_POW_OVERFLOW, node);
  12271. }
  12272. else
  12273. asASSERT(false); // Should not be possible
  12274. }
  12275. else
  12276. {
  12277. if( op == ttPlus )
  12278. v = lctx->type.GetConstantD() + rctx->type.GetConstantD();
  12279. else if( op == ttMinus )
  12280. v = lctx->type.GetConstantD() - rctx->type.GetConstantD();
  12281. else if( op == ttStar )
  12282. v = lctx->type.GetConstantD() * rctx->type.GetConstantD();
  12283. else if( op == ttSlash )
  12284. {
  12285. if( rctx->type.GetConstantD() == 0 )
  12286. v = 0;
  12287. else
  12288. v = lctx->type.GetConstantD() / rctx->type.GetConstantD();
  12289. }
  12290. else if( op == ttPercent )
  12291. {
  12292. if( rctx->type.GetConstantD() == 0 )
  12293. v = 0;
  12294. else
  12295. v = fmod(lctx->type.GetConstantD(), rctx->type.GetConstantD());
  12296. }
  12297. else if( op == ttStarStar )
  12298. {
  12299. v = pow(lctx->type.GetConstantD(), rctx->type.GetConstantD());
  12300. if( v == HUGE_VAL )
  12301. Error(TXT_POW_OVERFLOW, node);
  12302. }
  12303. }
  12304. ctx->type.SetConstantD(lctx->type.dataType, v);
  12305. }
  12306. else
  12307. {
  12308. // Shouldn't be possible
  12309. asASSERT(false);
  12310. }
  12311. }
  12312. }
  12313. void asCCompiler::CompileBitwiseOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType op)
  12314. {
  12315. // TODO: If a constant is only using 32bits, then a 32bit operation is preferred
  12316. if( op == ttUnrecognizedToken )
  12317. op = node->tokenType;
  12318. if( op == ttAmp || op == ttAndAssign ||
  12319. op == ttBitOr || op == ttOrAssign ||
  12320. op == ttBitXor || op == ttXorAssign )
  12321. {
  12322. // Also do not permit float/double to be implicitly converted to integer in this case
  12323. // as the user may think the result is a bitwise operation on the float value but it's not
  12324. if (lctx->type.dataType.IsFloatType() || lctx->type.dataType.IsDoubleType())
  12325. {
  12326. asCString str;
  12327. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  12328. Error(str, node);
  12329. // Set an integer value and allow the compiler to continue
  12330. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), 0);
  12331. return;
  12332. }
  12333. if (rctx->type.dataType.IsFloatType() || rctx->type.dataType.IsDoubleType())
  12334. {
  12335. asCString str;
  12336. str.Format(TXT_ILLEGAL_OPERATION_ON_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  12337. Error(str, node);
  12338. // Set an integer value and allow the compiler to continue
  12339. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), 0);
  12340. return;
  12341. }
  12342. // Convert left hand operand to integer if it's not already one
  12343. asCDataType to;
  12344. if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 ||
  12345. rctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  12346. to.SetTokenType(ttInt64);
  12347. else
  12348. to.SetTokenType(ttInt);
  12349. // Do the actual conversion (keep sign/unsigned if possible)
  12350. int l = int(reservedVariables.GetLength());
  12351. rctx->bc.GetVarsUsed(reservedVariables);
  12352. if( lctx->type.dataType.IsUnsignedType() )
  12353. to.SetTokenType( to.GetSizeOnStackDWords() == 1 ? ttUInt : ttUInt64 );
  12354. else
  12355. to.SetTokenType( to.GetSizeOnStackDWords() == 1 ? ttInt : ttInt64 );
  12356. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true);
  12357. reservedVariables.SetLength(l);
  12358. // Verify that the conversion was successful
  12359. if( lctx->type.dataType != to )
  12360. {
  12361. asCString str;
  12362. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  12363. Error(str, node);
  12364. }
  12365. // Convert right hand operand to same size as left hand
  12366. l = int(reservedVariables.GetLength());
  12367. lctx->bc.GetVarsUsed(reservedVariables);
  12368. if( rctx->type.dataType.IsUnsignedType() )
  12369. to.SetTokenType( to.GetSizeOnStackDWords() == 1 ? ttUInt : ttUInt64 );
  12370. else
  12371. to.SetTokenType( to.GetSizeOnStackDWords() == 1 ? ttInt : ttInt64 );
  12372. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true);
  12373. reservedVariables.SetLength(l);
  12374. if( rctx->type.dataType != to )
  12375. {
  12376. asCString str;
  12377. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  12378. Error(str, node);
  12379. }
  12380. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  12381. if( !isConstant )
  12382. {
  12383. ConvertToVariableNotIn(lctx, rctx);
  12384. ConvertToVariableNotIn(rctx, lctx);
  12385. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  12386. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  12387. if( op == ttAndAssign || op == ttOrAssign || op == ttXorAssign )
  12388. {
  12389. // Compound assignments execute the right hand value first
  12390. MergeExprBytecode(ctx, rctx);
  12391. MergeExprBytecode(ctx, lctx);
  12392. }
  12393. else
  12394. {
  12395. MergeExprBytecode(ctx, lctx);
  12396. MergeExprBytecode(ctx, rctx);
  12397. }
  12398. ProcessDeferredParams(ctx);
  12399. asEBCInstr instruction = asBC_BAND;
  12400. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  12401. {
  12402. if( op == ttAmp || op == ttAndAssign )
  12403. instruction = asBC_BAND;
  12404. else if( op == ttBitOr || op == ttOrAssign )
  12405. instruction = asBC_BOR;
  12406. else if( op == ttBitXor || op == ttXorAssign )
  12407. instruction = asBC_BXOR;
  12408. }
  12409. else
  12410. {
  12411. if( op == ttAmp || op == ttAndAssign )
  12412. instruction = asBC_BAND64;
  12413. else if( op == ttBitOr || op == ttOrAssign )
  12414. instruction = asBC_BOR64;
  12415. else if( op == ttBitXor || op == ttXorAssign )
  12416. instruction = asBC_BXOR64;
  12417. }
  12418. // Do the operation
  12419. int a = AllocateVariable(lctx->type.dataType, true);
  12420. int b = lctx->type.stackOffset;
  12421. int c = rctx->type.stackOffset;
  12422. ctx->bc.InstrW_W_W(instruction, a, b, c);
  12423. ctx->type.SetVariable(lctx->type.dataType, a, true);
  12424. }
  12425. else
  12426. {
  12427. if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  12428. {
  12429. asQWORD v = 0;
  12430. if( op == ttAmp )
  12431. v = lctx->type.GetConstantQW() & rctx->type.GetConstantQW();
  12432. else if( op == ttBitOr )
  12433. v = lctx->type.GetConstantQW() | rctx->type.GetConstantQW();
  12434. else if( op == ttBitXor )
  12435. v = lctx->type.GetConstantQW() ^ rctx->type.GetConstantQW();
  12436. // Remember the result
  12437. ctx->type.SetConstantQW(lctx->type.dataType, v);
  12438. }
  12439. else
  12440. {
  12441. asDWORD v = 0;
  12442. if( op == ttAmp )
  12443. v = lctx->type.GetConstantDW() & rctx->type.GetConstantDW();
  12444. else if( op == ttBitOr )
  12445. v = lctx->type.GetConstantDW() | rctx->type.GetConstantDW();
  12446. else if( op == ttBitXor )
  12447. v = lctx->type.GetConstantDW() ^ rctx->type.GetConstantDW();
  12448. // Remember the result
  12449. ctx->type.SetConstantDW(lctx->type.dataType, v);
  12450. }
  12451. }
  12452. }
  12453. else if( op == ttBitShiftLeft || op == ttShiftLeftAssign ||
  12454. op == ttBitShiftRight || op == ttShiftRightLAssign ||
  12455. op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  12456. {
  12457. // Don't permit object to primitive conversion, since we don't know which integer type is the correct one
  12458. // Also do not permit float/double to be implicitly converted to integer in this case
  12459. if( lctx->type.dataType.IsObject() || lctx->type.dataType.IsFloatType() || lctx->type.dataType.IsDoubleType() )
  12460. {
  12461. asCString str;
  12462. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf());
  12463. Error(str, node);
  12464. // Set an integer value and allow the compiler to continue
  12465. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), 0);
  12466. return;
  12467. }
  12468. // Convert left hand operand to integer if it's not already one
  12469. asCDataType to = lctx->type.dataType;
  12470. if( lctx->type.dataType.IsUnsignedType() &&
  12471. lctx->type.dataType.GetSizeInMemoryBytes() < 4 )
  12472. {
  12473. // Upgrade to 32bit
  12474. to = asCDataType::CreatePrimitive(ttUInt, false);
  12475. }
  12476. else if( !lctx->type.dataType.IsUnsignedType() )
  12477. {
  12478. if (lctx->type.dataType.GetSizeInMemoryDWords() == 2)
  12479. to = asCDataType::CreatePrimitive(ttInt64, false);
  12480. else
  12481. to = asCDataType::CreatePrimitive(ttInt, false);
  12482. }
  12483. // Do the actual conversion
  12484. int l = int(reservedVariables.GetLength());
  12485. rctx->bc.GetVarsUsed(reservedVariables);
  12486. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true);
  12487. reservedVariables.SetLength(l);
  12488. // Verify that the conversion was successful
  12489. if( lctx->type.dataType != to )
  12490. {
  12491. asCString str;
  12492. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  12493. Error(str, node);
  12494. }
  12495. // Right operand must be 32bit uint
  12496. l = int(reservedVariables.GetLength());
  12497. lctx->bc.GetVarsUsed(reservedVariables);
  12498. ImplicitConversion(rctx, asCDataType::CreatePrimitive(ttUInt, true), node, asIC_IMPLICIT_CONV, true);
  12499. reservedVariables.SetLength(l);
  12500. if( !rctx->type.dataType.IsUnsignedType() )
  12501. {
  12502. asCString str;
  12503. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), "uint");
  12504. Error(str, node);
  12505. }
  12506. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  12507. if( !isConstant )
  12508. {
  12509. ConvertToVariableNotIn(lctx, rctx);
  12510. ConvertToVariableNotIn(rctx, lctx);
  12511. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  12512. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  12513. if( op == ttShiftLeftAssign || op == ttShiftRightLAssign || op == ttShiftRightAAssign )
  12514. {
  12515. // Compound assignments execute the right hand value first
  12516. MergeExprBytecode(ctx, rctx);
  12517. MergeExprBytecode(ctx, lctx);
  12518. }
  12519. else
  12520. {
  12521. MergeExprBytecode(ctx, lctx);
  12522. MergeExprBytecode(ctx, rctx);
  12523. }
  12524. ProcessDeferredParams(ctx);
  12525. asEBCInstr instruction = asBC_BSLL;
  12526. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  12527. {
  12528. if( op == ttBitShiftLeft || op == ttShiftLeftAssign )
  12529. instruction = asBC_BSLL;
  12530. else if( op == ttBitShiftRight || op == ttShiftRightLAssign )
  12531. instruction = asBC_BSRL;
  12532. else if( op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  12533. instruction = asBC_BSRA;
  12534. }
  12535. else
  12536. {
  12537. if( op == ttBitShiftLeft || op == ttShiftLeftAssign )
  12538. instruction = asBC_BSLL64;
  12539. else if( op == ttBitShiftRight || op == ttShiftRightLAssign )
  12540. instruction = asBC_BSRL64;
  12541. else if( op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  12542. instruction = asBC_BSRA64;
  12543. }
  12544. // Do the operation
  12545. int a = AllocateVariable(lctx->type.dataType, true);
  12546. int b = lctx->type.stackOffset;
  12547. int c = rctx->type.stackOffset;
  12548. ctx->bc.InstrW_W_W(instruction, a, b, c);
  12549. ctx->type.SetVariable(lctx->type.dataType, a, true);
  12550. }
  12551. else
  12552. {
  12553. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  12554. {
  12555. asDWORD v = 0;
  12556. if( op == ttBitShiftLeft )
  12557. v = lctx->type.GetConstantDW() << rctx->type.GetConstantDW();
  12558. else if( op == ttBitShiftRight )
  12559. v = lctx->type.GetConstantDW() >> rctx->type.GetConstantDW();
  12560. else if( op == ttBitShiftRightArith )
  12561. v = int(lctx->type.GetConstantDW()) >> rctx->type.GetConstantDW();
  12562. ctx->type.SetConstantDW(lctx->type.dataType, v);
  12563. }
  12564. else
  12565. {
  12566. asQWORD v = 0;
  12567. if( op == ttBitShiftLeft )
  12568. v = lctx->type.GetConstantQW() << rctx->type.GetConstantDW();
  12569. else if( op == ttBitShiftRight )
  12570. v = lctx->type.GetConstantQW() >> rctx->type.GetConstantDW();
  12571. else if( op == ttBitShiftRightArith )
  12572. v = asINT64(lctx->type.GetConstantQW()) >> rctx->type.GetConstantDW();
  12573. ctx->type.SetConstantQW(lctx->type.dataType, v);
  12574. }
  12575. }
  12576. }
  12577. }
  12578. void asCCompiler::CompileComparisonOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType op)
  12579. {
  12580. // Both operands must be of the same type
  12581. // If either operand is a non-primitive then first convert them to the best number type
  12582. if( !lctx->type.dataType.IsPrimitive() )
  12583. {
  12584. int l = int(reservedVariables.GetLength());
  12585. rctx->bc.GetVarsUsed(reservedVariables);
  12586. ImplicitConvObjectToBestMathType(lctx, node);
  12587. reservedVariables.SetLength(l);
  12588. }
  12589. if( !rctx->type.dataType.IsPrimitive() )
  12590. {
  12591. int l = int(reservedVariables.GetLength());
  12592. lctx->bc.GetVarsUsed(reservedVariables);
  12593. ImplicitConvObjectToBestMathType(rctx, node);
  12594. reservedVariables.SetLength(l);
  12595. }
  12596. // Implicitly convert the operands to matching types
  12597. asCDataType to;
  12598. if( lctx->type.dataType.IsDoubleType() || rctx->type.dataType.IsDoubleType() )
  12599. to.SetTokenType(ttDouble);
  12600. else if( lctx->type.dataType.IsFloatType() || rctx->type.dataType.IsFloatType() )
  12601. to.SetTokenType(ttFloat);
  12602. else if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 || rctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  12603. {
  12604. // Convert to int64 if both are signed or if one is non-constant and signed
  12605. if( (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) ||
  12606. (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) )
  12607. to.SetTokenType(ttInt64);
  12608. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  12609. to.SetTokenType(ttUInt64);
  12610. else
  12611. to.SetTokenType(ttInt64);
  12612. }
  12613. else
  12614. {
  12615. // Convert to int32 if both are signed or if one is non-constant and signed
  12616. if( (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) ||
  12617. (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) )
  12618. to.SetTokenType(ttInt);
  12619. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  12620. to.SetTokenType(ttUInt);
  12621. else if( lctx->type.dataType.IsBooleanType() || rctx->type.dataType.IsBooleanType() )
  12622. to.SetTokenType(ttBool);
  12623. else
  12624. to.SetTokenType(ttInt);
  12625. }
  12626. // If doing an operation with double constant and float variable, the constant should be converted to float
  12627. if( (lctx->type.isConstant && lctx->type.dataType.IsDoubleType() && !rctx->type.isConstant && rctx->type.dataType.IsFloatType()) ||
  12628. (rctx->type.isConstant && rctx->type.dataType.IsDoubleType() && !lctx->type.isConstant && lctx->type.dataType.IsFloatType()) )
  12629. to.SetTokenType(ttFloat);
  12630. asASSERT( to.GetTokenType() != ttUnrecognizedToken );
  12631. // Do we have a mismatch between the sign of the operand?
  12632. bool signMismatch = false;
  12633. for( int n = 0; !signMismatch && n < 2; n++ )
  12634. {
  12635. asCExprContext *opCtx = n ? rctx : lctx;
  12636. if( opCtx->type.dataType.IsUnsignedType() != to.IsUnsignedType() )
  12637. {
  12638. // We have a mismatch, unless the value is a literal constant and the conversion won't affect its value
  12639. signMismatch = true;
  12640. if( opCtx->type.isConstant )
  12641. {
  12642. if( opCtx->type.dataType.GetTokenType() == ttUInt64 || opCtx->type.dataType.GetTokenType() == ttInt64 )
  12643. {
  12644. if( !(opCtx->type.GetConstantQW() & (asQWORD(1)<<63)) )
  12645. signMismatch = false;
  12646. }
  12647. else if(opCtx->type.dataType.GetTokenType() == ttUInt || opCtx->type.dataType.GetTokenType() == ttInt || opCtx->type.dataType.IsEnumType() )
  12648. {
  12649. if( !(opCtx->type.GetConstantDW() & (1<<31)) )
  12650. signMismatch = false;
  12651. }
  12652. else if (opCtx->type.dataType.GetTokenType() == ttUInt16 || opCtx->type.dataType.GetTokenType() == ttInt16)
  12653. {
  12654. if (!(opCtx->type.GetConstantW() & (1 << 15)))
  12655. signMismatch = false;
  12656. }
  12657. else if (opCtx->type.dataType.GetTokenType() == ttUInt8 || opCtx->type.dataType.GetTokenType() == ttInt8)
  12658. {
  12659. if (!(opCtx->type.GetConstantB() & (1 << 7)))
  12660. signMismatch = false;
  12661. }
  12662. // It's not necessary to check for floats or double, because if
  12663. // it was then the types for the conversion will never be unsigned
  12664. }
  12665. }
  12666. }
  12667. // Check for signed/unsigned mismatch
  12668. if( signMismatch )
  12669. Warning(TXT_SIGNED_UNSIGNED_MISMATCH, node);
  12670. // Attempt to resolve ambiguous enumerations
  12671. if( lctx->type.dataType.IsEnumType() && rctx->enumValue != "" )
  12672. ImplicitConversion(rctx, lctx->type.dataType, node, asIC_IMPLICIT_CONV);
  12673. else if( rctx->type.dataType.IsEnumType() && lctx->enumValue != "" )
  12674. ImplicitConversion(lctx, rctx->type.dataType, node, asIC_IMPLICIT_CONV);
  12675. // Do the actual conversion
  12676. int l = int(reservedVariables.GetLength());
  12677. rctx->bc.GetVarsUsed(reservedVariables);
  12678. if( lctx->type.dataType.IsReference() )
  12679. ConvertToVariable(lctx);
  12680. if( rctx->type.dataType.IsReference() )
  12681. ConvertToVariable(rctx);
  12682. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV);
  12683. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV);
  12684. reservedVariables.SetLength(l);
  12685. // Verify that the conversion was successful
  12686. bool ok = true;
  12687. if( !lctx->type.dataType.IsEqualExceptConst(to) )
  12688. {
  12689. asCString str;
  12690. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  12691. Error(str, node);
  12692. ok = false;
  12693. }
  12694. if( !rctx->type.dataType.IsEqualExceptConst(to) )
  12695. {
  12696. asCString str;
  12697. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  12698. Error(str, node);
  12699. ok = false;
  12700. }
  12701. if( !ok )
  12702. {
  12703. // It wasn't possible to get two valid operands, so we just return
  12704. // a boolean result and let the compiler continue.
  12705. #if AS_SIZEOF_BOOL == 1
  12706. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  12707. #else
  12708. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  12709. #endif
  12710. return;
  12711. }
  12712. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  12713. if( op == ttUnrecognizedToken )
  12714. op = node->tokenType;
  12715. if( !isConstant )
  12716. {
  12717. if( to.IsBooleanType() )
  12718. {
  12719. if( op == ttEqual || op == ttNotEqual )
  12720. {
  12721. // Must convert to temporary variable, because we are changing the value before comparison
  12722. ConvertToTempVariableNotIn(lctx, rctx);
  12723. ConvertToTempVariableNotIn(rctx, lctx);
  12724. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  12725. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  12726. // Make sure they are equal if not false
  12727. lctx->bc.InstrWORD(asBC_NOT, lctx->type.stackOffset);
  12728. rctx->bc.InstrWORD(asBC_NOT, rctx->type.stackOffset);
  12729. MergeExprBytecode(ctx, lctx);
  12730. MergeExprBytecode(ctx, rctx);
  12731. ProcessDeferredParams(ctx);
  12732. int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, true), true);
  12733. int b = lctx->type.stackOffset;
  12734. int c = rctx->type.stackOffset;
  12735. if( op == ttEqual )
  12736. {
  12737. ctx->bc.InstrW_W(asBC_CMPi,b,c);
  12738. ctx->bc.Instr(asBC_TZ);
  12739. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  12740. }
  12741. else if( op == ttNotEqual )
  12742. {
  12743. ctx->bc.InstrW_W(asBC_CMPi,b,c);
  12744. ctx->bc.Instr(asBC_TNZ);
  12745. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  12746. }
  12747. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  12748. }
  12749. else
  12750. {
  12751. // TODO: Use TXT_ILLEGAL_OPERATION_ON
  12752. Error(TXT_ILLEGAL_OPERATION, node);
  12753. #if AS_SIZEOF_BOOL == 1
  12754. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), 0);
  12755. #else
  12756. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), 0);
  12757. #endif
  12758. }
  12759. }
  12760. else
  12761. {
  12762. ConvertToVariableNotIn(lctx, rctx);
  12763. ConvertToVariableNotIn(rctx, lctx);
  12764. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  12765. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  12766. MergeExprBytecode(ctx, lctx);
  12767. MergeExprBytecode(ctx, rctx);
  12768. ProcessDeferredParams(ctx);
  12769. asEBCInstr iCmp = asBC_CMPi, iT = asBC_TZ;
  12770. if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  12771. iCmp = asBC_CMPi;
  12772. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  12773. iCmp = asBC_CMPu;
  12774. else if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  12775. iCmp = asBC_CMPi64;
  12776. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  12777. iCmp = asBC_CMPu64;
  12778. else if( lctx->type.dataType.IsFloatType() )
  12779. iCmp = asBC_CMPf;
  12780. else if( lctx->type.dataType.IsDoubleType() )
  12781. iCmp = asBC_CMPd;
  12782. else
  12783. asASSERT(false);
  12784. if( op == ttEqual )
  12785. iT = asBC_TZ;
  12786. else if( op == ttNotEqual )
  12787. iT = asBC_TNZ;
  12788. else if( op == ttLessThan )
  12789. iT = asBC_TS;
  12790. else if( op == ttLessThanOrEqual )
  12791. iT = asBC_TNP;
  12792. else if( op == ttGreaterThan )
  12793. iT = asBC_TP;
  12794. else if( op == ttGreaterThanOrEqual )
  12795. iT = asBC_TNS;
  12796. int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, true), true);
  12797. int b = lctx->type.stackOffset;
  12798. int c = rctx->type.stackOffset;
  12799. ctx->bc.InstrW_W(iCmp, b, c);
  12800. ctx->bc.Instr(iT);
  12801. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  12802. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  12803. }
  12804. }
  12805. else
  12806. {
  12807. if( to.IsBooleanType() )
  12808. {
  12809. if( op == ttEqual || op == ttNotEqual )
  12810. {
  12811. asDWORD lv, rv;
  12812. #if AS_SIZEOF_BOOL == 1
  12813. lv = lctx->type.GetConstantB();
  12814. rv = rctx->type.GetConstantB();
  12815. #else
  12816. lv = lctx->type.GetConstantDW();
  12817. rv = rctx->type.GetConstantDW();
  12818. #endif
  12819. // Make sure they are equal if not false
  12820. if (lv != 0) lv = VALUE_OF_BOOLEAN_TRUE;
  12821. if (rv != 0) rv = VALUE_OF_BOOLEAN_TRUE;
  12822. asDWORD v = 0;
  12823. if (op == ttEqual)
  12824. v = (lv == rv) ? VALUE_OF_BOOLEAN_TRUE : 0;
  12825. else if (op == ttNotEqual)
  12826. v = (lv != rv) ? VALUE_OF_BOOLEAN_TRUE : 0;
  12827. #if AS_SIZEOF_BOOL == 1
  12828. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), (asBYTE)v);
  12829. #else
  12830. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), v);
  12831. #endif
  12832. }
  12833. else
  12834. {
  12835. // TODO: Use TXT_ILLEGAL_OPERATION_ON
  12836. Error(TXT_ILLEGAL_OPERATION, node);
  12837. }
  12838. }
  12839. else
  12840. {
  12841. int i = 0;
  12842. if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  12843. {
  12844. int v = int(lctx->type.GetConstantDW()) - int(rctx->type.GetConstantDW());
  12845. if( v < 0 ) i = -1;
  12846. if( v > 0 ) i = 1;
  12847. }
  12848. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  12849. {
  12850. asDWORD v1 = lctx->type.GetConstantDW();
  12851. asDWORD v2 = rctx->type.GetConstantDW();
  12852. if( v1 < v2 ) i = -1;
  12853. if( v1 > v2 ) i = 1;
  12854. }
  12855. else if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  12856. {
  12857. asINT64 v = asINT64(lctx->type.GetConstantQW()) - asINT64(rctx->type.GetConstantQW());
  12858. if( v < 0 ) i = -1;
  12859. if( v > 0 ) i = 1;
  12860. }
  12861. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  12862. {
  12863. asQWORD v1 = lctx->type.GetConstantQW();
  12864. asQWORD v2 = rctx->type.GetConstantQW();
  12865. if( v1 < v2 ) i = -1;
  12866. if( v1 > v2 ) i = 1;
  12867. }
  12868. else if( lctx->type.dataType.IsFloatType() )
  12869. {
  12870. float v = lctx->type.GetConstantF() - rctx->type.GetConstantF();
  12871. if( v < 0 ) i = -1;
  12872. if( v > 0 ) i = 1;
  12873. }
  12874. else if( lctx->type.dataType.IsDoubleType() )
  12875. {
  12876. double v = lctx->type.GetConstantD() - rctx->type.GetConstantD();
  12877. if( v < 0 ) i = -1;
  12878. if( v > 0 ) i = 1;
  12879. }
  12880. if( op == ttEqual )
  12881. i = (i == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  12882. else if( op == ttNotEqual )
  12883. i = (i != 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  12884. else if( op == ttLessThan )
  12885. i = (i < 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  12886. else if( op == ttLessThanOrEqual )
  12887. i = (i <= 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  12888. else if( op == ttGreaterThan )
  12889. i = (i > 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  12890. else if( op == ttGreaterThanOrEqual )
  12891. i = (i >= 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  12892. #if AS_SIZEOF_BOOL == 1
  12893. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), (asBYTE)i);
  12894. #else
  12895. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), i);
  12896. #endif
  12897. }
  12898. }
  12899. }
  12900. void asCCompiler::PushVariableOnStack(asCExprContext *ctx, bool asReference)
  12901. {
  12902. // Put the result on the stack
  12903. if( asReference )
  12904. {
  12905. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  12906. ctx->type.dataType.MakeReference(true);
  12907. }
  12908. else
  12909. {
  12910. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  12911. ctx->bc.InstrSHORT(asBC_PshV4, ctx->type.stackOffset);
  12912. else
  12913. ctx->bc.InstrSHORT(asBC_PshV8, ctx->type.stackOffset);
  12914. }
  12915. }
  12916. void asCCompiler::CompileBooleanOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType op)
  12917. {
  12918. // Both operands must be booleans
  12919. asCDataType to;
  12920. to.SetTokenType(ttBool);
  12921. // Do the actual conversion
  12922. int l = int(reservedVariables.GetLength());
  12923. rctx->bc.GetVarsUsed(reservedVariables);
  12924. lctx->bc.GetVarsUsed(reservedVariables);
  12925. // Allow value types to be converted to bool using 'bool opImplConv()'
  12926. if( lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
  12927. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV);
  12928. if( rctx->type.dataType.GetTypeInfo() && (rctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) )
  12929. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV);
  12930. reservedVariables.SetLength(l);
  12931. // Verify that the conversion was successful
  12932. if( !lctx->type.dataType.IsBooleanType() )
  12933. {
  12934. asCString str;
  12935. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), "bool");
  12936. Error(str, node);
  12937. // Force the conversion to allow compilation to proceed
  12938. lctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  12939. }
  12940. if( !rctx->type.dataType.IsBooleanType() )
  12941. {
  12942. asCString str;
  12943. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), "bool");
  12944. Error(str, node);
  12945. // Force the conversion to allow compilation to proceed
  12946. rctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  12947. }
  12948. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  12949. ctx->type.Set(asCDataType::CreatePrimitive(ttBool, true));
  12950. // What kind of operator is it?
  12951. if( op == ttUnrecognizedToken )
  12952. op = node->tokenType;
  12953. if( op == ttXor )
  12954. {
  12955. if( !isConstant )
  12956. {
  12957. // Must convert to temporary variable, because we are changing the value before comparison
  12958. ConvertToTempVariableNotIn(lctx, rctx);
  12959. ConvertToTempVariableNotIn(rctx, lctx);
  12960. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  12961. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  12962. // Make sure they are equal if not false
  12963. lctx->bc.InstrWORD(asBC_NOT, lctx->type.stackOffset);
  12964. rctx->bc.InstrWORD(asBC_NOT, rctx->type.stackOffset);
  12965. MergeExprBytecode(ctx, lctx);
  12966. MergeExprBytecode(ctx, rctx);
  12967. ProcessDeferredParams(ctx);
  12968. int a = AllocateVariable(ctx->type.dataType, true);
  12969. int b = lctx->type.stackOffset;
  12970. int c = rctx->type.stackOffset;
  12971. ctx->bc.InstrW_W_W(asBC_BXOR,a,b,c);
  12972. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  12973. }
  12974. else
  12975. {
  12976. // Make sure they are equal if not false
  12977. #if AS_SIZEOF_BOOL == 1
  12978. if( lctx->type.GetConstantB() != 0 ) lctx->type.SetConstantB(VALUE_OF_BOOLEAN_TRUE);
  12979. if( rctx->type.GetConstantB() != 0 ) rctx->type.SetConstantB(VALUE_OF_BOOLEAN_TRUE);
  12980. asBYTE v = 0;
  12981. v = lctx->type.GetConstantB() - rctx->type.GetConstantB();
  12982. if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  12983. ctx->type.isConstant = true;
  12984. ctx->type.SetConstantB(v);
  12985. #else
  12986. if( lctx->type.GetConstantDW() != 0 ) lctx->type.SetConstantDW(VALUE_OF_BOOLEAN_TRUE);
  12987. if( rctx->type.GetConstantDW() != 0 ) rctx->type.SetConstantDW(VALUE_OF_BOOLEAN_TRUE);
  12988. asDWORD v = 0;
  12989. v = lctx->type.GetConstantDW() - rctx->type.GetConstantDW();
  12990. if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  12991. ctx->type.isConstant = true;
  12992. ctx->type.SetConstantDW(v);
  12993. #endif
  12994. }
  12995. }
  12996. else if( op == ttAnd ||
  12997. op == ttOr )
  12998. {
  12999. if( !isConstant )
  13000. {
  13001. // If or-operator and first value is 1 the second value shouldn't be calculated
  13002. // if and-operator and first value is 0 the second value shouldn't be calculated
  13003. ConvertToVariable(lctx);
  13004. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  13005. MergeExprBytecode(ctx, lctx);
  13006. int offset = AllocateVariable(asCDataType::CreatePrimitive(ttBool, false), true);
  13007. int label1 = nextLabel++;
  13008. int label2 = nextLabel++;
  13009. ctx->bc.InstrSHORT(asBC_CpyVtoR4, lctx->type.stackOffset);
  13010. ctx->bc.Instr(asBC_ClrHi);
  13011. if( op == ttAnd )
  13012. {
  13013. ctx->bc.InstrDWORD(asBC_JNZ, label1);
  13014. ctx->bc.InstrW_DW(asBC_SetV4, (asWORD)offset, 0);
  13015. ctx->bc.InstrINT(asBC_JMP, label2);
  13016. }
  13017. else if( op == ttOr )
  13018. {
  13019. ctx->bc.InstrDWORD(asBC_JZ, label1);
  13020. #if AS_SIZEOF_BOOL == 1
  13021. ctx->bc.InstrSHORT_B(asBC_SetV1, (short)offset, VALUE_OF_BOOLEAN_TRUE);
  13022. #else
  13023. ctx->bc.InstrSHORT_DW(asBC_SetV4, (short)offset, VALUE_OF_BOOLEAN_TRUE);
  13024. #endif
  13025. ctx->bc.InstrINT(asBC_JMP, label2);
  13026. }
  13027. ctx->bc.Label((short)label1);
  13028. ConvertToVariable(rctx);
  13029. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  13030. rctx->bc.InstrW_W(asBC_CpyVtoV4, offset, rctx->type.stackOffset);
  13031. MergeExprBytecode(ctx, rctx);
  13032. ctx->bc.Label((short)label2);
  13033. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, false), offset, true);
  13034. }
  13035. else
  13036. {
  13037. #if AS_SIZEOF_BOOL == 1
  13038. asBYTE v = 0;
  13039. if( op == ttAnd )
  13040. v = lctx->type.GetConstantB() && rctx->type.GetConstantB();
  13041. else if( op == ttOr )
  13042. v = lctx->type.GetConstantB() || rctx->type.GetConstantB();
  13043. // Remember the result
  13044. ctx->type.isConstant = true;
  13045. ctx->type.SetConstantB(v);
  13046. #else
  13047. asDWORD v = 0;
  13048. if( op == ttAnd )
  13049. v = lctx->type.GetConstantDW() && rctx->type.GetConstantDW();
  13050. else if( op == ttOr )
  13051. v = lctx->type.GetConstantDW() || rctx->type.GetConstantDW();
  13052. // Remember the result
  13053. ctx->type.isConstant = true;
  13054. ctx->type.SetConstantDW(v);
  13055. #endif
  13056. }
  13057. }
  13058. }
  13059. void asCCompiler::CompileOperatorOnHandles(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType opToken)
  13060. {
  13061. // Process the property accessor as get
  13062. ProcessPropertyGetAccessor(lctx, node);
  13063. ProcessPropertyGetAccessor(rctx, node);
  13064. DetermineSingleFunc(lctx, node);
  13065. DetermineSingleFunc(rctx, node);
  13066. // Make sure lctx doesn't end up with a variable used in rctx
  13067. if( lctx->type.isTemporary && rctx->bc.IsVarUsed(lctx->type.stackOffset) )
  13068. {
  13069. asCArray<int> vars;
  13070. rctx->bc.GetVarsUsed(vars);
  13071. int offset = AllocateVariable(lctx->type.dataType, true);
  13072. rctx->bc.ExchangeVar(lctx->type.stackOffset, offset);
  13073. ReleaseTemporaryVariable(offset, 0);
  13074. }
  13075. if( opToken == ttUnrecognizedToken )
  13076. opToken = node->tokenType;
  13077. // Warn if not both operands are explicit handles or null handles
  13078. if( (opToken == ttEqual || opToken == ttNotEqual) &&
  13079. ((!(lctx->type.isExplicitHandle || lctx->type.IsNullConstant()) && !(lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE))) ||
  13080. (!(rctx->type.isExplicitHandle || rctx->type.IsNullConstant()) && !(rctx->type.dataType.GetTypeInfo() && (rctx->type.dataType.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE)))) )
  13081. {
  13082. Warning(TXT_HANDLE_COMPARISON, node);
  13083. }
  13084. // If one of the operands is a value type used as handle, we should look for the opEquals method
  13085. if( ((lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE)) ||
  13086. (rctx->type.dataType.GetTypeInfo() && (rctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE))) &&
  13087. (opToken == ttEqual || opToken == ttIs ||
  13088. opToken == ttNotEqual || opToken == ttNotIs) )
  13089. {
  13090. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  13091. // Find the matching opEquals method
  13092. int r = CompileOverloadedDualOperator2(node, "opEquals", lctx, rctx, true, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  13093. if( r == 0 )
  13094. {
  13095. // Try again by switching the order of the operands
  13096. r = CompileOverloadedDualOperator2(node, "opEquals", rctx, lctx, false, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  13097. }
  13098. if( r == 1 )
  13099. {
  13100. if( opToken == ttNotEqual || opToken == ttNotIs )
  13101. ctx->bc.InstrSHORT(asBC_NOT, ctx->type.stackOffset);
  13102. // Success, don't continue
  13103. return;
  13104. }
  13105. else if( r == 0 )
  13106. {
  13107. // Couldn't find opEquals method
  13108. Error(TXT_NO_APPROPRIATE_OPEQUALS, node);
  13109. }
  13110. // Compiler error, don't continue
  13111. #if AS_SIZEOF_BOOL == 1
  13112. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  13113. #else
  13114. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  13115. #endif
  13116. return;
  13117. }
  13118. // Implicitly convert null to the other type
  13119. asCDataType to;
  13120. if( lctx->type.IsNullConstant() )
  13121. to = rctx->type.dataType;
  13122. else if( rctx->type.IsNullConstant() )
  13123. to = lctx->type.dataType;
  13124. else
  13125. {
  13126. // Find a common base type
  13127. asCExprContext tmp(engine);
  13128. tmp.type = rctx->type;
  13129. ImplicitConversion(&tmp, lctx->type.dataType, 0, asIC_IMPLICIT_CONV, false);
  13130. if( tmp.type.dataType.GetTypeInfo() == lctx->type.dataType.GetTypeInfo() )
  13131. to = lctx->type.dataType;
  13132. else
  13133. to = rctx->type.dataType;
  13134. // Assume handle-to-const as it is not possible to convert handle-to-const to handle-to-non-const
  13135. to.MakeHandleToConst(true);
  13136. }
  13137. // Need to pop the value if it is a null constant
  13138. if( lctx->type.IsNullConstant() )
  13139. lctx->bc.Instr(asBC_PopPtr);
  13140. if( rctx->type.IsNullConstant() )
  13141. rctx->bc.Instr(asBC_PopPtr);
  13142. // Convert both sides to explicit handles
  13143. to.MakeHandle(true);
  13144. to.MakeReference(false);
  13145. if( !to.IsObjectHandle() )
  13146. {
  13147. // Compiler error, don't continue
  13148. Error(TXT_OPERANDS_MUST_BE_HANDLES, node);
  13149. #if AS_SIZEOF_BOOL == 1
  13150. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  13151. #else
  13152. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  13153. #endif
  13154. return;
  13155. }
  13156. // Do the conversion
  13157. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV);
  13158. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV);
  13159. // Both operands must be of the same type
  13160. // Verify that the conversion was successful
  13161. if( !lctx->type.dataType.IsEqualExceptConst(to) )
  13162. {
  13163. asCString str;
  13164. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  13165. Error(str, node);
  13166. }
  13167. if( !rctx->type.dataType.IsEqualExceptConst(to) )
  13168. {
  13169. asCString str;
  13170. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf());
  13171. Error(str, node);
  13172. }
  13173. // Make sure it really is handles that are being compared
  13174. if( !lctx->type.dataType.IsObjectHandle() )
  13175. {
  13176. Error(TXT_OPERANDS_MUST_BE_HANDLES, node);
  13177. }
  13178. ctx->type.Set(asCDataType::CreatePrimitive(ttBool, true));
  13179. if( opToken == ttEqual || opToken == ttNotEqual || opToken == ttIs || opToken == ttNotIs )
  13180. {
  13181. // Make sure handles received as parameters by reference are copied to a local variable before the
  13182. // asBC_CmpPtr, so we don't end up comparing the reference to the handle instead of the handle itself
  13183. if( lctx->type.isVariable && !lctx->type.isTemporary && lctx->type.stackOffset <= 0 )
  13184. lctx->type.isVariable = false;
  13185. if( rctx->type.isVariable && !rctx->type.isTemporary && rctx->type.stackOffset <= 0 )
  13186. rctx->type.isVariable = false;
  13187. // TODO: runtime optimize: don't do REFCPY if not necessary
  13188. ConvertToVariableNotIn(lctx, rctx);
  13189. ConvertToVariable(rctx);
  13190. // Pop the pointers from the stack as they will not be used
  13191. lctx->bc.Instr(asBC_PopPtr);
  13192. rctx->bc.Instr(asBC_PopPtr);
  13193. MergeExprBytecode(ctx, lctx);
  13194. MergeExprBytecode(ctx, rctx);
  13195. int a = AllocateVariable(ctx->type.dataType, true);
  13196. int b = lctx->type.stackOffset;
  13197. int c = rctx->type.stackOffset;
  13198. ctx->bc.InstrW_W(asBC_CmpPtr, b, c);
  13199. if( opToken == ttEqual || opToken == ttIs )
  13200. ctx->bc.Instr(asBC_TZ);
  13201. else if( opToken == ttNotEqual || opToken == ttNotIs )
  13202. ctx->bc.Instr(asBC_TNZ);
  13203. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  13204. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  13205. ReleaseTemporaryVariable(lctx->type, &ctx->bc);
  13206. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  13207. ProcessDeferredParams(ctx);
  13208. }
  13209. else
  13210. {
  13211. // TODO: Use TXT_ILLEGAL_OPERATION_ON
  13212. Error(TXT_ILLEGAL_OPERATION, node);
  13213. }
  13214. }
  13215. void asCCompiler::PerformFunctionCall(int funcId, asCExprContext *ctx, bool isConstructor, asCArray<asCExprContext*> *args, asCObjectType *objType, bool useVariable, int varOffset, int funcPtrVar)
  13216. {
  13217. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  13218. // A shared object may not call non-shared functions
  13219. if( outFunc->IsShared() && !descr->IsShared() )
  13220. {
  13221. asCString msg;
  13222. msg.Format(TXT_SHARED_CANNOT_CALL_NON_SHARED_FUNC_s, descr->GetDeclarationStr().AddressOf());
  13223. Error(msg, ctx->exprNode);
  13224. }
  13225. // Check if the function is private or protected
  13226. if (descr->IsPrivate())
  13227. {
  13228. asCObjectType *type = descr->objectType;
  13229. if (type == 0 && descr->traits.GetTrait(asTRAIT_CONSTRUCTOR))
  13230. type = CastToObjectType(descr->returnType.GetTypeInfo());
  13231. asASSERT(type);
  13232. if( (type != outFunc->GetObjectType()) )
  13233. {
  13234. asCString msg;
  13235. msg.Format(TXT_PRIVATE_METHOD_CALL_s, descr->GetDeclarationStr().AddressOf());
  13236. Error(msg, ctx->exprNode);
  13237. }
  13238. }
  13239. else if (descr->IsProtected())
  13240. {
  13241. asCObjectType *type = descr->objectType;
  13242. if (type == 0 && descr->traits.GetTrait(asTRAIT_CONSTRUCTOR))
  13243. type = CastToObjectType(descr->returnType.GetTypeInfo());
  13244. asASSERT(type);
  13245. if (!(type == outFunc->objectType || (outFunc->objectType && outFunc->objectType->DerivesFrom(type))))
  13246. {
  13247. asCString msg;
  13248. msg.Format(TXT_PROTECTED_METHOD_CALL_s, descr->GetDeclarationStr().AddressOf());
  13249. Error(msg, ctx->exprNode);
  13250. }
  13251. }
  13252. int argSize = descr->GetSpaceNeededForArguments();
  13253. // If we're calling a class method we must make sure the object is guaranteed to stay
  13254. // alive throughout the call by holding on to a reference in a local variable. This must
  13255. // be done for any methods that return references, and any calls on script objects.
  13256. // Application registered objects are assumed to know to keep themselves alive even
  13257. // if the method doesn't return a reference.
  13258. if( !ctx->type.isRefSafe &&
  13259. descr->objectType &&
  13260. (ctx->type.dataType.IsObjectHandle() || ctx->type.dataType.SupportHandles()) &&
  13261. (descr->returnType.IsReference() || (ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_SCRIPT_OBJECT)) &&
  13262. !(ctx->type.isVariable || ctx->type.isTemporary) &&
  13263. !(ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_SCOPED) &&
  13264. !(ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_ASHANDLE) )
  13265. {
  13266. // TODO: runtime optimize: Avoid this for global variables, by storing a reference to the global variable once in a
  13267. // local variable and then refer to the same for each call. An alias for the global variable
  13268. // should be stored in the variable scope so that the compiler can find it. For loops and
  13269. // scopes that will always be executed, i.e. non-if scopes the alias should be stored in the
  13270. // higher scope to increase the probability of re-use.
  13271. int tempRef = AllocateVariable(ctx->type.dataType, true);
  13272. ctx->bc.InstrSHORT(asBC_PSF, (short)tempRef);
  13273. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo());
  13274. // Add the release of this reference as a deferred expression
  13275. asSDeferredParam deferred;
  13276. deferred.origExpr = 0;
  13277. deferred.argInOutFlags = asTM_INREF;
  13278. deferred.argNode = 0;
  13279. deferred.argType.SetVariable(ctx->type.dataType, tempRef, true);
  13280. ctx->deferredParams.PushLast(deferred);
  13281. // Forget the current type
  13282. ctx->type.SetDummy();
  13283. }
  13284. // Check if there is a need to add a hidden pointer for when the function returns an object by value
  13285. if( descr->DoesReturnOnStack() && !useVariable )
  13286. {
  13287. useVariable = true;
  13288. varOffset = AllocateVariable(descr->returnType, true);
  13289. // Push the pointer to the pre-allocated space for the return value
  13290. ctx->bc.InstrSHORT(asBC_PSF, short(varOffset));
  13291. if( descr->objectType )
  13292. {
  13293. // The object pointer is already on the stack, but should be the top
  13294. // one, so we need to swap the pointers in order to get the correct
  13295. ctx->bc.Instr(asBC_SwapPtr);
  13296. }
  13297. }
  13298. if( isConstructor )
  13299. {
  13300. // Sometimes the value types are allocated on the heap,
  13301. // which is when this way of constructing them is used.
  13302. asASSERT(useVariable == false);
  13303. if( (objType->flags & asOBJ_TEMPLATE) )
  13304. {
  13305. asASSERT( descr->funcType == asFUNC_SCRIPT );
  13306. // Find the id of the real constructor and not the generated stub
  13307. asUINT id = 0;
  13308. asDWORD *bc = descr->scriptData->byteCode.AddressOf();
  13309. while( bc )
  13310. {
  13311. if( (*(asBYTE*)bc) == asBC_CALLSYS )
  13312. {
  13313. id = asBC_INTARG(bc);
  13314. break;
  13315. }
  13316. bc += asBCTypeSize[asBCInfo[*(asBYTE*)bc].type];
  13317. }
  13318. asASSERT( id );
  13319. ctx->bc.InstrPTR(asBC_OBJTYPE, objType);
  13320. ctx->bc.Alloc(asBC_ALLOC, objType, id, argSize + AS_PTR_SIZE + AS_PTR_SIZE);
  13321. }
  13322. else
  13323. ctx->bc.Alloc(asBC_ALLOC, objType, descr->id, argSize+AS_PTR_SIZE);
  13324. // The instruction has already moved the returned object to the variable
  13325. ctx->type.Set(asCDataType::CreatePrimitive(ttVoid, false));
  13326. ctx->type.isLValue = false;
  13327. // Clean up arguments
  13328. if( args )
  13329. AfterFunctionCall(funcId, *args, ctx, false);
  13330. ProcessDeferredParams(ctx);
  13331. return;
  13332. }
  13333. else
  13334. {
  13335. if( descr->objectType )
  13336. argSize += AS_PTR_SIZE;
  13337. // If the function returns an object by value the address of the location
  13338. // where the value should be stored is passed as an argument too
  13339. if( descr->DoesReturnOnStack() )
  13340. argSize += AS_PTR_SIZE;
  13341. // TODO: runtime optimize: If it is known that a class method cannot be overridden the call
  13342. // should be made with asBC_CALL as it is faster. Examples where this
  13343. // is known is for example finalled methods where the class doesn't derive
  13344. // from any other, or even non-finalled methods but where it is known
  13345. // at compile time the true type of the object. The first should be
  13346. // quite easy to determine, but the latter will be quite complex and possibly
  13347. // not worth it.
  13348. if( descr->funcType == asFUNC_IMPORTED )
  13349. ctx->bc.Call(asBC_CALLBND , descr->id, argSize);
  13350. // TODO: Maybe we need two different byte codes
  13351. else if( descr->funcType == asFUNC_INTERFACE || descr->funcType == asFUNC_VIRTUAL )
  13352. ctx->bc.Call(asBC_CALLINTF, descr->id, argSize);
  13353. else if( descr->funcType == asFUNC_SCRIPT )
  13354. ctx->bc.Call(asBC_CALL , descr->id, argSize);
  13355. else if( descr->funcType == asFUNC_SYSTEM )
  13356. {
  13357. // Check if we can use the faster asBC_Thiscall1 instruction, i.e. one of
  13358. // type &obj::func(int)
  13359. // type &obj::func(uint)
  13360. if( descr->GetObjectType() && descr->returnType.IsReference() &&
  13361. descr->parameterTypes.GetLength() == 1 &&
  13362. (descr->parameterTypes[0].IsIntegerType() || descr->parameterTypes[0].IsUnsignedType()) &&
  13363. descr->parameterTypes[0].GetSizeInMemoryBytes() == 4 &&
  13364. !descr->parameterTypes[0].IsReference() )
  13365. ctx->bc.Call(asBC_Thiscall1, descr->id, argSize);
  13366. else
  13367. ctx->bc.Call(asBC_CALLSYS , descr->id, argSize);
  13368. }
  13369. else if( descr->funcType == asFUNC_FUNCDEF )
  13370. ctx->bc.CallPtr(asBC_CallPtr, funcPtrVar, argSize);
  13371. }
  13372. if( (descr->returnType.IsObject() || descr->returnType.IsFuncdef()) && !descr->returnType.IsReference() )
  13373. {
  13374. int returnOffset = 0;
  13375. asCExprValue tmpExpr = ctx->type;
  13376. if( descr->DoesReturnOnStack() )
  13377. {
  13378. asASSERT( useVariable );
  13379. // The variable was allocated before the function was called
  13380. returnOffset = varOffset;
  13381. ctx->type.SetVariable(descr->returnType, returnOffset, true);
  13382. // The variable was initialized by the function, so we need to mark it as initialized here
  13383. ctx->bc.ObjInfo(varOffset, asOBJ_INIT);
  13384. }
  13385. else
  13386. {
  13387. if( useVariable )
  13388. {
  13389. // Use the given variable
  13390. returnOffset = varOffset;
  13391. ctx->type.SetVariable(descr->returnType, returnOffset, false);
  13392. }
  13393. else
  13394. {
  13395. // Allocate a temporary variable for the returned object
  13396. // The returned object will actually be allocated on the heap, so
  13397. // we must force the allocation of the variable to do the same
  13398. returnOffset = AllocateVariable(descr->returnType, true, !descr->returnType.IsObjectHandle());
  13399. ctx->type.SetVariable(descr->returnType, returnOffset, true);
  13400. }
  13401. // Move the pointer from the object register to the temporary variable
  13402. ctx->bc.InstrSHORT(asBC_STOREOBJ, (short)returnOffset);
  13403. }
  13404. ReleaseTemporaryVariable(tmpExpr, &ctx->bc);
  13405. ctx->type.dataType.MakeReference(IsVariableOnHeap(returnOffset));
  13406. ctx->type.isLValue = false; // It is a reference, but not an lvalue
  13407. // Clean up arguments
  13408. if( args )
  13409. AfterFunctionCall(funcId, *args, ctx, false);
  13410. ProcessDeferredParams(ctx);
  13411. ctx->bc.InstrSHORT(asBC_PSF, (short)returnOffset);
  13412. }
  13413. else if( descr->returnType.IsReference() )
  13414. {
  13415. asASSERT(useVariable == false);
  13416. // We cannot clean up the arguments yet, because the
  13417. // reference might be pointing to one of them.
  13418. if( args )
  13419. AfterFunctionCall(funcId, *args, ctx, true);
  13420. // Do not process the output parameters yet, because it
  13421. // might invalidate the returned reference
  13422. // If the context holds a variable that needs cleanup
  13423. // store it as a deferred parameter so it will be cleaned up
  13424. // afterwards.
  13425. if( ctx->type.isTemporary )
  13426. {
  13427. asSDeferredParam defer;
  13428. defer.argNode = 0;
  13429. defer.argType = ctx->type;
  13430. defer.argInOutFlags = asTM_INOUTREF;
  13431. defer.origExpr = 0;
  13432. ctx->deferredParams.PushLast(defer);
  13433. }
  13434. ctx->type.Set(descr->returnType);
  13435. if( !descr->returnType.IsPrimitive() )
  13436. {
  13437. ctx->bc.Instr(asBC_PshRPtr);
  13438. if( descr->returnType.IsObject() &&
  13439. !descr->returnType.IsObjectHandle() )
  13440. {
  13441. // We are getting the pointer to the object
  13442. // not a pointer to a object variable
  13443. ctx->type.dataType.MakeReference(false);
  13444. }
  13445. }
  13446. // A returned reference can be used as lvalue
  13447. ctx->type.isLValue = true;
  13448. }
  13449. else
  13450. {
  13451. asCExprValue tmpExpr = ctx->type;
  13452. if( descr->returnType.GetSizeInMemoryBytes() )
  13453. {
  13454. int offset;
  13455. if (useVariable)
  13456. offset = varOffset;
  13457. else
  13458. {
  13459. // Allocate a temporary variable to hold the value, but make sure
  13460. // the temporary variable isn't used in any of the deferred arguments
  13461. int l = int(reservedVariables.GetLength());
  13462. for (asUINT n = 0; args && n < args->GetLength(); n++)
  13463. {
  13464. asCExprContext *expr = (*args)[n]->origExpr;
  13465. if (expr)
  13466. expr->bc.GetVarsUsed(reservedVariables);
  13467. }
  13468. offset = AllocateVariable(descr->returnType, true);
  13469. reservedVariables.SetLength(l);
  13470. }
  13471. ctx->type.SetVariable(descr->returnType, offset, true);
  13472. // Move the value from the return register to the variable
  13473. if( descr->returnType.GetSizeOnStackDWords() == 1 )
  13474. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)offset);
  13475. else if( descr->returnType.GetSizeOnStackDWords() == 2 )
  13476. ctx->bc.InstrSHORT(asBC_CpyRtoV8, (short)offset);
  13477. }
  13478. else
  13479. ctx->type.Set(descr->returnType);
  13480. ReleaseTemporaryVariable(tmpExpr, &ctx->bc);
  13481. ctx->type.isLValue = false;
  13482. // Clean up arguments
  13483. if( args )
  13484. AfterFunctionCall(funcId, *args, ctx, false);
  13485. ProcessDeferredParams(ctx);
  13486. }
  13487. }
  13488. // This only merges the bytecode, but doesn't modify the type of the final context
  13489. void asCCompiler::MergeExprBytecode(asCExprContext *before, asCExprContext *after)
  13490. {
  13491. before->bc.AddCode(&after->bc);
  13492. for( asUINT n = 0; n < after->deferredParams.GetLength(); n++ )
  13493. {
  13494. before->deferredParams.PushLast(after->deferredParams[n]);
  13495. after->deferredParams[n].origExpr = 0;
  13496. }
  13497. after->deferredParams.SetLength(0);
  13498. }
  13499. // This merges both bytecode and the type of the final context
  13500. void asCCompiler::MergeExprBytecodeAndType(asCExprContext *before, asCExprContext *after)
  13501. {
  13502. MergeExprBytecode(before, after);
  13503. before->Merge(after);
  13504. }
  13505. void asCCompiler::FilterConst(asCArray<int> &funcs, bool removeConst)
  13506. {
  13507. if( funcs.GetLength() == 0 ) return;
  13508. // This is only done for object methods
  13509. asCScriptFunction *desc = builder->GetFunctionDescription(funcs[0]);
  13510. if( desc->objectType == 0 ) return;
  13511. // Check if there are any non-const matches
  13512. asUINT n;
  13513. bool foundNonConst = false;
  13514. for( n = 0; n < funcs.GetLength(); n++ )
  13515. {
  13516. desc = builder->GetFunctionDescription(funcs[n]);
  13517. if( desc->IsReadOnly() != removeConst )
  13518. {
  13519. foundNonConst = true;
  13520. break;
  13521. }
  13522. }
  13523. if( foundNonConst )
  13524. {
  13525. // Remove all const methods
  13526. for( n = 0; n < funcs.GetLength(); n++ )
  13527. {
  13528. desc = builder->GetFunctionDescription(funcs[n]);
  13529. if( desc->IsReadOnly() == removeConst )
  13530. {
  13531. if( n == funcs.GetLength() - 1 )
  13532. funcs.PopLast();
  13533. else
  13534. funcs[n] = funcs.PopLast();
  13535. n--;
  13536. }
  13537. }
  13538. }
  13539. }
  13540. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  13541. asCExprValue::asCExprValue()
  13542. {
  13543. isTemporary = false;
  13544. stackOffset = 0;
  13545. isConstant = false;
  13546. isVariable = false;
  13547. isExplicitHandle = false;
  13548. qwordValue = 0;
  13549. isLValue = false;
  13550. isRefToLocal = false;
  13551. isRefSafe = false;
  13552. }
  13553. void asCExprValue::Set(const asCDataType &dt)
  13554. {
  13555. dataType = dt;
  13556. isTemporary = false;
  13557. stackOffset = 0;
  13558. isConstant = false;
  13559. isVariable = false;
  13560. isExplicitHandle = false;
  13561. qwordValue = 0;
  13562. isLValue = false;
  13563. isRefToLocal = false;
  13564. isRefSafe = false;
  13565. }
  13566. void asCExprValue::SetVariable(const asCDataType &in_dt, int in_stackOffset, bool in_isTemporary)
  13567. {
  13568. Set(in_dt);
  13569. this->isVariable = true;
  13570. this->isTemporary = in_isTemporary;
  13571. this->stackOffset = (short)in_stackOffset;
  13572. }
  13573. void asCExprValue::SetConstantQW(const asCDataType &dt, asQWORD value)
  13574. {
  13575. Set(dt);
  13576. isConstant = true;
  13577. SetConstantQW(value);
  13578. }
  13579. void asCExprValue::SetConstantDW(const asCDataType &dt, asDWORD value)
  13580. {
  13581. Set(dt);
  13582. isConstant = true;
  13583. SetConstantDW(value);
  13584. }
  13585. void asCExprValue::SetConstantB(const asCDataType &dt, asBYTE value)
  13586. {
  13587. Set(dt);
  13588. isConstant = true;
  13589. SetConstantB(value);
  13590. }
  13591. void asCExprValue::SetConstantW(const asCDataType &dt, asWORD value)
  13592. {
  13593. Set(dt);
  13594. isConstant = true;
  13595. SetConstantW(value);
  13596. }
  13597. void asCExprValue::SetConstantF(const asCDataType &dt, float value)
  13598. {
  13599. Set(dt);
  13600. isConstant = true;
  13601. SetConstantF(value);
  13602. }
  13603. void asCExprValue::SetConstantD(const asCDataType &dt, double value)
  13604. {
  13605. Set(dt);
  13606. isConstant = true;
  13607. SetConstantD(value);
  13608. }
  13609. void asCExprValue::SetConstantQW(asQWORD value)
  13610. {
  13611. asASSERT(dataType.GetSizeInMemoryBytes() == 8);
  13612. qwordValue = value;
  13613. }
  13614. void asCExprValue::SetConstantDW(asDWORD value)
  13615. {
  13616. asASSERT(dataType.GetSizeInMemoryBytes() == 4);
  13617. dwordValue = value;
  13618. }
  13619. void asCExprValue::SetConstantW(asWORD value)
  13620. {
  13621. asASSERT(dataType.GetSizeInMemoryBytes() == 2);
  13622. wordValue = value;
  13623. }
  13624. void asCExprValue::SetConstantB(asBYTE value)
  13625. {
  13626. asASSERT(dataType.GetSizeInMemoryBytes() == 1);
  13627. byteValue = value;
  13628. }
  13629. void asCExprValue::SetConstantF(float value)
  13630. {
  13631. asASSERT(dataType.GetSizeInMemoryBytes() == 4);
  13632. floatValue = value;
  13633. }
  13634. void asCExprValue::SetConstantD(double value)
  13635. {
  13636. asASSERT(dataType.GetSizeInMemoryBytes() == 8);
  13637. doubleValue = value;
  13638. }
  13639. asQWORD asCExprValue::GetConstantQW()
  13640. {
  13641. asASSERT(dataType.GetSizeInMemoryBytes() == 8);
  13642. return qwordValue;
  13643. }
  13644. asDWORD asCExprValue::GetConstantDW()
  13645. {
  13646. asASSERT(dataType.GetSizeInMemoryBytes() == 4);
  13647. return dwordValue;
  13648. }
  13649. asWORD asCExprValue::GetConstantW()
  13650. {
  13651. asASSERT(dataType.GetSizeInMemoryBytes() == 2);
  13652. return wordValue;
  13653. }
  13654. asBYTE asCExprValue::GetConstantB()
  13655. {
  13656. asASSERT(dataType.GetSizeInMemoryBytes() == 1);
  13657. return byteValue;
  13658. }
  13659. float asCExprValue::GetConstantF()
  13660. {
  13661. asASSERT(dataType.GetSizeInMemoryBytes() == 4);
  13662. return floatValue;
  13663. }
  13664. double asCExprValue::GetConstantD()
  13665. {
  13666. asASSERT(dataType.GetSizeInMemoryBytes() == 8);
  13667. return doubleValue;
  13668. }
  13669. void asCExprValue::SetConstantData(const asCDataType &dt, asQWORD qw)
  13670. {
  13671. Set(dt);
  13672. isConstant = true;
  13673. // This code is necessary to guarantee that the code
  13674. // works on both big endian and little endian CPUs.
  13675. if (dataType.GetSizeInMemoryBytes() == 1)
  13676. byteValue = (asBYTE)qw;
  13677. if (dataType.GetSizeInMemoryBytes() == 2)
  13678. wordValue = (asWORD)qw;
  13679. if (dataType.GetSizeInMemoryBytes() == 4)
  13680. dwordValue = (asDWORD)qw;
  13681. else
  13682. qwordValue = qw;
  13683. }
  13684. asQWORD asCExprValue::GetConstantData()
  13685. {
  13686. asQWORD qw = 0;
  13687. // This code is necessary to guarantee that the code
  13688. // works on both big endian and little endian CPUs.
  13689. if (dataType.GetSizeInMemoryBytes() == 1)
  13690. qw = byteValue;
  13691. if (dataType.GetSizeInMemoryBytes() == 2)
  13692. qw = wordValue;
  13693. if (dataType.GetSizeInMemoryBytes() == 4)
  13694. qw = dwordValue;
  13695. else
  13696. qw = qwordValue;
  13697. return qw;
  13698. }
  13699. void asCExprValue::SetUndefinedFuncHandle(asCScriptEngine *engine)
  13700. {
  13701. // This is used for when the expression evaluates to a
  13702. // function, but it is not yet known exactly which. The
  13703. // owner expression will hold the name of the function
  13704. // to determine the exact function when the signature is
  13705. // known.
  13706. Set(asCDataType::CreateObjectHandle(&engine->functionBehaviours, true));
  13707. isConstant = true;
  13708. isExplicitHandle = false;
  13709. qwordValue = 1; // Set to a different value than 0 to differentiate from null constant
  13710. isLValue = false;
  13711. }
  13712. bool asCExprValue::IsUndefinedFuncHandle() const
  13713. {
  13714. if (isConstant == false) return false;
  13715. if (qwordValue == 0) return false;
  13716. if (isLValue) return false;
  13717. if (dataType.GetTypeInfo() == 0) return false;
  13718. if (dataType.GetTypeInfo()->name != "$func") return false;
  13719. if (dataType.IsFuncdef()) return false;
  13720. return true;
  13721. }
  13722. void asCExprValue::SetNullConstant()
  13723. {
  13724. Set(asCDataType::CreateNullHandle());
  13725. isConstant = true;
  13726. isExplicitHandle = false;
  13727. qwordValue = 0;
  13728. isLValue = false;
  13729. }
  13730. bool asCExprValue::IsNullConstant() const
  13731. {
  13732. // We can't check the actual object type, because the null constant may have been cast to another type
  13733. if (isConstant && dataType.IsObjectHandle() && qwordValue == 0)
  13734. return true;
  13735. return false;
  13736. }
  13737. void asCExprValue::SetVoid()
  13738. {
  13739. Set(asCDataType::CreatePrimitive(ttVoid, false));
  13740. isLValue = false;
  13741. isConstant = true;
  13742. }
  13743. bool asCExprValue::IsVoid() const
  13744. {
  13745. if (dataType.GetTokenType() == ttVoid)
  13746. return true;
  13747. return false;
  13748. }
  13749. void asCExprValue::SetDummy()
  13750. {
  13751. SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), 0);
  13752. }
  13753. ////////////////////////////////////////////////////////////////////////////////////////////////
  13754. asCExprContext::asCExprContext(asCScriptEngine *engine) : bc(engine)
  13755. {
  13756. property_arg = 0;
  13757. Clear();
  13758. }
  13759. asCExprContext::~asCExprContext()
  13760. {
  13761. if (property_arg)
  13762. asDELETE(property_arg, asCExprContext);
  13763. }
  13764. void asCExprContext::Clear()
  13765. {
  13766. bc.ClearAll();
  13767. type.Set(asCDataType());
  13768. deferredParams.SetLength(0);
  13769. if (property_arg)
  13770. asDELETE(property_arg, asCExprContext);
  13771. property_arg = 0;
  13772. exprNode = 0;
  13773. origExpr = 0;
  13774. property_get = 0;
  13775. property_set = 0;
  13776. property_const = false;
  13777. property_handle = false;
  13778. property_ref = false;
  13779. methodName = "";
  13780. enumValue = "";
  13781. symbolNamespace = 0;
  13782. isVoidExpression = false;
  13783. isCleanArg = false;
  13784. isAnonymousInitList = false;
  13785. }
  13786. bool asCExprContext::IsClassMethod() const
  13787. {
  13788. if (type.dataType.GetTypeInfo() == 0) return false;
  13789. if (methodName == "") return false;
  13790. if (type.dataType.GetTypeInfo() == &type.dataType.GetTypeInfo()->engine->functionBehaviours) return false;
  13791. if (isAnonymousInitList) return false;
  13792. return true;
  13793. }
  13794. bool asCExprContext::IsGlobalFunc() const
  13795. {
  13796. if (type.dataType.GetTypeInfo() == 0) return false;
  13797. if (methodName == "") return false;
  13798. if (type.dataType.GetTypeInfo() != &type.dataType.GetTypeInfo()->engine->functionBehaviours) return false;
  13799. if (isAnonymousInitList) return false;
  13800. return true;
  13801. }
  13802. void asCExprContext::SetLambda(asCScriptNode *funcDecl)
  13803. {
  13804. asASSERT(funcDecl && funcDecl->nodeType == snFunction);
  13805. asASSERT(bc.GetLastInstr() == -1);
  13806. Clear();
  13807. type.SetUndefinedFuncHandle(bc.GetEngine());
  13808. exprNode = funcDecl;
  13809. }
  13810. bool asCExprContext::IsLambda() const
  13811. {
  13812. if (type.IsUndefinedFuncHandle() && exprNode && exprNode->nodeType == snFunction)
  13813. return true;
  13814. return false;
  13815. }
  13816. void asCExprContext::SetVoidExpression()
  13817. {
  13818. Clear();
  13819. type.SetVoid();
  13820. isVoidExpression = true;
  13821. }
  13822. bool asCExprContext::IsVoidExpression() const
  13823. {
  13824. if (isVoidExpression && type.IsVoid() && exprNode == 0)
  13825. return true;
  13826. return false;
  13827. }
  13828. void asCExprContext::SetAnonymousInitList(asCScriptNode *initList)
  13829. {
  13830. Clear();
  13831. exprNode = initList;
  13832. isAnonymousInitList = true;
  13833. }
  13834. bool asCExprContext::IsAnonymousInitList() const
  13835. {
  13836. if (isAnonymousInitList && exprNode && exprNode->nodeType == snInitList)
  13837. return true;
  13838. return false;
  13839. }
  13840. void asCExprContext::Merge(asCExprContext *after)
  13841. {
  13842. type = after->type;
  13843. property_get = after->property_get;
  13844. property_set = after->property_set;
  13845. property_const = after->property_const;
  13846. property_handle = after->property_handle;
  13847. property_ref = after->property_ref;
  13848. property_arg = after->property_arg;
  13849. exprNode = after->exprNode;
  13850. methodName = after->methodName;
  13851. enumValue = after->enumValue;
  13852. isVoidExpression = after->isVoidExpression;
  13853. isCleanArg = after->isCleanArg;
  13854. isAnonymousInitList = after->isAnonymousInitList;
  13855. after->property_arg = 0;
  13856. // Do not copy the origExpr member
  13857. }
  13858. END_AS_NAMESPACE
  13859. #endif // AS_NO_COMPILER