as_compiler.cpp 396 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871987298739874987598769877987898799880988198829883988498859886988798889889989098919892989398949895989698979898989999009901990299039904990599069907990899099910991199129913991499159916991799189919992099219922992399249925992699279928992999309931993299339934993599369937993899399940994199429943994499459946994799489949995099519952995399549955995699579958995999609961996299639964996599669967996899699970997199729973997499759976997799789979998099819982998399849985998699879988998999909991999299939994999599969997999899991000010001100021000310004100051000610007100081000910010100111001210013100141001510016100171001810019100201002110022100231002410025100261002710028100291003010031100321003310034100351003610037100381003910040100411004210043100441004510046100471004810049100501005110052100531005410055100561005710058100591006010061100621006310064100651006610067100681006910070100711007210073100741007510076100771007810079100801008110082100831008410085100861008710088100891009010091100921009310094100951009610097100981009910100101011010210103101041010510106101071010810109101101011110112101131011410115101161011710118101191012010121101221012310124101251012610127101281012910130101311013210133101341013510136101371013810139101401014110142101431014410145101461014710148101491015010151101521015310154101551015610157101581015910160101611016210163101641016510166101671016810169101701017110172101731017410175101761017710178101791018010181101821018310184101851018610187101881018910190101911019210193101941019510196101971019810199102001020110202102031020410205102061020710208102091021010211102121021310214102151021610217102181021910220102211022210223102241022510226102271022810229102301023110232102331023410235102361023710238102391024010241102421024310244102451024610247102481024910250102511025210253102541025510256102571025810259102601026110262102631026410265102661026710268102691027010271102721027310274102751027610277102781027910280102811028210283102841028510286102871028810289102901029110292102931029410295102961029710298102991030010301103021030310304103051030610307103081030910310103111031210313103141031510316103171031810319103201032110322103231032410325103261032710328103291033010331103321033310334103351033610337103381033910340103411034210343103441034510346103471034810349103501035110352103531035410355103561035710358103591036010361103621036310364103651036610367103681036910370103711037210373103741037510376103771037810379103801038110382103831038410385103861038710388103891039010391103921039310394103951039610397103981039910400104011040210403104041040510406104071040810409104101041110412104131041410415104161041710418104191042010421104221042310424104251042610427104281042910430104311043210433104341043510436104371043810439104401044110442104431044410445104461044710448104491045010451104521045310454104551045610457104581045910460104611046210463104641046510466104671046810469104701047110472104731047410475104761047710478104791048010481104821048310484104851048610487104881048910490104911049210493104941049510496104971049810499105001050110502105031050410505105061050710508105091051010511105121051310514105151051610517105181051910520105211052210523105241052510526105271052810529105301053110532105331053410535105361053710538105391054010541105421054310544105451054610547105481054910550105511055210553105541055510556105571055810559105601056110562105631056410565105661056710568105691057010571105721057310574105751057610577105781057910580105811058210583105841058510586105871058810589105901059110592105931059410595105961059710598105991060010601106021060310604106051060610607106081060910610106111061210613106141061510616106171061810619106201062110622106231062410625106261062710628106291063010631106321063310634106351063610637106381063910640106411064210643106441064510646106471064810649106501065110652106531065410655106561065710658106591066010661106621066310664106651066610667106681066910670106711067210673106741067510676106771067810679106801068110682106831068410685106861068710688106891069010691106921069310694106951069610697106981069910700107011070210703107041070510706107071070810709107101071110712107131071410715107161071710718107191072010721107221072310724107251072610727107281072910730107311073210733107341073510736107371073810739107401074110742107431074410745107461074710748107491075010751107521075310754107551075610757107581075910760107611076210763107641076510766107671076810769107701077110772107731077410775107761077710778107791078010781107821078310784107851078610787107881078910790107911079210793107941079510796107971079810799108001080110802108031080410805108061080710808108091081010811108121081310814108151081610817108181081910820108211082210823108241082510826108271082810829108301083110832108331083410835108361083710838108391084010841108421084310844108451084610847108481084910850108511085210853108541085510856108571085810859108601086110862108631086410865108661086710868108691087010871108721087310874108751087610877108781087910880108811088210883108841088510886108871088810889108901089110892108931089410895108961089710898108991090010901109021090310904109051090610907109081090910910109111091210913109141091510916109171091810919109201092110922109231092410925109261092710928109291093010931109321093310934109351093610937109381093910940109411094210943109441094510946109471094810949109501095110952109531095410955109561095710958109591096010961109621096310964109651096610967109681096910970109711097210973109741097510976109771097810979109801098110982109831098410985109861098710988109891099010991109921099310994109951099610997109981099911000110011100211003110041100511006110071100811009110101101111012110131101411015110161101711018110191102011021110221102311024110251102611027110281102911030110311103211033110341103511036110371103811039110401104111042110431104411045110461104711048110491105011051110521105311054110551105611057110581105911060110611106211063110641106511066110671106811069110701107111072110731107411075110761107711078110791108011081110821108311084110851108611087110881108911090110911109211093110941109511096110971109811099111001110111102111031110411105111061110711108111091111011111111121111311114111151111611117111181111911120111211112211123111241112511126111271112811129111301113111132111331113411135111361113711138111391114011141111421114311144111451114611147111481114911150111511115211153111541115511156111571115811159111601116111162111631116411165111661116711168111691117011171111721117311174111751117611177111781117911180111811118211183111841118511186111871118811189111901119111192111931119411195111961119711198111991120011201112021120311204112051120611207112081120911210112111121211213112141121511216112171121811219112201122111222112231122411225112261122711228112291123011231112321123311234112351123611237112381123911240112411124211243112441124511246112471124811249112501125111252112531125411255112561125711258112591126011261112621126311264112651126611267112681126911270112711127211273112741127511276112771127811279112801128111282112831128411285112861128711288112891129011291112921129311294112951129611297112981129911300113011130211303113041130511306113071130811309113101131111312113131131411315113161131711318113191132011321113221132311324113251132611327113281132911330113311133211333113341133511336113371133811339113401134111342113431134411345113461134711348113491135011351113521135311354113551135611357113581135911360113611136211363113641136511366113671136811369113701137111372113731137411375113761137711378113791138011381113821138311384113851138611387113881138911390113911139211393113941139511396113971139811399114001140111402114031140411405114061140711408114091141011411114121141311414114151141611417114181141911420114211142211423114241142511426114271142811429114301143111432114331143411435114361143711438114391144011441114421144311444114451144611447114481144911450114511145211453114541145511456114571145811459114601146111462114631146411465114661146711468114691147011471114721147311474114751147611477114781147911480114811148211483114841148511486114871148811489114901149111492114931149411495114961149711498114991150011501115021150311504115051150611507115081150911510115111151211513115141151511516115171151811519115201152111522115231152411525115261152711528115291153011531115321153311534115351153611537115381153911540115411154211543115441154511546115471154811549115501155111552115531155411555115561155711558115591156011561115621156311564115651156611567115681156911570115711157211573115741157511576115771157811579115801158111582115831158411585115861158711588115891159011591115921159311594115951159611597115981159911600116011160211603116041160511606116071160811609116101161111612116131161411615116161161711618116191162011621116221162311624116251162611627116281162911630116311163211633116341163511636116371163811639116401164111642116431164411645116461164711648116491165011651116521165311654116551165611657116581165911660116611166211663116641166511666116671166811669116701167111672116731167411675116761167711678116791168011681116821168311684116851168611687116881168911690116911169211693116941169511696116971169811699117001170111702117031170411705117061170711708117091171011711117121171311714117151171611717117181171911720117211172211723117241172511726117271172811729117301173111732117331173411735117361173711738117391174011741117421174311744117451174611747117481174911750117511175211753117541175511756117571175811759117601176111762117631176411765117661176711768117691177011771117721177311774117751177611777117781177911780117811178211783117841178511786117871178811789117901179111792117931179411795117961179711798117991180011801118021180311804118051180611807118081180911810118111181211813118141181511816118171181811819118201182111822118231182411825118261182711828118291183011831118321183311834118351183611837118381183911840118411184211843118441184511846118471184811849118501185111852118531185411855118561185711858118591186011861118621186311864118651186611867118681186911870118711187211873118741187511876118771187811879118801188111882118831188411885118861188711888118891189011891118921189311894118951189611897118981189911900119011190211903119041190511906119071190811909119101191111912119131191411915119161191711918119191192011921119221192311924119251192611927119281192911930119311193211933119341193511936119371193811939119401194111942119431194411945119461194711948119491195011951119521195311954119551195611957119581195911960119611196211963119641196511966119671196811969119701197111972119731197411975119761197711978119791198011981119821198311984119851198611987119881198911990119911199211993119941199511996119971199811999120001200112002120031200412005120061200712008120091201012011120121201312014120151201612017120181201912020120211202212023120241202512026120271202812029120301203112032120331203412035120361203712038120391204012041120421204312044120451204612047120481204912050120511205212053120541205512056120571205812059120601206112062120631206412065120661206712068120691207012071120721207312074120751207612077120781207912080120811208212083120841208512086120871208812089120901209112092120931209412095120961209712098120991210012101121021210312104121051210612107121081210912110121111211212113121141211512116121171211812119121201212112122121231212412125121261212712128121291213012131121321213312134121351213612137121381213912140121411214212143121441214512146121471214812149121501215112152121531215412155121561215712158121591216012161121621216312164121651216612167121681216912170121711217212173121741217512176121771217812179121801218112182121831218412185121861218712188121891219012191121921219312194121951219612197121981219912200122011220212203122041220512206122071220812209122101221112212122131221412215122161221712218122191222012221122221222312224122251222612227122281222912230122311223212233122341223512236122371223812239122401224112242122431224412245122461224712248122491225012251122521225312254122551225612257122581225912260122611226212263122641226512266122671226812269122701227112272122731227412275122761227712278122791228012281122821228312284122851228612287122881228912290122911229212293122941229512296122971229812299123001230112302123031230412305123061230712308123091231012311123121231312314123151231612317123181231912320123211232212323123241232512326123271232812329123301233112332123331233412335123361233712338123391234012341123421234312344123451234612347123481234912350123511235212353123541235512356123571235812359123601236112362123631236412365123661236712368123691237012371123721237312374123751237612377123781237912380123811238212383123841238512386123871238812389123901239112392123931239412395123961239712398123991240012401124021240312404124051240612407124081240912410124111241212413124141241512416124171241812419124201242112422124231242412425124261242712428124291243012431124321243312434124351243612437124381243912440124411244212443124441244512446124471244812449124501245112452124531245412455124561245712458124591246012461124621246312464124651246612467124681246912470124711247212473124741247512476124771247812479124801248112482124831248412485124861248712488124891249012491124921249312494124951249612497124981249912500125011250212503125041250512506125071250812509125101251112512125131251412515125161251712518125191252012521125221252312524125251252612527125281252912530125311253212533125341253512536125371253812539125401254112542125431254412545125461254712548125491255012551125521255312554125551255612557125581255912560125611256212563125641256512566125671256812569125701257112572125731257412575125761257712578125791258012581125821258312584125851258612587125881258912590
  1. /*
  2. AngelCode Scripting Library
  3. Copyright (c) 2003-2013 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()
  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. BEGIN_AS_NAMESPACE
  40. //
  41. // The calling convention rules for script functions:
  42. // - 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
  43. // - 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
  44. // - The object pointer is always passed as the first argument, position 0
  45. // - 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
  46. //
  47. // TODO: I must correct the interpretation of a references to objects in the compiler.
  48. // A reference should mean that a pointer to the object is on the stack.
  49. // No expression should end up as non-references to objects, as the actual object is
  50. // never put on the stack.
  51. // Local variables are declared as non-references, but the expression should be a reference to the variable.
  52. // Function parameters of called functions can also be non-references, but in that case it means the
  53. // object will be passed by value (currently on the heap, which will be moved to the application stack).
  54. //
  55. // The compiler shouldn't use the asCDataType::IsReference. The datatype should always be stored as non-references.
  56. // Instead the compiler should keep track of references in TypeInfo, where it should also state how the reference
  57. // is currently stored, i.e. in variable, in register, on stack, etc.
  58. asCCompiler::asCCompiler(asCScriptEngine *engine) : byteCode(engine)
  59. {
  60. builder = 0;
  61. script = 0;
  62. variables = 0;
  63. isProcessingDeferredParams = false;
  64. isCompilingDefaultArg = false;
  65. noCodeOutput = 0;
  66. }
  67. asCCompiler::~asCCompiler()
  68. {
  69. while( variables )
  70. {
  71. asCVariableScope *var = variables;
  72. variables = variables->parent;
  73. asDELETE(var,asCVariableScope);
  74. }
  75. }
  76. void asCCompiler::Reset(asCBuilder *builder, asCScriptCode *script, asCScriptFunction *outFunc)
  77. {
  78. this->builder = builder;
  79. this->engine = builder->engine;
  80. this->script = script;
  81. this->outFunc = outFunc;
  82. hasCompileErrors = false;
  83. m_isConstructor = false;
  84. m_isConstructorCalled = false;
  85. m_classDecl = 0;
  86. nextLabel = 0;
  87. breakLabels.SetLength(0);
  88. continueLabels.SetLength(0);
  89. byteCode.ClearAll();
  90. }
  91. int asCCompiler::CompileDefaultConstructor(asCBuilder *builder, asCScriptCode *script, asCScriptNode *node, asCScriptFunction *outFunc, sClassDeclaration *classDecl)
  92. {
  93. Reset(builder, script, outFunc);
  94. m_classDecl = classDecl;
  95. // Insert a JitEntry at the start of the function for JIT compilers
  96. byteCode.InstrPTR(asBC_JitEntry, 0);
  97. // Add a variable scope that might be needed to declare dummy variables
  98. // in case the member initialization refers to undefined symbols.
  99. AddVariableScope();
  100. // Initialize the class members that have no explicit expression first. This will allow the
  101. // base class' constructor to access these members without worry they will be uninitialized.
  102. // This can happen if the base class' constructor calls a method that is overridden by the derived class
  103. CompileMemberInitialization(&byteCode, true);
  104. // If the class is derived from another, then the base class' default constructor must be called
  105. if( outFunc->objectType->derivedFrom )
  106. {
  107. // Make sure the base class really has a default constructor
  108. if( outFunc->objectType->derivedFrom->beh.construct == 0 )
  109. Error(TEXT_BASE_DOESNT_HAVE_DEF_CONSTR, node);
  110. // Call the base class' default constructor
  111. byteCode.InstrSHORT(asBC_PSF, 0);
  112. byteCode.Instr(asBC_RDSPtr);
  113. byteCode.Call(asBC_CALL, outFunc->objectType->derivedFrom->beh.construct, AS_PTR_SIZE);
  114. }
  115. // Initialize the class members that explicit expressions afterwards. This allow the expressions
  116. // to access the base class members without worry they will be uninitialized
  117. CompileMemberInitialization(&byteCode, false);
  118. byteCode.OptimizeLocally(tempVariableOffsets);
  119. // If there are compile errors, there is no reason to build the final code
  120. if( hasCompileErrors )
  121. return -1;
  122. // Pop the object pointer from the stack
  123. byteCode.Ret(AS_PTR_SIZE);
  124. // Count total variable size
  125. int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1;
  126. outFunc->scriptData->variableSpace = varSize;
  127. FinalizeFunction();
  128. #ifdef AS_DEBUG
  129. // DEBUG: output byte code
  130. byteCode.DebugOutput(("__" + outFunc->objectType->name + "_" + outFunc->name + "__defconstr.txt").AddressOf(), engine, outFunc);
  131. #endif
  132. return 0;
  133. }
  134. int asCCompiler::CompileFactory(asCBuilder *builder, asCScriptCode *script, asCScriptFunction *outFunc)
  135. {
  136. Reset(builder, script, outFunc);
  137. // Insert a JitEntry at the start of the function for JIT compilers
  138. byteCode.InstrPTR(asBC_JitEntry, 0);
  139. // Find the corresponding constructor
  140. asCDataType dt = asCDataType::CreateObject(outFunc->returnType.GetObjectType(), false);
  141. int constructor = 0;
  142. for( unsigned int n = 0; n < dt.GetBehaviour()->factories.GetLength(); n++ )
  143. {
  144. if( dt.GetBehaviour()->factories[n] == outFunc->id )
  145. {
  146. constructor = dt.GetBehaviour()->constructors[n];
  147. break;
  148. }
  149. }
  150. // Allocate the class and instanciate it with the constructor
  151. int varOffset = AllocateVariable(dt, true);
  152. outFunc->scriptData->variableSpace = AS_PTR_SIZE;
  153. byteCode.InstrSHORT(asBC_PSF, (short)varOffset);
  154. // Copy all arguments to the top of the stack
  155. // TODO: runtime optimize: Might be interesting to have a specific instruction for copying all arguments
  156. int offset = (int)outFunc->GetSpaceNeededForArguments();
  157. for( int a = int(outFunc->parameterTypes.GetLength()) - 1; a >= 0; a-- )
  158. {
  159. if( !outFunc->parameterTypes[a].IsPrimitive() ||
  160. outFunc->parameterTypes[a].IsReference() )
  161. {
  162. offset -= AS_PTR_SIZE;
  163. byteCode.InstrSHORT(asBC_PshVPtr, short(-offset));
  164. }
  165. else
  166. {
  167. if( outFunc->parameterTypes[a].GetSizeOnStackDWords() == 2 )
  168. {
  169. offset -= 2;
  170. byteCode.InstrSHORT(asBC_PshV8, short(-offset));
  171. }
  172. else
  173. {
  174. offset -= 1;
  175. byteCode.InstrSHORT(asBC_PshV4, short(-offset));
  176. }
  177. }
  178. }
  179. int argDwords = (int)outFunc->GetSpaceNeededForArguments();
  180. byteCode.Alloc(asBC_ALLOC, dt.GetObjectType(), constructor, argDwords + AS_PTR_SIZE);
  181. // Return a handle to the newly created object
  182. byteCode.InstrSHORT(asBC_LOADOBJ, (short)varOffset);
  183. byteCode.Ret(argDwords);
  184. FinalizeFunction();
  185. // Tell the virtual machine not to clean up parameters on exception
  186. outFunc->dontCleanUpOnException = true;
  187. /*
  188. #ifdef AS_DEBUG
  189. // DEBUG: output byte code
  190. asCString args;
  191. args.Format("%d", outFunc->parameterTypes.GetLength());
  192. byteCode.DebugOutput(("__" + outFunc->name + "__factory" + args + ".txt").AddressOf(), engine);
  193. #endif
  194. */
  195. return 0;
  196. }
  197. void asCCompiler::FinalizeFunction()
  198. {
  199. TimeIt("asCCompiler::FinalizeFunction");
  200. asASSERT( outFunc->scriptData );
  201. asUINT n;
  202. // Finalize the bytecode
  203. byteCode.Finalize(tempVariableOffsets);
  204. byteCode.ExtractObjectVariableInfo(outFunc);
  205. // Compile the list of object variables for the exception handler
  206. // Start with the variables allocated on the heap, and then the ones allocated on the stack
  207. for( n = 0; n < variableAllocations.GetLength(); n++ )
  208. {
  209. if( variableAllocations[n].IsObject() && !variableAllocations[n].IsReference() )
  210. {
  211. if( variableIsOnHeap[n] )
  212. {
  213. outFunc->scriptData->objVariableTypes.PushLast(variableAllocations[n].GetObjectType());
  214. outFunc->scriptData->funcVariableTypes.PushLast(variableAllocations[n].GetFuncDef());
  215. outFunc->scriptData->objVariablePos.PushLast(GetVariableOffset(n));
  216. }
  217. }
  218. }
  219. outFunc->scriptData->objVariablesOnHeap = asUINT(outFunc->scriptData->objVariablePos.GetLength());
  220. for( n = 0; n < variableAllocations.GetLength(); n++ )
  221. {
  222. if( variableAllocations[n].IsObject() && !variableAllocations[n].IsReference() )
  223. {
  224. if( !variableIsOnHeap[n] )
  225. {
  226. outFunc->scriptData->objVariableTypes.PushLast(variableAllocations[n].GetObjectType());
  227. outFunc->scriptData->funcVariableTypes.PushLast(variableAllocations[n].GetFuncDef());
  228. outFunc->scriptData->objVariablePos.PushLast(GetVariableOffset(n));
  229. }
  230. }
  231. }
  232. // Copy byte code to the function
  233. asASSERT( outFunc->scriptData->byteCode.GetLength() == 0 );
  234. outFunc->scriptData->byteCode.SetLength(byteCode.GetSize());
  235. byteCode.Output(outFunc->scriptData->byteCode.AddressOf());
  236. outFunc->AddReferences();
  237. outFunc->scriptData->stackNeeded = byteCode.largestStackUsed + outFunc->scriptData->variableSpace;
  238. outFunc->scriptData->lineNumbers = byteCode.lineNumbers;
  239. // Extract the script section indexes too if there are any entries that are different from the function's script section
  240. int lastIdx = outFunc->scriptData->scriptSectionIdx;
  241. for( n = 0; n < byteCode.sectionIdxs.GetLength(); n++ )
  242. {
  243. if( byteCode.sectionIdxs[n] != lastIdx )
  244. {
  245. lastIdx = byteCode.sectionIdxs[n];
  246. outFunc->scriptData->sectionIdxs.PushLast(byteCode.lineNumbers[n*2]);
  247. outFunc->scriptData->sectionIdxs.PushLast(lastIdx);
  248. }
  249. }
  250. }
  251. // internal
  252. int asCCompiler::SetupParametersAndReturnVariable(asCArray<asCString> &parameterNames, asCScriptNode *func)
  253. {
  254. int stackPos = 0;
  255. if( outFunc->objectType )
  256. stackPos = -AS_PTR_SIZE; // The first parameter is the pointer to the object
  257. // Add the first variable scope, which the parameters and
  258. // variables declared in the outermost statement block is
  259. // part of.
  260. AddVariableScope();
  261. bool isDestructor = false;
  262. asCDataType returnType;
  263. // Examine return type
  264. returnType = outFunc->returnType;
  265. // Check if this is a constructor or destructor
  266. if( returnType.GetTokenType() == ttVoid && outFunc->objectType )
  267. {
  268. if( outFunc->name[0] == '~' )
  269. isDestructor = true;
  270. else if( outFunc->objectType->name == outFunc->name )
  271. m_isConstructor = true;
  272. }
  273. // Is the return type allowed?
  274. if( (!returnType.CanBeInstanciated() && returnType != asCDataType::CreatePrimitive(ttVoid, false)) ||
  275. (returnType.IsReference() && !returnType.CanBeInstanciated()) )
  276. {
  277. // TODO: Hasn't this been validated by the builder already?
  278. asCString str;
  279. str.Format(TXT_RETURN_CANT_BE_s, returnType.Format().AddressOf());
  280. Error(str, func);
  281. }
  282. // If the return type is a value type returned by value the address of the
  283. // location where the value will be stored is pushed on the stack before
  284. // the arguments
  285. if( !(isDestructor || m_isConstructor) && outFunc->DoesReturnOnStack() )
  286. stackPos -= AS_PTR_SIZE;
  287. asCVariableScope vs(0);
  288. // Declare parameters
  289. asUINT n;
  290. for( n = 0; n < parameterNames.GetLength(); n++ )
  291. {
  292. // Get the parameter type
  293. asCDataType &type = outFunc->parameterTypes[n];
  294. asETypeModifiers inoutFlag = outFunc->inOutFlags[n];
  295. // Is the data type allowed?
  296. // TODO: Hasn't this been validated by the builder already?
  297. if( (type.IsReference() && inoutFlag != asTM_INOUTREF && !type.CanBeInstanciated()) ||
  298. (!type.IsReference() && !type.CanBeInstanciated()) )
  299. {
  300. asCString parm = type.Format();
  301. if( inoutFlag == asTM_INREF )
  302. parm += "in";
  303. else if( inoutFlag == asTM_OUTREF )
  304. parm += "out";
  305. asCString str;
  306. str.Format(TXT_PARAMETER_CANT_BE_s, parm.AddressOf());
  307. Error(str, func);
  308. }
  309. // If the parameter has a name then declare it as variable
  310. if( parameterNames[n] != "" )
  311. {
  312. asCString &name = parameterNames[n];
  313. if( vs.DeclareVariable(name.AddressOf(), type, stackPos, true) < 0 )
  314. {
  315. // TODO: It might be an out-of-memory too
  316. Error(TXT_PARAMETER_ALREADY_DECLARED, func);
  317. }
  318. // Add marker for variable declaration
  319. byteCode.VarDecl((int)outFunc->scriptData->variables.GetLength());
  320. outFunc->AddVariable(name, type, stackPos);
  321. }
  322. else
  323. vs.DeclareVariable("", type, stackPos, true);
  324. // Move to next parameter
  325. stackPos -= type.GetSizeOnStackDWords();
  326. }
  327. for( n = asUINT(vs.variables.GetLength()); n-- > 0; )
  328. variables->DeclareVariable(vs.variables[n]->name.AddressOf(), vs.variables[n]->type, vs.variables[n]->stackOffset, vs.variables[n]->onHeap);
  329. variables->DeclareVariable("return", returnType, stackPos, true);
  330. return stackPos;
  331. }
  332. void asCCompiler::CompileMemberInitialization(asCByteCode *byteCode, bool onlyDefaults)
  333. {
  334. asASSERT( m_classDecl );
  335. // Initialize each member in the order they were declared
  336. for( asUINT n = 0; n < outFunc->objectType->properties.GetLength(); n++ )
  337. {
  338. asCObjectProperty *prop = outFunc->objectType->properties[n];
  339. // Check if the property has an initialization expression
  340. asCScriptNode *declNode = 0;
  341. asCScriptNode *initNode = 0;
  342. asCScriptCode *initScript = 0;
  343. for( asUINT m = 0; m < m_classDecl->propInits.GetLength(); m++ )
  344. {
  345. if( m_classDecl->propInits[m].name == prop->name )
  346. {
  347. declNode = m_classDecl->propInits[m].declNode;
  348. initNode = m_classDecl->propInits[m].initNode;
  349. initScript = m_classDecl->propInits[m].file;
  350. break;
  351. }
  352. }
  353. // If declNode is null, the property was inherited in which case
  354. // it was already initialized by the base class' constructor
  355. if( declNode )
  356. {
  357. if( initNode )
  358. {
  359. if( onlyDefaults )
  360. continue;
  361. #ifdef AS_NO_MEMBER_INIT
  362. // Give an error as the initialization in the declaration has been disabled
  363. asCScriptCode *origScript = script;
  364. script = initScript;
  365. Error("Initialization of members in declaration is not supported", initNode);
  366. script = origScript;
  367. // Clear the initialization node
  368. initNode = 0;
  369. initScript = script;
  370. #else
  371. // Re-parse the initialization expression as the parser now knows the types, which it didn't earlier
  372. asCParser parser(builder);
  373. int r = parser.ParseVarInit(initScript, initNode);
  374. if( r < 0 )
  375. continue;
  376. initNode = parser.GetScriptNode();
  377. #endif
  378. }
  379. else
  380. {
  381. if( !onlyDefaults )
  382. continue;
  383. }
  384. #ifdef AS_NO_MEMBER_INIT
  385. // The initialization will be done in the asCScriptObject constructor, so
  386. // here we should just validate that the member has a default constructor
  387. if( prop->type.IsObject() &&
  388. !prop->type.IsObjectHandle() &&
  389. (((prop->type.GetObjectType()->flags & asOBJ_REF) &&
  390. prop->type.GetBehaviour()->factory == 0) ||
  391. ((prop->type.GetObjectType()->flags & asOBJ_VALUE) &&
  392. prop->type.GetBehaviour()->construct == 0 &&
  393. !(prop->type.GetObjectType()->flags & asOBJ_POD))) )
  394. {
  395. // Class has no default factory/constructor.
  396. asCString str;
  397. // TODO: funcdef: asCDataType should have a GetTypeName()
  398. if( prop->type.GetFuncDef() )
  399. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, prop->type.GetFuncDef()->GetName());
  400. else
  401. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, prop->type.GetObjectType()->GetName());
  402. Error(str, declNode);
  403. }
  404. #else
  405. // Temporarily set the script that is being compiled to where the member initialization is declared.
  406. // The script can be different when including mixin classes from a different script section
  407. asCScriptCode *origScript = script;
  408. script = initScript;
  409. // Add a line instruction with the position of the declaration
  410. LineInstr(byteCode, declNode->tokenPos);
  411. // Compile the initialization
  412. asQWORD constantValue;
  413. asCByteCode bc(engine);
  414. CompileInitialization(initNode, &bc, prop->type, declNode, prop->byteOffset, &constantValue, 2);
  415. byteCode->AddCode(&bc);
  416. script = origScript;
  417. #endif
  418. }
  419. }
  420. }
  421. // Entry
  422. int asCCompiler::CompileFunction(asCBuilder *builder, asCScriptCode *script, asCArray<asCString> &parameterNames, asCScriptNode *func, asCScriptFunction *outFunc, sClassDeclaration *classDecl)
  423. {
  424. TimeIt("asCCompiler::CompileFunction");
  425. Reset(builder, script, outFunc);
  426. int buildErrors = builder->numErrors;
  427. int stackPos = SetupParametersAndReturnVariable(parameterNames, func);
  428. //--------------------------------------------
  429. // Compile the statement block
  430. if( m_isConstructor )
  431. m_classDecl = classDecl;
  432. // We need to parse the statement block now
  433. asCScriptNode *blockBegin;
  434. // If the function signature was implicit, e.g. virtual property
  435. // accessor, then the received node already is the statement block
  436. if( func->nodeType != snStatementBlock )
  437. blockBegin = func->lastChild;
  438. else
  439. blockBegin = func;
  440. // TODO: memory: We can parse the statement block one statement at a time, thus save even more memory
  441. // 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
  442. asCParser parser(builder);
  443. int r = parser.ParseStatementBlock(script, blockBegin);
  444. if( r < 0 ) return -1;
  445. asCScriptNode *block = parser.GetScriptNode();
  446. // Reserve a label for the cleanup code
  447. nextLabel++;
  448. bool hasReturn;
  449. asCByteCode bc(engine);
  450. LineInstr(&bc, blockBegin->tokenPos);
  451. CompileStatementBlock(block, false, &hasReturn, &bc);
  452. LineInstr(&bc, blockBegin->tokenPos + blockBegin->tokenLength);
  453. // Make sure there is a return in all paths (if not return type is void)
  454. // Don't bother with this check if there are compiler errors, e.g. Unreachable code
  455. if( !hasCompileErrors && outFunc->returnType != asCDataType::CreatePrimitive(ttVoid, false) )
  456. {
  457. if( hasReturn == false )
  458. Error(TXT_NOT_ALL_PATHS_RETURN, blockBegin);
  459. }
  460. //------------------------------------------------
  461. // Concatenate the bytecode
  462. // Insert a JitEntry at the start of the function for JIT compilers
  463. byteCode.InstrPTR(asBC_JitEntry, 0);
  464. if( outFunc->objectType )
  465. {
  466. if( m_isConstructor )
  467. {
  468. if( outFunc->objectType->derivedFrom )
  469. {
  470. // Call the base class' default constructor unless called manually in the code
  471. if( !m_isConstructorCalled )
  472. {
  473. if( outFunc->objectType->derivedFrom->beh.construct )
  474. {
  475. // Initialize members without explicit expression first
  476. CompileMemberInitialization(&byteCode, true);
  477. // Call base class' constructor
  478. asCByteCode tmpBC(engine);
  479. tmpBC.InstrSHORT(asBC_PSF, 0);
  480. tmpBC.Instr(asBC_RDSPtr);
  481. tmpBC.Call(asBC_CALL, outFunc->objectType->derivedFrom->beh.construct, AS_PTR_SIZE);
  482. tmpBC.OptimizeLocally(tempVariableOffsets);
  483. byteCode.AddCode(&tmpBC);
  484. // Add the initialization of the members with explicit expressions
  485. CompileMemberInitialization(&byteCode, false);
  486. }
  487. else
  488. Error(TEXT_BASE_DOESNT_HAVE_DEF_CONSTR, blockBegin);
  489. }
  490. else
  491. {
  492. // Only initialize members that don't have an explicit expression
  493. // The members that are explicitly initialized will be initialized after the call to base class' constructor
  494. CompileMemberInitialization(&byteCode, true);
  495. }
  496. }
  497. else
  498. {
  499. // Add the initialization of the members
  500. CompileMemberInitialization(&byteCode, true);
  501. CompileMemberInitialization(&byteCode, false);
  502. }
  503. }
  504. // Increase the reference for the object pointer, so that it is guaranteed to live during the entire call
  505. if( !m_isConstructor && !outFunc->returnType.IsReference() )
  506. {
  507. // TODO: runtime optimize: If the function is trivial, i.e. doesn't access any outside functions,
  508. // then this is not necessary. If I implement this, then the function needs
  509. // to set a flag so the exception handler doesn't try to release the handle.
  510. // It is not necessary to do this for constructors, as they have no outside references that can be released anyway
  511. // It is not necessary to do this for methods that return references, as the caller is guaranteed to hold a reference to the object
  512. asCByteCode tmpBC(engine);
  513. tmpBC.InstrSHORT(asBC_PSF, 0);
  514. tmpBC.Instr(asBC_RDSPtr);
  515. tmpBC.Call(asBC_CALLSYS, outFunc->objectType->beh.addref, AS_PTR_SIZE);
  516. tmpBC.OptimizeLocally(tempVariableOffsets);
  517. byteCode.AddCode(&tmpBC);
  518. }
  519. }
  520. // Add the code for the statement block
  521. byteCode.AddCode(&bc);
  522. // Count total variable size
  523. int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1;
  524. outFunc->scriptData->variableSpace = varSize;
  525. // Deallocate all local variables
  526. int n;
  527. for( n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  528. {
  529. sVariable *v = variables->variables[n];
  530. if( v->stackOffset > 0 )
  531. {
  532. // Call variables destructors
  533. if( v->name != "return" && v->name != "return address" )
  534. CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode);
  535. DeallocateVariable(v->stackOffset);
  536. }
  537. }
  538. // This is the label that return statements jump to
  539. // in order to exit the function
  540. byteCode.Label(0);
  541. // Call destructors for function parameters
  542. for( n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  543. {
  544. sVariable *v = variables->variables[n];
  545. if( v->stackOffset <= 0 )
  546. {
  547. // Call variable destructors here, for variables not yet destroyed
  548. if( v->name != "return" && v->name != "return address" )
  549. CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode);
  550. }
  551. // Do not deallocate parameters
  552. }
  553. // Release the object pointer again
  554. if( outFunc->objectType && !m_isConstructor && !outFunc->returnType.IsReference() )
  555. byteCode.InstrW_PTR(asBC_FREE, 0, outFunc->objectType);
  556. // Check if the number of labels in the functions isn't too many to be handled
  557. if( nextLabel >= (1<<15) )
  558. Error(TXT_TOO_MANY_JUMP_LABELS, func);
  559. // If there are compile errors, there is no reason to build the final code
  560. if( hasCompileErrors || builder->numErrors != buildErrors )
  561. return -1;
  562. // At this point there should be no variables allocated
  563. asASSERT(variableAllocations.GetLength() == freeVariables.GetLength());
  564. // Remove the variable scope
  565. RemoveVariableScope();
  566. byteCode.Ret(-stackPos);
  567. FinalizeFunction();
  568. #ifdef AS_DEBUG
  569. // DEBUG: output byte code
  570. if( outFunc->objectType )
  571. byteCode.DebugOutput(("__" + outFunc->objectType->name + "_" + outFunc->name + ".txt").AddressOf(), engine, outFunc);
  572. else
  573. byteCode.DebugOutput(("__" + outFunc->name + ".txt").AddressOf(), engine, outFunc);
  574. #endif
  575. return 0;
  576. }
  577. int asCCompiler::CallCopyConstructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asSExprContext *arg, asCScriptNode *node, bool isGlobalVar, bool derefDest)
  578. {
  579. if( !type.IsObject() )
  580. return 0;
  581. // CallCopyConstructor should not be called for object handles.
  582. asASSERT( !type.IsObjectHandle() );
  583. asCArray<asSExprContext*> args;
  584. args.PushLast(arg);
  585. // The reference parameter must be pushed on the stack
  586. asASSERT( arg->type.dataType.GetObjectType() == type.GetObjectType() );
  587. // Since we're calling the copy constructor, we have to trust the function to not do
  588. // anything stupid otherwise we will just enter a loop, as we try to make temporary
  589. // copies of the argument in order to guarantee safety.
  590. if( type.GetObjectType()->flags & asOBJ_REF )
  591. {
  592. asSExprContext ctx(engine);
  593. int func = 0;
  594. asSTypeBehaviour *beh = type.GetBehaviour();
  595. if( beh ) func = beh->copyfactory;
  596. if( func > 0 )
  597. {
  598. if( !isGlobalVar )
  599. {
  600. // Call factory and store the handle in the given variable
  601. PerformFunctionCall(func, &ctx, false, &args, type.GetObjectType(), true, offset);
  602. // Pop the reference left by the function call
  603. ctx.bc.Instr(asBC_PopPtr);
  604. }
  605. else
  606. {
  607. // Call factory
  608. PerformFunctionCall(func, &ctx, false, &args, type.GetObjectType());
  609. // Store the returned handle in the global variable
  610. ctx.bc.Instr(asBC_RDSPtr);
  611. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  612. ctx.bc.InstrPTR(asBC_REFCPY, type.GetObjectType());
  613. ctx.bc.Instr(asBC_PopPtr);
  614. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  615. }
  616. bc->AddCode(&ctx.bc);
  617. return 0;
  618. }
  619. }
  620. else
  621. {
  622. asSTypeBehaviour *beh = type.GetBehaviour();
  623. int func = beh ? beh->copyconstruct : 0;
  624. if( func > 0 )
  625. {
  626. // Push the address where the object will be stored on the stack, before the argument
  627. // TODO: When the context is serializable this probably has to be changed, since this
  628. // pointer can remain on the stack while the context is suspended. There is no
  629. // risk the pointer becomes invalid though, there is just no easy way to serialize it.
  630. asCByteCode tmp(engine);
  631. if( isGlobalVar )
  632. tmp.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  633. else if( isObjectOnHeap )
  634. tmp.InstrSHORT(asBC_PSF, (short)offset);
  635. tmp.AddCode(bc);
  636. bc->AddCode(&tmp);
  637. // When the object is allocated on the stack the object pointer
  638. // must be pushed on the stack after the arguments
  639. if( !isObjectOnHeap )
  640. {
  641. asASSERT( !isGlobalVar );
  642. bc->InstrSHORT(asBC_PSF, (short)offset);
  643. if( derefDest )
  644. {
  645. // The variable is a reference to the real location, so we need to dereference it
  646. bc->Instr(asBC_RDSPtr);
  647. }
  648. }
  649. asSExprContext ctx(engine);
  650. PerformFunctionCall(func, &ctx, isObjectOnHeap, &args, type.GetObjectType());
  651. bc->AddCode(&ctx.bc);
  652. // TODO: value on stack: This probably needs to be done in PerformFunctionCall
  653. // Mark the object as initialized
  654. if( !isObjectOnHeap )
  655. bc->ObjInfo(offset, asOBJ_INIT);
  656. return 0;
  657. }
  658. }
  659. // Class has no copy constructor/factory.
  660. asCString str;
  661. str.Format(TXT_NO_COPY_CONSTRUCTOR_FOR_s, type.GetObjectType()->GetName());
  662. Error(str, node);
  663. return -1;
  664. }
  665. int asCCompiler::CallDefaultConstructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asCScriptNode *node, int isVarGlobOrMem, bool derefDest)
  666. {
  667. if( !type.IsObject() || type.IsObjectHandle() )
  668. return 0;
  669. if( type.GetObjectType()->flags & asOBJ_REF )
  670. {
  671. asSExprContext ctx(engine);
  672. ctx.exprNode = node;
  673. int func = 0;
  674. asSTypeBehaviour *beh = type.GetBehaviour();
  675. if( beh ) func = beh->factory;
  676. if( func > 0 )
  677. {
  678. if( isVarGlobOrMem == 0 )
  679. {
  680. // Call factory and store the handle in the given variable
  681. PerformFunctionCall(func, &ctx, false, 0, type.GetObjectType(), true, offset);
  682. // Pop the reference left by the function call
  683. ctx.bc.Instr(asBC_PopPtr);
  684. }
  685. else
  686. {
  687. // Call factory
  688. PerformFunctionCall(func, &ctx, false, 0, type.GetObjectType());
  689. // TODO: runtime optimize: Should have a way of storing the object pointer directly to the destination
  690. // instead of first storing it in a local variable and then copying it to the
  691. // destination.
  692. if( !(type.GetObjectType()->flags & asOBJ_SCOPED) )
  693. {
  694. // Only dereference the variable if not a scoped type
  695. ctx.bc.Instr(asBC_RDSPtr);
  696. }
  697. if( isVarGlobOrMem == 1 )
  698. {
  699. // Store the returned handle in the global variable
  700. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  701. }
  702. else
  703. {
  704. // Store the returned handle in the class member
  705. ctx.bc.InstrSHORT(asBC_PSF, 0);
  706. ctx.bc.Instr(asBC_RDSPtr);
  707. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
  708. }
  709. if( type.GetObjectType()->flags & asOBJ_SCOPED )
  710. {
  711. // For scoped typed we must move the reference from the local
  712. // variable rather than copy it as there is no AddRef behaviour
  713. ctx.bc.InstrSHORT_DW(asBC_COPY, AS_PTR_SIZE, asTYPEID_OBJHANDLE | engine->GetTypeIdFromDataType(type));
  714. // Clear the local variable so the reference isn't released
  715. ctx.bc.InstrSHORT(asBC_ClrVPtr, ctx.type.stackOffset);
  716. }
  717. else
  718. {
  719. ctx.bc.InstrPTR(asBC_REFCPY, type.GetObjectType());
  720. }
  721. ctx.bc.Instr(asBC_PopPtr);
  722. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  723. }
  724. bc->AddCode(&ctx.bc);
  725. return 0;
  726. }
  727. }
  728. else
  729. {
  730. asSTypeBehaviour *beh = type.GetBehaviour();
  731. int func = 0;
  732. if( beh ) func = beh->construct;
  733. // Allocate and initialize with the default constructor
  734. if( func != 0 || (type.GetObjectType()->flags & asOBJ_POD) )
  735. {
  736. if( !isObjectOnHeap )
  737. {
  738. asASSERT( isVarGlobOrMem == 0 );
  739. // There is nothing to do if there is no function,
  740. // as the memory is already allocated on the stack
  741. if( func )
  742. {
  743. // Call the constructor as a normal function
  744. bc->InstrSHORT(asBC_PSF, (short)offset);
  745. if( derefDest )
  746. bc->Instr(asBC_RDSPtr);
  747. asSExprContext ctx(engine);
  748. PerformFunctionCall(func, &ctx, false, 0, type.GetObjectType());
  749. bc->AddCode(&ctx.bc);
  750. // TODO: value on stack: This probably needs to be done in PerformFunctionCall
  751. // Mark the object as initialized
  752. bc->ObjInfo(offset, asOBJ_INIT);
  753. }
  754. }
  755. else
  756. {
  757. if( isVarGlobOrMem == 0 )
  758. bc->InstrSHORT(asBC_PSF, (short)offset);
  759. else if( isVarGlobOrMem == 1 )
  760. bc->InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  761. else
  762. {
  763. bc->InstrSHORT(asBC_PSF, 0);
  764. bc->Instr(asBC_RDSPtr);
  765. bc->InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
  766. }
  767. bc->Alloc(asBC_ALLOC, type.GetObjectType(), func, AS_PTR_SIZE);
  768. }
  769. return 0;
  770. }
  771. }
  772. // Class has no default factory/constructor.
  773. asCString str;
  774. // TODO: funcdef: asCDataType should have a GetTypeName()
  775. if( type.GetFuncDef() )
  776. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, type.GetFuncDef()->GetName());
  777. else
  778. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, type.GetObjectType()->GetName());
  779. Error(str, node);
  780. return -1;
  781. }
  782. void asCCompiler::CallDestructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc)
  783. {
  784. if( !type.IsReference() )
  785. {
  786. // Call destructor for the data type
  787. if( type.IsObject() )
  788. {
  789. // Nothing is done for list pattern types, as this is taken care of by the CompileInitList method
  790. if( type.GetObjectType()->flags & asOBJ_LIST_PATTERN )
  791. return;
  792. if( isObjectOnHeap || type.IsObjectHandle() )
  793. {
  794. // Free the memory
  795. bc->InstrW_PTR(asBC_FREE, (short)offset, type.GetObjectType());
  796. }
  797. else
  798. {
  799. asASSERT( type.GetObjectType()->GetFlags() & asOBJ_VALUE );
  800. if( type.GetBehaviour()->destruct )
  801. {
  802. // Call the destructor as a regular function
  803. asSExprContext ctx(engine);
  804. ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
  805. PerformFunctionCall(type.GetBehaviour()->destruct, &ctx);
  806. ctx.bc.OptimizeLocally(tempVariableOffsets);
  807. bc->AddCode(&ctx.bc);
  808. }
  809. // TODO: Value on stack: This probably needs to be done in PerformFunctionCall
  810. // Mark the object as destroyed
  811. bc->ObjInfo(offset, asOBJ_UNINIT);
  812. }
  813. }
  814. }
  815. }
  816. void asCCompiler::LineInstr(asCByteCode *bc, size_t pos)
  817. {
  818. int r, c;
  819. script->ConvertPosToRowCol(pos, &r, &c);
  820. bc->Line(r, c, script->idx);
  821. }
  822. void asCCompiler::CompileStatementBlock(asCScriptNode *block, bool ownVariableScope, bool *hasReturn, asCByteCode *bc)
  823. {
  824. *hasReturn = false;
  825. bool isFinished = false;
  826. bool hasUnreachableCode = false;
  827. bool hasReturnBefore = false;
  828. if( ownVariableScope )
  829. {
  830. bc->Block(true);
  831. AddVariableScope();
  832. }
  833. asCScriptNode *node = block->firstChild;
  834. while( node )
  835. {
  836. if( !hasUnreachableCode && (*hasReturn || isFinished) )
  837. {
  838. // Empty statements don't count
  839. if( node->nodeType != snExpressionStatement || node->firstChild )
  840. {
  841. hasUnreachableCode = true;
  842. Warning(TXT_UNREACHABLE_CODE, node);
  843. }
  844. if( *hasReturn )
  845. hasReturnBefore = true;
  846. }
  847. if( node->nodeType == snBreak || node->nodeType == snContinue )
  848. isFinished = true;
  849. asCByteCode statement(engine);
  850. if( node->nodeType == snDeclaration )
  851. CompileDeclaration(node, &statement);
  852. else
  853. CompileStatement(node, hasReturn, &statement);
  854. // Ignore missing returns in unreachable code paths
  855. if( !(*hasReturn) && hasReturnBefore )
  856. *hasReturn = true;
  857. LineInstr(bc, node->tokenPos);
  858. bc->AddCode(&statement);
  859. if( !hasCompileErrors )
  860. {
  861. asASSERT( tempVariables.GetLength() == 0 );
  862. asASSERT( reservedVariables.GetLength() == 0 );
  863. }
  864. node = node->next;
  865. }
  866. if( ownVariableScope )
  867. {
  868. // Deallocate variables in this block, in reverse order
  869. for( int n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  870. {
  871. sVariable *v = variables->variables[n];
  872. // Call variable destructors here, for variables not yet destroyed
  873. // If the block is terminated with a break, continue, or
  874. // return the variables are already destroyed
  875. if( !isFinished && !*hasReturn )
  876. CallDestructor(v->type, v->stackOffset, v->onHeap, bc);
  877. // Don't deallocate function parameters
  878. if( v->stackOffset > 0 )
  879. DeallocateVariable(v->stackOffset);
  880. }
  881. RemoveVariableScope();
  882. bc->Block(false);
  883. }
  884. }
  885. // Entry
  886. int asCCompiler::CompileGlobalVariable(asCBuilder *builder, asCScriptCode *script, asCScriptNode *node, sGlobalVariableDescription *gvar, asCScriptFunction *outFunc)
  887. {
  888. Reset(builder, script, outFunc);
  889. // Add a variable scope (even though variables can't be declared)
  890. AddVariableScope();
  891. gvar->isPureConstant = false;
  892. // Parse the initialization nodes
  893. asCParser parser(builder);
  894. if( node )
  895. {
  896. int r = parser.ParseVarInit(script, node);
  897. if( r < 0 )
  898. return r;
  899. node = parser.GetScriptNode();
  900. }
  901. // Compile the expression
  902. asSExprContext ctx(engine);
  903. asQWORD constantValue;
  904. if( CompileInitialization(node, &ctx.bc, gvar->datatype, gvar->idNode, gvar->index, &constantValue, 1) )
  905. {
  906. // Should the variable be marked as pure constant?
  907. if( gvar->datatype.IsPrimitive() && gvar->datatype.IsReadOnly() )
  908. {
  909. gvar->isPureConstant = true;
  910. gvar->constantValue = constantValue;
  911. }
  912. }
  913. // Concatenate the bytecode
  914. int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1;
  915. // Add information on the line number for the global variable
  916. size_t pos = 0;
  917. if( gvar->idNode )
  918. pos = gvar->idNode->tokenPos;
  919. else if( gvar->nextNode )
  920. pos = gvar->nextNode->tokenPos;
  921. LineInstr(&byteCode, pos);
  922. // Reserve space for all local variables
  923. outFunc->scriptData->variableSpace = varSize;
  924. ctx.bc.OptimizeLocally(tempVariableOffsets);
  925. byteCode.AddCode(&ctx.bc);
  926. // Deallocate variables in this block, in reverse order
  927. for( int n = (int)variables->variables.GetLength() - 1; n >= 0; --n )
  928. {
  929. sVariable *v = variables->variables[n];
  930. // Call variable destructors here, for variables not yet destroyed
  931. CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode);
  932. DeallocateVariable(v->stackOffset);
  933. }
  934. if( hasCompileErrors ) return -1;
  935. // At this point there should be no variables allocated
  936. asASSERT(variableAllocations.GetLength() == freeVariables.GetLength());
  937. // Remove the variable scope again
  938. RemoveVariableScope();
  939. byteCode.Ret(0);
  940. FinalizeFunction();
  941. #ifdef AS_DEBUG
  942. // DEBUG: output byte code
  943. byteCode.DebugOutput(("___init_" + gvar->name + ".txt").AddressOf(), engine, outFunc);
  944. #endif
  945. return 0;
  946. }
  947. void asCCompiler::DetermineSingleFunc(asSExprContext *ctx, asCScriptNode *node)
  948. {
  949. // Don't do anything if this is not a deferred global function
  950. if( !ctx->IsGlobalFunc() )
  951. return;
  952. // Determine the namespace
  953. asSNameSpace *ns = 0;
  954. asCString name = "";
  955. int pos = ctx->methodName.FindLast("::");
  956. if( pos >= 0 )
  957. {
  958. asCString nsName = ctx->methodName.SubString(0, pos+2);
  959. ns = DetermineNameSpace(nsName);
  960. name = ctx->methodName.SubString(pos+2);
  961. }
  962. else
  963. {
  964. DetermineNameSpace("");
  965. name = ctx->methodName;
  966. }
  967. asCArray<int> funcs;
  968. if( ns )
  969. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  970. // CompileVariableAccess should guarantee that at least one function is exists
  971. asASSERT( funcs.GetLength() > 0 );
  972. if( funcs.GetLength() > 1 )
  973. {
  974. asCString str;
  975. str.Format(TXT_MULTIPLE_MATCHING_SIGNATURES_TO_s, ctx->methodName.AddressOf());
  976. Error(str, node);
  977. // Fall through so the compiler can continue as if only one function was matching
  978. }
  979. // A shared object may not access global functions unless they too are shared (e.g. registered functions)
  980. if( !builder->GetFunctionDescription(funcs[0])->IsShared() &&
  981. outFunc->IsShared() )
  982. {
  983. asCString msg;
  984. msg.Format(TXT_SHARED_CANNOT_CALL_NON_SHARED_FUNC_s, builder->GetFunctionDescription(funcs[0])->GetDeclaration());
  985. Error(msg, node);
  986. // Fall through so the compiler can continue anyway
  987. }
  988. // Push the function pointer on the stack
  989. ctx->bc.InstrPTR(asBC_FuncPtr, builder->GetFunctionDescription(funcs[0]));
  990. ctx->type.Set(asCDataType::CreateFuncDef(builder->GetFunctionDescription(funcs[0])));
  991. ctx->type.dataType.MakeHandle(true);
  992. ctx->type.isExplicitHandle = true;
  993. ctx->methodName = "";
  994. }
  995. void asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, asCScriptNode *node, bool isFunction, int refType, bool isMakingCopy)
  996. {
  997. asCDataType param = *paramType;
  998. if( paramType->GetTokenType() == ttQuestion )
  999. {
  1000. // The function is expecting a var type. If the argument is a function name, we must now decide which function it is
  1001. DetermineSingleFunc(ctx, node);
  1002. // Since the function is expecting a var type ?, then we don't want to convert the argument to anything else
  1003. param = ctx->type.dataType;
  1004. param.MakeHandle(ctx->type.isExplicitHandle || ctx->type.IsNullConstant());
  1005. // If value assign is disabled for reference types, then make
  1006. // sure to always pass the handle to ? parameters
  1007. if( builder->engine->ep.disallowValueAssignForRefType &&
  1008. ctx->type.dataType.GetObjectType() && (ctx->type.dataType.GetObjectType()->flags & asOBJ_REF) && !(ctx->type.dataType.GetObjectType()->flags & asOBJ_SCOPED) )
  1009. {
  1010. param.MakeHandle(true);
  1011. }
  1012. param.MakeReference(paramType->IsReference());
  1013. param.MakeReadOnly(paramType->IsReadOnly());
  1014. }
  1015. else
  1016. param = *paramType;
  1017. asCDataType dt = param;
  1018. // Need to protect arguments by reference
  1019. if( isFunction && dt.IsReference() )
  1020. {
  1021. // Allocate a temporary variable of the same type as the argument
  1022. dt.MakeReference(false);
  1023. dt.MakeReadOnly(false);
  1024. int offset;
  1025. if( refType == 1 ) // &in
  1026. {
  1027. ProcessPropertyGetAccessor(ctx, node);
  1028. // Add the type id as hidden arg if the parameter is a ? type
  1029. if( paramType->GetTokenType() == ttQuestion )
  1030. {
  1031. asCByteCode tmpBC(engine);
  1032. // Place the type id on the stack as a hidden parameter
  1033. tmpBC.InstrDWORD(asBC_TYPEID, engine->GetTypeIdFromDataType(param));
  1034. // Insert the code before the expression code
  1035. tmpBC.AddCode(&ctx->bc);
  1036. ctx->bc.AddCode(&tmpBC);
  1037. }
  1038. // If the reference is const, then it is not necessary to make a copy if the value already is a variable
  1039. // Even if the same variable is passed in another argument as non-const then there is no problem
  1040. if( dt.IsPrimitive() || dt.IsNullHandle() )
  1041. {
  1042. IsVariableInitialized(&ctx->type, node);
  1043. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  1044. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true);
  1045. if( !(param.IsReadOnly() && ctx->type.isVariable) )
  1046. ConvertToTempVariable(ctx);
  1047. PushVariableOnStack(ctx, true);
  1048. ctx->type.dataType.MakeReadOnly(param.IsReadOnly());
  1049. }
  1050. else
  1051. {
  1052. IsVariableInitialized(&ctx->type, node);
  1053. if( !isMakingCopy )
  1054. {
  1055. ImplicitConversion(ctx, param, node, asIC_IMPLICIT_CONV, true);
  1056. if( !ctx->type.dataType.IsEqualExceptRef(param) )
  1057. {
  1058. asCString str;
  1059. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), param.Format().AddressOf());
  1060. Error(str, node);
  1061. ctx->type.Set(param);
  1062. }
  1063. }
  1064. // If the argument already is a temporary
  1065. // variable we don't need to allocate another
  1066. // If the parameter is read-only and the object already is a local
  1067. // variable then it is not necessary to make a copy either
  1068. if( !ctx->type.isTemporary && !(param.IsReadOnly() && ctx->type.isVariable) && !isMakingCopy )
  1069. {
  1070. // Make sure the variable is not used in the expression
  1071. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1072. // TODO: copy: Use copy constructor if available. See PrepareTemporaryObject()
  1073. // Allocate and construct the temporary object
  1074. asCByteCode tmpBC(engine);
  1075. CallDefaultConstructor(dt, offset, IsVariableOnHeap(offset), &tmpBC, node);
  1076. // Insert the code before the expression code
  1077. tmpBC.AddCode(&ctx->bc);
  1078. ctx->bc.AddCode(&tmpBC);
  1079. // Assign the evaluated expression to the temporary variable
  1080. PrepareForAssignment(&dt, ctx, node, true);
  1081. dt.MakeReference(IsVariableOnHeap(offset));
  1082. asCTypeInfo type;
  1083. type.Set(dt);
  1084. type.isTemporary = true;
  1085. type.stackOffset = (short)offset;
  1086. if( dt.IsObjectHandle() )
  1087. type.isExplicitHandle = true;
  1088. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  1089. PerformAssignment(&type, &ctx->type, &ctx->bc, node);
  1090. ctx->bc.Instr(asBC_PopPtr);
  1091. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  1092. ctx->type.Set(dt);
  1093. ctx->type.isTemporary = true;
  1094. ctx->type.stackOffset = offset;
  1095. if( dt.IsObjectHandle() )
  1096. ctx->type.isExplicitHandle = true;
  1097. ctx->type.dataType.MakeReference(false);
  1098. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  1099. if( dt.IsObject() && !dt.IsObjectHandle() )
  1100. ctx->bc.Instr(asBC_RDSPtr);
  1101. if( paramType->IsReadOnly() )
  1102. ctx->type.dataType.MakeReadOnly(true);
  1103. }
  1104. else if( isMakingCopy )
  1105. {
  1106. // We must guarantee that the address to the value is on the stack
  1107. if( ctx->type.dataType.IsObject() &&
  1108. !ctx->type.dataType.IsObjectHandle() &&
  1109. ctx->type.dataType.IsReference() )
  1110. Dereference(ctx, true);
  1111. }
  1112. }
  1113. }
  1114. else if( refType == 2 ) // &out
  1115. {
  1116. // Add the type id as hidden arg if the parameter is a ? type
  1117. if( paramType->GetTokenType() == ttQuestion )
  1118. {
  1119. asCByteCode tmpBC(engine);
  1120. // Place the type id on the stack as a hidden parameter
  1121. tmpBC.InstrDWORD(asBC_TYPEID, engine->GetTypeIdFromDataType(param));
  1122. // Insert the code before the expression code
  1123. tmpBC.AddCode(&ctx->bc);
  1124. ctx->bc.AddCode(&tmpBC);
  1125. }
  1126. // Make sure the variable is not used in the expression
  1127. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1128. if( dt.IsPrimitive() )
  1129. {
  1130. ctx->type.SetVariable(dt, offset, true);
  1131. PushVariableOnStack(ctx, true);
  1132. }
  1133. else
  1134. {
  1135. // Allocate and construct the temporary object
  1136. asCByteCode tmpBC(engine);
  1137. CallDefaultConstructor(dt, offset, IsVariableOnHeap(offset), &tmpBC, node);
  1138. // Insert the code before the expression code
  1139. tmpBC.AddCode(&ctx->bc);
  1140. ctx->bc.AddCode(&tmpBC);
  1141. dt.MakeReference((!dt.IsObject() || dt.IsObjectHandle()));
  1142. asCTypeInfo type;
  1143. type.Set(dt);
  1144. type.isTemporary = true;
  1145. type.stackOffset = (short)offset;
  1146. ctx->type = type;
  1147. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  1148. if( dt.IsObject() && !dt.IsObjectHandle() )
  1149. ctx->bc.Instr(asBC_RDSPtr);
  1150. }
  1151. // After the function returns the temporary variable will
  1152. // be assigned to the expression, if it is a valid lvalue
  1153. }
  1154. else if( refType == asTM_INOUTREF )
  1155. {
  1156. ProcessPropertyGetAccessor(ctx, node);
  1157. // Add the type id as hidden arg if the parameter is a ? type
  1158. if( paramType->GetTokenType() == ttQuestion )
  1159. {
  1160. asCByteCode tmpBC(engine);
  1161. // Place the type id on the stack as a hidden parameter
  1162. tmpBC.InstrDWORD(asBC_TYPEID, engine->GetTypeIdFromDataType(param));
  1163. // Insert the code before the expression code
  1164. tmpBC.AddCode(&ctx->bc);
  1165. ctx->bc.AddCode(&tmpBC);
  1166. }
  1167. // Literal constants cannot be passed to inout ref arguments
  1168. if( !ctx->type.isVariable && ctx->type.isConstant )
  1169. {
  1170. Error(TXT_NOT_VALID_REFERENCE, node);
  1171. }
  1172. // Only objects that support object handles
  1173. // can be guaranteed to be safe. Local variables are
  1174. // already safe, so there is no need to add an extra
  1175. // references
  1176. if( !engine->ep.allowUnsafeReferences &&
  1177. !ctx->type.isVariable &&
  1178. ctx->type.dataType.IsObject() &&
  1179. !ctx->type.dataType.IsObjectHandle() &&
  1180. ((ctx->type.dataType.GetBehaviour()->addref &&
  1181. ctx->type.dataType.GetBehaviour()->release) ||
  1182. (ctx->type.dataType.GetObjectType()->flags & asOBJ_NOCOUNT)) )
  1183. {
  1184. // Store a handle to the object as local variable
  1185. asSExprContext tmp(engine);
  1186. asCDataType dt = ctx->type.dataType;
  1187. dt.MakeHandle(true);
  1188. dt.MakeReference(false);
  1189. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1190. // Copy the handle
  1191. if( !ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReference() )
  1192. ctx->bc.Instr(asBC_RDSPtr);
  1193. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1194. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetObjectType());
  1195. ctx->bc.Instr(asBC_PopPtr);
  1196. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1197. dt.MakeHandle(false);
  1198. dt.MakeReference(true);
  1199. // Release previous temporary variable stored in the context (if any)
  1200. if( ctx->type.isTemporary )
  1201. {
  1202. ReleaseTemporaryVariable(ctx->type.stackOffset, &ctx->bc);
  1203. }
  1204. ctx->type.SetVariable(dt, offset, true);
  1205. }
  1206. // Make sure the reference to the value is on the stack
  1207. // For objects, the reference needs to be dereferenced so the pointer on the stack is to the actual object
  1208. // For handles, the reference shouldn't be changed because the pointer on the stack should be to the handle
  1209. if( ctx->type.dataType.IsObject() && ctx->type.dataType.IsReference() && !param.IsObjectHandle() )
  1210. Dereference(ctx, true);
  1211. else if( ctx->type.isVariable && !ctx->type.dataType.IsObject() )
  1212. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  1213. else if( ctx->type.dataType.IsPrimitive() )
  1214. ctx->bc.Instr(asBC_PshRPtr);
  1215. else if( ctx->type.dataType.IsObjectHandle() && !ctx->type.dataType.IsReference() )
  1216. ImplicitConversion(ctx, param, node, asIC_IMPLICIT_CONV, true, false);
  1217. }
  1218. }
  1219. else
  1220. {
  1221. ProcessPropertyGetAccessor(ctx, node);
  1222. if( dt.IsPrimitive() )
  1223. {
  1224. IsVariableInitialized(&ctx->type, node);
  1225. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  1226. // Implicitly convert primitives to the parameter type
  1227. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV);
  1228. if( ctx->type.isVariable )
  1229. {
  1230. PushVariableOnStack(ctx, dt.IsReference());
  1231. }
  1232. else if( ctx->type.isConstant )
  1233. {
  1234. ConvertToVariable(ctx);
  1235. PushVariableOnStack(ctx, dt.IsReference());
  1236. }
  1237. }
  1238. else
  1239. {
  1240. IsVariableInitialized(&ctx->type, node);
  1241. // Implicitly convert primitives to the parameter type
  1242. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV);
  1243. // Was the conversion successful?
  1244. if( !ctx->type.dataType.IsEqualExceptRef(dt) )
  1245. {
  1246. asCString str;
  1247. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), dt.Format().AddressOf());
  1248. Error(str, node);
  1249. ctx->type.Set(dt);
  1250. }
  1251. if( dt.IsObjectHandle() )
  1252. ctx->type.isExplicitHandle = true;
  1253. if( dt.IsObject() )
  1254. {
  1255. if( !dt.IsReference() )
  1256. {
  1257. // Objects passed by value must be placed in temporary variables
  1258. // so that they are guaranteed to not be referenced anywhere else.
  1259. // The object must also be allocated on the heap, as the memory will
  1260. // be deleted by in as_callfunc_xxx.
  1261. // TODO: value on stack: How can we avoid this unnecessary allocation?
  1262. // Local variables doesn't need to be copied into
  1263. // a temp if we're already compiling an assignment
  1264. if( !isMakingCopy || !ctx->type.dataType.IsObjectHandle() || !ctx->type.isVariable )
  1265. PrepareTemporaryObject(node, ctx, true);
  1266. // The implicit conversion shouldn't convert the object to
  1267. // non-reference yet. It will be dereferenced just before the call.
  1268. // Otherwise the object might be missed by the exception handler.
  1269. dt.MakeReference(true);
  1270. }
  1271. else
  1272. {
  1273. // An object passed by reference should place the pointer to
  1274. // the object on the stack.
  1275. dt.MakeReference(false);
  1276. }
  1277. }
  1278. }
  1279. }
  1280. // Don't put any pointer on the stack yet
  1281. if( param.IsReference() || param.IsObject() )
  1282. {
  1283. // &inout parameter may leave the reference on the stack already
  1284. if( refType != 3 )
  1285. {
  1286. asASSERT( ctx->type.isVariable || ctx->type.isTemporary || isMakingCopy );
  1287. if( ctx->type.isVariable || ctx->type.isTemporary )
  1288. {
  1289. ctx->bc.Instr(asBC_PopPtr);
  1290. ctx->bc.InstrSHORT(asBC_VAR, ctx->type.stackOffset);
  1291. ProcessDeferredParams(ctx);
  1292. }
  1293. }
  1294. }
  1295. }
  1296. void asCCompiler::PrepareFunctionCall(int funcId, asCByteCode *bc, asCArray<asSExprContext *> &args)
  1297. {
  1298. // When a match has been found, compile the final byte code using correct parameter types
  1299. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  1300. // If the function being called is the opAssign or copy constructor for the same type
  1301. // as the argument, then we should avoid making temporary copy of the argument
  1302. bool makingCopy = false;
  1303. if( descr->parameterTypes.GetLength() == 1 &&
  1304. descr->parameterTypes[0].IsEqualExceptRefAndConst(args[0]->type.dataType) &&
  1305. ((descr->name == "opAssign" && descr->objectType && descr->objectType == args[0]->type.dataType.GetObjectType()) ||
  1306. (args[0]->type.dataType.GetObjectType() && descr->name == args[0]->type.dataType.GetObjectType()->name)) )
  1307. makingCopy = true;
  1308. // Add code for arguments
  1309. asSExprContext e(engine);
  1310. for( int n = (int)args.GetLength()-1; n >= 0; n-- )
  1311. {
  1312. // Make sure PrepareArgument doesn't use any variable that is already
  1313. // being used by any of the following argument expressions
  1314. int l = int(reservedVariables.GetLength());
  1315. for( int m = n-1; m >= 0; m-- )
  1316. args[m]->bc.GetVarsUsed(reservedVariables);
  1317. PrepareArgument2(&e, args[n], &descr->parameterTypes[n], true, descr->inOutFlags[n], makingCopy);
  1318. reservedVariables.SetLength(l);
  1319. }
  1320. bc->AddCode(&e.bc);
  1321. }
  1322. void asCCompiler::MoveArgsToStack(int funcId, asCByteCode *bc, asCArray<asSExprContext *> &args, bool addOneToOffset)
  1323. {
  1324. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  1325. int offset = 0;
  1326. if( addOneToOffset )
  1327. offset += AS_PTR_SIZE;
  1328. // The address of where the return value should be stored is push on top of the arguments
  1329. if( descr->DoesReturnOnStack() )
  1330. offset += AS_PTR_SIZE;
  1331. #ifdef AS_DEBUG
  1332. // If the function being called is the opAssign or copy constructor for the same type
  1333. // as the argument, then we should avoid making temporary copy of the argument
  1334. bool makingCopy = false;
  1335. if( descr->parameterTypes.GetLength() == 1 &&
  1336. descr->parameterTypes[0].IsEqualExceptRefAndConst(args[0]->type.dataType) &&
  1337. ((descr->name == "opAssign" && descr->objectType && descr->objectType == args[0]->type.dataType.GetObjectType()) ||
  1338. (args[0]->type.dataType.GetObjectType() && descr->name == args[0]->type.dataType.GetObjectType()->name)) )
  1339. makingCopy = true;
  1340. #endif
  1341. // Move the objects that are sent by value to the stack just before the call
  1342. for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ )
  1343. {
  1344. if( descr->parameterTypes[n].IsReference() )
  1345. {
  1346. if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() )
  1347. {
  1348. if( descr->inOutFlags[n] != asTM_INOUTREF )
  1349. {
  1350. #ifdef AS_DEBUG
  1351. asASSERT( args[n]->type.isVariable || args[n]->type.isTemporary || makingCopy );
  1352. #endif
  1353. if( (args[n]->type.isVariable || args[n]->type.isTemporary) )
  1354. {
  1355. if( !IsVariableOnHeap(args[n]->type.stackOffset) )
  1356. // TODO: runtime optimize: Actually the reference can be pushed on the stack directly
  1357. // as the value allocated on the stack is guaranteed to be safe
  1358. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1359. else
  1360. bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset);
  1361. }
  1362. }
  1363. if( args[n]->type.dataType.IsObjectHandle() )
  1364. bc->InstrWORD(asBC_ChkNullS, (asWORD)offset);
  1365. }
  1366. else if( descr->inOutFlags[n] != asTM_INOUTREF )
  1367. {
  1368. if( descr->parameterTypes[n].GetTokenType() == ttQuestion &&
  1369. args[n]->type.dataType.IsObject() && !args[n]->type.dataType.IsObjectHandle() )
  1370. {
  1371. // Send the object as a reference to the object,
  1372. // and not to the variable holding the object
  1373. if( !IsVariableOnHeap(args[n]->type.stackOffset) )
  1374. // TODO: runtime optimize: Actually the reference can be pushed on the stack directly
  1375. // as the value allocated on the stack is guaranteed to be safe
  1376. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1377. else
  1378. bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset);
  1379. }
  1380. else
  1381. {
  1382. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1383. }
  1384. }
  1385. }
  1386. else if( descr->parameterTypes[n].IsObject() )
  1387. {
  1388. // TODO: value on stack: What can we do to avoid this unnecessary allocation?
  1389. // The object must be allocated on the heap, because this memory will be deleted in as_callfunc_xxx
  1390. asASSERT(IsVariableOnHeap(args[n]->type.stackOffset));
  1391. bc->InstrWORD(asBC_GETOBJ, (asWORD)offset);
  1392. // The temporary variable must not be freed as it will no longer hold an object
  1393. DeallocateVariable(args[n]->type.stackOffset);
  1394. args[n]->type.isTemporary = false;
  1395. }
  1396. offset += descr->parameterTypes[n].GetSizeOnStackDWords();
  1397. }
  1398. }
  1399. int asCCompiler::CompileArgumentList(asCScriptNode *node, asCArray<asSExprContext*> &args)
  1400. {
  1401. asASSERT(node->nodeType == snArgList);
  1402. // Count arguments
  1403. asCScriptNode *arg = node->firstChild;
  1404. int argCount = 0;
  1405. while( arg )
  1406. {
  1407. argCount++;
  1408. arg = arg->next;
  1409. }
  1410. // Prepare the arrays
  1411. args.SetLength(argCount);
  1412. int n;
  1413. for( n = 0; n < argCount; n++ )
  1414. args[n] = 0;
  1415. n = argCount-1;
  1416. // Compile the arguments in reverse order (as they will be pushed on the stack)
  1417. bool anyErrors = false;
  1418. arg = node->lastChild;
  1419. while( arg )
  1420. {
  1421. asSExprContext expr(engine);
  1422. int r = CompileAssignment(arg, &expr);
  1423. if( r < 0 ) anyErrors = true;
  1424. args[n] = asNEW(asSExprContext)(engine);
  1425. if( args[n] == 0 )
  1426. {
  1427. // Out of memory
  1428. return -1;
  1429. }
  1430. MergeExprBytecodeAndType(args[n], &expr);
  1431. n--;
  1432. arg = arg->prev;
  1433. }
  1434. return anyErrors ? -1 : 0;
  1435. }
  1436. int asCCompiler::CompileDefaultArgs(asCScriptNode *node, asCArray<asSExprContext*> &args, asCScriptFunction *func)
  1437. {
  1438. bool anyErrors = false;
  1439. asCArray<int> varsUsed;
  1440. int explicitArgs = (int)args.GetLength();
  1441. for( int p = 0; p < explicitArgs; p++ )
  1442. args[p]->bc.GetVarsUsed(varsUsed);
  1443. // Compile the arguments in reverse order (as they will be pushed on the stack)
  1444. args.SetLength(func->parameterTypes.GetLength());
  1445. for( asUINT c = explicitArgs; c < args.GetLength(); c++ )
  1446. args[c] = 0;
  1447. for( int n = (int)func->parameterTypes.GetLength() - 1; n >= explicitArgs; n-- )
  1448. {
  1449. if( func->defaultArgs[n] == 0 ) { anyErrors = true; continue; }
  1450. // Parse the default arg string
  1451. asCParser parser(builder);
  1452. asCScriptCode code;
  1453. code.SetCode("default arg", func->defaultArgs[n]->AddressOf(), false);
  1454. int r = parser.ParseExpression(&code);
  1455. if( r < 0 )
  1456. {
  1457. asCString msg;
  1458. msg.Format(TXT_FAILED_TO_COMPILE_DEF_ARG_d_IN_FUNC_s, n, func->GetDeclaration());
  1459. Error(msg, node);
  1460. anyErrors = true;
  1461. continue;
  1462. }
  1463. asCScriptNode *arg = parser.GetScriptNode();
  1464. // Temporarily set the script code to the default arg expression
  1465. asCScriptCode *origScript = script;
  1466. script = &code;
  1467. // Don't allow the expression to access local variables
  1468. // TODO: namespace: The default arg should see the symbols declared in the same scope as the function that is called
  1469. isCompilingDefaultArg = true;
  1470. asSExprContext expr(engine);
  1471. r = CompileExpression(arg, &expr);
  1472. // Don't allow address of class method
  1473. if( expr.methodName != "" )
  1474. {
  1475. // TODO: Improve error message
  1476. Error(TXT_DEF_ARG_TYPE_DOESNT_MATCH, arg);
  1477. r = -1;
  1478. }
  1479. // Make sure the expression can be implicitly converted to the parameter type
  1480. if( r >= 0 )
  1481. {
  1482. asCArray<int> funcs;
  1483. funcs.PushLast(func->id);
  1484. asCArray<asSOverloadCandidate> matches;
  1485. if( MatchArgument(funcs, matches, &expr, n) == 0 )
  1486. {
  1487. Error(TXT_DEF_ARG_TYPE_DOESNT_MATCH, arg);
  1488. r = -1;
  1489. }
  1490. }
  1491. isCompilingDefaultArg = false;
  1492. script = origScript;
  1493. if( r < 0 )
  1494. {
  1495. asCString msg;
  1496. msg.Format(TXT_FAILED_TO_COMPILE_DEF_ARG_d_IN_FUNC_s, n, func->GetDeclaration());
  1497. Error(msg, node);
  1498. anyErrors = true;
  1499. continue;
  1500. }
  1501. args[n] = asNEW(asSExprContext)(engine);
  1502. if( args[n] == 0 )
  1503. {
  1504. // Out of memory
  1505. return -1;
  1506. }
  1507. MergeExprBytecodeAndType(args[n], &expr);
  1508. // Make sure the default arg expression doesn't end up
  1509. // with a variable that is used in a previous expression
  1510. if( args[n]->type.isVariable )
  1511. {
  1512. int offset = args[n]->type.stackOffset;
  1513. if( varsUsed.Exists(offset) )
  1514. {
  1515. // Release the current temporary variable
  1516. ReleaseTemporaryVariable(args[n]->type, 0);
  1517. asCDataType dt = args[n]->type.dataType;
  1518. dt.MakeReference(false);
  1519. // Reserve all variables already used in the expression so none of them will be used
  1520. asCArray<int> used;
  1521. args[n]->bc.GetVarsUsed(used);
  1522. size_t prevReserved = reservedVariables.GetLength();
  1523. reservedVariables.Concatenate(used);
  1524. int newOffset = AllocateVariable(dt, true, IsVariableOnHeap(offset));
  1525. asASSERT( IsVariableOnHeap(offset) == IsVariableOnHeap(newOffset) );
  1526. reservedVariables.SetLength(prevReserved);
  1527. // Replace the variable in the expression
  1528. args[n]->bc.ExchangeVar(offset, newOffset);
  1529. args[n]->type.stackOffset = (short)newOffset;
  1530. args[n]->type.isTemporary = true;
  1531. args[n]->type.isVariable = true;
  1532. }
  1533. }
  1534. }
  1535. return anyErrors ? -1 : 0;
  1536. }
  1537. asUINT asCCompiler::MatchFunctions(asCArray<int> &funcs, asCArray<asSExprContext*> &args, asCScriptNode *node, const char *name, asCObjectType *objectType, bool isConstMethod, bool silent, bool allowObjectConstruct, const asCString &scope)
  1538. {
  1539. asCArray<int> origFuncs = funcs; // Keep the original list for error message
  1540. asUINT cost = 0;
  1541. asUINT n;
  1542. if( funcs.GetLength() > 0 )
  1543. {
  1544. // Check the number of parameters in the found functions
  1545. for( n = 0; n < funcs.GetLength(); ++n )
  1546. {
  1547. asCScriptFunction *desc = builder->GetFunctionDescription(funcs[n]);
  1548. if( desc->parameterTypes.GetLength() != args.GetLength() )
  1549. {
  1550. bool noMatch = true;
  1551. if( args.GetLength() < desc->parameterTypes.GetLength() )
  1552. {
  1553. // Count the number of default args
  1554. asUINT defaultArgs = 0;
  1555. for( asUINT d = 0; d < desc->defaultArgs.GetLength(); d++ )
  1556. if( desc->defaultArgs[d] )
  1557. defaultArgs++;
  1558. if( args.GetLength() >= desc->parameterTypes.GetLength() - defaultArgs )
  1559. noMatch = false;
  1560. }
  1561. if( noMatch )
  1562. {
  1563. // remove it from the list
  1564. if( n == funcs.GetLength()-1 )
  1565. funcs.PopLast();
  1566. else
  1567. funcs[n] = funcs.PopLast();
  1568. n--;
  1569. }
  1570. }
  1571. }
  1572. // Match functions with the parameters, and discard those that do not match
  1573. asCArray<asSOverloadCandidate> matchingFuncs;
  1574. matchingFuncs.SetLengthNoConstruct( funcs.GetLength() );
  1575. for ( n = 0; n < funcs.GetLength(); ++n )
  1576. {
  1577. matchingFuncs[n].funcId = funcs[n];
  1578. matchingFuncs[n].cost = 0;
  1579. }
  1580. for( n = 0; n < args.GetLength(); ++n )
  1581. {
  1582. asCArray<asSOverloadCandidate> tempFuncs;
  1583. MatchArgument(funcs, tempFuncs, args[n], n, allowObjectConstruct);
  1584. // Intersect the found functions with the list of matching functions
  1585. for( asUINT f = 0; f < matchingFuncs.GetLength(); f++ )
  1586. {
  1587. asUINT c;
  1588. for( c = 0; c < tempFuncs.GetLength(); c++ )
  1589. {
  1590. if( matchingFuncs[f].funcId == tempFuncs[c].funcId )
  1591. {
  1592. // Sum argument cost
  1593. matchingFuncs[f].cost += tempFuncs[c].cost;
  1594. break;
  1595. } // End if match
  1596. }
  1597. // Was the function a match?
  1598. if( c == tempFuncs.GetLength() )
  1599. {
  1600. // No, remove it from the list
  1601. if( f == matchingFuncs.GetLength()-1 )
  1602. matchingFuncs.PopLast();
  1603. else
  1604. matchingFuncs[f] = matchingFuncs.PopLast();
  1605. f--;
  1606. }
  1607. }
  1608. }
  1609. // Select the overload(s) with the lowest overall cost
  1610. funcs.SetLength(0);
  1611. asUINT bestCost = asUINT(-1);
  1612. for( n = 0; n < matchingFuncs.GetLength(); ++n )
  1613. {
  1614. cost = matchingFuncs[n].cost;
  1615. if( cost < bestCost )
  1616. {
  1617. funcs.SetLength(0);
  1618. bestCost = cost;
  1619. }
  1620. if( cost == bestCost )
  1621. funcs.PushLast( matchingFuncs[n].funcId );
  1622. }
  1623. // Cost returned is equivalent to the best cost discovered
  1624. cost = bestCost;
  1625. }
  1626. if( !isConstMethod )
  1627. FilterConst(funcs);
  1628. if( funcs.GetLength() != 1 && !silent )
  1629. {
  1630. // Build a readable string of the function with parameter types
  1631. asCString str;
  1632. if( scope != "" )
  1633. {
  1634. if( scope == "::" )
  1635. str = scope;
  1636. else
  1637. str = scope + "::";
  1638. }
  1639. str += name;
  1640. str += "(";
  1641. if( args.GetLength() )
  1642. {
  1643. if( args[0]->methodName != "" )
  1644. str += args[0]->methodName;
  1645. else
  1646. str += args[0]->type.dataType.Format();
  1647. }
  1648. for( n = 1; n < args.GetLength(); n++ )
  1649. {
  1650. str += ", ";
  1651. if( args[n]->methodName != "" )
  1652. str += args[n]->methodName;
  1653. else
  1654. str += args[n]->type.dataType.Format();
  1655. }
  1656. str += ")";
  1657. if( isConstMethod )
  1658. str += " const";
  1659. if( objectType && scope == "" )
  1660. str = objectType->name + "::" + str;
  1661. if( funcs.GetLength() == 0 )
  1662. {
  1663. str.Format(TXT_NO_MATCHING_SIGNATURES_TO_s, str.AddressOf());
  1664. Error(str, node);
  1665. // Print the list of candidates
  1666. if( origFuncs.GetLength() > 0 )
  1667. {
  1668. int r = 0, c = 0;
  1669. asASSERT( node );
  1670. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  1671. builder->WriteInfo(script->name.AddressOf(), TXT_CANDIDATES_ARE, r, c, false);
  1672. PrintMatchingFuncs(origFuncs, node);
  1673. }
  1674. }
  1675. else
  1676. {
  1677. str.Format(TXT_MULTIPLE_MATCHING_SIGNATURES_TO_s, str.AddressOf());
  1678. Error(str, node);
  1679. PrintMatchingFuncs(funcs, node);
  1680. }
  1681. }
  1682. return cost;
  1683. }
  1684. void asCCompiler::CompileDeclaration(asCScriptNode *decl, asCByteCode *bc)
  1685. {
  1686. // Get the data type
  1687. asCDataType type = builder->CreateDataTypeFromNode(decl->firstChild, script, outFunc->nameSpace);
  1688. // Declare all variables in this declaration
  1689. asCScriptNode *node = decl->firstChild->next;
  1690. while( node )
  1691. {
  1692. // Is the type allowed?
  1693. if( !type.CanBeInstanciated() )
  1694. {
  1695. asCString str;
  1696. // TODO: Change to "'type' cannot be declared as variable"
  1697. str.Format(TXT_DATA_TYPE_CANT_BE_s, type.Format().AddressOf());
  1698. Error(str, node);
  1699. // Use int instead to avoid further problems
  1700. type = asCDataType::CreatePrimitive(ttInt, false);
  1701. }
  1702. // A shared object may not declare variables of non-shared types
  1703. if( outFunc->IsShared() )
  1704. {
  1705. asCObjectType *ot = type.GetObjectType();
  1706. if( ot && !ot->IsShared() )
  1707. {
  1708. asCString msg;
  1709. msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, ot->name.AddressOf());
  1710. Error(msg, decl);
  1711. }
  1712. }
  1713. // Get the name of the identifier
  1714. asCString name(&script->code[node->tokenPos], node->tokenLength);
  1715. // Verify that the name isn't used by a dynamic data type
  1716. if( engine->GetObjectType(name.AddressOf(), outFunc->nameSpace) != 0 )
  1717. {
  1718. asCString str;
  1719. str.Format(TXT_ILLEGAL_VARIABLE_NAME_s, name.AddressOf());
  1720. Error(str, node);
  1721. }
  1722. int offset = AllocateVariable(type, false);
  1723. if( variables->DeclareVariable(name.AddressOf(), type, offset, IsVariableOnHeap(offset)) < 0 )
  1724. {
  1725. // TODO: It might be an out-of-memory too
  1726. asCString str;
  1727. str.Format(TXT_s_ALREADY_DECLARED, name.AddressOf());
  1728. Error(str, node);
  1729. // Don't continue after this error, as it will just
  1730. // lead to more errors that are likely false
  1731. return;
  1732. }
  1733. // Add marker that the variable has been declared
  1734. bc->VarDecl((int)outFunc->scriptData->variables.GetLength());
  1735. outFunc->AddVariable(name, type, offset);
  1736. // Keep the node for the variable decl
  1737. asCScriptNode *varNode = node;
  1738. node = node->next;
  1739. if( node == 0 || node->nodeType == snIdentifier )
  1740. {
  1741. // Initialize with default constructor
  1742. CompileInitialization(0, bc, type, varNode, offset, 0, 0);
  1743. }
  1744. else
  1745. {
  1746. // Compile the initialization expression
  1747. asQWORD constantValue = 0;
  1748. if( CompileInitialization(node, bc, type, varNode, offset, &constantValue, 0) )
  1749. {
  1750. // Check if the variable should be marked as pure constant
  1751. if( type.IsPrimitive() && type.IsReadOnly() )
  1752. {
  1753. sVariable *v = variables->GetVariable(name.AddressOf());
  1754. v->isPureConstant = true;
  1755. v->constantValue = constantValue;
  1756. }
  1757. }
  1758. node = node->next;
  1759. }
  1760. }
  1761. bc->OptimizeLocally(tempVariableOffsets);
  1762. }
  1763. bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, asCDataType &type, asCScriptNode *errNode, int offset, asQWORD *constantValue, int isVarGlobOrMem)
  1764. {
  1765. bool isConstantExpression = false;
  1766. if( node && node->nodeType == snArgList )
  1767. {
  1768. // Make sure it is an object and not a handle
  1769. if( type.GetObjectType() == 0 || type.IsObjectHandle() )
  1770. {
  1771. Error(TXT_MUST_BE_OBJECT, node);
  1772. }
  1773. else
  1774. {
  1775. // Compile the arguments
  1776. asCArray<asSExprContext *> args;
  1777. if( CompileArgumentList(node, args) >= 0 )
  1778. {
  1779. // Find all constructors
  1780. asCArray<int> funcs;
  1781. asSTypeBehaviour *beh = type.GetBehaviour();
  1782. if( beh )
  1783. {
  1784. if( type.GetObjectType()->flags & asOBJ_REF )
  1785. funcs = beh->factories;
  1786. else
  1787. funcs = beh->constructors;
  1788. }
  1789. asCString str = type.Format();
  1790. MatchFunctions(funcs, args, node, str.AddressOf());
  1791. if( funcs.GetLength() == 1 )
  1792. {
  1793. int r = asSUCCESS;
  1794. // Add the default values for arguments not explicitly supplied
  1795. asCScriptFunction *func = (funcs[0] & FUNC_IMPORTED) == 0 ? engine->scriptFunctions[funcs[0]] : 0;
  1796. if( func && args.GetLength() < (asUINT)func->GetParamCount() )
  1797. r = CompileDefaultArgs(node, args, func);
  1798. if( r == asSUCCESS )
  1799. {
  1800. asSExprContext ctx(engine);
  1801. if( type.GetObjectType() && (type.GetObjectType()->flags & asOBJ_REF) )
  1802. {
  1803. if( isVarGlobOrMem == 0 )
  1804. MakeFunctionCall(&ctx, funcs[0], 0, args, node, true, offset);
  1805. else
  1806. {
  1807. MakeFunctionCall(&ctx, funcs[0], 0, args, node);
  1808. ctx.bc.Instr(asBC_RDSPtr);
  1809. if( isVarGlobOrMem == 1 )
  1810. {
  1811. // Store the returned handle in the global variable
  1812. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  1813. }
  1814. else
  1815. {
  1816. // Store the returned handle in the member
  1817. ctx.bc.InstrSHORT(asBC_PSF, 0);
  1818. ctx.bc.Instr(asBC_RDSPtr);
  1819. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
  1820. }
  1821. ctx.bc.InstrPTR(asBC_REFCPY, type.GetObjectType());
  1822. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  1823. }
  1824. // Pop the reference left by the function call
  1825. ctx.bc.Instr(asBC_PopPtr);
  1826. }
  1827. else
  1828. {
  1829. bool onHeap = false;
  1830. if( isVarGlobOrMem == 0 )
  1831. {
  1832. // When the object is allocated on the heap, the address where the
  1833. // reference will be stored must be pushed on the stack before the
  1834. // arguments. This reference on the stack is safe, even if the script
  1835. // is suspended during the evaluation of the arguments.
  1836. onHeap = IsVariableOnHeap(offset);
  1837. if( onHeap )
  1838. ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
  1839. }
  1840. else
  1841. {
  1842. // Push the address of the location where the variable will be stored on the stack.
  1843. // This reference is safe, because the addresses of the global variables cannot change.
  1844. // TODO: When serialization of the context is implemented this will probably have to change,
  1845. // because this pointer may be on the stack while the context is suspended, and may
  1846. // be difficult to serialize as the context doesn't know that the value represents a
  1847. // pointer.
  1848. onHeap = true;
  1849. if( isVarGlobOrMem == 1 )
  1850. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  1851. else
  1852. {
  1853. ctx.bc.InstrSHORT(asBC_PSF, 0);
  1854. ctx.bc.Instr(asBC_RDSPtr);
  1855. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
  1856. }
  1857. }
  1858. PrepareFunctionCall(funcs[0], &ctx.bc, args);
  1859. MoveArgsToStack(funcs[0], &ctx.bc, args, false);
  1860. // When the object is allocated on the stack, the address to the
  1861. // object is pushed on the stack after the arguments as the object pointer
  1862. if( !onHeap )
  1863. ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
  1864. PerformFunctionCall(funcs[0], &ctx, onHeap, &args, type.GetObjectType());
  1865. if( isVarGlobOrMem == 0 )
  1866. {
  1867. // Mark the object in the local variable as initialized
  1868. ctx.bc.ObjInfo(offset, asOBJ_INIT);
  1869. }
  1870. }
  1871. bc->AddCode(&ctx.bc);
  1872. }
  1873. }
  1874. }
  1875. // Cleanup
  1876. for( asUINT n = 0; n < args.GetLength(); n++ )
  1877. if( args[n] )
  1878. {
  1879. asDELETE(args[n],asSExprContext);
  1880. }
  1881. }
  1882. }
  1883. else if( node && node->nodeType == snInitList )
  1884. {
  1885. asCTypeInfo ti;
  1886. ti.Set(type);
  1887. ti.isVariable = (isVarGlobOrMem == 0);
  1888. ti.isTemporary = false;
  1889. ti.stackOffset = (short)offset;
  1890. ti.isLValue = true;
  1891. CompileInitList(&ti, node, bc, isVarGlobOrMem);
  1892. }
  1893. else if( node && node->nodeType == snAssignment )
  1894. {
  1895. asSExprContext ctx(engine);
  1896. // TODO: copy: Here we should look for the best matching constructor, instead of
  1897. // just the copy constructor. Only if no appropriate constructor is
  1898. // available should the assignment operator be used.
  1899. // Call the default constructor here
  1900. if( isVarGlobOrMem == 0 )
  1901. CallDefaultConstructor(type, offset, IsVariableOnHeap(offset), &ctx.bc, errNode);
  1902. else
  1903. CallDefaultConstructor(type, offset, true, &ctx.bc, errNode, isVarGlobOrMem);
  1904. // Compile the expression
  1905. asSExprContext expr(engine);
  1906. int r = CompileAssignment(node, &expr);
  1907. if( r >= 0 )
  1908. {
  1909. if( type.IsPrimitive() )
  1910. {
  1911. if( type.IsReadOnly() && expr.type.isConstant )
  1912. {
  1913. ImplicitConversion(&expr, type, node, asIC_IMPLICIT_CONV);
  1914. // Tell caller that the expression is a constant so it can mark the variable as pure constant
  1915. isConstantExpression = true;
  1916. *constantValue = expr.type.qwordValue;
  1917. }
  1918. asSExprContext lctx(engine);
  1919. if( isVarGlobOrMem == 0 )
  1920. lctx.type.SetVariable(type, offset, false);
  1921. else if( isVarGlobOrMem == 1 )
  1922. {
  1923. lctx.type.Set(type);
  1924. lctx.type.dataType.MakeReference(true);
  1925. // If it is an enum value, i.e. offset is negative, that is being compiled then
  1926. // we skip this as the bytecode won't be used anyway, only the constant value
  1927. if( offset >= 0 )
  1928. lctx.bc.InstrPTR(asBC_LDG, engine->globalProperties[offset]->GetAddressOfValue());
  1929. }
  1930. else
  1931. {
  1932. asASSERT( isVarGlobOrMem == 2 );
  1933. lctx.type.Set(type);
  1934. lctx.type.dataType.MakeReference(true);
  1935. // Load the reference of the primitive member into the register
  1936. lctx.bc.InstrSHORT(asBC_PSF, 0);
  1937. lctx.bc.Instr(asBC_RDSPtr);
  1938. lctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
  1939. lctx.bc.Instr(asBC_PopRPtr);
  1940. }
  1941. lctx.type.dataType.MakeReadOnly(false);
  1942. lctx.type.isLValue = true;
  1943. DoAssignment(&ctx, &lctx, &expr, node, node, ttAssignment, node);
  1944. ProcessDeferredParams(&ctx);
  1945. }
  1946. else
  1947. {
  1948. // TODO: runtime optimize: Here we should look for the best matching constructor, instead of
  1949. // just the copy constructor. Only if no appropriate constructor is
  1950. // available should the assignment operator be used.
  1951. asSExprContext lexpr(engine);
  1952. lexpr.type.Set(type);
  1953. if( isVarGlobOrMem == 0 )
  1954. lexpr.type.dataType.MakeReference(IsVariableOnHeap(offset));
  1955. else
  1956. lexpr.type.dataType.MakeReference(true);
  1957. // Allow initialization of constant variables
  1958. lexpr.type.dataType.MakeReadOnly(false);
  1959. if( type.IsObjectHandle() )
  1960. lexpr.type.isExplicitHandle = true;
  1961. if( isVarGlobOrMem == 0 )
  1962. {
  1963. lexpr.bc.InstrSHORT(asBC_PSF, (short)offset);
  1964. lexpr.type.stackOffset = (short)offset;
  1965. lexpr.type.isVariable = true;
  1966. }
  1967. else if( isVarGlobOrMem == 1 )
  1968. {
  1969. lexpr.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  1970. }
  1971. else
  1972. {
  1973. lexpr.bc.InstrSHORT(asBC_PSF, 0);
  1974. lexpr.bc.Instr(asBC_RDSPtr);
  1975. lexpr.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
  1976. lexpr.type.stackOffset = -1;
  1977. }
  1978. lexpr.type.isLValue = true;
  1979. // If left expression resolves into a registered type
  1980. // check if the assignment operator is overloaded, and check
  1981. // the type of the right hand expression. If none is found
  1982. // the default action is a direct copy if it is the same type
  1983. // and a simple assignment.
  1984. bool assigned = false;
  1985. // Even though an ASHANDLE can be an explicit handle the overloaded operator needs to be called
  1986. if( lexpr.type.dataType.IsObject() && (!lexpr.type.isExplicitHandle || (lexpr.type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE)) )
  1987. {
  1988. assigned = CompileOverloadedDualOperator(node, &lexpr, &expr, &ctx);
  1989. if( assigned )
  1990. {
  1991. // Pop the resulting value
  1992. if( !ctx.type.dataType.IsPrimitive() )
  1993. ctx.bc.Instr(asBC_PopPtr);
  1994. // Release the argument
  1995. ProcessDeferredParams(&ctx);
  1996. // Release temporary variable that may be allocated by the overloaded operator
  1997. ReleaseTemporaryVariable(ctx.type, &ctx.bc);
  1998. }
  1999. }
  2000. if( !assigned )
  2001. {
  2002. PrepareForAssignment(&lexpr.type.dataType, &expr, node, false);
  2003. // If the expression is constant and the variable also is constant
  2004. // then mark the variable as pure constant. This will allow the compiler
  2005. // to optimize expressions with this variable.
  2006. if( type.IsReadOnly() && expr.type.isConstant )
  2007. {
  2008. isConstantExpression = true;
  2009. *constantValue = expr.type.qwordValue;
  2010. }
  2011. // Add expression code to bytecode
  2012. MergeExprBytecode(&ctx, &expr);
  2013. // Add byte code for storing value of expression in variable
  2014. ctx.bc.AddCode(&lexpr.bc);
  2015. PerformAssignment(&lexpr.type, &expr.type, &ctx.bc, errNode);
  2016. // Release temporary variables used by expression
  2017. ReleaseTemporaryVariable(expr.type, &ctx.bc);
  2018. ctx.bc.Instr(asBC_PopPtr);
  2019. ProcessDeferredParams(&ctx);
  2020. }
  2021. }
  2022. }
  2023. bc->AddCode(&ctx.bc);
  2024. }
  2025. else
  2026. {
  2027. asASSERT( node == 0 );
  2028. // Call the default constructor here, as no explicit initialization is done
  2029. if( isVarGlobOrMem == 0 )
  2030. CallDefaultConstructor(type, offset, IsVariableOnHeap(offset), bc, errNode);
  2031. else
  2032. CallDefaultConstructor(type, offset, true, bc, errNode, isVarGlobOrMem);
  2033. }
  2034. bc->OptimizeLocally(tempVariableOffsets);
  2035. return isConstantExpression;
  2036. }
  2037. void asCCompiler::CompileInitList(asCTypeInfo *var, asCScriptNode *node, asCByteCode *bc, int isVarGlobOrMem)
  2038. {
  2039. // Check if the type supports initialization lists
  2040. if( var->dataType.GetObjectType() == 0 ||
  2041. var->dataType.GetBehaviour()->listFactory == 0 ||
  2042. var->dataType.IsObjectHandle() )
  2043. {
  2044. asCString str;
  2045. str.Format(TXT_INIT_LIST_CANNOT_BE_USED_WITH_s, var->dataType.Format().AddressOf());
  2046. Error(str, node);
  2047. return;
  2048. }
  2049. // Construct the buffer with the elements
  2050. // Find the list factory
  2051. // TODO: initlist: Add support for value types as well
  2052. int funcId = var->dataType.GetBehaviour()->listFactory;
  2053. asASSERT( engine->scriptFunctions[funcId]->listPattern );
  2054. // TODO: runtime optimize: A future optimization should be to use the stack space directly
  2055. // for small buffers so that the dynamic allocation is skipped
  2056. // Create a new special object type for the lists. Both asCRestore and the
  2057. // context exception handler will need this to know how to parse the buffer.
  2058. asCObjectType *listPatternType = engine->GetListPatternType(funcId);
  2059. // Allocate a temporary variable to hold the pointer to the buffer
  2060. int bufferVar = AllocateVariable(asCDataType::CreateObject(listPatternType, false), true);
  2061. asUINT bufferSize = 0;
  2062. // Evaluate all elements of the list
  2063. asSExprContext valueExpr(engine);
  2064. asCScriptNode *el = node;
  2065. asSListPatternNode *patternNode = engine->scriptFunctions[listPatternType->templateSubTypes[0].GetBehaviour()->listFactory]->listPattern;
  2066. int r = CompileInitListElement(patternNode, el, engine->GetTypeIdFromDataType(asCDataType::CreateObject(listPatternType, false)), bufferVar, bufferSize, valueExpr.bc);
  2067. asASSERT( r || patternNode == 0 );
  2068. UNUSED_VAR(r);
  2069. // After all values have been evaluated we know the final size of the buffer
  2070. asSExprContext allocExpr(engine);
  2071. allocExpr.bc.InstrSHORT_DW(asBC_AllocMem, bufferVar, bufferSize);
  2072. // Merge the bytecode into the final sequence
  2073. bc->AddCode(&allocExpr.bc);
  2074. bc->AddCode(&valueExpr.bc);
  2075. // The object itself is the last to be created and will receive the pointer to the buffer
  2076. asCArray<asSExprContext *> args;
  2077. asSExprContext arg1(engine);
  2078. bc->InstrSHORT(asBC_PshVPtr, bufferVar);
  2079. arg1.type.Set(asCDataType::CreatePrimitive(ttUInt, false));
  2080. arg1.type.dataType.MakeReference(true);
  2081. args.PushLast(&arg1);
  2082. asSExprContext ctx(engine);
  2083. if( var->isVariable )
  2084. {
  2085. asASSERT( isVarGlobOrMem == 0 );
  2086. // Call factory and store the handle in the given variable
  2087. PerformFunctionCall(funcId, &ctx, false, &args, 0, true, var->stackOffset);
  2088. ctx.bc.Instr(asBC_PopPtr);
  2089. }
  2090. else
  2091. {
  2092. PerformFunctionCall(funcId, &ctx, false, &args);
  2093. ctx.bc.Instr(asBC_RDSPtr);
  2094. if( isVarGlobOrMem == 1 )
  2095. {
  2096. // Store the returned handle in the global variable
  2097. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[var->stackOffset]->GetAddressOfValue());
  2098. }
  2099. else
  2100. {
  2101. // Store the returned handle in the member
  2102. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2103. ctx.bc.Instr(asBC_RDSPtr);
  2104. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)var->stackOffset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
  2105. }
  2106. ctx.bc.InstrPTR(asBC_REFCPY, var->dataType.GetObjectType());
  2107. ctx.bc.Instr(asBC_PopPtr);
  2108. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  2109. }
  2110. bc->AddCode(&ctx.bc);
  2111. // Free the temporary buffer. The FREE instruction will make sure to destroy
  2112. // each element in the buffer so there is no need to do this manually
  2113. bc->InstrW_PTR(asBC_FREE, bufferVar, listPatternType);
  2114. ReleaseTemporaryVariable(bufferVar, bc);
  2115. }
  2116. int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScriptNode *&valueNode, int bufferTypeId, short bufferVar, asUINT &bufferSize, asCByteCode &byteCode)
  2117. {
  2118. if( patternNode->type == asLPT_START )
  2119. {
  2120. if( valueNode->nodeType != snInitList )
  2121. {
  2122. Error(TXT_EXPECTED_LIST, valueNode);
  2123. return -1;
  2124. }
  2125. // Compile all values until asLPT_END
  2126. patternNode = patternNode->next;
  2127. asCScriptNode *node = valueNode->firstChild;
  2128. while( patternNode->type != asLPT_END )
  2129. {
  2130. if( node == 0 )
  2131. {
  2132. Error(TXT_NOT_ENOUGH_VALUES_FOR_LIST, valueNode);
  2133. return -1;
  2134. }
  2135. int r = CompileInitListElement(patternNode, node, bufferTypeId, bufferVar, bufferSize, byteCode);
  2136. if( r < 0 ) return r;
  2137. asASSERT( patternNode );
  2138. }
  2139. if( node )
  2140. {
  2141. Error(TXT_TOO_MANY_VALUES_FOR_LIST, valueNode);
  2142. return -1;
  2143. }
  2144. // Move to the next node
  2145. valueNode = valueNode->next;
  2146. patternNode = patternNode->next;
  2147. }
  2148. else if( patternNode->type == asLPT_REPEAT )
  2149. {
  2150. // The following values will be repeated N times
  2151. patternNode = patternNode->next;
  2152. // Keep track of the patternNode so it can be reset
  2153. asSListPatternNode *nextNode = patternNode;
  2154. // The first dword will hold the number of elements in the list
  2155. asDWORD currSize = bufferSize;
  2156. bufferSize += 4;
  2157. asUINT countElements = 0;
  2158. asSExprContext ctx(engine);
  2159. while( valueNode )
  2160. {
  2161. patternNode = nextNode;
  2162. int r = CompileInitListElement(patternNode, valueNode, bufferTypeId, bufferVar, bufferSize, ctx.bc);
  2163. if( r < 0 ) return r;
  2164. countElements++;
  2165. }
  2166. // The first dword in the buffer will hold the number of elements
  2167. byteCode.InstrSHORT_DW_DW(asBC_SetListSize, bufferVar, currSize, countElements);
  2168. // Add the values
  2169. byteCode.AddCode(&ctx.bc);
  2170. }
  2171. else if( patternNode->type == asLPT_TYPE )
  2172. {
  2173. // TODO: list: Values on the list must be aligned to 32bit boundaries, except if the type
  2174. // is smaller than 32bit.
  2175. // Determine the size of the element
  2176. asUINT size = 0;
  2177. asCDataType dt = reinterpret_cast<asSListPatternDataTypeNode*>(patternNode)->dataType;
  2178. if( valueNode->nodeType == snAssignment || valueNode->nodeType == snInitList )
  2179. {
  2180. asSExprContext lctx(engine);
  2181. asSExprContext rctx(engine);
  2182. if( valueNode->nodeType == snAssignment )
  2183. {
  2184. // Compile the assignment expression
  2185. CompileAssignment(valueNode, &rctx);
  2186. if( dt.GetTokenType() == ttQuestion )
  2187. {
  2188. // We now know the type
  2189. dt = rctx.type.dataType;
  2190. dt.MakeReadOnly(false);
  2191. // Place the type id in the buffer
  2192. byteCode.InstrSHORT_DW_DW(asBC_SetListType, bufferVar, bufferSize, engine->GetTypeIdFromDataType(dt));
  2193. bufferSize += 4;
  2194. }
  2195. }
  2196. else if( valueNode->nodeType == snInitList )
  2197. {
  2198. if( dt.GetTokenType() == ttQuestion )
  2199. {
  2200. // Can't use init lists with var type as it is not possible to determine what type should be allocated
  2201. asCString str;
  2202. str.Format(TXT_INIT_LIST_CANNOT_BE_USED_WITH_s, "?");
  2203. Error(str.AddressOf(), valueNode);
  2204. rctx.type.SetDummy();
  2205. dt = rctx.type.dataType;
  2206. }
  2207. else
  2208. {
  2209. // Allocate a temporary variable that will be initialized with the list
  2210. int offset = AllocateVariable(dt, true);
  2211. rctx.type.Set(dt);
  2212. rctx.type.isVariable = true;
  2213. rctx.type.isTemporary = true;
  2214. rctx.type.stackOffset = (short)offset;
  2215. CompileInitList(&rctx.type, valueNode, &rctx.bc, 0);
  2216. // Put the object on the stack
  2217. rctx.bc.InstrSHORT(asBC_PSF, rctx.type.stackOffset);
  2218. // It is a reference that we place on the stack
  2219. rctx.type.dataType.MakeReference(true);
  2220. }
  2221. }
  2222. // Compile the lvalue
  2223. lctx.bc.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize);
  2224. lctx.type.Set(dt);
  2225. lctx.type.isLValue = true;
  2226. if( dt.IsPrimitive() )
  2227. {
  2228. lctx.bc.Instr(asBC_PopRPtr);
  2229. lctx.type.dataType.MakeReference(true);
  2230. }
  2231. else if( dt.IsObjectHandle() ||
  2232. dt.GetObjectType()->flags & asOBJ_REF )
  2233. {
  2234. lctx.type.isExplicitHandle = true;
  2235. lctx.type.dataType.MakeReference(true);
  2236. }
  2237. else
  2238. {
  2239. asASSERT( dt.GetObjectType()->flags & asOBJ_VALUE );
  2240. // Make sure the object has been constructed before the assignment
  2241. // TODO: runtime optimize: Use copy constructor instead of assignment to initialize the objects
  2242. asSTypeBehaviour *beh = dt.GetBehaviour();
  2243. int func = 0;
  2244. if( beh ) func = beh->construct;
  2245. if( func == 0 && (dt.GetObjectType()->flags & asOBJ_POD) == 0 )
  2246. {
  2247. asCString str;
  2248. // TODO: funcdef: asCDataType should have a GetTypeName()
  2249. if( dt.GetFuncDef() )
  2250. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetFuncDef()->GetName());
  2251. else
  2252. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetObjectType()->GetName());
  2253. Error(str, valueNode);
  2254. }
  2255. else if( func )
  2256. {
  2257. // Call the constructor as a normal function
  2258. byteCode.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize);
  2259. asSExprContext ctx(engine);
  2260. PerformFunctionCall(func, &ctx, false, 0, dt.GetObjectType());
  2261. byteCode.AddCode(&ctx.bc);
  2262. }
  2263. }
  2264. asSExprContext ctx(engine);
  2265. DoAssignment(&ctx, &lctx, &rctx, valueNode, valueNode, ttAssignment, valueNode);
  2266. if( !lctx.type.dataType.IsPrimitive() )
  2267. ctx.bc.Instr(asBC_PopPtr);
  2268. // Release temporary variables used by expression
  2269. ReleaseTemporaryVariable(ctx.type, &ctx.bc);
  2270. ProcessDeferredParams(&ctx);
  2271. byteCode.AddCode(&ctx.bc);
  2272. }
  2273. else
  2274. {
  2275. // There is no specific value so we need to fill it with a default value
  2276. // TODO: list: For value types with default constructor we need to call the constructor
  2277. if( dt.GetTokenType() == ttQuestion )
  2278. {
  2279. // Place the type id for a null handle in the buffer
  2280. byteCode.InstrSHORT_DW_DW(asBC_SetListType, bufferVar, bufferSize, 0);
  2281. bufferSize += 4;
  2282. dt = asCDataType::CreateNullHandle();
  2283. // No need to initialize the handle as the buffer is already initialized with zeroes
  2284. }
  2285. }
  2286. // Determine size of the element
  2287. if( dt.IsPrimitive() || (!dt.IsNullHandle() && (dt.GetObjectType()->flags & asOBJ_VALUE)) )
  2288. size = dt.GetSizeInMemoryBytes();
  2289. else
  2290. size = AS_PTR_SIZE*4;
  2291. asASSERT( size <= 4 || (size & 0x3) == 0 );
  2292. // Move to the next element
  2293. bufferSize += size;
  2294. patternNode = patternNode->next;
  2295. valueNode = valueNode->next;
  2296. }
  2297. else
  2298. asASSERT( false );
  2299. return 0;
  2300. }
  2301. void asCCompiler::CompileStatement(asCScriptNode *statement, bool *hasReturn, asCByteCode *bc)
  2302. {
  2303. // Don't clear the hasReturn flag if this is an empty statement
  2304. // to avoid false errors of 'not all paths return'
  2305. if( statement->nodeType != snExpressionStatement || statement->firstChild )
  2306. *hasReturn = false;
  2307. if( statement->nodeType == snStatementBlock )
  2308. CompileStatementBlock(statement, true, hasReturn, bc);
  2309. else if( statement->nodeType == snIf )
  2310. CompileIfStatement(statement, hasReturn, bc);
  2311. else if( statement->nodeType == snFor )
  2312. CompileForStatement(statement, bc);
  2313. else if( statement->nodeType == snWhile )
  2314. CompileWhileStatement(statement, bc);
  2315. else if( statement->nodeType == snDoWhile )
  2316. CompileDoWhileStatement(statement, bc);
  2317. else if( statement->nodeType == snExpressionStatement )
  2318. CompileExpressionStatement(statement, bc);
  2319. else if( statement->nodeType == snBreak )
  2320. CompileBreakStatement(statement, bc);
  2321. else if( statement->nodeType == snContinue )
  2322. CompileContinueStatement(statement, bc);
  2323. else if( statement->nodeType == snSwitch )
  2324. CompileSwitchStatement(statement, hasReturn, bc);
  2325. else if( statement->nodeType == snReturn )
  2326. {
  2327. CompileReturnStatement(statement, bc);
  2328. *hasReturn = true;
  2329. }
  2330. }
  2331. void asCCompiler::CompileSwitchStatement(asCScriptNode *snode, bool *, asCByteCode *bc)
  2332. {
  2333. // TODO: inheritance: Must guarantee that all options in the switch case call a constructor, or that none call it.
  2334. // Reserve label for break statements
  2335. int breakLabel = nextLabel++;
  2336. breakLabels.PushLast(breakLabel);
  2337. // Add a variable scope that will be used by CompileBreak
  2338. // to know where to stop deallocating variables
  2339. AddVariableScope(true, false);
  2340. //---------------------------
  2341. // Compile the switch expression
  2342. //-------------------------------
  2343. // Compile the switch expression
  2344. asSExprContext expr(engine);
  2345. CompileAssignment(snode->firstChild, &expr);
  2346. // Verify that the expression is a primitive type
  2347. if( !expr.type.dataType.IsIntegerType() && !expr.type.dataType.IsUnsignedType() )
  2348. {
  2349. Error(TXT_SWITCH_MUST_BE_INTEGRAL, snode->firstChild);
  2350. return;
  2351. }
  2352. ProcessPropertyGetAccessor(&expr, snode);
  2353. // TODO: Need to support 64bit integers
  2354. // Convert the expression to a 32bit variable
  2355. asCDataType to;
  2356. if( expr.type.dataType.IsIntegerType() )
  2357. to.SetTokenType(ttInt);
  2358. else if( expr.type.dataType.IsUnsignedType() )
  2359. to.SetTokenType(ttUInt);
  2360. // Make sure the value is in a variable
  2361. if( expr.type.dataType.IsReference() )
  2362. ConvertToVariable(&expr);
  2363. ImplicitConversion(&expr, to, snode->firstChild, asIC_IMPLICIT_CONV, true);
  2364. ConvertToVariable(&expr);
  2365. int offset = expr.type.stackOffset;
  2366. ProcessDeferredParams(&expr);
  2367. //-------------------------------
  2368. // Determine case values and labels
  2369. //--------------------------------
  2370. // Remember the first label so that we can later pass the
  2371. // correct label to each CompileCase()
  2372. int firstCaseLabel = nextLabel;
  2373. int defaultLabel = 0;
  2374. asCArray<int> caseValues;
  2375. asCArray<int> caseLabels;
  2376. // Compile all case comparisons and make them jump to the right label
  2377. asCScriptNode *cnode = snode->firstChild->next;
  2378. while( cnode )
  2379. {
  2380. // Each case should have a constant expression
  2381. if( cnode->firstChild && cnode->firstChild->nodeType == snExpression )
  2382. {
  2383. // Compile expression
  2384. asSExprContext c(engine);
  2385. CompileExpression(cnode->firstChild, &c);
  2386. // Verify that the result is a constant
  2387. if( !c.type.isConstant )
  2388. Error(TXT_SWITCH_CASE_MUST_BE_CONSTANT, cnode->firstChild);
  2389. // Verify that the result is an integral number
  2390. if( !c.type.dataType.IsIntegerType() && !c.type.dataType.IsUnsignedType() )
  2391. Error(TXT_SWITCH_MUST_BE_INTEGRAL, cnode->firstChild);
  2392. ImplicitConversion(&c, to, cnode->firstChild, asIC_IMPLICIT_CONV, true);
  2393. // Has this case been declared already?
  2394. if( caseValues.IndexOf(c.type.intValue) >= 0 )
  2395. {
  2396. Error(TXT_DUPLICATE_SWITCH_CASE, cnode->firstChild);
  2397. }
  2398. // TODO: Optimize: We can insert the numbers sorted already
  2399. // Store constant for later use
  2400. caseValues.PushLast(c.type.intValue);
  2401. // Reserve label for this case
  2402. caseLabels.PushLast(nextLabel++);
  2403. }
  2404. else
  2405. {
  2406. // TODO: It shouldn't be necessary for the default case to be the last one.
  2407. // Is default the last case?
  2408. if( cnode->next )
  2409. {
  2410. Error(TXT_DEFAULT_MUST_BE_LAST, cnode);
  2411. break;
  2412. }
  2413. // Reserve label for this case
  2414. defaultLabel = nextLabel++;
  2415. }
  2416. cnode = cnode->next;
  2417. }
  2418. // check for empty switch
  2419. if (caseValues.GetLength() == 0)
  2420. {
  2421. Error(TXT_EMPTY_SWITCH, snode);
  2422. return;
  2423. }
  2424. if( defaultLabel == 0 )
  2425. defaultLabel = breakLabel;
  2426. //---------------------------------
  2427. // Output the optimized case comparisons
  2428. // with jumps to the case code
  2429. //------------------------------------
  2430. // Sort the case values by increasing value. Do the sort together with the labels
  2431. // A simple bubble sort is sufficient since we don't expect a huge number of values
  2432. for( asUINT fwd = 1; fwd < caseValues.GetLength(); fwd++ )
  2433. {
  2434. for( int bck = fwd - 1; bck >= 0; bck-- )
  2435. {
  2436. int bckp = bck + 1;
  2437. if( caseValues[bck] > caseValues[bckp] )
  2438. {
  2439. // Swap the values in both arrays
  2440. int swap = caseValues[bckp];
  2441. caseValues[bckp] = caseValues[bck];
  2442. caseValues[bck] = swap;
  2443. swap = caseLabels[bckp];
  2444. caseLabels[bckp] = caseLabels[bck];
  2445. caseLabels[bck] = swap;
  2446. }
  2447. else
  2448. break;
  2449. }
  2450. }
  2451. // Find ranges of consecutive numbers
  2452. asCArray<int> ranges;
  2453. ranges.PushLast(0);
  2454. asUINT n;
  2455. for( n = 1; n < caseValues.GetLength(); ++n )
  2456. {
  2457. // We can join numbers that are less than 5 numbers
  2458. // apart since the output code will still be smaller
  2459. if( caseValues[n] > caseValues[n-1] + 5 )
  2460. ranges.PushLast(n);
  2461. }
  2462. // If the value is larger than the largest case value, jump to default
  2463. int tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  2464. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[caseValues.GetLength()-1]);
  2465. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  2466. expr.bc.InstrDWORD(asBC_JP, defaultLabel);
  2467. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  2468. // TODO: runtime optimize: We could possibly optimize this even more by doing a
  2469. // binary search instead of a linear search through the ranges
  2470. // For each range
  2471. int range;
  2472. for( range = 0; range < (int)ranges.GetLength(); range++ )
  2473. {
  2474. // Find the largest value in this range
  2475. int maxRange = caseValues[ranges[range]];
  2476. int index = ranges[range];
  2477. for( ; (index < (int)caseValues.GetLength()) && (caseValues[index] <= maxRange + 5); index++ )
  2478. maxRange = caseValues[index];
  2479. // If there are only 2 numbers then it is better to compare them directly
  2480. if( index - ranges[range] > 2 )
  2481. {
  2482. // If the value is smaller than the smallest case value in the range, jump to default
  2483. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  2484. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[ranges[range]]);
  2485. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  2486. expr.bc.InstrDWORD(asBC_JS, defaultLabel);
  2487. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  2488. int nextRangeLabel = nextLabel++;
  2489. // If this is the last range we don't have to make this test
  2490. if( range < (int)ranges.GetLength() - 1 )
  2491. {
  2492. // If the value is larger than the largest case value in the range, jump to the next range
  2493. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  2494. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, maxRange);
  2495. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  2496. expr.bc.InstrDWORD(asBC_JP, nextRangeLabel);
  2497. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  2498. }
  2499. // Jump forward according to the value
  2500. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  2501. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[ranges[range]]);
  2502. expr.bc.InstrW_W_W(asBC_SUBi, tmpOffset, offset, tmpOffset);
  2503. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  2504. expr.bc.JmpP(tmpOffset, maxRange - caseValues[ranges[range]]);
  2505. // Add the list of jumps to the correct labels (any holes, jump to default)
  2506. index = ranges[range];
  2507. for( int n = caseValues[index]; n <= maxRange; n++ )
  2508. {
  2509. if( caseValues[index] == n )
  2510. expr.bc.InstrINT(asBC_JMP, caseLabels[index++]);
  2511. else
  2512. expr.bc.InstrINT(asBC_JMP, defaultLabel);
  2513. }
  2514. expr.bc.Label((short)nextRangeLabel);
  2515. }
  2516. else
  2517. {
  2518. // Simply make a comparison with each value
  2519. int n;
  2520. for( n = ranges[range]; n < index; ++n )
  2521. {
  2522. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  2523. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[n]);
  2524. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  2525. expr.bc.InstrDWORD(asBC_JZ, caseLabels[n]);
  2526. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  2527. }
  2528. }
  2529. }
  2530. // Catch any value that falls trough
  2531. expr.bc.InstrINT(asBC_JMP, defaultLabel);
  2532. // Release the temporary variable previously stored
  2533. ReleaseTemporaryVariable(expr.type, &expr.bc);
  2534. // TODO: optimize: Should optimize each piece individually
  2535. expr.bc.OptimizeLocally(tempVariableOffsets);
  2536. //----------------------------------
  2537. // Output case implementations
  2538. //----------------------------------
  2539. // Compile case implementations, each one with the label before it
  2540. cnode = snode->firstChild->next;
  2541. while( cnode )
  2542. {
  2543. // Each case should have a constant expression
  2544. if( cnode->firstChild && cnode->firstChild->nodeType == snExpression )
  2545. {
  2546. expr.bc.Label((short)firstCaseLabel++);
  2547. CompileCase(cnode->firstChild->next, &expr.bc);
  2548. }
  2549. else
  2550. {
  2551. expr.bc.Label((short)defaultLabel);
  2552. // Is default the last case?
  2553. if( cnode->next )
  2554. {
  2555. // We've already reported this error
  2556. break;
  2557. }
  2558. CompileCase(cnode->firstChild, &expr.bc);
  2559. }
  2560. cnode = cnode->next;
  2561. }
  2562. //--------------------------------
  2563. bc->AddCode(&expr.bc);
  2564. // Add break label
  2565. bc->Label((short)breakLabel);
  2566. breakLabels.PopLast();
  2567. RemoveVariableScope();
  2568. }
  2569. void asCCompiler::CompileCase(asCScriptNode *node, asCByteCode *bc)
  2570. {
  2571. bool isFinished = false;
  2572. bool hasReturn = false;
  2573. bool hasUnreachableCode = false;
  2574. while( node )
  2575. {
  2576. if( !hasUnreachableCode && (hasReturn || isFinished) )
  2577. {
  2578. hasUnreachableCode = true;
  2579. Warning(TXT_UNREACHABLE_CODE, node);
  2580. break;
  2581. }
  2582. if( node->nodeType == snBreak || node->nodeType == snContinue )
  2583. isFinished = true;
  2584. asCByteCode statement(engine);
  2585. if( node->nodeType == snDeclaration )
  2586. {
  2587. Error(TXT_DECL_IN_SWITCH, node);
  2588. // Compile it anyway to avoid further compiler errors
  2589. CompileDeclaration(node, &statement);
  2590. }
  2591. else
  2592. CompileStatement(node, &hasReturn, &statement);
  2593. LineInstr(bc, node->tokenPos);
  2594. bc->AddCode(&statement);
  2595. if( !hasCompileErrors )
  2596. asASSERT( tempVariables.GetLength() == 0 );
  2597. node = node->next;
  2598. }
  2599. }
  2600. void asCCompiler::CompileIfStatement(asCScriptNode *inode, bool *hasReturn, asCByteCode *bc)
  2601. {
  2602. // We will use one label for the if statement
  2603. // and possibly another for the else statement
  2604. int afterLabel = nextLabel++;
  2605. // Compile the expression
  2606. asSExprContext expr(engine);
  2607. CompileAssignment(inode->firstChild, &expr);
  2608. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  2609. {
  2610. Error(TXT_EXPR_MUST_BE_BOOL, inode->firstChild);
  2611. expr.type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), 1);
  2612. }
  2613. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  2614. ProcessDeferredParams(&expr);
  2615. if( !expr.type.isConstant )
  2616. {
  2617. ProcessPropertyGetAccessor(&expr, inode);
  2618. ConvertToVariable(&expr);
  2619. // Add a test
  2620. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  2621. expr.bc.Instr(asBC_ClrHi);
  2622. expr.bc.InstrDWORD(asBC_JZ, afterLabel);
  2623. ReleaseTemporaryVariable(expr.type, &expr.bc);
  2624. expr.bc.OptimizeLocally(tempVariableOffsets);
  2625. bc->AddCode(&expr.bc);
  2626. }
  2627. else if( expr.type.dwordValue == 0 )
  2628. {
  2629. // Jump to the else case
  2630. bc->InstrINT(asBC_JMP, afterLabel);
  2631. // TODO: Should we warn that the expression will always go to the else?
  2632. }
  2633. // Compile the if statement
  2634. bool origIsConstructorCalled = m_isConstructorCalled;
  2635. bool hasReturn1;
  2636. asCByteCode ifBC(engine);
  2637. CompileStatement(inode->firstChild->next, &hasReturn1, &ifBC);
  2638. // Add the byte code
  2639. LineInstr(bc, inode->firstChild->next->tokenPos);
  2640. bc->AddCode(&ifBC);
  2641. if( inode->firstChild->next->nodeType == snExpressionStatement && inode->firstChild->next->firstChild == 0 )
  2642. {
  2643. // Don't allow if( expr );
  2644. Error(TXT_IF_WITH_EMPTY_STATEMENT, inode->firstChild->next);
  2645. }
  2646. // If one of the statements call the constructor, the other must as well
  2647. // otherwise it is possible the constructor is never called
  2648. bool constructorCall1 = false;
  2649. bool constructorCall2 = false;
  2650. if( !origIsConstructorCalled && m_isConstructorCalled )
  2651. constructorCall1 = true;
  2652. // Do we have an else statement?
  2653. if( inode->firstChild->next != inode->lastChild )
  2654. {
  2655. // Reset the constructor called flag so the else statement can call the constructor too
  2656. m_isConstructorCalled = origIsConstructorCalled;
  2657. int afterElse = 0;
  2658. if( !hasReturn1 )
  2659. {
  2660. afterElse = nextLabel++;
  2661. // Add jump to after the else statement
  2662. bc->InstrINT(asBC_JMP, afterElse);
  2663. }
  2664. // Add label for the else statement
  2665. bc->Label((short)afterLabel);
  2666. bool hasReturn2;
  2667. asCByteCode elseBC(engine);
  2668. CompileStatement(inode->lastChild, &hasReturn2, &elseBC);
  2669. // Add byte code for the else statement
  2670. LineInstr(bc, inode->lastChild->tokenPos);
  2671. bc->AddCode(&elseBC);
  2672. if( inode->lastChild->nodeType == snExpressionStatement && inode->lastChild->firstChild == 0 )
  2673. {
  2674. // Don't allow if( expr ) {} else;
  2675. Error(TXT_ELSE_WITH_EMPTY_STATEMENT, inode->lastChild);
  2676. }
  2677. if( !hasReturn1 )
  2678. {
  2679. // Add label for the end of else statement
  2680. bc->Label((short)afterElse);
  2681. }
  2682. // The if statement only has return if both alternatives have
  2683. *hasReturn = hasReturn1 && hasReturn2;
  2684. if( !origIsConstructorCalled && m_isConstructorCalled )
  2685. constructorCall2 = true;
  2686. }
  2687. else
  2688. {
  2689. // Add label for the end of if statement
  2690. bc->Label((short)afterLabel);
  2691. *hasReturn = false;
  2692. }
  2693. // Make sure both or neither conditions call a constructor
  2694. if( (constructorCall1 && !constructorCall2) ||
  2695. (constructorCall2 && !constructorCall1) )
  2696. {
  2697. Error(TXT_BOTH_CONDITIONS_MUST_CALL_CONSTRUCTOR, inode);
  2698. }
  2699. m_isConstructorCalled = origIsConstructorCalled || constructorCall1 || constructorCall2;
  2700. }
  2701. void asCCompiler::CompileForStatement(asCScriptNode *fnode, asCByteCode *bc)
  2702. {
  2703. // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables
  2704. AddVariableScope(true, true);
  2705. // We will use three labels for the for loop
  2706. int conditionLabel = nextLabel++;
  2707. int afterLabel = nextLabel++;
  2708. int continueLabel = nextLabel++;
  2709. int insideLabel = nextLabel++;
  2710. continueLabels.PushLast(continueLabel);
  2711. breakLabels.PushLast(afterLabel);
  2712. //---------------------------------------
  2713. // Compile the initialization statement
  2714. asCByteCode initBC(engine);
  2715. LineInstr(&initBC, fnode->firstChild->tokenPos);
  2716. if( fnode->firstChild->nodeType == snDeclaration )
  2717. CompileDeclaration(fnode->firstChild, &initBC);
  2718. else
  2719. CompileExpressionStatement(fnode->firstChild, &initBC);
  2720. //-----------------------------------
  2721. // Compile the condition statement
  2722. asSExprContext expr(engine);
  2723. asCScriptNode *second = fnode->firstChild->next;
  2724. if( second->firstChild )
  2725. {
  2726. int r = CompileAssignment(second->firstChild, &expr);
  2727. if( r >= 0 )
  2728. {
  2729. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  2730. Error(TXT_EXPR_MUST_BE_BOOL, second);
  2731. else
  2732. {
  2733. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  2734. ProcessDeferredParams(&expr);
  2735. ProcessPropertyGetAccessor(&expr, second);
  2736. // If expression is false exit the loop
  2737. ConvertToVariable(&expr);
  2738. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  2739. expr.bc.Instr(asBC_ClrHi);
  2740. expr.bc.InstrDWORD(asBC_JNZ, insideLabel);
  2741. ReleaseTemporaryVariable(expr.type, &expr.bc);
  2742. expr.bc.OptimizeLocally(tempVariableOffsets);
  2743. // Prepend the line instruction for the condition
  2744. asCByteCode tmp(engine);
  2745. LineInstr(&tmp, second->firstChild->tokenPos);
  2746. tmp.AddCode(&expr.bc);
  2747. expr.bc.AddCode(&tmp);
  2748. }
  2749. }
  2750. }
  2751. //---------------------------
  2752. // Compile the increment statement
  2753. asCByteCode nextBC(engine);
  2754. asCScriptNode *third = second->next;
  2755. if( third->nodeType == snExpressionStatement )
  2756. {
  2757. LineInstr(&nextBC, third->tokenPos);
  2758. CompileExpressionStatement(third, &nextBC);
  2759. }
  2760. //------------------------------
  2761. // Compile loop statement
  2762. bool hasReturn;
  2763. asCByteCode forBC(engine);
  2764. CompileStatement(fnode->lastChild, &hasReturn, &forBC);
  2765. //-------------------------------
  2766. // Join the code pieces
  2767. bc->AddCode(&initBC);
  2768. bc->InstrDWORD(asBC_JMP, conditionLabel);
  2769. bc->Label((short)insideLabel);
  2770. // Add a suspend bytecode inside the loop to guarantee
  2771. // that the application can suspend the execution
  2772. bc->Instr(asBC_SUSPEND);
  2773. bc->InstrPTR(asBC_JitEntry, 0);
  2774. LineInstr(bc, fnode->lastChild->tokenPos);
  2775. bc->AddCode(&forBC);
  2776. bc->Label((short)continueLabel);
  2777. bc->AddCode(&nextBC);
  2778. bc->Label((short)conditionLabel);
  2779. if( expr.bc.GetLastInstr() == -1 )
  2780. // There is no condition, so we just always jump
  2781. bc->InstrDWORD(asBC_JMP, insideLabel);
  2782. else
  2783. bc->AddCode(&expr.bc);
  2784. bc->Label((short)afterLabel);
  2785. continueLabels.PopLast();
  2786. breakLabels.PopLast();
  2787. // Deallocate variables in this block, in reverse order
  2788. for( int n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  2789. {
  2790. sVariable *v = variables->variables[n];
  2791. // Call variable destructors here, for variables not yet destroyed
  2792. CallDestructor(v->type, v->stackOffset, v->onHeap, bc);
  2793. // Don't deallocate function parameters
  2794. if( v->stackOffset > 0 )
  2795. DeallocateVariable(v->stackOffset);
  2796. }
  2797. RemoveVariableScope();
  2798. }
  2799. void asCCompiler::CompileWhileStatement(asCScriptNode *wnode, asCByteCode *bc)
  2800. {
  2801. // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables
  2802. AddVariableScope(true, true);
  2803. // We will use two labels for the while loop
  2804. int beforeLabel = nextLabel++;
  2805. int afterLabel = nextLabel++;
  2806. continueLabels.PushLast(beforeLabel);
  2807. breakLabels.PushLast(afterLabel);
  2808. // Add label before the expression
  2809. bc->Label((short)beforeLabel);
  2810. // Compile expression
  2811. asSExprContext expr(engine);
  2812. CompileAssignment(wnode->firstChild, &expr);
  2813. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  2814. Error(TXT_EXPR_MUST_BE_BOOL, wnode->firstChild);
  2815. else
  2816. {
  2817. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  2818. ProcessDeferredParams(&expr);
  2819. ProcessPropertyGetAccessor(&expr, wnode);
  2820. // Add byte code for the expression
  2821. ConvertToVariable(&expr);
  2822. // Jump to end of statement if expression is false
  2823. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  2824. expr.bc.Instr(asBC_ClrHi);
  2825. expr.bc.InstrDWORD(asBC_JZ, afterLabel);
  2826. ReleaseTemporaryVariable(expr.type, &expr.bc);
  2827. expr.bc.OptimizeLocally(tempVariableOffsets);
  2828. bc->AddCode(&expr.bc);
  2829. }
  2830. // Add a suspend bytecode inside the loop to guarantee
  2831. // that the application can suspend the execution
  2832. bc->Instr(asBC_SUSPEND);
  2833. bc->InstrPTR(asBC_JitEntry, 0);
  2834. // Compile statement
  2835. bool hasReturn;
  2836. asCByteCode whileBC(engine);
  2837. CompileStatement(wnode->lastChild, &hasReturn, &whileBC);
  2838. // Add byte code for the statement
  2839. LineInstr(bc, wnode->lastChild->tokenPos);
  2840. bc->AddCode(&whileBC);
  2841. // Jump to the expression
  2842. bc->InstrINT(asBC_JMP, beforeLabel);
  2843. // Add label after the statement
  2844. bc->Label((short)afterLabel);
  2845. continueLabels.PopLast();
  2846. breakLabels.PopLast();
  2847. RemoveVariableScope();
  2848. }
  2849. void asCCompiler::CompileDoWhileStatement(asCScriptNode *wnode, asCByteCode *bc)
  2850. {
  2851. // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables
  2852. AddVariableScope(true, true);
  2853. // We will use two labels for the while loop
  2854. int beforeLabel = nextLabel++;
  2855. int beforeTest = nextLabel++;
  2856. int afterLabel = nextLabel++;
  2857. continueLabels.PushLast(beforeTest);
  2858. breakLabels.PushLast(afterLabel);
  2859. // Add label before the statement
  2860. bc->Label((short)beforeLabel);
  2861. // Compile statement
  2862. bool hasReturn;
  2863. asCByteCode whileBC(engine);
  2864. CompileStatement(wnode->firstChild, &hasReturn, &whileBC);
  2865. // Add byte code for the statement
  2866. LineInstr(bc, wnode->firstChild->tokenPos);
  2867. bc->AddCode(&whileBC);
  2868. // Add label before the expression
  2869. bc->Label((short)beforeTest);
  2870. // Add a suspend bytecode inside the loop to guarantee
  2871. // that the application can suspend the execution
  2872. bc->Instr(asBC_SUSPEND);
  2873. bc->InstrPTR(asBC_JitEntry, 0);
  2874. // Add a line instruction
  2875. LineInstr(bc, wnode->lastChild->tokenPos);
  2876. // Compile expression
  2877. asSExprContext expr(engine);
  2878. CompileAssignment(wnode->lastChild, &expr);
  2879. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  2880. Error(TXT_EXPR_MUST_BE_BOOL, wnode->firstChild);
  2881. else
  2882. {
  2883. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  2884. ProcessDeferredParams(&expr);
  2885. ProcessPropertyGetAccessor(&expr, wnode);
  2886. // Add byte code for the expression
  2887. ConvertToVariable(&expr);
  2888. // Jump to next iteration if expression is true
  2889. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  2890. expr.bc.Instr(asBC_ClrHi);
  2891. expr.bc.InstrDWORD(asBC_JNZ, beforeLabel);
  2892. ReleaseTemporaryVariable(expr.type, &expr.bc);
  2893. expr.bc.OptimizeLocally(tempVariableOffsets);
  2894. bc->AddCode(&expr.bc);
  2895. }
  2896. // Add label after the statement
  2897. bc->Label((short)afterLabel);
  2898. continueLabels.PopLast();
  2899. breakLabels.PopLast();
  2900. RemoveVariableScope();
  2901. }
  2902. void asCCompiler::CompileBreakStatement(asCScriptNode *node, asCByteCode *bc)
  2903. {
  2904. if( breakLabels.GetLength() == 0 )
  2905. {
  2906. Error(TXT_INVALID_BREAK, node);
  2907. return;
  2908. }
  2909. // Add destructor calls for all variables that will go out of scope
  2910. // Put this clean up in a block to allow exception handler to understand them
  2911. bc->Block(true);
  2912. asCVariableScope *vs = variables;
  2913. while( !vs->isBreakScope )
  2914. {
  2915. for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- )
  2916. CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc);
  2917. vs = vs->parent;
  2918. }
  2919. bc->Block(false);
  2920. bc->InstrINT(asBC_JMP, breakLabels[breakLabels.GetLength()-1]);
  2921. }
  2922. void asCCompiler::CompileContinueStatement(asCScriptNode *node, asCByteCode *bc)
  2923. {
  2924. if( continueLabels.GetLength() == 0 )
  2925. {
  2926. Error(TXT_INVALID_CONTINUE, node);
  2927. return;
  2928. }
  2929. // Add destructor calls for all variables that will go out of scope
  2930. // Put this clean up in a block to allow exception handler to understand them
  2931. bc->Block(true);
  2932. asCVariableScope *vs = variables;
  2933. while( !vs->isContinueScope )
  2934. {
  2935. for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- )
  2936. CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc);
  2937. vs = vs->parent;
  2938. }
  2939. bc->Block(false);
  2940. bc->InstrINT(asBC_JMP, continueLabels[continueLabels.GetLength()-1]);
  2941. }
  2942. void asCCompiler::CompileExpressionStatement(asCScriptNode *enode, asCByteCode *bc)
  2943. {
  2944. if( enode->firstChild )
  2945. {
  2946. // Compile the expression
  2947. asSExprContext expr(engine);
  2948. CompileAssignment(enode->firstChild, &expr);
  2949. // If we get here and there is still an unprocessed property
  2950. // accessor, then process it as a get access. Don't call if there is
  2951. // already a compile error, or we might report an error that is not valid
  2952. if( !hasCompileErrors )
  2953. ProcessPropertyGetAccessor(&expr, enode);
  2954. // Pop the value from the stack
  2955. if( !expr.type.dataType.IsPrimitive() )
  2956. expr.bc.Instr(asBC_PopPtr);
  2957. // Release temporary variables used by expression
  2958. ReleaseTemporaryVariable(expr.type, &expr.bc);
  2959. ProcessDeferredParams(&expr);
  2960. expr.bc.OptimizeLocally(tempVariableOffsets);
  2961. bc->AddCode(&expr.bc);
  2962. }
  2963. }
  2964. void asCCompiler::PrepareTemporaryObject(asCScriptNode *node, asSExprContext *ctx, bool forceOnHeap)
  2965. {
  2966. // If the object already is stored in temporary variable then nothing needs to be done
  2967. // Note, a type can be temporary without being a variable, in which case it is holding off
  2968. // on releasing a previously used object.
  2969. if( ctx->type.isTemporary && ctx->type.isVariable &&
  2970. !(forceOnHeap && !IsVariableOnHeap(ctx->type.stackOffset)) )
  2971. {
  2972. // If the temporary object is currently not a reference
  2973. // the expression needs to be reevaluated to a reference
  2974. if( !ctx->type.dataType.IsReference() )
  2975. {
  2976. ctx->bc.Instr(asBC_PopPtr);
  2977. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  2978. ctx->type.dataType.MakeReference(true);
  2979. }
  2980. return;
  2981. }
  2982. // Allocate temporary variable
  2983. asCDataType dt = ctx->type.dataType;
  2984. dt.MakeReference(false);
  2985. dt.MakeReadOnly(false);
  2986. int offset = AllocateVariable(dt, true, forceOnHeap);
  2987. // Objects stored on the stack are not considered references
  2988. dt.MakeReference(IsVariableOnHeap(offset));
  2989. asCTypeInfo lvalue;
  2990. lvalue.Set(dt);
  2991. lvalue.isExplicitHandle = ctx->type.isExplicitHandle;
  2992. bool isExplicitHandle = ctx->type.isExplicitHandle;
  2993. if( !dt.IsObjectHandle() &&
  2994. dt.GetObjectType() && (dt.GetBehaviour()->copyconstruct || dt.GetBehaviour()->copyfactory) )
  2995. {
  2996. PrepareForAssignment(&lvalue.dataType, ctx, node, true);
  2997. // Use the copy constructor/factory when available
  2998. CallCopyConstructor(dt, offset, IsVariableOnHeap(offset), &ctx->bc, ctx, node);
  2999. }
  3000. else
  3001. {
  3002. // Allocate and construct the temporary object
  3003. int r = CallDefaultConstructor(dt, offset, IsVariableOnHeap(offset), &ctx->bc, node);
  3004. if( r < 0 )
  3005. {
  3006. Error(TXT_FAILED_TO_CREATE_TEMP_OBJ, node);
  3007. }
  3008. else
  3009. {
  3010. // Assign the object to the temporary variable
  3011. PrepareForAssignment(&lvalue.dataType, ctx, node, true);
  3012. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  3013. r = PerformAssignment(&lvalue, &ctx->type, &ctx->bc, node);
  3014. if( r < 0 )
  3015. {
  3016. Error(TXT_FAILED_TO_CREATE_TEMP_OBJ, node);
  3017. }
  3018. // Release any temp that may have been created as the result of opAssign
  3019. ReleaseTemporaryVariable(lvalue, &ctx->bc);
  3020. // Pop the original reference
  3021. if( !lvalue.dataType.IsPrimitive() )
  3022. ctx->bc.Instr(asBC_PopPtr);
  3023. }
  3024. // If the expression was holding off on releasing a
  3025. // previously used object, we need to release it now
  3026. if( ctx->type.isTemporary )
  3027. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3028. }
  3029. // Push the reference to the temporary variable on the stack
  3030. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  3031. ctx->type.Set(dt);
  3032. ctx->type.isTemporary = true;
  3033. ctx->type.stackOffset = (short)offset;
  3034. ctx->type.isVariable = true;
  3035. ctx->type.isExplicitHandle = isExplicitHandle;
  3036. ctx->type.dataType.MakeReference(IsVariableOnHeap(offset));
  3037. }
  3038. void asCCompiler::CompileReturnStatement(asCScriptNode *rnode, asCByteCode *bc)
  3039. {
  3040. // Get return type and location
  3041. sVariable *v = variables->GetVariable("return");
  3042. // Basic validations
  3043. if( v->type.GetSizeOnStackDWords() > 0 && !rnode->firstChild )
  3044. {
  3045. Error(TXT_MUST_RETURN_VALUE, rnode);
  3046. return;
  3047. }
  3048. else if( v->type.GetSizeOnStackDWords() == 0 && rnode->firstChild )
  3049. {
  3050. Error(TXT_CANT_RETURN_VALUE, rnode);
  3051. return;
  3052. }
  3053. // Compile the expression
  3054. if( rnode->firstChild )
  3055. {
  3056. // Compile the expression
  3057. asSExprContext expr(engine);
  3058. int r = CompileAssignment(rnode->firstChild, &expr);
  3059. if( r < 0 ) return;
  3060. if( v->type.IsReference() )
  3061. {
  3062. // The expression that gives the reference must not use any of the
  3063. // variables that must be destroyed upon exit, because then it means
  3064. // reference will stay alive while the clean-up is done, which could
  3065. // potentially mean that the reference is invalidated by the clean-up.
  3066. //
  3067. // When the function is returning a reference, the clean-up of the
  3068. // variables must be done before the evaluation of the expression.
  3069. //
  3070. // A reference to a global variable, or a class member for class methods
  3071. // should be allowed to be returned.
  3072. if( !(expr.type.dataType.IsReference() ||
  3073. (expr.type.dataType.IsObject() && !expr.type.dataType.IsObjectHandle())) )
  3074. {
  3075. // Clean up the potential deferred parameters
  3076. ProcessDeferredParams(&expr);
  3077. Error(TXT_NOT_VALID_REFERENCE, rnode);
  3078. return;
  3079. }
  3080. // No references to local variables, temporary variables, or parameters
  3081. // are allowed to be returned, since they go out of scope when the function
  3082. // returns. Even reference parameters are disallowed, since it is not possible
  3083. // to know the scope of them. The exception is the 'this' pointer, which
  3084. // is treated by the compiler as a local variable, but isn't really so.
  3085. if( (expr.type.isVariable && !(expr.type.stackOffset == 0 && outFunc->objectType)) || expr.type.isTemporary )
  3086. {
  3087. // Clean up the potential deferred parameters
  3088. ProcessDeferredParams(&expr);
  3089. Error(TXT_CANNOT_RETURN_REF_TO_LOCAL, rnode);
  3090. return;
  3091. }
  3092. // The type must match exactly as we cannot convert
  3093. // the reference without loosing the original value
  3094. if( !(v->type.IsEqualExceptConst(expr.type.dataType) ||
  3095. (expr.type.dataType.IsObject() &&
  3096. !expr.type.dataType.IsObjectHandle() &&
  3097. v->type.IsEqualExceptRefAndConst(expr.type.dataType))) ||
  3098. (!v->type.IsReadOnly() && expr.type.dataType.IsReadOnly()) )
  3099. {
  3100. // Clean up the potential deferred parameters
  3101. ProcessDeferredParams(&expr);
  3102. asCString str;
  3103. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, expr.type.dataType.Format().AddressOf(), v->type.Format().AddressOf());
  3104. Error(str, rnode);
  3105. return;
  3106. }
  3107. // The expression must not have any deferred expressions, because the evaluation
  3108. // of these cannot be done without keeping the reference which is not safe
  3109. if( expr.deferredParams.GetLength() )
  3110. {
  3111. // Clean up the potential deferred parameters
  3112. ProcessDeferredParams(&expr);
  3113. Error(TXT_REF_CANT_BE_RETURNED_DEFERRED_PARAM, rnode);
  3114. return;
  3115. }
  3116. // Make sure the expression isn't using any local variables that
  3117. // will need to be cleaned up before the function completes
  3118. asCArray<int> usedVars;
  3119. expr.bc.GetVarsUsed(usedVars);
  3120. for( asUINT n = 0; n < usedVars.GetLength(); n++ )
  3121. {
  3122. int var = GetVariableSlot(usedVars[n]);
  3123. if( var != -1 )
  3124. {
  3125. asCDataType dt = variableAllocations[var];
  3126. if( dt.IsObject() )
  3127. {
  3128. ProcessDeferredParams(&expr);
  3129. Error(TXT_REF_CANT_BE_RETURNED_LOCAL_VARS, rnode);
  3130. return;
  3131. }
  3132. }
  3133. }
  3134. // All objects in the function must be cleaned up before the expression
  3135. // is evaluated, otherwise there is a possibility that the cleanup will
  3136. // invalidate the reference.
  3137. // Destroy the local variables before loading
  3138. // the reference into the register. This will
  3139. // be done before the expression is evaluated.
  3140. DestroyVariables(bc);
  3141. // For primitives the reference is already in the register,
  3142. // but for non-primitives the reference is on the stack so we
  3143. // need to load it into the register
  3144. if( !expr.type.dataType.IsPrimitive() )
  3145. {
  3146. if( !expr.type.dataType.IsObjectHandle() &&
  3147. expr.type.dataType.IsReference() )
  3148. expr.bc.Instr(asBC_RDSPtr);
  3149. expr.bc.Instr(asBC_PopRPtr);
  3150. }
  3151. // There are no temporaries to release so we're done
  3152. }
  3153. else // if( !v->type.IsReference() )
  3154. {
  3155. ProcessPropertyGetAccessor(&expr, rnode);
  3156. // Prepare the value for assignment
  3157. IsVariableInitialized(&expr.type, rnode->firstChild);
  3158. if( v->type.IsPrimitive() )
  3159. {
  3160. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  3161. // Implicitly convert the value to the return type
  3162. ImplicitConversion(&expr, v->type, rnode->firstChild, asIC_IMPLICIT_CONV);
  3163. // Verify that the conversion was successful
  3164. if( expr.type.dataType != v->type )
  3165. {
  3166. asCString str;
  3167. str.Format(TXT_NO_CONVERSION_s_TO_s, expr.type.dataType.Format().AddressOf(), v->type.Format().AddressOf());
  3168. Error(str, rnode);
  3169. return;
  3170. }
  3171. else
  3172. {
  3173. ConvertToVariable(&expr);
  3174. // Clean up the local variables and process deferred parameters
  3175. DestroyVariables(&expr.bc);
  3176. ProcessDeferredParams(&expr);
  3177. ReleaseTemporaryVariable(expr.type, &expr.bc);
  3178. // Load the variable in the register
  3179. if( v->type.GetSizeOnStackDWords() == 1 )
  3180. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  3181. else
  3182. expr.bc.InstrSHORT(asBC_CpyVtoR8, expr.type.stackOffset);
  3183. }
  3184. }
  3185. else if( v->type.IsObject() )
  3186. {
  3187. // Value types are returned on the stack, in a location
  3188. // that has been reserved by the calling function.
  3189. if( outFunc->DoesReturnOnStack() )
  3190. {
  3191. // TODO: runtime optimize: If the return type has a constructor that takes the type of the expression,
  3192. // it should be called directly instead of first converting the expression and
  3193. // then copy the value.
  3194. if( !v->type.IsEqualExceptRefAndConst(expr.type.dataType) )
  3195. {
  3196. ImplicitConversion(&expr, v->type, rnode->firstChild, asIC_IMPLICIT_CONV);
  3197. if( !v->type.IsEqualExceptRefAndConst(expr.type.dataType) )
  3198. {
  3199. asCString str;
  3200. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, expr.type.dataType.Format().AddressOf(), v->type.Format().AddressOf());
  3201. Error(str, rnode->firstChild);
  3202. return;
  3203. }
  3204. }
  3205. int offset = outFunc->objectType ? -AS_PTR_SIZE : 0;
  3206. if( v->type.GetObjectType()->beh.copyconstruct )
  3207. {
  3208. PrepareForAssignment(&v->type, &expr, rnode->firstChild, false);
  3209. CallCopyConstructor(v->type, offset, false, &expr.bc, &expr, rnode->firstChild, false, true);
  3210. }
  3211. else
  3212. {
  3213. // If the copy constructor doesn't exist, then a manual assignment needs to be done instead.
  3214. CallDefaultConstructor(v->type, offset, false, &expr.bc, rnode->firstChild, 0, true);
  3215. PrepareForAssignment(&v->type, &expr, rnode->firstChild, false);
  3216. expr.bc.InstrSHORT(asBC_PSF, (short)offset);
  3217. expr.bc.Instr(asBC_RDSPtr);
  3218. asSExprContext lexpr(engine);
  3219. lexpr.type.Set(v->type);
  3220. lexpr.type.isLValue = true;
  3221. PerformAssignment(&lexpr.type, &expr.type, &expr.bc, rnode->firstChild);
  3222. expr.bc.Instr(asBC_PopPtr);
  3223. // Release any temporary variable
  3224. ReleaseTemporaryVariable(expr.type, &expr.bc);
  3225. }
  3226. // Clean up the local variables and process deferred parameters
  3227. DestroyVariables(&expr.bc);
  3228. ProcessDeferredParams(&expr);
  3229. }
  3230. else
  3231. {
  3232. asASSERT( v->type.GetObjectType()->flags & asOBJ_REF );
  3233. // Prepare the expression to be loaded into the object
  3234. // register. This will place the reference in local variable
  3235. PrepareArgument(&v->type, &expr, rnode->firstChild, false, 0);
  3236. // Pop the reference to the temporary variable
  3237. expr.bc.Instr(asBC_PopPtr);
  3238. // Clean up the local variables and process deferred parameters
  3239. DestroyVariables(&expr.bc);
  3240. ProcessDeferredParams(&expr);
  3241. // Load the object pointer into the object register
  3242. // LOADOBJ also clears the address in the variable
  3243. expr.bc.InstrSHORT(asBC_LOADOBJ, expr.type.stackOffset);
  3244. // LOADOBJ cleared the address in the variable so the object will not be freed
  3245. // here, but the temporary variable must still be freed so the slot can be reused
  3246. // By releasing without the bytecode we do just that.
  3247. ReleaseTemporaryVariable(expr.type, 0);
  3248. }
  3249. }
  3250. }
  3251. expr.bc.OptimizeLocally(tempVariableOffsets);
  3252. bc->AddCode(&expr.bc);
  3253. }
  3254. else
  3255. {
  3256. // For functions that don't return anything
  3257. // we just detroy the local variables
  3258. DestroyVariables(bc);
  3259. }
  3260. // Jump to the end of the function
  3261. bc->InstrINT(asBC_JMP, 0);
  3262. }
  3263. void asCCompiler::DestroyVariables(asCByteCode *bc)
  3264. {
  3265. // Call destructor on all variables except for the function parameters
  3266. // Put the clean-up in a block to allow exception handler to understand this
  3267. bc->Block(true);
  3268. asCVariableScope *vs = variables;
  3269. while( vs )
  3270. {
  3271. for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- )
  3272. if( vs->variables[n]->stackOffset > 0 )
  3273. CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc);
  3274. vs = vs->parent;
  3275. }
  3276. bc->Block(false);
  3277. }
  3278. void asCCompiler::AddVariableScope(bool isBreakScope, bool isContinueScope)
  3279. {
  3280. variables = asNEW(asCVariableScope)(variables);
  3281. if( variables == 0 )
  3282. {
  3283. // Out of memory
  3284. return;
  3285. }
  3286. variables->isBreakScope = isBreakScope;
  3287. variables->isContinueScope = isContinueScope;
  3288. }
  3289. void asCCompiler::RemoveVariableScope()
  3290. {
  3291. if( variables )
  3292. {
  3293. asCVariableScope *var = variables;
  3294. variables = variables->parent;
  3295. asDELETE(var,asCVariableScope);
  3296. }
  3297. }
  3298. void asCCompiler::Error(const asCString &msg, asCScriptNode *node)
  3299. {
  3300. asCString str;
  3301. int r = 0, c = 0;
  3302. asASSERT( node );
  3303. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  3304. builder->WriteError(script->name, msg, r, c);
  3305. hasCompileErrors = true;
  3306. }
  3307. void asCCompiler::Warning(const asCString &msg, asCScriptNode *node)
  3308. {
  3309. asCString str;
  3310. int r = 0, c = 0;
  3311. asASSERT( node );
  3312. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  3313. builder->WriteWarning(script->name, msg, r, c);
  3314. }
  3315. void asCCompiler::Information(const asCString &msg, asCScriptNode *node)
  3316. {
  3317. asCString str;
  3318. int r = 0, c = 0;
  3319. asASSERT( node );
  3320. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  3321. builder->WriteInfo(script->name, msg, r, c, false);
  3322. }
  3323. void asCCompiler::PrintMatchingFuncs(asCArray<int> &funcs, asCScriptNode *node)
  3324. {
  3325. int r = 0, c = 0;
  3326. asASSERT( node );
  3327. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  3328. for( unsigned int n = 0; n < funcs.GetLength(); n++ )
  3329. {
  3330. asIScriptFunction *func = builder->GetFunctionDescription(funcs[n]);
  3331. builder->WriteInfo(script->name, func->GetDeclaration(true), r, c, false);
  3332. }
  3333. }
  3334. int asCCompiler::AllocateVariableNotIn(const asCDataType &type, bool isTemporary, bool forceOnHeap, asSExprContext *ctx)
  3335. {
  3336. int l = int(reservedVariables.GetLength());
  3337. ctx->bc.GetVarsUsed(reservedVariables);
  3338. int var = AllocateVariable(type, isTemporary, forceOnHeap);
  3339. reservedVariables.SetLength(l);
  3340. return var;
  3341. }
  3342. int asCCompiler::AllocateVariable(const asCDataType &type, bool isTemporary, bool forceOnHeap)
  3343. {
  3344. asCDataType t(type);
  3345. if( t.IsPrimitive() && t.GetSizeOnStackDWords() == 1 )
  3346. t.SetTokenType(ttInt);
  3347. if( t.IsPrimitive() && t.GetSizeOnStackDWords() == 2 )
  3348. t.SetTokenType(ttDouble);
  3349. // Only null handles have the token type unrecognized token
  3350. asASSERT( t.IsObjectHandle() || t.GetTokenType() != ttUnrecognizedToken );
  3351. bool isOnHeap = true;
  3352. if( t.IsPrimitive() ||
  3353. (t.GetObjectType() && (t.GetObjectType()->GetFlags() & asOBJ_VALUE) && !forceOnHeap) )
  3354. {
  3355. // Primitives and value types (unless overridden) are allocated on the stack
  3356. isOnHeap = false;
  3357. }
  3358. // Find a free location with the same type
  3359. for( asUINT n = 0; n < freeVariables.GetLength(); n++ )
  3360. {
  3361. int slot = freeVariables[n];
  3362. if( variableAllocations[slot].IsEqualExceptConst(t) &&
  3363. variableIsTemporary[slot] == isTemporary &&
  3364. variableIsOnHeap[slot] == isOnHeap )
  3365. {
  3366. // We can't return by slot, must count variable sizes
  3367. int offset = GetVariableOffset(slot);
  3368. // Verify that it is not in the list of reserved variables
  3369. bool isUsed = false;
  3370. if( reservedVariables.GetLength() )
  3371. isUsed = reservedVariables.Exists(offset);
  3372. if( !isUsed )
  3373. {
  3374. if( n != freeVariables.GetLength() - 1 )
  3375. freeVariables[n] = freeVariables.PopLast();
  3376. else
  3377. freeVariables.PopLast();
  3378. if( isTemporary )
  3379. tempVariables.PushLast(offset);
  3380. return offset;
  3381. }
  3382. }
  3383. }
  3384. variableAllocations.PushLast(t);
  3385. variableIsTemporary.PushLast(isTemporary);
  3386. variableIsOnHeap.PushLast(isOnHeap);
  3387. int offset = GetVariableOffset((int)variableAllocations.GetLength()-1);
  3388. if( isTemporary )
  3389. {
  3390. // Add offset to the currently allocated temporary variables
  3391. tempVariables.PushLast(offset);
  3392. // Add offset to all known offsets to temporary variables, whether allocated or not
  3393. tempVariableOffsets.PushLast(offset);
  3394. }
  3395. return offset;
  3396. }
  3397. int asCCompiler::GetVariableOffset(int varIndex)
  3398. {
  3399. // Return offset to the last dword on the stack
  3400. int varOffset = 1;
  3401. for( int n = 0; n < varIndex; n++ )
  3402. {
  3403. if( !variableIsOnHeap[n] && variableAllocations[n].IsObject() )
  3404. varOffset += variableAllocations[n].GetSizeInMemoryDWords();
  3405. else
  3406. varOffset += variableAllocations[n].GetSizeOnStackDWords();
  3407. }
  3408. if( varIndex < (int)variableAllocations.GetLength() )
  3409. {
  3410. int size;
  3411. if( !variableIsOnHeap[varIndex] && variableAllocations[varIndex].IsObject() )
  3412. size = variableAllocations[varIndex].GetSizeInMemoryDWords();
  3413. else
  3414. size = variableAllocations[varIndex].GetSizeOnStackDWords();
  3415. if( size > 1 )
  3416. varOffset += size-1;
  3417. }
  3418. return varOffset;
  3419. }
  3420. int asCCompiler::GetVariableSlot(int offset)
  3421. {
  3422. int varOffset = 1;
  3423. for( asUINT n = 0; n < variableAllocations.GetLength(); n++ )
  3424. {
  3425. if( !variableIsOnHeap[n] && variableAllocations[n].IsObject() )
  3426. varOffset += -1 + variableAllocations[n].GetSizeInMemoryDWords();
  3427. else
  3428. varOffset += -1 + variableAllocations[n].GetSizeOnStackDWords();
  3429. if( varOffset == offset )
  3430. return n;
  3431. varOffset++;
  3432. }
  3433. return -1;
  3434. }
  3435. bool asCCompiler::IsVariableOnHeap(int offset)
  3436. {
  3437. int varSlot = GetVariableSlot(offset);
  3438. if( varSlot < 0 )
  3439. {
  3440. // This happens for function arguments that are considered as on the heap
  3441. return true;
  3442. }
  3443. return variableIsOnHeap[varSlot];
  3444. }
  3445. void asCCompiler::DeallocateVariable(int offset)
  3446. {
  3447. // Remove temporary variable
  3448. int n;
  3449. for( n = 0; n < (int)tempVariables.GetLength(); n++ )
  3450. {
  3451. if( offset == tempVariables[n] )
  3452. {
  3453. if( n == (int)tempVariables.GetLength()-1 )
  3454. tempVariables.PopLast();
  3455. else
  3456. tempVariables[n] = tempVariables.PopLast();
  3457. break;
  3458. }
  3459. }
  3460. n = GetVariableSlot(offset);
  3461. if( n != -1 )
  3462. {
  3463. freeVariables.PushLast(n);
  3464. return;
  3465. }
  3466. // We might get here if the variable was implicitly declared
  3467. // because it was use before a formal declaration, in this case
  3468. // the offset is 0x7FFF
  3469. asASSERT(offset == 0x7FFF);
  3470. }
  3471. void asCCompiler::ReleaseTemporaryVariable(asCTypeInfo &t, asCByteCode *bc)
  3472. {
  3473. if( t.isTemporary )
  3474. {
  3475. ReleaseTemporaryVariable(t.stackOffset, bc);
  3476. t.isTemporary = false;
  3477. }
  3478. }
  3479. void asCCompiler::ReleaseTemporaryVariable(int offset, asCByteCode *bc)
  3480. {
  3481. if( bc )
  3482. {
  3483. // We need to call the destructor on the true variable type
  3484. int n = GetVariableSlot(offset);
  3485. asASSERT( n >= 0 );
  3486. if( n >= 0 )
  3487. {
  3488. asCDataType dt = variableAllocations[n];
  3489. bool isOnHeap = variableIsOnHeap[n];
  3490. // Call destructor
  3491. CallDestructor(dt, offset, isOnHeap, bc);
  3492. }
  3493. }
  3494. DeallocateVariable(offset);
  3495. }
  3496. void asCCompiler::Dereference(asSExprContext *ctx, bool generateCode)
  3497. {
  3498. if( ctx->type.dataType.IsReference() )
  3499. {
  3500. if( ctx->type.dataType.IsObject() )
  3501. {
  3502. ctx->type.dataType.MakeReference(false);
  3503. if( generateCode )
  3504. ctx->bc.Instr(asBC_RDSPtr);
  3505. }
  3506. else
  3507. {
  3508. // This should never happen as primitives are treated differently
  3509. asASSERT(false);
  3510. }
  3511. }
  3512. }
  3513. bool asCCompiler::IsVariableInitialized(asCTypeInfo *type, asCScriptNode *node)
  3514. {
  3515. // No need to check if there is no variable scope
  3516. if( variables == 0 ) return true;
  3517. // Temporary variables are assumed to be initialized
  3518. if( type->isTemporary ) return true;
  3519. // Verify that it is a variable
  3520. if( !type->isVariable ) return true;
  3521. // Find the variable
  3522. sVariable *v = variables->GetVariableByOffset(type->stackOffset);
  3523. // The variable isn't found if it is a constant, in which case it is guaranteed to be initialized
  3524. if( v == 0 ) return true;
  3525. if( v->isInitialized ) return true;
  3526. // Complex types don't need this test
  3527. if( v->type.IsObject() ) return true;
  3528. // Mark as initialized so that the user will not be bothered again
  3529. v->isInitialized = true;
  3530. // Write warning
  3531. asCString str;
  3532. str.Format(TXT_s_NOT_INITIALIZED, (const char *)v->name.AddressOf());
  3533. Warning(str, node);
  3534. return false;
  3535. }
  3536. void asCCompiler::PrepareOperand(asSExprContext *ctx, asCScriptNode *node)
  3537. {
  3538. // Check if the variable is initialized (if it indeed is a variable)
  3539. IsVariableInitialized(&ctx->type, node);
  3540. asCDataType to = ctx->type.dataType;
  3541. to.MakeReference(false);
  3542. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV);
  3543. ProcessDeferredParams(ctx);
  3544. }
  3545. void asCCompiler::PrepareForAssignment(asCDataType *lvalue, asSExprContext *rctx, asCScriptNode *node, bool toTemporary, asSExprContext *lvalueExpr)
  3546. {
  3547. // Reserve the temporary variables used in the lvalue expression so they won't end up being used by the rvalue too
  3548. int l = int(reservedVariables.GetLength());
  3549. if( lvalueExpr ) lvalueExpr->bc.GetVarsUsed(reservedVariables);
  3550. ProcessPropertyGetAccessor(rctx, node);
  3551. // Make sure the rvalue is initialized if it is a variable
  3552. IsVariableInitialized(&rctx->type, node);
  3553. if( lvalue->IsPrimitive() )
  3554. {
  3555. if( rctx->type.dataType.IsPrimitive() )
  3556. {
  3557. if( rctx->type.dataType.IsReference() )
  3558. {
  3559. // Cannot do implicit conversion of references so we first convert the reference to a variable
  3560. ConvertToVariableNotIn(rctx, lvalueExpr);
  3561. }
  3562. }
  3563. // Implicitly convert the value to the right type
  3564. ImplicitConversion(rctx, *lvalue, node, asIC_IMPLICIT_CONV);
  3565. // Check data type
  3566. if( !lvalue->IsEqualExceptRefAndConst(rctx->type.dataType) )
  3567. {
  3568. asCString str;
  3569. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format().AddressOf(), lvalue->Format().AddressOf());
  3570. Error(str, node);
  3571. rctx->type.SetDummy();
  3572. }
  3573. // Make sure the rvalue is a variable
  3574. if( !rctx->type.isVariable )
  3575. ConvertToVariableNotIn(rctx, lvalueExpr);
  3576. }
  3577. else
  3578. {
  3579. asCDataType to = *lvalue;
  3580. to.MakeReference(false);
  3581. // TODO: ImplicitConversion should know to do this by itself
  3582. // First convert to a handle which will do a reference cast
  3583. if( !lvalue->IsObjectHandle() &&
  3584. (lvalue->GetObjectType()->flags & asOBJ_SCRIPT_OBJECT) )
  3585. to.MakeHandle(true);
  3586. // Don't allow the implicit conversion to create an object
  3587. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true, !toTemporary);
  3588. if( !lvalue->IsObjectHandle() &&
  3589. (lvalue->GetObjectType()->flags & asOBJ_SCRIPT_OBJECT) )
  3590. {
  3591. // Then convert to a reference, which will validate the handle
  3592. to.MakeHandle(false);
  3593. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true, !toTemporary);
  3594. }
  3595. // Check data type
  3596. if( !lvalue->IsEqualExceptRefAndConst(rctx->type.dataType) )
  3597. {
  3598. asCString str;
  3599. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format().AddressOf(), lvalue->Format().AddressOf());
  3600. Error(str, node);
  3601. }
  3602. else
  3603. {
  3604. // If the assignment will be made with the copy behaviour then the rvalue must not be a reference
  3605. if( lvalue->IsObject() )
  3606. asASSERT(!rctx->type.dataType.IsReference());
  3607. }
  3608. }
  3609. // Unreserve variables
  3610. reservedVariables.SetLength(l);
  3611. }
  3612. bool asCCompiler::IsLValue(asCTypeInfo &type)
  3613. {
  3614. if( !type.isLValue ) return false;
  3615. if( type.dataType.IsReadOnly() ) return false;
  3616. if( !type.dataType.IsObject() && !type.isVariable && !type.dataType.IsReference() ) return false;
  3617. return true;
  3618. }
  3619. int asCCompiler::PerformAssignment(asCTypeInfo *lvalue, asCTypeInfo *rvalue, asCByteCode *bc, asCScriptNode *node)
  3620. {
  3621. if( lvalue->dataType.IsReadOnly() )
  3622. {
  3623. Error(TXT_REF_IS_READ_ONLY, node);
  3624. return -1;
  3625. }
  3626. if( lvalue->dataType.IsPrimitive() )
  3627. {
  3628. if( lvalue->isVariable )
  3629. {
  3630. // Copy the value between the variables directly
  3631. if( lvalue->dataType.GetSizeInMemoryDWords() == 1 )
  3632. bc->InstrW_W(asBC_CpyVtoV4, lvalue->stackOffset, rvalue->stackOffset);
  3633. else
  3634. bc->InstrW_W(asBC_CpyVtoV8, lvalue->stackOffset, rvalue->stackOffset);
  3635. // Mark variable as initialized
  3636. sVariable *v = variables->GetVariableByOffset(lvalue->stackOffset);
  3637. if( v ) v->isInitialized = true;
  3638. }
  3639. else if( lvalue->dataType.IsReference() )
  3640. {
  3641. // Copy the value of the variable to the reference in the register
  3642. int s = lvalue->dataType.GetSizeInMemoryBytes();
  3643. if( s == 1 )
  3644. bc->InstrSHORT(asBC_WRTV1, rvalue->stackOffset);
  3645. else if( s == 2 )
  3646. bc->InstrSHORT(asBC_WRTV2, rvalue->stackOffset);
  3647. else if( s == 4 )
  3648. bc->InstrSHORT(asBC_WRTV4, rvalue->stackOffset);
  3649. else if( s == 8 )
  3650. bc->InstrSHORT(asBC_WRTV8, rvalue->stackOffset);
  3651. }
  3652. else
  3653. {
  3654. Error(TXT_NOT_VALID_LVALUE, node);
  3655. return -1;
  3656. }
  3657. }
  3658. else if( !lvalue->isExplicitHandle )
  3659. {
  3660. asSExprContext ctx(engine);
  3661. ctx.type = *lvalue;
  3662. Dereference(&ctx, true);
  3663. *lvalue = ctx.type;
  3664. bc->AddCode(&ctx.bc);
  3665. // TODO: Should find the opAssign method that implements the default copy behaviour.
  3666. // The beh->copy member will be removed.
  3667. asSTypeBehaviour *beh = lvalue->dataType.GetBehaviour();
  3668. if( beh->copy && beh->copy != engine->scriptTypeBehaviours.beh.copy )
  3669. {
  3670. asSExprContext res(engine);
  3671. PerformFunctionCall(beh->copy, &res, false, 0, lvalue->dataType.GetObjectType());
  3672. bc->AddCode(&res.bc);
  3673. *lvalue = res.type;
  3674. }
  3675. else if( beh->copy == engine->scriptTypeBehaviours.beh.copy )
  3676. {
  3677. // Call the default copy operator for script classes
  3678. // This is done differently because the default copy operator
  3679. // is registered as returning int&, but in reality it returns
  3680. // a reference to the object.
  3681. // TODO: Avoid this special case by implementing a copystub for
  3682. // script classes that uses the default copy operator
  3683. bc->Call(asBC_CALLSYS, beh->copy, 2*AS_PTR_SIZE);
  3684. bc->Instr(asBC_PshRPtr);
  3685. }
  3686. else
  3687. {
  3688. // Default copy operator
  3689. if( lvalue->dataType.GetSizeInMemoryDWords() == 0 ||
  3690. !(lvalue->dataType.GetObjectType()->flags & asOBJ_POD) )
  3691. {
  3692. asCString msg;
  3693. msg.Format(TXT_NO_DEFAULT_COPY_OP_FOR_s, lvalue->dataType.GetObjectType()->name.AddressOf());
  3694. Error(msg, node);
  3695. return -1;
  3696. }
  3697. // Copy larger data types from a reference
  3698. // TODO: runtime optimize: COPY should pop both arguments and store the reference in the register.
  3699. bc->InstrSHORT_DW(asBC_COPY, (short)lvalue->dataType.GetSizeInMemoryDWords(), engine->GetTypeIdFromDataType(lvalue->dataType));
  3700. }
  3701. }
  3702. else
  3703. {
  3704. // TODO: The object handle can be stored in a variable as well
  3705. if( !lvalue->dataType.IsReference() )
  3706. {
  3707. Error(TXT_NOT_VALID_REFERENCE, node);
  3708. return -1;
  3709. }
  3710. bc->InstrPTR(asBC_REFCPY, lvalue->dataType.GetObjectType());
  3711. // Mark variable as initialized
  3712. if( variables )
  3713. {
  3714. sVariable *v = variables->GetVariableByOffset(lvalue->stackOffset);
  3715. if( v ) v->isInitialized = true;
  3716. }
  3717. }
  3718. return 0;
  3719. }
  3720. bool asCCompiler::CompileRefCast(asSExprContext *ctx, const asCDataType &to, bool isExplicit, asCScriptNode *node, bool generateCode)
  3721. {
  3722. bool conversionDone = false;
  3723. asCArray<int> ops;
  3724. asUINT n;
  3725. if( ctx->type.dataType.GetObjectType()->flags & asOBJ_SCRIPT_OBJECT )
  3726. {
  3727. // We need it to be a reference
  3728. if( !ctx->type.dataType.IsReference() )
  3729. {
  3730. asCDataType to = ctx->type.dataType;
  3731. to.MakeReference(true);
  3732. ImplicitConversion(ctx, to, 0, isExplicit ? asIC_EXPLICIT_REF_CAST : asIC_IMPLICIT_CONV, generateCode);
  3733. }
  3734. if( isExplicit )
  3735. {
  3736. // Allow dynamic cast between object handles (only for script objects).
  3737. // At run time this may result in a null handle,
  3738. // which when used will throw an exception
  3739. conversionDone = true;
  3740. if( generateCode )
  3741. {
  3742. ctx->bc.InstrDWORD(asBC_Cast, engine->GetTypeIdFromDataType(to));
  3743. // Allocate a temporary variable for the returned object
  3744. int returnOffset = AllocateVariable(to, true);
  3745. // Move the pointer from the object register to the temporary variable
  3746. ctx->bc.InstrSHORT(asBC_STOREOBJ, (short)returnOffset);
  3747. ctx->bc.InstrSHORT(asBC_PSF, (short)returnOffset);
  3748. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3749. ctx->type.SetVariable(to, returnOffset, true);
  3750. ctx->type.dataType.MakeReference(true);
  3751. }
  3752. else
  3753. {
  3754. ctx->type.dataType = to;
  3755. ctx->type.dataType.MakeReference(true);
  3756. }
  3757. }
  3758. else
  3759. {
  3760. if( ctx->type.dataType.GetObjectType()->DerivesFrom(to.GetObjectType()) )
  3761. {
  3762. conversionDone = true;
  3763. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3764. }
  3765. }
  3766. }
  3767. else
  3768. {
  3769. // Find a suitable registered behaviour
  3770. asSTypeBehaviour *beh = &ctx->type.dataType.GetObjectType()->beh;
  3771. for( n = 0; n < beh->operators.GetLength(); n+= 2 )
  3772. {
  3773. if( (isExplicit && asBEHAVE_REF_CAST == beh->operators[n]) ||
  3774. asBEHAVE_IMPLICIT_REF_CAST == beh->operators[n] )
  3775. {
  3776. int funcId = beh->operators[n+1];
  3777. // Is the operator for the output type?
  3778. asCScriptFunction *func = engine->scriptFunctions[funcId];
  3779. if( func->returnType.GetObjectType() != to.GetObjectType() )
  3780. continue;
  3781. ops.PushLast(funcId);
  3782. }
  3783. }
  3784. // It shouldn't be possible to have more than one
  3785. asASSERT( ops.GetLength() <= 1 );
  3786. // Should only have one behaviour for each output type
  3787. if( ops.GetLength() == 1 )
  3788. {
  3789. if( generateCode )
  3790. {
  3791. // TODO: runtime optimize: Instead of producing bytecode for checking if the handle is
  3792. // null, we can create a special CALLSYS instruction that checks
  3793. // if the object pointer is null and if so sets the object register
  3794. // to null directly without executing the function.
  3795. //
  3796. // Alternatively I could force the ref cast behaviours be global
  3797. // functions with 1 parameter, even though they should still be
  3798. // registered with RegisterObjectBehaviour()
  3799. // Add code to avoid calling the cast behaviour if the handle is already null,
  3800. // because that will raise a null pointer exception due to the cast behaviour
  3801. // being a class method, and the this pointer cannot be null.
  3802. if( ctx->type.isVariable )
  3803. ctx->bc.Instr(asBC_PopPtr);
  3804. else
  3805. {
  3806. Dereference(ctx, true);
  3807. ConvertToVariable(ctx);
  3808. }
  3809. // TODO: runtime optimize: should have immediate comparison for null pointer
  3810. int offset = AllocateVariable(asCDataType::CreateNullHandle(), true);
  3811. // 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)
  3812. ctx->bc.InstrSHORT(asBC_ClrVPtr, (asWORD)offset);
  3813. ctx->bc.InstrW_W(asBC_CmpPtr, ctx->type.stackOffset, offset);
  3814. DeallocateVariable(offset);
  3815. int afterLabel = nextLabel++;
  3816. ctx->bc.InstrDWORD(asBC_JZ, afterLabel);
  3817. // Call the cast operator
  3818. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  3819. ctx->bc.Instr(asBC_RDSPtr);
  3820. ctx->type.dataType.MakeReference(false);
  3821. asCTypeInfo objType = ctx->type;
  3822. asCArray<asSExprContext *> args;
  3823. MakeFunctionCall(ctx, ops[0], objType.dataType.GetObjectType(), args, node);
  3824. ctx->bc.Instr(asBC_PopPtr);
  3825. int endLabel = nextLabel++;
  3826. ctx->bc.InstrINT(asBC_JMP, endLabel);
  3827. ctx->bc.Label((short)afterLabel);
  3828. // Make a NULL pointer
  3829. ctx->bc.InstrSHORT(asBC_ClrVPtr, ctx->type.stackOffset);
  3830. ctx->bc.Label((short)endLabel);
  3831. // Since we're receiving a handle, we can release the original variable
  3832. ReleaseTemporaryVariable(objType, &ctx->bc);
  3833. // Push the reference to the handle on the stack
  3834. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  3835. }
  3836. else
  3837. {
  3838. asCScriptFunction *func = engine->scriptFunctions[ops[0]];
  3839. ctx->type.Set(func->returnType);
  3840. }
  3841. }
  3842. else if( ops.GetLength() == 0 )
  3843. {
  3844. // Check for the generic ref cast behaviour
  3845. for( n = 0; n < beh->operators.GetLength(); n+= 2 )
  3846. {
  3847. if( (isExplicit && asBEHAVE_REF_CAST == beh->operators[n]) ||
  3848. asBEHAVE_IMPLICIT_REF_CAST == beh->operators[n] )
  3849. {
  3850. int funcId = beh->operators[n+1];
  3851. // Does the operator take the ?&out parameter?
  3852. asCScriptFunction *func = engine->scriptFunctions[funcId];
  3853. if( func->parameterTypes.GetLength() != 1 ||
  3854. func->parameterTypes[0].GetTokenType() != ttQuestion ||
  3855. func->inOutFlags[0] != asTM_OUTREF )
  3856. continue;
  3857. ops.PushLast(funcId);
  3858. }
  3859. }
  3860. // It shouldn't be possible to have more than one
  3861. asASSERT( ops.GetLength() <= 1 );
  3862. if( ops.GetLength() == 1 )
  3863. {
  3864. if( generateCode )
  3865. {
  3866. asASSERT(to.IsObjectHandle());
  3867. // Allocate a temporary variable of the requested handle type
  3868. int stackOffset = AllocateVariableNotIn(to, true, false, ctx);
  3869. // Pass the reference of that variable to the function as output parameter
  3870. asCDataType toRef(to);
  3871. toRef.MakeReference(true);
  3872. asCArray<asSExprContext *> args;
  3873. asSExprContext arg(engine);
  3874. arg.bc.InstrSHORT(asBC_PSF, (short)stackOffset);
  3875. // Don't mark the variable as temporary, so it won't be freed too early
  3876. arg.type.SetVariable(toRef, stackOffset, false);
  3877. arg.type.isLValue = true;
  3878. arg.type.isExplicitHandle = true;
  3879. args.PushLast(&arg);
  3880. asCTypeInfo prev = ctx->type;
  3881. // Call the behaviour method
  3882. MakeFunctionCall(ctx, ops[0], ctx->type.dataType.GetObjectType(), args, node);
  3883. // Release previous temporary variable
  3884. ReleaseTemporaryVariable(prev, &ctx->bc);
  3885. // Use the reference to the variable as the result of the expression
  3886. // Now we can mark the variable as temporary
  3887. ctx->type.SetVariable(toRef, stackOffset, true);
  3888. ctx->bc.InstrSHORT(asBC_PSF, (short)stackOffset);
  3889. }
  3890. else
  3891. {
  3892. // All casts are legal
  3893. ctx->type.Set(to);
  3894. }
  3895. }
  3896. }
  3897. }
  3898. return conversionDone;
  3899. }
  3900. asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const asCDataType &toOrig, asCScriptNode *node, EImplicitConv convType, bool generateCode)
  3901. {
  3902. asCDataType to = toOrig;
  3903. to.MakeReference(false);
  3904. asASSERT( !ctx->type.dataType.IsReference() );
  3905. // Maybe no conversion is needed
  3906. if( to.IsEqualExceptConst(ctx->type.dataType) )
  3907. {
  3908. // A primitive is const or not
  3909. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  3910. return asCC_NO_CONV;
  3911. }
  3912. // Determine the cost of this conversion
  3913. asUINT cost = asCC_NO_CONV;
  3914. if( (to.IsIntegerType() || to.IsUnsignedType()) && (ctx->type.dataType.IsFloatType() || ctx->type.dataType.IsDoubleType()) )
  3915. cost = asCC_INT_FLOAT_CONV;
  3916. else if( (to.IsFloatType() || to.IsDoubleType()) && (ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType()) )
  3917. cost = asCC_INT_FLOAT_CONV;
  3918. else if( to.IsUnsignedType() && ctx->type.dataType.IsIntegerType() )
  3919. cost = asCC_SIGNED_CONV;
  3920. else if( to.IsIntegerType() && ctx->type.dataType.IsUnsignedType() )
  3921. cost = asCC_SIGNED_CONV;
  3922. else if( to.GetSizeInMemoryBytes() || ctx->type.dataType.GetSizeInMemoryBytes() )
  3923. cost = asCC_PRIMITIVE_SIZE_CONV;
  3924. // Start by implicitly converting constant values
  3925. if( ctx->type.isConstant )
  3926. {
  3927. ImplicitConversionConstant(ctx, to, node, convType);
  3928. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  3929. return cost;
  3930. }
  3931. // Allow implicit conversion between numbers
  3932. if( generateCode )
  3933. {
  3934. // When generating the code the decision has already been made, so we don't bother determining the cost
  3935. // Convert smaller types to 32bit first
  3936. int s = ctx->type.dataType.GetSizeInMemoryBytes();
  3937. if( s < 4 )
  3938. {
  3939. ConvertToTempVariable(ctx);
  3940. if( ctx->type.dataType.IsIntegerType() )
  3941. {
  3942. if( s == 1 )
  3943. ctx->bc.InstrSHORT(asBC_sbTOi, ctx->type.stackOffset);
  3944. else if( s == 2 )
  3945. ctx->bc.InstrSHORT(asBC_swTOi, ctx->type.stackOffset);
  3946. ctx->type.dataType.SetTokenType(ttInt);
  3947. }
  3948. else if( ctx->type.dataType.IsUnsignedType() )
  3949. {
  3950. if( s == 1 )
  3951. ctx->bc.InstrSHORT(asBC_ubTOi, ctx->type.stackOffset);
  3952. else if( s == 2 )
  3953. ctx->bc.InstrSHORT(asBC_uwTOi, ctx->type.stackOffset);
  3954. ctx->type.dataType.SetTokenType(ttUInt);
  3955. }
  3956. }
  3957. if( (to.IsIntegerType() && to.GetSizeInMemoryDWords() == 1 && !to.IsEnumType()) ||
  3958. (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST) )
  3959. {
  3960. if( ctx->type.dataType.IsIntegerType() ||
  3961. ctx->type.dataType.IsUnsignedType() )
  3962. {
  3963. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  3964. {
  3965. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3966. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3967. }
  3968. else
  3969. {
  3970. ConvertToTempVariable(ctx);
  3971. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3972. int offset = AllocateVariable(to, true);
  3973. ctx->bc.InstrW_W(asBC_i64TOi, offset, ctx->type.stackOffset);
  3974. ctx->type.SetVariable(to, offset, true);
  3975. }
  3976. }
  3977. else if( ctx->type.dataType.IsFloatType() )
  3978. {
  3979. ConvertToTempVariable(ctx);
  3980. ctx->bc.InstrSHORT(asBC_fTOi, ctx->type.stackOffset);
  3981. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3982. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3983. }
  3984. else if( ctx->type.dataType.IsDoubleType() )
  3985. {
  3986. ConvertToTempVariable(ctx);
  3987. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3988. int offset = AllocateVariable(to, true);
  3989. ctx->bc.InstrW_W(asBC_dTOi, offset, ctx->type.stackOffset);
  3990. ctx->type.SetVariable(to, offset, true);
  3991. }
  3992. // Convert to smaller integer if necessary
  3993. int s = to.GetSizeInMemoryBytes();
  3994. if( s < 4 )
  3995. {
  3996. ConvertToTempVariable(ctx);
  3997. if( s == 1 )
  3998. ctx->bc.InstrSHORT(asBC_iTOb, ctx->type.stackOffset);
  3999. else if( s == 2 )
  4000. ctx->bc.InstrSHORT(asBC_iTOw, ctx->type.stackOffset);
  4001. }
  4002. }
  4003. if( to.IsIntegerType() && to.GetSizeInMemoryDWords() == 2 )
  4004. {
  4005. if( ctx->type.dataType.IsIntegerType() ||
  4006. ctx->type.dataType.IsUnsignedType() )
  4007. {
  4008. if( ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  4009. {
  4010. ctx->type.dataType.SetTokenType(to.GetTokenType());
  4011. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4012. }
  4013. else
  4014. {
  4015. ConvertToTempVariable(ctx);
  4016. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4017. int offset = AllocateVariable(to, true);
  4018. if( ctx->type.dataType.IsUnsignedType() )
  4019. ctx->bc.InstrW_W(asBC_uTOi64, offset, ctx->type.stackOffset);
  4020. else
  4021. ctx->bc.InstrW_W(asBC_iTOi64, offset, ctx->type.stackOffset);
  4022. ctx->type.SetVariable(to, offset, true);
  4023. }
  4024. }
  4025. else if( ctx->type.dataType.IsFloatType() )
  4026. {
  4027. ConvertToTempVariable(ctx);
  4028. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4029. int offset = AllocateVariable(to, true);
  4030. ctx->bc.InstrW_W(asBC_fTOi64, offset, ctx->type.stackOffset);
  4031. ctx->type.SetVariable(to, offset, true);
  4032. }
  4033. else if( ctx->type.dataType.IsDoubleType() )
  4034. {
  4035. ConvertToTempVariable(ctx);
  4036. ctx->bc.InstrSHORT(asBC_dTOi64, ctx->type.stackOffset);
  4037. ctx->type.dataType.SetTokenType(to.GetTokenType());
  4038. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4039. }
  4040. }
  4041. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 1 )
  4042. {
  4043. if( ctx->type.dataType.IsIntegerType() ||
  4044. ctx->type.dataType.IsUnsignedType() )
  4045. {
  4046. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  4047. {
  4048. ctx->type.dataType.SetTokenType(to.GetTokenType());
  4049. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4050. }
  4051. else
  4052. {
  4053. ConvertToTempVariable(ctx);
  4054. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4055. int offset = AllocateVariable(to, true);
  4056. ctx->bc.InstrW_W(asBC_i64TOi, offset, ctx->type.stackOffset);
  4057. ctx->type.SetVariable(to, offset, true);
  4058. }
  4059. }
  4060. else if( ctx->type.dataType.IsFloatType() )
  4061. {
  4062. ConvertToTempVariable(ctx);
  4063. ctx->bc.InstrSHORT(asBC_fTOu, ctx->type.stackOffset);
  4064. ctx->type.dataType.SetTokenType(to.GetTokenType());
  4065. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4066. }
  4067. else if( ctx->type.dataType.IsDoubleType() )
  4068. {
  4069. ConvertToTempVariable(ctx);
  4070. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4071. int offset = AllocateVariable(to, true);
  4072. ctx->bc.InstrW_W(asBC_dTOu, offset, ctx->type.stackOffset);
  4073. ctx->type.SetVariable(to, offset, true);
  4074. }
  4075. // Convert to smaller integer if necessary
  4076. int s = to.GetSizeInMemoryBytes();
  4077. if( s < 4 )
  4078. {
  4079. ConvertToTempVariable(ctx);
  4080. if( s == 1 )
  4081. ctx->bc.InstrSHORT(asBC_iTOb, ctx->type.stackOffset);
  4082. else if( s == 2 )
  4083. ctx->bc.InstrSHORT(asBC_iTOw, ctx->type.stackOffset);
  4084. }
  4085. }
  4086. if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 2 )
  4087. {
  4088. if( ctx->type.dataType.IsIntegerType() ||
  4089. ctx->type.dataType.IsUnsignedType() )
  4090. {
  4091. if( ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  4092. {
  4093. ctx->type.dataType.SetTokenType(to.GetTokenType());
  4094. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4095. }
  4096. else
  4097. {
  4098. ConvertToTempVariable(ctx);
  4099. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4100. int offset = AllocateVariable(to, true);
  4101. if( ctx->type.dataType.IsUnsignedType() )
  4102. ctx->bc.InstrW_W(asBC_uTOi64, offset, ctx->type.stackOffset);
  4103. else
  4104. ctx->bc.InstrW_W(asBC_iTOi64, offset, ctx->type.stackOffset);
  4105. ctx->type.SetVariable(to, offset, true);
  4106. }
  4107. }
  4108. else if( ctx->type.dataType.IsFloatType() )
  4109. {
  4110. ConvertToTempVariable(ctx);
  4111. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4112. int offset = AllocateVariable(to, true);
  4113. ctx->bc.InstrW_W(asBC_fTOu64, offset, ctx->type.stackOffset);
  4114. ctx->type.SetVariable(to, offset, true);
  4115. }
  4116. else if( ctx->type.dataType.IsDoubleType() )
  4117. {
  4118. ConvertToTempVariable(ctx);
  4119. ctx->bc.InstrSHORT(asBC_dTOu64, ctx->type.stackOffset);
  4120. ctx->type.dataType.SetTokenType(to.GetTokenType());
  4121. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4122. }
  4123. }
  4124. else if( to.IsFloatType() )
  4125. {
  4126. if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  4127. {
  4128. ConvertToTempVariable(ctx);
  4129. ctx->bc.InstrSHORT(asBC_iTOf, ctx->type.stackOffset);
  4130. ctx->type.dataType.SetTokenType(to.GetTokenType());
  4131. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4132. }
  4133. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  4134. {
  4135. ConvertToTempVariable(ctx);
  4136. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4137. int offset = AllocateVariable(to, true);
  4138. ctx->bc.InstrW_W(asBC_i64TOf, offset, ctx->type.stackOffset);
  4139. ctx->type.SetVariable(to, offset, true);
  4140. }
  4141. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  4142. {
  4143. ConvertToTempVariable(ctx);
  4144. ctx->bc.InstrSHORT(asBC_uTOf, ctx->type.stackOffset);
  4145. ctx->type.dataType.SetTokenType(to.GetTokenType());
  4146. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4147. }
  4148. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  4149. {
  4150. ConvertToTempVariable(ctx);
  4151. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4152. int offset = AllocateVariable(to, true);
  4153. ctx->bc.InstrW_W(asBC_u64TOf, offset, ctx->type.stackOffset);
  4154. ctx->type.SetVariable(to, offset, true);
  4155. }
  4156. else if( ctx->type.dataType.IsDoubleType() )
  4157. {
  4158. ConvertToTempVariable(ctx);
  4159. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4160. int offset = AllocateVariable(to, true);
  4161. ctx->bc.InstrW_W(asBC_dTOf, offset, ctx->type.stackOffset);
  4162. ctx->type.SetVariable(to, offset, true);
  4163. }
  4164. }
  4165. else if( to.IsDoubleType() )
  4166. {
  4167. if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  4168. {
  4169. ConvertToTempVariable(ctx);
  4170. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4171. int offset = AllocateVariable(to, true);
  4172. ctx->bc.InstrW_W(asBC_iTOd, offset, ctx->type.stackOffset);
  4173. ctx->type.SetVariable(to, offset, true);
  4174. }
  4175. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  4176. {
  4177. ConvertToTempVariable(ctx);
  4178. ctx->bc.InstrSHORT(asBC_i64TOd, ctx->type.stackOffset);
  4179. ctx->type.dataType.SetTokenType(to.GetTokenType());
  4180. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4181. }
  4182. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  4183. {
  4184. ConvertToTempVariable(ctx);
  4185. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4186. int offset = AllocateVariable(to, true);
  4187. ctx->bc.InstrW_W(asBC_uTOd, offset, ctx->type.stackOffset);
  4188. ctx->type.SetVariable(to, offset, true);
  4189. }
  4190. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  4191. {
  4192. ConvertToTempVariable(ctx);
  4193. ctx->bc.InstrSHORT(asBC_u64TOd, ctx->type.stackOffset);
  4194. ctx->type.dataType.SetTokenType(to.GetTokenType());
  4195. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4196. }
  4197. else if( ctx->type.dataType.IsFloatType() )
  4198. {
  4199. ConvertToTempVariable(ctx);
  4200. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4201. int offset = AllocateVariable(to, true);
  4202. ctx->bc.InstrW_W(asBC_fTOd, offset, ctx->type.stackOffset);
  4203. ctx->type.SetVariable(to, offset, true);
  4204. }
  4205. }
  4206. }
  4207. else
  4208. {
  4209. if( ((to.IsIntegerType() && !to.IsEnumType()) || to.IsUnsignedType() ||
  4210. to.IsFloatType() || to.IsDoubleType() ||
  4211. (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST)) &&
  4212. (ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType() ||
  4213. ctx->type.dataType.IsFloatType() || ctx->type.dataType.IsDoubleType()) )
  4214. {
  4215. ctx->type.dataType.SetTokenType(to.GetTokenType());
  4216. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4217. }
  4218. }
  4219. // Primitive types on the stack, can be const or non-const
  4220. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  4221. return cost;
  4222. }
  4223. asUINT asCCompiler::ImplicitConversion(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode, bool allowObjectConstruct)
  4224. {
  4225. asASSERT( ctx->type.dataType.GetTokenType() != ttUnrecognizedToken ||
  4226. ctx->type.dataType.IsNullHandle() );
  4227. // No conversion from void to any other type
  4228. if( ctx->type.dataType.GetTokenType() == ttVoid )
  4229. return asCC_NO_CONV;
  4230. // Do we want a var type?
  4231. if( to.GetTokenType() == ttQuestion )
  4232. {
  4233. // Any type can be converted to a var type, but only when not generating code
  4234. asASSERT( !generateCode );
  4235. ctx->type.dataType = to;
  4236. return asCC_VARIABLE_CONV;
  4237. }
  4238. // Do we want a primitive?
  4239. else if( to.IsPrimitive() )
  4240. {
  4241. if( !ctx->type.dataType.IsPrimitive() )
  4242. return ImplicitConvObjectToPrimitive(ctx, to, node, convType, generateCode);
  4243. else
  4244. return ImplicitConvPrimitiveToPrimitive(ctx, to, node, convType, generateCode);
  4245. }
  4246. else // The target is a complex type
  4247. {
  4248. if( ctx->type.dataType.IsPrimitive() )
  4249. return ImplicitConvPrimitiveToObject(ctx, to, node, convType, generateCode, allowObjectConstruct);
  4250. else if( ctx->type.IsNullConstant() || ctx->type.dataType.GetObjectType() )
  4251. return ImplicitConvObjectToObject(ctx, to, node, convType, generateCode, allowObjectConstruct);
  4252. }
  4253. return asCC_NO_CONV;
  4254. }
  4255. asUINT asCCompiler::ImplicitConvObjectToPrimitive(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode)
  4256. {
  4257. if( ctx->type.isExplicitHandle )
  4258. {
  4259. // An explicit handle cannot be converted to a primitive
  4260. if( convType != asIC_IMPLICIT_CONV && node )
  4261. {
  4262. asCString str;
  4263. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  4264. Error(str, node);
  4265. }
  4266. return asCC_NO_CONV;
  4267. }
  4268. // TODO: Must use the const cast behaviour if the object is read-only
  4269. // Find matching value cast behaviours
  4270. // Here we're only interested in those that convert the type to a primitive type
  4271. asCArray<int> funcs;
  4272. asSTypeBehaviour *beh = ctx->type.dataType.GetBehaviour();
  4273. if( beh )
  4274. {
  4275. if( convType == asIC_EXPLICIT_VAL_CAST )
  4276. {
  4277. for( unsigned int n = 0; n < beh->operators.GetLength(); n += 2 )
  4278. {
  4279. // accept both implicit and explicit cast
  4280. if( (beh->operators[n] == asBEHAVE_VALUE_CAST ||
  4281. beh->operators[n] == asBEHAVE_IMPLICIT_VALUE_CAST) &&
  4282. builder->GetFunctionDescription(beh->operators[n+1])->returnType.IsPrimitive() )
  4283. funcs.PushLast(beh->operators[n+1]);
  4284. }
  4285. }
  4286. else
  4287. {
  4288. for( unsigned int n = 0; n < beh->operators.GetLength(); n += 2 )
  4289. {
  4290. // accept only implicit cast
  4291. if( beh->operators[n] == asBEHAVE_IMPLICIT_VALUE_CAST &&
  4292. builder->GetFunctionDescription(beh->operators[n+1])->returnType.IsPrimitive() )
  4293. funcs.PushLast(beh->operators[n+1]);
  4294. }
  4295. }
  4296. }
  4297. // This matrix describes the priorities of the types to search for, for each target type
  4298. // The first column is the target type, the priorities goes from left to right
  4299. eTokenType matchMtx[10][10] =
  4300. {
  4301. {ttDouble, ttFloat, ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8},
  4302. {ttFloat, ttDouble, ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8},
  4303. {ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8, ttDouble, ttFloat},
  4304. {ttUInt64, ttInt64, ttUInt, ttInt, ttUInt16, ttInt16, ttUInt8, ttInt8, ttDouble, ttFloat},
  4305. {ttInt, ttUInt, ttInt64, ttUInt64, ttInt16, ttUInt16, ttInt8, ttUInt8, ttDouble, ttFloat},
  4306. {ttUInt, ttInt, ttUInt64, ttInt64, ttUInt16, ttInt16, ttUInt8, ttInt8, ttDouble, ttFloat},
  4307. {ttInt16, ttUInt16, ttInt, ttUInt, ttInt64, ttUInt64, ttInt8, ttUInt8, ttDouble, ttFloat},
  4308. {ttUInt16, ttInt16, ttUInt, ttInt, ttUInt64, ttInt64, ttUInt8, ttInt8, ttDouble, ttFloat},
  4309. {ttInt8, ttUInt8, ttInt16, ttUInt16, ttInt, ttUInt, ttInt64, ttUInt64, ttDouble, ttFloat},
  4310. {ttUInt8, ttInt8, ttUInt16, ttInt16, ttUInt, ttInt, ttUInt64, ttInt64, ttDouble, ttFloat},
  4311. };
  4312. // Which row to use?
  4313. eTokenType *row = 0;
  4314. for( unsigned int type = 0; type < 10; type++ )
  4315. {
  4316. if( to.GetTokenType() == matchMtx[type][0] )
  4317. {
  4318. row = &matchMtx[type][0];
  4319. break;
  4320. }
  4321. }
  4322. // Find the best matching cast operator
  4323. int funcId = 0;
  4324. if( row )
  4325. {
  4326. asCDataType target(to);
  4327. // Priority goes from left to right in the matrix
  4328. for( unsigned int attempt = 0; attempt < 10 && funcId == 0; attempt++ )
  4329. {
  4330. target.SetTokenType(row[attempt]);
  4331. for( unsigned int n = 0; n < funcs.GetLength(); n++ )
  4332. {
  4333. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[n]);
  4334. if( descr->returnType.IsEqualExceptConst(target) )
  4335. {
  4336. funcId = funcs[n];
  4337. break;
  4338. }
  4339. }
  4340. }
  4341. }
  4342. // Did we find a suitable function?
  4343. if( funcId != 0 )
  4344. {
  4345. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  4346. if( generateCode )
  4347. {
  4348. asCTypeInfo objType = ctx->type;
  4349. Dereference(ctx, true);
  4350. PerformFunctionCall(funcId, ctx);
  4351. ReleaseTemporaryVariable(objType, &ctx->bc);
  4352. }
  4353. else
  4354. ctx->type.Set(descr->returnType);
  4355. // Allow one more implicit conversion to another primitive type
  4356. return asCC_OBJ_TO_PRIMITIVE_CONV + ImplicitConversion(ctx, to, node, convType, generateCode, false);
  4357. }
  4358. else
  4359. {
  4360. if( convType != asIC_IMPLICIT_CONV && node )
  4361. {
  4362. asCString str;
  4363. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  4364. Error(str, node);
  4365. }
  4366. }
  4367. return asCC_NO_CONV;
  4368. }
  4369. asUINT asCCompiler::ImplicitConvObjectRef(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode)
  4370. {
  4371. // Convert null to any object type handle, but not to a non-handle type
  4372. if( ctx->type.IsNullConstant() && ctx->methodName == "" )
  4373. {
  4374. if( to.IsObjectHandle() )
  4375. {
  4376. ctx->type.dataType = to;
  4377. return asCC_REF_CONV;
  4378. }
  4379. return asCC_NO_CONV;
  4380. }
  4381. asASSERT(ctx->type.dataType.GetObjectType() || ctx->methodName != "");
  4382. // First attempt to convert the base type without instanciating another instance
  4383. if( to.GetObjectType() != ctx->type.dataType.GetObjectType() && ctx->methodName == "" )
  4384. {
  4385. // If the to type is an interface and the from type implements it, then we can convert it immediately
  4386. if( ctx->type.dataType.GetObjectType()->Implements(to.GetObjectType()) )
  4387. {
  4388. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4389. return asCC_REF_CONV;
  4390. }
  4391. // If the to type is a class and the from type derives from it, then we can convert it immediately
  4392. else if( ctx->type.dataType.GetObjectType()->DerivesFrom(to.GetObjectType()) )
  4393. {
  4394. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4395. return asCC_REF_CONV;
  4396. }
  4397. // If the types are not equal yet, then we may still be able to find a reference cast
  4398. else if( ctx->type.dataType.GetObjectType() != to.GetObjectType() )
  4399. {
  4400. // A ref cast must not remove the constness
  4401. bool isConst = false;
  4402. if( (ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsHandleToConst()) ||
  4403. (!ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReadOnly()) )
  4404. isConst = true;
  4405. // We may still be able to find an implicit ref cast behaviour
  4406. CompileRefCast(ctx, to, convType == asIC_EXPLICIT_REF_CAST, node, generateCode);
  4407. ctx->type.dataType.MakeHandleToConst(isConst);
  4408. // Was the conversion done?
  4409. if( ctx->type.dataType.GetObjectType() == to.GetObjectType() )
  4410. return asCC_REF_CONV;
  4411. }
  4412. }
  4413. // Convert matching function types
  4414. if( to.GetFuncDef() )
  4415. {
  4416. // If the input expression is already a funcdef, check if it can be converted
  4417. if( ctx->type.dataType.GetFuncDef() &&
  4418. to.GetFuncDef() != ctx->type.dataType.GetFuncDef() )
  4419. {
  4420. asCScriptFunction *toFunc = to.GetFuncDef();
  4421. asCScriptFunction *fromFunc = ctx->type.dataType.GetFuncDef();
  4422. if( toFunc->IsSignatureExceptNameEqual(fromFunc) )
  4423. {
  4424. ctx->type.dataType.SetFuncDef(toFunc);
  4425. return asCC_REF_CONV;
  4426. }
  4427. }
  4428. // If the input expression is a deferred function ref, check if there is a matching func
  4429. if( ctx->methodName != "" )
  4430. {
  4431. // Determine the namespace
  4432. asSNameSpace *ns = 0;
  4433. asCString name = "";
  4434. int pos = ctx->methodName.FindLast("::");
  4435. if( pos >= 0 )
  4436. {
  4437. asCString nsName = ctx->methodName.SubString(0, pos+2);
  4438. // Trim off the last ::
  4439. if( nsName.GetLength() > 2 )
  4440. nsName.SetLength(nsName.GetLength()-2);
  4441. ns = DetermineNameSpace(nsName);
  4442. name = ctx->methodName.SubString(pos+2);
  4443. }
  4444. else
  4445. {
  4446. DetermineNameSpace("");
  4447. name = ctx->methodName;
  4448. }
  4449. asCArray<int> funcs;
  4450. if( ns )
  4451. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  4452. // Check if any of the functions have perfect match
  4453. for( asUINT n = 0; n < funcs.GetLength(); n++ )
  4454. {
  4455. asCScriptFunction *func = builder->GetFunctionDescription(funcs[n]);
  4456. if( to.GetFuncDef()->IsSignatureExceptNameEqual(func) )
  4457. {
  4458. if( generateCode )
  4459. {
  4460. ctx->bc.InstrPTR(asBC_FuncPtr, func);
  4461. // Make sure the identified function is shared if we're compiling a shared function
  4462. if( !func->IsShared() && outFunc->IsShared() )
  4463. {
  4464. asCString msg;
  4465. msg.Format(TXT_SHARED_CANNOT_CALL_NON_SHARED_FUNC_s, func->GetDeclaration());
  4466. Error(msg, node);
  4467. }
  4468. }
  4469. ctx->type.dataType = asCDataType::CreateFuncDef(to.GetFuncDef());
  4470. return asCC_REF_CONV;
  4471. }
  4472. }
  4473. }
  4474. }
  4475. return asCC_NO_CONV;
  4476. }
  4477. asUINT asCCompiler::ImplicitConvObjectValue(asSExprContext *ctx, const asCDataType &to, asCScriptNode * /*node*/, EImplicitConv convType, bool generateCode)
  4478. {
  4479. asUINT cost = asCC_NO_CONV;
  4480. // If the base type is still different, and we are allowed to instance
  4481. // another object then we can try an implicit value cast
  4482. if( to.GetObjectType() != ctx->type.dataType.GetObjectType() )
  4483. {
  4484. // TODO: Implement support for implicit constructor/factory
  4485. asCArray<int> funcs;
  4486. asSTypeBehaviour *beh = ctx->type.dataType.GetBehaviour();
  4487. if( beh )
  4488. {
  4489. if( convType == asIC_EXPLICIT_VAL_CAST )
  4490. {
  4491. for( unsigned int n = 0; n < beh->operators.GetLength(); n += 2 )
  4492. {
  4493. // accept both implicit and explicit cast
  4494. if( (beh->operators[n] == asBEHAVE_VALUE_CAST ||
  4495. beh->operators[n] == asBEHAVE_IMPLICIT_VALUE_CAST) &&
  4496. builder->GetFunctionDescription(beh->operators[n+1])->returnType.GetObjectType() == to.GetObjectType() )
  4497. funcs.PushLast(beh->operators[n+1]);
  4498. }
  4499. }
  4500. else
  4501. {
  4502. for( unsigned int n = 0; n < beh->operators.GetLength(); n += 2 )
  4503. {
  4504. // accept only implicit cast
  4505. if( beh->operators[n] == asBEHAVE_IMPLICIT_VALUE_CAST &&
  4506. builder->GetFunctionDescription(beh->operators[n+1])->returnType.GetObjectType() == to.GetObjectType() )
  4507. funcs.PushLast(beh->operators[n+1]);
  4508. }
  4509. }
  4510. }
  4511. // TODO: If there are multiple valid value casts, then we must choose the most appropriate one
  4512. asASSERT( funcs.GetLength() <= 1 );
  4513. if( funcs.GetLength() == 1 )
  4514. {
  4515. asCScriptFunction *f = builder->GetFunctionDescription(funcs[0]);
  4516. if( generateCode )
  4517. {
  4518. asCTypeInfo objType = ctx->type;
  4519. Dereference(ctx, true);
  4520. bool useVariable = false;
  4521. int stackOffset = 0;
  4522. if( f->DoesReturnOnStack() )
  4523. {
  4524. useVariable = true;
  4525. stackOffset = AllocateVariable(f->returnType, true);
  4526. // Push the pointer to the pre-allocated space for the return value
  4527. ctx->bc.InstrSHORT(asBC_PSF, short(stackOffset));
  4528. // The object pointer is already on the stack, but should be the top
  4529. // one, so we need to swap the pointers in order to get the correct
  4530. ctx->bc.Instr(asBC_SwapPtr);
  4531. }
  4532. PerformFunctionCall(funcs[0], ctx, false, 0, 0, useVariable, stackOffset);
  4533. ReleaseTemporaryVariable(objType, &ctx->bc);
  4534. }
  4535. else
  4536. ctx->type.Set(f->returnType);
  4537. cost = asCC_TO_OBJECT_CONV;
  4538. }
  4539. }
  4540. return cost;
  4541. }
  4542. asUINT asCCompiler::ImplicitConvObjectToObject(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode, bool allowObjectConstruct)
  4543. {
  4544. // First try a ref cast
  4545. asUINT cost = ImplicitConvObjectRef(ctx, to, node, convType, generateCode);
  4546. // If the desired type is an asOBJ_ASHANDLE then we'll assume it is allowed to implicitly
  4547. // construct the object through any of the available constructors
  4548. if( to.GetObjectType() && (to.GetObjectType()->flags & asOBJ_ASHANDLE) && to.GetObjectType() != ctx->type.dataType.GetObjectType() && allowObjectConstruct )
  4549. {
  4550. asCArray<int> funcs;
  4551. funcs = to.GetObjectType()->beh.constructors;
  4552. asCArray<asSExprContext *> args;
  4553. args.PushLast(ctx);
  4554. cost = asCC_TO_OBJECT_CONV + MatchFunctions(funcs, args, node, 0, 0, false, true, false);
  4555. // Did we find a matching constructor?
  4556. if( funcs.GetLength() == 1 )
  4557. {
  4558. if( generateCode )
  4559. {
  4560. // If the ASHANDLE receives a variable type parameter, then we need to
  4561. // make sure the expression is treated as a handle and not as a value
  4562. asCScriptFunction *func = engine->scriptFunctions[funcs[0]];
  4563. if( func->parameterTypes[0].GetTokenType() == ttQuestion )
  4564. {
  4565. if( !ctx->type.isExplicitHandle )
  4566. {
  4567. asCDataType toHandle = ctx->type.dataType;
  4568. toHandle.MakeHandle(true);
  4569. toHandle.MakeReference(true);
  4570. toHandle.MakeHandleToConst(ctx->type.dataType.IsReadOnly());
  4571. ImplicitConversion(ctx, toHandle, node, asIC_IMPLICIT_CONV, true, false);
  4572. asASSERT( ctx->type.dataType.IsObjectHandle() );
  4573. }
  4574. ctx->type.isExplicitHandle = true;
  4575. }
  4576. // TODO: This should really reuse the code from CompileConstructCall
  4577. // Allocate the new object
  4578. asCTypeInfo tempObj;
  4579. tempObj.dataType = to;
  4580. tempObj.dataType.MakeReference(false);
  4581. tempObj.stackOffset = (short)AllocateVariable(tempObj.dataType, true);
  4582. tempObj.dataType.MakeReference(true);
  4583. tempObj.isTemporary = true;
  4584. tempObj.isVariable = true;
  4585. bool onHeap = IsVariableOnHeap(tempObj.stackOffset);
  4586. // Push the address of the object on the stack
  4587. asSExprContext e(engine);
  4588. if( onHeap )
  4589. e.bc.InstrSHORT(asBC_VAR, tempObj.stackOffset);
  4590. PrepareFunctionCall(funcs[0], &e.bc, args);
  4591. MoveArgsToStack(funcs[0], &e.bc, args, false);
  4592. // If the object is allocated on the stack, then call the constructor as a normal function
  4593. if( onHeap )
  4594. {
  4595. int offset = 0;
  4596. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]);
  4597. offset = descr->parameterTypes[0].GetSizeOnStackDWords();
  4598. e.bc.InstrWORD(asBC_GETREF, (asWORD)offset);
  4599. }
  4600. else
  4601. e.bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  4602. PerformFunctionCall(funcs[0], &e, onHeap, &args, tempObj.dataType.GetObjectType());
  4603. // Add tag that the object has been initialized
  4604. e.bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT);
  4605. // The constructor doesn't return anything,
  4606. // so we have to manually inform the type of
  4607. // the return value
  4608. e.type = tempObj;
  4609. if( !onHeap )
  4610. e.type.dataType.MakeReference(false);
  4611. // Push the address of the object on the stack again
  4612. e.bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  4613. MergeExprBytecodeAndType(ctx, &e);
  4614. }
  4615. else
  4616. {
  4617. ctx->type.Set(asCDataType::CreateObject(to.GetObjectType(), false));
  4618. }
  4619. }
  4620. }
  4621. // If the base type is still different, and we are allowed to instance
  4622. // another object then we can try an implicit value cast
  4623. if( to.GetObjectType() != ctx->type.dataType.GetObjectType() && allowObjectConstruct )
  4624. {
  4625. // Attempt implicit value cast
  4626. cost = ImplicitConvObjectValue(ctx, to, node, convType, generateCode);
  4627. }
  4628. // If we still haven't converted the base type to the correct type, then there is
  4629. // no need to continue as it is not possible to do the conversion
  4630. if( to.GetObjectType() != ctx->type.dataType.GetObjectType() )
  4631. return asCC_NO_CONV;
  4632. if( to.IsObjectHandle() )
  4633. {
  4634. // There is no extra cost in converting to a handle
  4635. // reference to handle -> handle
  4636. // reference -> handle
  4637. // object -> handle
  4638. // handle -> reference to handle
  4639. // reference -> reference to handle
  4640. // object -> reference to handle
  4641. // TODO: If the type is handle, then we can't use IsReadOnly to determine the constness of the basetype
  4642. // If the rvalue is a handle to a const object, then
  4643. // the lvalue must also be a handle to a const object
  4644. if( ctx->type.dataType.IsReadOnly() && !to.IsReadOnly() )
  4645. {
  4646. if( convType != asIC_IMPLICIT_CONV )
  4647. {
  4648. asASSERT(node);
  4649. asCString str;
  4650. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  4651. Error(str, node);
  4652. }
  4653. }
  4654. if( !ctx->type.dataType.IsObjectHandle() )
  4655. {
  4656. // An object type can be directly converted to a handle of the
  4657. // same type by doing a ref copy to a new variable
  4658. if( ctx->type.dataType.SupportHandles() )
  4659. {
  4660. asCDataType dt = ctx->type.dataType;
  4661. dt.MakeHandle(true);
  4662. dt.MakeReference(false);
  4663. if( generateCode )
  4664. {
  4665. // If the expression is already a local variable, then it is not
  4666. // necessary to do a ref copy, as the ref objects on the stack are
  4667. // really handles, only the handles cannot be modified.
  4668. if( ctx->type.isVariable )
  4669. {
  4670. bool isHandleToConst = ctx->type.dataType.IsReadOnly();
  4671. ctx->type.dataType.MakeReadOnly(false);
  4672. ctx->type.dataType.MakeHandle(true);
  4673. ctx->type.dataType.MakeReadOnly(true);
  4674. ctx->type.dataType.MakeHandleToConst(isHandleToConst);
  4675. if( to.IsReference() && !ctx->type.dataType.IsReference() )
  4676. {
  4677. ctx->bc.Instr(asBC_PopPtr);
  4678. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  4679. ctx->type.dataType.MakeReference(true);
  4680. }
  4681. else if( ctx->type.dataType.IsReference() )
  4682. {
  4683. ctx->bc.Instr(asBC_RDSPtr);
  4684. ctx->type.dataType.MakeReference(false);
  4685. }
  4686. }
  4687. else
  4688. {
  4689. int offset = AllocateVariable(dt, true);
  4690. if( ctx->type.dataType.IsReference() )
  4691. ctx->bc.Instr(asBC_RDSPtr);
  4692. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  4693. ctx->bc.InstrPTR(asBC_REFCPY, dt.GetObjectType());
  4694. ctx->bc.Instr(asBC_PopPtr);
  4695. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  4696. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4697. if( to.IsReference() )
  4698. dt.MakeReference(true);
  4699. else
  4700. ctx->bc.Instr(asBC_RDSPtr);
  4701. ctx->type.SetVariable(dt, offset, true);
  4702. }
  4703. }
  4704. else
  4705. ctx->type.dataType = dt;
  4706. // When this conversion is done the expression is no longer an lvalue
  4707. ctx->type.isLValue = false;
  4708. }
  4709. }
  4710. if( ctx->type.dataType.IsObjectHandle() )
  4711. {
  4712. // A handle to non-const can be converted to a
  4713. // handle to const, but not the other way
  4714. if( to.IsHandleToConst() )
  4715. ctx->type.dataType.MakeHandleToConst(true);
  4716. // A const handle can be converted to a non-const
  4717. // handle and vice versa as the handle is just a value
  4718. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  4719. }
  4720. if( to.IsReference() && !ctx->type.dataType.IsReference() )
  4721. {
  4722. if( generateCode )
  4723. {
  4724. asASSERT( ctx->type.dataType.IsObjectHandle() );
  4725. // If the input type is a handle, then a simple ref copy is enough
  4726. bool isExplicitHandle = ctx->type.isExplicitHandle;
  4727. ctx->type.isExplicitHandle = ctx->type.dataType.IsObjectHandle();
  4728. // If the input type is read-only we'll need to temporarily
  4729. // remove this constness, otherwise the assignment will fail
  4730. bool typeIsReadOnly = ctx->type.dataType.IsReadOnly();
  4731. ctx->type.dataType.MakeReadOnly(false);
  4732. // If the object already is a temporary variable, then the copy
  4733. // doesn't have to be made as it is already a unique object
  4734. PrepareTemporaryObject(node, ctx);
  4735. ctx->type.dataType.MakeReadOnly(typeIsReadOnly);
  4736. ctx->type.isExplicitHandle = isExplicitHandle;
  4737. }
  4738. // A non-reference can be converted to a reference,
  4739. // by putting the value in a temporary variable
  4740. ctx->type.dataType.MakeReference(true);
  4741. // Since it is a new temporary variable it doesn't have to be const
  4742. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  4743. }
  4744. else if( !to.IsReference() && ctx->type.dataType.IsReference() )
  4745. {
  4746. Dereference(ctx, generateCode);
  4747. }
  4748. }
  4749. else // if( !to.IsObjectHandle() )
  4750. {
  4751. if( !to.IsReference() )
  4752. {
  4753. // reference to handle -> object
  4754. // handle -> object
  4755. // reference -> object
  4756. // An implicit handle can be converted to an object by adding a check for null pointer
  4757. if( ctx->type.dataType.IsObjectHandle() && !ctx->type.isExplicitHandle )
  4758. {
  4759. if( generateCode )
  4760. {
  4761. if( ctx->type.dataType.IsReference() )
  4762. {
  4763. // The pointer on the stack refers to the handle
  4764. ctx->bc.Instr(asBC_ChkRefS);
  4765. }
  4766. else
  4767. {
  4768. // The pointer on the stack refers to the object
  4769. ctx->bc.Instr(asBC_CHKREF);
  4770. }
  4771. }
  4772. ctx->type.dataType.MakeHandle(false);
  4773. }
  4774. // A const object can be converted to a non-const object through a copy
  4775. if( ctx->type.dataType.IsReadOnly() && !to.IsReadOnly() &&
  4776. allowObjectConstruct )
  4777. {
  4778. // Does the object type allow a copy to be made?
  4779. if( ctx->type.dataType.CanBeCopied() )
  4780. {
  4781. if( generateCode )
  4782. {
  4783. // Make a temporary object with the copy
  4784. PrepareTemporaryObject(node, ctx);
  4785. }
  4786. // In case the object was already in a temporary variable, then the function
  4787. // didn't really do anything so we need to remove the constness here
  4788. ctx->type.dataType.MakeReadOnly(false);
  4789. // Add the cost for the copy
  4790. cost += asCC_TO_OBJECT_CONV;
  4791. }
  4792. }
  4793. if( ctx->type.dataType.IsReference() )
  4794. {
  4795. // This may look strange, but a value type allocated on the stack is already
  4796. // correct, so nothing should be done other than remove the mark as reference.
  4797. // For types allocated on the heap, it is necessary to dereference the pointer
  4798. // that is currently on the stack
  4799. if( IsVariableOnHeap(ctx->type.stackOffset) )
  4800. Dereference(ctx, generateCode);
  4801. else
  4802. ctx->type.dataType.MakeReference(false);
  4803. }
  4804. // A non-const object can be converted to a const object directly
  4805. if( !ctx->type.dataType.IsReadOnly() && to.IsReadOnly() )
  4806. {
  4807. ctx->type.dataType.MakeReadOnly(true);
  4808. }
  4809. }
  4810. else // if( to.IsReference() )
  4811. {
  4812. // reference to handle -> reference
  4813. // handle -> reference
  4814. // object -> reference
  4815. if( ctx->type.dataType.IsReference() )
  4816. {
  4817. if( ctx->type.isExplicitHandle && ctx->type.dataType.GetObjectType() && (ctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE) )
  4818. {
  4819. // ASHANDLE objects are really value types, so explicit handle can be removed
  4820. ctx->type.isExplicitHandle = false;
  4821. ctx->type.dataType.MakeHandle(false);
  4822. }
  4823. // A reference to a handle can be converted to a reference to an object
  4824. // by first reading the address, then verifying that it is not null
  4825. if( !to.IsObjectHandle() && ctx->type.dataType.IsObjectHandle() && !ctx->type.isExplicitHandle )
  4826. {
  4827. ctx->type.dataType.MakeHandle(false);
  4828. if( generateCode )
  4829. ctx->bc.Instr(asBC_ChkRefS);
  4830. }
  4831. // A reference to a non-const can be converted to a reference to a const
  4832. if( to.IsReadOnly() )
  4833. ctx->type.dataType.MakeReadOnly(true);
  4834. else if( ctx->type.dataType.IsReadOnly() )
  4835. {
  4836. // A reference to a const can be converted to a reference to a
  4837. // non-const by copying the object to a temporary variable
  4838. ctx->type.dataType.MakeReadOnly(false);
  4839. if( generateCode )
  4840. {
  4841. // If the object already is a temporary variable, then the copy
  4842. // doesn't have to be made as it is already a unique object
  4843. PrepareTemporaryObject(node, ctx);
  4844. }
  4845. // Add the cost for the copy
  4846. cost += asCC_TO_OBJECT_CONV;
  4847. }
  4848. }
  4849. else // if( !ctx->type.dataType.IsReference() )
  4850. {
  4851. // A non-reference handle can be converted to a non-handle reference by checking against null handle
  4852. if( ctx->type.dataType.IsObjectHandle() )
  4853. {
  4854. bool readOnly = false;
  4855. if( ctx->type.dataType.IsHandleToConst() )
  4856. readOnly = true;
  4857. if( generateCode )
  4858. {
  4859. if( ctx->type.isVariable )
  4860. ctx->bc.InstrSHORT(asBC_ChkNullV, ctx->type.stackOffset);
  4861. else
  4862. ctx->bc.Instr(asBC_CHKREF);
  4863. }
  4864. ctx->type.dataType.MakeHandle(false);
  4865. ctx->type.dataType.MakeReference(true);
  4866. // Make sure a handle to const isn't converted to non-const reference
  4867. if( readOnly )
  4868. ctx->type.dataType.MakeReadOnly(true);
  4869. }
  4870. else
  4871. {
  4872. // A value type allocated on the stack is differentiated
  4873. // by it not being a reference. But it can be handled as
  4874. // reference by pushing the pointer on the stack
  4875. if( (ctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_VALUE) &&
  4876. (ctx->type.isVariable || ctx->type.isTemporary) &&
  4877. !IsVariableOnHeap(ctx->type.stackOffset) )
  4878. {
  4879. // Actually the pointer is already pushed on the stack in
  4880. // CompileVariableAccess, so we don't need to do anything else
  4881. }
  4882. else if( generateCode )
  4883. {
  4884. // A non-reference can be converted to a reference,
  4885. // by putting the value in a temporary variable
  4886. // If the input type is read-only we'll need to temporarily
  4887. // remove this constness, otherwise the assignment will fail
  4888. bool typeIsReadOnly = ctx->type.dataType.IsReadOnly();
  4889. ctx->type.dataType.MakeReadOnly(false);
  4890. // If the object already is a temporary variable, then the copy
  4891. // doesn't have to be made as it is already a unique object
  4892. PrepareTemporaryObject(node, ctx);
  4893. ctx->type.dataType.MakeReadOnly(typeIsReadOnly);
  4894. // Add the cost for the copy
  4895. cost += asCC_TO_OBJECT_CONV;
  4896. }
  4897. // This may look strange as the conversion was to make the expression a reference
  4898. // but a value type allocated on the stack is a reference even without the type
  4899. // being marked as such.
  4900. ctx->type.dataType.MakeReference(IsVariableOnHeap(ctx->type.stackOffset));
  4901. }
  4902. // TODO: If the variable is an object allocated on the stack the following is not true as the copy may not have been made
  4903. // Since it is a new temporary variable it doesn't have to be const
  4904. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  4905. }
  4906. }
  4907. }
  4908. return cost;
  4909. }
  4910. asUINT asCCompiler::ImplicitConvPrimitiveToObject(asSExprContext *ctx, const asCDataType &to, asCScriptNode * /*node*/, EImplicitConv /*isExplicit*/, bool generateCode, bool /*allowObjectConstruct*/)
  4911. {
  4912. // Reference types currently don't allow implicit conversion from primitive to object
  4913. // TODO: Allow implicit conversion to scoped reference types as they are supposed to appear like ordinary value types
  4914. asCObjectType *objType = to.GetObjectType();
  4915. asASSERT( objType );
  4916. if( !objType || (objType->flags & asOBJ_REF) )
  4917. return asCC_NO_CONV;
  4918. // For value types the object must have a constructor that takes a single primitive argument either by value or as input reference
  4919. asCArray<int> funcs;
  4920. for( asUINT n = 0; n < objType->beh.constructors.GetLength(); n++ )
  4921. {
  4922. asCScriptFunction *func = engine->scriptFunctions[objType->beh.constructors[n]];
  4923. if( func->parameterTypes.GetLength() == 1 &&
  4924. func->parameterTypes[0].IsPrimitive() &&
  4925. !(func->inOutFlags[0] & asTM_OUTREF) )
  4926. {
  4927. funcs.PushLast(func->id);
  4928. }
  4929. }
  4930. if( funcs.GetLength() == 0 )
  4931. return asCC_NO_CONV;
  4932. // Check if it is possible to choose a best match
  4933. asSExprContext arg(engine);
  4934. arg.type = ctx->type;
  4935. asCArray<asSExprContext*> args;
  4936. args.PushLast(&arg);
  4937. asUINT cost = asCC_TO_OBJECT_CONV + MatchFunctions(funcs, args, 0, 0, objType, false, true, false);
  4938. if( funcs.GetLength() != 1 )
  4939. return asCC_NO_CONV;
  4940. if( !generateCode )
  4941. {
  4942. ctx->type.Set(to);
  4943. return cost;
  4944. }
  4945. // TODO: clean up: This part is similar to CompileConstructCall(). It should be put in a common function
  4946. bool onHeap = true;
  4947. // Value types and script types are allocated through the constructor
  4948. asCTypeInfo tempObj;
  4949. tempObj.dataType = to;
  4950. tempObj.stackOffset = (short)AllocateVariable(to, true);
  4951. tempObj.dataType.MakeReference(true);
  4952. tempObj.isTemporary = true;
  4953. tempObj.isVariable = true;
  4954. onHeap = IsVariableOnHeap(tempObj.stackOffset);
  4955. // Push the address of the object on the stack
  4956. if( onHeap )
  4957. ctx->bc.InstrSHORT(asBC_VAR, tempObj.stackOffset);
  4958. PrepareFunctionCall(funcs[0], &ctx->bc, args);
  4959. MoveArgsToStack(funcs[0], &ctx->bc, args, false);
  4960. if( !(objType->flags & asOBJ_REF) )
  4961. {
  4962. // If the object is allocated on the stack, then call the constructor as a normal function
  4963. if( onHeap )
  4964. {
  4965. int offset = 0;
  4966. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]);
  4967. for( asUINT n = 0; n < args.GetLength(); n++ )
  4968. offset += descr->parameterTypes[n].GetSizeOnStackDWords();
  4969. ctx->bc.InstrWORD(asBC_GETREF, (asWORD)offset);
  4970. }
  4971. else
  4972. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  4973. PerformFunctionCall(funcs[0], ctx, onHeap, &args, tempObj.dataType.GetObjectType());
  4974. // Add tag that the object has been initialized
  4975. ctx->bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT);
  4976. // The constructor doesn't return anything,
  4977. // so we have to manually inform the type of
  4978. // the return value
  4979. ctx->type = tempObj;
  4980. if( !onHeap )
  4981. ctx->type.dataType.MakeReference(false);
  4982. // Push the address of the object on the stack again
  4983. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  4984. }
  4985. else
  4986. {
  4987. asASSERT( objType->flags & asOBJ_SCOPED );
  4988. // Call the factory to create the reference type
  4989. PerformFunctionCall(funcs[0], ctx, false, &args);
  4990. }
  4991. return cost;
  4992. }
  4993. void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCDataType &to, asCScriptNode *node, EImplicitConv convType)
  4994. {
  4995. asASSERT(from->type.isConstant);
  4996. // TODO: node should be the node of the value that is
  4997. // converted (not the operator that provokes the implicit
  4998. // conversion)
  4999. // If the base type is correct there is no more to do
  5000. if( to.IsEqualExceptRefAndConst(from->type.dataType) ) return;
  5001. // References cannot be constants
  5002. if( from->type.dataType.IsReference() ) return;
  5003. if( (to.IsIntegerType() && to.GetSizeInMemoryDWords() == 1 && !to.IsEnumType()) ||
  5004. (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST) )
  5005. {
  5006. if( from->type.dataType.IsFloatType() ||
  5007. from->type.dataType.IsDoubleType() ||
  5008. from->type.dataType.IsUnsignedType() ||
  5009. from->type.dataType.IsIntegerType() )
  5010. {
  5011. // Transform the value
  5012. // Float constants can be implicitly converted to int
  5013. if( from->type.dataType.IsFloatType() )
  5014. {
  5015. float fc = from->type.floatValue;
  5016. int ic = int(fc);
  5017. if( float(ic) != fc )
  5018. {
  5019. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5020. }
  5021. from->type.intValue = ic;
  5022. }
  5023. // Double constants can be implicitly converted to int
  5024. else if( from->type.dataType.IsDoubleType() )
  5025. {
  5026. double fc = from->type.doubleValue;
  5027. int ic = int(fc);
  5028. if( double(ic) != fc )
  5029. {
  5030. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5031. }
  5032. from->type.intValue = ic;
  5033. }
  5034. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  5035. {
  5036. // Verify that it is possible to convert to signed without getting negative
  5037. if( from->type.intValue < 0 )
  5038. {
  5039. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  5040. }
  5041. // Convert to 32bit
  5042. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  5043. from->type.intValue = from->type.byteValue;
  5044. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  5045. from->type.intValue = from->type.wordValue;
  5046. }
  5047. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  5048. {
  5049. // Convert to 32bit
  5050. from->type.intValue = int(from->type.qwordValue);
  5051. }
  5052. else if( from->type.dataType.IsIntegerType() &&
  5053. from->type.dataType.GetSizeInMemoryBytes() < 4 )
  5054. {
  5055. // Convert to 32bit
  5056. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  5057. from->type.intValue = (signed char)from->type.byteValue;
  5058. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  5059. from->type.intValue = (short)from->type.wordValue;
  5060. }
  5061. // Set the resulting type
  5062. if( to.IsEnumType() )
  5063. from->type.dataType = to;
  5064. else
  5065. from->type.dataType = asCDataType::CreatePrimitive(ttInt, true);
  5066. }
  5067. // Check if a downsize is necessary
  5068. if( to.IsIntegerType() &&
  5069. from->type.dataType.IsIntegerType() &&
  5070. from->type.dataType.GetSizeInMemoryBytes() > to.GetSizeInMemoryBytes() )
  5071. {
  5072. // Verify if it is possible
  5073. if( to.GetSizeInMemoryBytes() == 1 )
  5074. {
  5075. if( char(from->type.intValue) != from->type.intValue )
  5076. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  5077. from->type.byteValue = char(from->type.intValue);
  5078. }
  5079. else if( to.GetSizeInMemoryBytes() == 2 )
  5080. {
  5081. if( short(from->type.intValue) != from->type.intValue )
  5082. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  5083. from->type.wordValue = short(from->type.intValue);
  5084. }
  5085. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  5086. }
  5087. }
  5088. else if( to.IsIntegerType() && to.GetSizeInMemoryDWords() == 2 )
  5089. {
  5090. // Float constants can be implicitly converted to int
  5091. if( from->type.dataType.IsFloatType() )
  5092. {
  5093. float fc = from->type.floatValue;
  5094. asINT64 ic = asINT64(fc);
  5095. if( float(ic) != fc )
  5096. {
  5097. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5098. }
  5099. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  5100. from->type.qwordValue = ic;
  5101. }
  5102. // Double constants can be implicitly converted to int
  5103. else if( from->type.dataType.IsDoubleType() )
  5104. {
  5105. double fc = from->type.doubleValue;
  5106. asINT64 ic = asINT64(fc);
  5107. if( double(ic) != fc )
  5108. {
  5109. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5110. }
  5111. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  5112. from->type.qwordValue = ic;
  5113. }
  5114. else if( from->type.dataType.IsUnsignedType() )
  5115. {
  5116. // Convert to 64bit
  5117. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  5118. from->type.qwordValue = from->type.byteValue;
  5119. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  5120. from->type.qwordValue = from->type.wordValue;
  5121. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  5122. from->type.qwordValue = from->type.dwordValue;
  5123. else if( from->type.dataType.GetSizeInMemoryBytes() == 8 )
  5124. {
  5125. if( asINT64(from->type.qwordValue) < 0 )
  5126. {
  5127. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  5128. }
  5129. }
  5130. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  5131. }
  5132. else if( from->type.dataType.IsIntegerType() )
  5133. {
  5134. // Convert to 64bit
  5135. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  5136. from->type.qwordValue = (signed char)from->type.byteValue;
  5137. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  5138. from->type.qwordValue = (short)from->type.wordValue;
  5139. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  5140. from->type.qwordValue = from->type.intValue;
  5141. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  5142. }
  5143. }
  5144. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 1 )
  5145. {
  5146. if( from->type.dataType.IsFloatType() )
  5147. {
  5148. float fc = from->type.floatValue;
  5149. // Some compilers set the value to 0 when converting a negative float to unsigned int.
  5150. // To maintain a consistent behaviour across compilers we convert to int first.
  5151. asUINT uic = asUINT(int(fc));
  5152. if( float(uic) != fc )
  5153. {
  5154. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5155. }
  5156. from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true);
  5157. from->type.intValue = uic;
  5158. // Try once more, in case of a smaller type
  5159. ImplicitConversionConstant(from, to, node, convType);
  5160. }
  5161. else if( from->type.dataType.IsDoubleType() )
  5162. {
  5163. double fc = from->type.doubleValue;
  5164. // Some compilers set the value to 0 when converting a negative double to unsigned int.
  5165. // To maintain a consistent behaviour across compilers we convert to int first.
  5166. asUINT uic = asUINT(int(fc));
  5167. if( double(uic) != fc )
  5168. {
  5169. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5170. }
  5171. from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true);
  5172. from->type.intValue = uic;
  5173. // Try once more, in case of a smaller type
  5174. ImplicitConversionConstant(from, to, node, convType);
  5175. }
  5176. else if( from->type.dataType.IsIntegerType() )
  5177. {
  5178. // Verify that it is possible to convert to unsigned without loosing negative
  5179. if( (from->type.dataType.GetSizeInMemoryBytes() > 4 && asINT64(from->type.qwordValue) < 0) ||
  5180. (from->type.dataType.GetSizeInMemoryBytes() <= 4 && from->type.intValue < 0) )
  5181. {
  5182. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  5183. }
  5184. // Check if any data is lost
  5185. if( from->type.dataType.GetSizeInMemoryBytes() > 4 && (from->type.qwordValue >> 32) != 0 && (from->type.qwordValue >> 32) != 0xFFFFFFFF )
  5186. {
  5187. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  5188. }
  5189. // Convert to 32bit
  5190. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  5191. from->type.intValue = (signed char)from->type.byteValue;
  5192. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  5193. from->type.intValue = (short)from->type.wordValue;
  5194. from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true);
  5195. // Try once more, in case of a smaller type
  5196. ImplicitConversionConstant(from, to, node, convType);
  5197. }
  5198. else if( from->type.dataType.IsUnsignedType() &&
  5199. from->type.dataType.GetSizeInMemoryBytes() < 4 )
  5200. {
  5201. // Convert to 32bit
  5202. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  5203. from->type.dwordValue = from->type.byteValue;
  5204. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  5205. from->type.dwordValue = from->type.wordValue;
  5206. from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true);
  5207. // Try once more, in case of a smaller type
  5208. ImplicitConversionConstant(from, to, node, convType);
  5209. }
  5210. else if( from->type.dataType.IsUnsignedType() &&
  5211. from->type.dataType.GetSizeInMemoryBytes() > to.GetSizeInMemoryBytes() )
  5212. {
  5213. // Verify if it is possible
  5214. if( to.GetSizeInMemoryBytes() == 1 )
  5215. {
  5216. if( asBYTE(from->type.dwordValue) != from->type.dwordValue )
  5217. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  5218. from->type.byteValue = asBYTE(from->type.dwordValue);
  5219. }
  5220. else if( to.GetSizeInMemoryBytes() == 2 )
  5221. {
  5222. if( asWORD(from->type.dwordValue) != from->type.dwordValue )
  5223. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  5224. from->type.wordValue = asWORD(from->type.dwordValue);
  5225. }
  5226. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  5227. }
  5228. }
  5229. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 2 )
  5230. {
  5231. if( from->type.dataType.IsFloatType() )
  5232. {
  5233. float fc = from->type.floatValue;
  5234. // Convert first to int64 then to uint64 to avoid negative float becoming 0 on gnuc base compilers
  5235. asQWORD uic = asQWORD(asINT64(fc));
  5236. #if !defined(_MSC_VER) || _MSC_VER > 1200 // MSVC++ 6
  5237. // MSVC6 doesn't support this conversion
  5238. if( float(uic) != fc )
  5239. {
  5240. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5241. }
  5242. #endif
  5243. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  5244. from->type.qwordValue = uic;
  5245. }
  5246. else if( from->type.dataType.IsDoubleType() )
  5247. {
  5248. double fc = from->type.doubleValue;
  5249. // Convert first to int64 then to uint64 to avoid negative float becoming 0 on gnuc base compilers
  5250. asQWORD uic = asQWORD(asINT64(fc));
  5251. #if !defined(_MSC_VER) || _MSC_VER > 1200 // MSVC++ 6
  5252. // MSVC6 doesn't support this conversion
  5253. if( double(uic) != fc )
  5254. {
  5255. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5256. }
  5257. #endif
  5258. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  5259. from->type.qwordValue = uic;
  5260. }
  5261. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  5262. {
  5263. // Convert to 64bit
  5264. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  5265. from->type.qwordValue = (asINT64)(signed char)from->type.byteValue;
  5266. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  5267. from->type.qwordValue = (asINT64)(short)from->type.wordValue;
  5268. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  5269. from->type.qwordValue = (asINT64)from->type.intValue;
  5270. // Verify that it is possible to convert to unsigned without loosing negative
  5271. if( asINT64(from->type.qwordValue) < 0 )
  5272. {
  5273. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  5274. }
  5275. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  5276. }
  5277. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  5278. {
  5279. // Verify that it is possible to convert to unsigned without loosing negative
  5280. if( asINT64(from->type.qwordValue) < 0 )
  5281. {
  5282. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  5283. }
  5284. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  5285. }
  5286. else if( from->type.dataType.IsUnsignedType() )
  5287. {
  5288. // Convert to 64bit
  5289. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  5290. from->type.qwordValue = from->type.byteValue;
  5291. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  5292. from->type.qwordValue = from->type.wordValue;
  5293. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  5294. from->type.qwordValue = from->type.dwordValue;
  5295. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  5296. }
  5297. }
  5298. else if( to.IsFloatType() )
  5299. {
  5300. if( from->type.dataType.IsDoubleType() )
  5301. {
  5302. double ic = from->type.doubleValue;
  5303. float fc = float(ic);
  5304. // Don't bother warning about this
  5305. // if( double(fc) != ic )
  5306. // {
  5307. // asCString str;
  5308. // str.Format(TXT_POSSIBLE_LOSS_OF_PRECISION);
  5309. // if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(str, node);
  5310. // }
  5311. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  5312. from->type.floatValue = fc;
  5313. }
  5314. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  5315. {
  5316. // Must properly convert value in case the from value is smaller
  5317. int ic;
  5318. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  5319. ic = (signed char)from->type.byteValue;
  5320. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  5321. ic = (short)from->type.wordValue;
  5322. else
  5323. ic = from->type.intValue;
  5324. float fc = float(ic);
  5325. if( int(fc) != ic )
  5326. {
  5327. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5328. }
  5329. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  5330. from->type.floatValue = fc;
  5331. }
  5332. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  5333. {
  5334. float fc = float(asINT64(from->type.qwordValue));
  5335. if( asINT64(fc) != asINT64(from->type.qwordValue) )
  5336. {
  5337. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5338. }
  5339. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  5340. from->type.floatValue = fc;
  5341. }
  5342. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  5343. {
  5344. // Must properly convert value in case the from value is smaller
  5345. unsigned int uic;
  5346. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  5347. uic = from->type.byteValue;
  5348. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  5349. uic = from->type.wordValue;
  5350. else
  5351. uic = from->type.dwordValue;
  5352. float fc = float(uic);
  5353. if( (unsigned int)(fc) != uic )
  5354. {
  5355. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5356. }
  5357. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  5358. from->type.floatValue = fc;
  5359. }
  5360. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  5361. {
  5362. float fc = float((asINT64)from->type.qwordValue);
  5363. if( asQWORD(fc) != from->type.qwordValue )
  5364. {
  5365. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5366. }
  5367. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  5368. from->type.floatValue = fc;
  5369. }
  5370. }
  5371. else if( to.IsDoubleType() )
  5372. {
  5373. if( from->type.dataType.IsFloatType() )
  5374. {
  5375. float ic = from->type.floatValue;
  5376. double fc = double(ic);
  5377. // Don't check for float->double
  5378. // if( float(fc) != ic )
  5379. // {
  5380. // acCString str;
  5381. // str.Format(TXT_NOT_EXACT_g_g_g, ic, fc, float(fc));
  5382. // if( !isExplicit ) Warning(str, node);
  5383. // }
  5384. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  5385. from->type.doubleValue = fc;
  5386. }
  5387. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  5388. {
  5389. // Must properly convert value in case the from value is smaller
  5390. int ic;
  5391. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  5392. ic = (signed char)from->type.byteValue;
  5393. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  5394. ic = (short)from->type.wordValue;
  5395. else
  5396. ic = from->type.intValue;
  5397. double fc = double(ic);
  5398. if( int(fc) != ic )
  5399. {
  5400. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5401. }
  5402. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  5403. from->type.doubleValue = fc;
  5404. }
  5405. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  5406. {
  5407. double fc = double(asINT64(from->type.qwordValue));
  5408. if( asINT64(fc) != asINT64(from->type.qwordValue) )
  5409. {
  5410. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5411. }
  5412. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  5413. from->type.doubleValue = fc;
  5414. }
  5415. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  5416. {
  5417. // Must properly convert value in case the from value is smaller
  5418. unsigned int uic;
  5419. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  5420. uic = from->type.byteValue;
  5421. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  5422. uic = from->type.wordValue;
  5423. else
  5424. uic = from->type.dwordValue;
  5425. double fc = double(uic);
  5426. if( (unsigned int)(fc) != uic )
  5427. {
  5428. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5429. }
  5430. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  5431. from->type.doubleValue = fc;
  5432. }
  5433. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  5434. {
  5435. double fc = double((asINT64)from->type.qwordValue);
  5436. if( asQWORD(fc) != from->type.qwordValue )
  5437. {
  5438. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5439. }
  5440. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  5441. from->type.doubleValue = fc;
  5442. }
  5443. }
  5444. }
  5445. int asCCompiler::DoAssignment(asSExprContext *ctx, asSExprContext *lctx, asSExprContext *rctx, asCScriptNode *lexpr, asCScriptNode *rexpr, int op, asCScriptNode *opNode)
  5446. {
  5447. // Don't allow any operators on expressions that take address of class method
  5448. // If methodName is set but the type is not an object, then it is a global function
  5449. if( lctx->methodName != "" || rctx->IsClassMethod() )
  5450. {
  5451. Error(TXT_INVALID_OP_ON_METHOD, opNode);
  5452. return -1;
  5453. }
  5454. // Implicit handle types should always be treated as handles in assignments
  5455. if (lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE) )
  5456. {
  5457. lctx->type.dataType.MakeHandle(true);
  5458. lctx->type.isExplicitHandle = true;
  5459. }
  5460. // Urho3D: if there is a handle type, and it does not have an overloaded assignment operator, convert to an explicit handle
  5461. // for scripting convenience. (For the Urho3D handle types, value assignment is not supported)
  5462. if (lctx->type.dataType.IsObjectHandle() && !lctx->type.dataType.IsTemplate() && !lctx->type.isExplicitHandle &&
  5463. !lctx->type.dataType.GetBehaviour()->copy)
  5464. lctx->type.isExplicitHandle = true;
  5465. // If the left hand expression is a property accessor, then that should be used
  5466. // to do the assignment instead of the ordinary operator. The exception is when
  5467. // the property accessor is for a handle property, and the operation is a value
  5468. // assignment.
  5469. if( (lctx->property_get || lctx->property_set) &&
  5470. !(lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle) )
  5471. {
  5472. if( op != ttAssignment )
  5473. {
  5474. // TODO: getset: We may actually be able to support this, if we can
  5475. // guarantee that the object reference will stay valid
  5476. // between the calls to the get and set accessors.
  5477. // Process the property to free the memory
  5478. ProcessPropertySetAccessor(lctx, rctx, opNode);
  5479. // Compound assignments are not allowed for properties
  5480. Error(TXT_COMPOUND_ASGN_WITH_PROP, opNode);
  5481. return -1;
  5482. }
  5483. // It is not allowed to do a handle assignment on a property
  5484. // accessor that doesn't take a handle in the set accessor.
  5485. if( lctx->property_set && lctx->type.isExplicitHandle )
  5486. {
  5487. // set_opIndex has 2 arguments, where as normal setters have only 1
  5488. asCArray<asCDataType>& parameterTypes =
  5489. builder->GetFunctionDescription(lctx->property_set)->parameterTypes;
  5490. if( !parameterTypes[parameterTypes.GetLength() - 1].IsObjectHandle() )
  5491. {
  5492. // Process the property to free the memory
  5493. ProcessPropertySetAccessor(lctx, rctx, opNode);
  5494. Error(TXT_HANDLE_ASSIGN_ON_NON_HANDLE_PROP, opNode);
  5495. return -1;
  5496. }
  5497. }
  5498. MergeExprBytecodeAndType(ctx, lctx);
  5499. return ProcessPropertySetAccessor(ctx, rctx, opNode);
  5500. }
  5501. else if( lctx->property_get && lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle )
  5502. {
  5503. // Get the handle to the object that will be used for the value assignment
  5504. ProcessPropertyGetAccessor(lctx, opNode);
  5505. }
  5506. if( lctx->type.dataType.IsPrimitive() )
  5507. {
  5508. if( !lctx->type.isLValue )
  5509. {
  5510. Error(TXT_NOT_LVALUE, lexpr);
  5511. return -1;
  5512. }
  5513. if( op != ttAssignment )
  5514. {
  5515. // Compute the operator before the assignment
  5516. asCTypeInfo lvalue = lctx->type;
  5517. if( lctx->type.isTemporary && !lctx->type.isVariable )
  5518. {
  5519. // The temporary variable must not be freed until the
  5520. // assignment has been performed. lvalue still holds
  5521. // the information about the temporary variable
  5522. lctx->type.isTemporary = false;
  5523. }
  5524. asSExprContext o(engine);
  5525. CompileOperator(opNode, lctx, rctx, &o);
  5526. MergeExprBytecode(rctx, &o);
  5527. rctx->type = o.type;
  5528. // Convert the rvalue to the right type and validate it
  5529. PrepareForAssignment(&lvalue.dataType, rctx, rexpr, false);
  5530. MergeExprBytecode(ctx, rctx);
  5531. lctx->type = lvalue;
  5532. // The lvalue continues the same, either it was a variable, or a reference in the register
  5533. }
  5534. else
  5535. {
  5536. // Convert the rvalue to the right type and validate it
  5537. PrepareForAssignment(&lctx->type.dataType, rctx, rexpr, false, lctx);
  5538. MergeExprBytecode(ctx, rctx);
  5539. MergeExprBytecode(ctx, lctx);
  5540. }
  5541. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  5542. PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode);
  5543. ctx->type = lctx->type;
  5544. }
  5545. else if( lctx->type.isExplicitHandle )
  5546. {
  5547. if( !lctx->type.isLValue )
  5548. {
  5549. Error(TXT_NOT_LVALUE, lexpr);
  5550. return -1;
  5551. }
  5552. // Object handles don't have any compound assignment operators
  5553. if( op != ttAssignment )
  5554. {
  5555. asCString str;
  5556. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format().AddressOf());
  5557. Error(str, lexpr);
  5558. return -1;
  5559. }
  5560. if( lctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE )
  5561. {
  5562. // The object is a value type but that should be treated as a handle
  5563. // Make sure the right hand value is a handle
  5564. if( !rctx->type.isExplicitHandle &&
  5565. !(rctx->type.dataType.GetObjectType() && (rctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE)) )
  5566. {
  5567. // Function names can be considered handles already
  5568. if( rctx->methodName == "" )
  5569. {
  5570. asCDataType dt = rctx->type.dataType;
  5571. dt.MakeHandle(true);
  5572. dt.MakeReference(false);
  5573. PrepareArgument(&dt, rctx, rexpr, true, asTM_INREF);
  5574. if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) )
  5575. {
  5576. asCString str;
  5577. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format().AddressOf(), lctx->type.dataType.Format().AddressOf());
  5578. Error(str, rexpr);
  5579. return -1;
  5580. }
  5581. }
  5582. }
  5583. if( CompileOverloadedDualOperator(opNode, lctx, rctx, ctx) )
  5584. {
  5585. // An overloaded assignment operator was found (or a compilation error occured)
  5586. return 0;
  5587. }
  5588. // The object must implement the opAssign method
  5589. Error(TXT_NO_APPROPRIATE_OPASSIGN, opNode);
  5590. return -1;
  5591. }
  5592. else
  5593. {
  5594. asCDataType dt = lctx->type.dataType;
  5595. dt.MakeReference(false);
  5596. PrepareArgument(&dt, rctx, rexpr, true, asTM_INREF , true);
  5597. if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) )
  5598. {
  5599. asCString str;
  5600. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format().AddressOf(), lctx->type.dataType.Format().AddressOf());
  5601. Error(str, rexpr);
  5602. return -1;
  5603. }
  5604. MergeExprBytecode(ctx, rctx);
  5605. MergeExprBytecode(ctx, lctx);
  5606. ctx->bc.InstrWORD(asBC_GETOBJREF, AS_PTR_SIZE);
  5607. PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode);
  5608. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  5609. ctx->type = lctx->type;
  5610. }
  5611. }
  5612. else // if( lctx->type.dataType.IsObject() )
  5613. {
  5614. // An ASHANDLE type must not allow a value assignment, as
  5615. // the opAssign operator is used for the handle assignment
  5616. if( lctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE )
  5617. {
  5618. asCString str;
  5619. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format().AddressOf());
  5620. Error(str, lexpr);
  5621. return -1;
  5622. }
  5623. // The lvalue reference may be marked as a temporary, if for example
  5624. // it was originated as a handle returned from a function. In such
  5625. // cases it must be possible to assign values to it anyway.
  5626. if( lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle )
  5627. {
  5628. // Convert the handle to a object reference
  5629. asCDataType to;
  5630. to = lctx->type.dataType;
  5631. to.MakeHandle(false);
  5632. ImplicitConversion(lctx, to, lexpr, asIC_IMPLICIT_CONV);
  5633. lctx->type.isLValue = true; // Handle may not have been an lvalue, but the dereferenced object is
  5634. }
  5635. // Check for overloaded assignment operator
  5636. if( CompileOverloadedDualOperator(opNode, lctx, rctx, ctx) )
  5637. {
  5638. // An overloaded assignment operator was found (or a compilation error occured)
  5639. return 0;
  5640. }
  5641. // No registered operator was found. In case the operation is a direct
  5642. // assignment and the rvalue is the same type as the lvalue, then we can
  5643. // still use the byte-for-byte copy to do the assignment
  5644. if( op != ttAssignment )
  5645. {
  5646. asCString str;
  5647. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format().AddressOf());
  5648. Error(str, lexpr);
  5649. return -1;
  5650. }
  5651. // If the left hand expression is simple, i.e. without any
  5652. // function calls or allocations of memory, then we can avoid
  5653. // doing a copy of the right hand expression (done by PrepareArgument).
  5654. // Instead the reference to the value can be placed directly on the
  5655. // stack.
  5656. //
  5657. // This optimization should only be done for value types, where
  5658. // the application developer is responsible for making the
  5659. // implementation safe against unwanted destruction of the input
  5660. // reference before the time.
  5661. bool simpleExpr = (lctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_VALUE) && lctx->bc.IsSimpleExpression();
  5662. // Implicitly convert the rvalue to the type of the lvalue
  5663. bool needConversion = false;
  5664. if( !lctx->type.dataType.IsEqualExceptRefAndConst(rctx->type.dataType) )
  5665. needConversion = true;
  5666. if( !simpleExpr || needConversion )
  5667. {
  5668. asCDataType dt = lctx->type.dataType;
  5669. dt.MakeReference(true);
  5670. dt.MakeReadOnly(true);
  5671. PrepareArgument(&dt, rctx, rexpr, true, 1, !needConversion);
  5672. if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) )
  5673. {
  5674. asCString str;
  5675. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format().AddressOf(), lctx->type.dataType.Format().AddressOf());
  5676. Error(str, rexpr);
  5677. return -1;
  5678. }
  5679. }
  5680. else
  5681. {
  5682. // Process any property accessor first, before placing the final reference on the stack
  5683. ProcessPropertyGetAccessor(rctx, rexpr);
  5684. if( rctx->type.dataType.IsReference() && (!(rctx->type.isVariable || rctx->type.isTemporary) || IsVariableOnHeap(rctx->type.stackOffset)) )
  5685. rctx->bc.Instr(asBC_RDSPtr);
  5686. }
  5687. MergeExprBytecode(ctx, rctx);
  5688. MergeExprBytecode(ctx, lctx);
  5689. if( !simpleExpr || needConversion )
  5690. {
  5691. if( (rctx->type.isVariable || rctx->type.isTemporary) )
  5692. {
  5693. if( !IsVariableOnHeap(rctx->type.stackOffset) )
  5694. // TODO: runtime optimize: Actually the reference can be pushed on the stack directly
  5695. // as the value allocated on the stack is guaranteed to be safe.
  5696. // The bytecode optimizer should be able to determine this and optimize away the VAR + GETREF
  5697. ctx->bc.InstrWORD(asBC_GETREF, AS_PTR_SIZE);
  5698. else
  5699. ctx->bc.InstrWORD(asBC_GETOBJREF, AS_PTR_SIZE);
  5700. }
  5701. }
  5702. PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode);
  5703. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  5704. ctx->type = lctx->type;
  5705. }
  5706. return 0;
  5707. }
  5708. int asCCompiler::CompileAssignment(asCScriptNode *expr, asSExprContext *ctx)
  5709. {
  5710. asCScriptNode *lexpr = expr->firstChild;
  5711. if( lexpr->next )
  5712. {
  5713. // Compile the two expression terms
  5714. asSExprContext lctx(engine), rctx(engine);
  5715. int rr = CompileAssignment(lexpr->next->next, &rctx);
  5716. int lr = CompileCondition(lexpr, &lctx);
  5717. if( lr >= 0 && rr >= 0 )
  5718. return DoAssignment(ctx, &lctx, &rctx, lexpr, lexpr->next->next, lexpr->next->tokenType, lexpr->next);
  5719. // Since the operands failed, the assignment was not computed
  5720. ctx->type.SetDummy();
  5721. return -1;
  5722. }
  5723. return CompileCondition(lexpr, ctx);
  5724. }
  5725. int asCCompiler::CompileCondition(asCScriptNode *expr, asSExprContext *ctx)
  5726. {
  5727. asCTypeInfo ctype;
  5728. // Compile the conditional expression
  5729. asCScriptNode *cexpr = expr->firstChild;
  5730. if( cexpr->next )
  5731. {
  5732. //-------------------------------
  5733. // Compile the condition
  5734. asSExprContext e(engine);
  5735. int r = CompileExpression(cexpr, &e);
  5736. if( r < 0 )
  5737. e.type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  5738. if( r >= 0 && !e.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  5739. {
  5740. Error(TXT_EXPR_MUST_BE_BOOL, cexpr);
  5741. e.type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  5742. }
  5743. ctype = e.type;
  5744. ProcessPropertyGetAccessor(&e, cexpr);
  5745. if( e.type.dataType.IsReference() ) ConvertToVariable(&e);
  5746. ProcessDeferredParams(&e);
  5747. //-------------------------------
  5748. // Compile the left expression
  5749. asSExprContext le(engine);
  5750. int lr = CompileAssignment(cexpr->next, &le);
  5751. //-------------------------------
  5752. // Compile the right expression
  5753. asSExprContext re(engine);
  5754. int rr = CompileAssignment(cexpr->next->next, &re);
  5755. if( lr >= 0 && rr >= 0 )
  5756. {
  5757. // Don't allow any operators on expressions that take address of class method
  5758. if( le.IsClassMethod() || re.IsClassMethod() )
  5759. {
  5760. Error(TXT_INVALID_OP_ON_METHOD, expr);
  5761. return -1;
  5762. }
  5763. ProcessPropertyGetAccessor(&le, cexpr->next);
  5764. ProcessPropertyGetAccessor(&re, cexpr->next->next);
  5765. bool isExplicitHandle = le.type.isExplicitHandle || re.type.isExplicitHandle;
  5766. // Allow a 0 or null in the first case to be implicitly converted to the second type
  5767. if( le.type.isConstant && le.type.intValue == 0 && le.type.dataType.IsUnsignedType() )
  5768. {
  5769. asCDataType to = re.type.dataType;
  5770. to.MakeReference(false);
  5771. to.MakeReadOnly(true);
  5772. ImplicitConversionConstant(&le, to, cexpr->next, asIC_IMPLICIT_CONV);
  5773. }
  5774. else if( le.type.IsNullConstant() )
  5775. {
  5776. asCDataType to = re.type.dataType;
  5777. to.MakeHandle(true);
  5778. ImplicitConversion(&le, to, cexpr->next, asIC_IMPLICIT_CONV);
  5779. }
  5780. //---------------------------------
  5781. // Output the byte code
  5782. int afterLabel = nextLabel++;
  5783. int elseLabel = nextLabel++;
  5784. // If left expression is void, then we don't need to store the result
  5785. if( le.type.dataType.IsEqualExceptConst(asCDataType::CreatePrimitive(ttVoid, false)) )
  5786. {
  5787. // Put the code for the condition expression on the output
  5788. MergeExprBytecode(ctx, &e);
  5789. // Added the branch decision
  5790. ctx->type = e.type;
  5791. ConvertToVariable(ctx);
  5792. ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset);
  5793. ctx->bc.Instr(asBC_ClrHi);
  5794. ctx->bc.InstrDWORD(asBC_JZ, elseLabel);
  5795. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5796. // Add the left expression
  5797. MergeExprBytecode(ctx, &le);
  5798. ctx->bc.InstrINT(asBC_JMP, afterLabel);
  5799. // Add the right expression
  5800. ctx->bc.Label((short)elseLabel);
  5801. MergeExprBytecode(ctx, &re);
  5802. ctx->bc.Label((short)afterLabel);
  5803. // Make sure both expressions have the same type
  5804. if( le.type.dataType != re.type.dataType )
  5805. Error(TXT_BOTH_MUST_BE_SAME, expr);
  5806. // Set the type of the result
  5807. ctx->type = le.type;
  5808. }
  5809. else
  5810. {
  5811. // Allocate temporary variable and copy the result to that one
  5812. asCTypeInfo temp;
  5813. temp = le.type;
  5814. temp.dataType.MakeReference(false);
  5815. temp.dataType.MakeReadOnly(false);
  5816. // Make sure the variable isn't used in any of the expressions,
  5817. // as it would be overwritten which may cause crashes or less visible bugs
  5818. int l = int(reservedVariables.GetLength());
  5819. e.bc.GetVarsUsed(reservedVariables);
  5820. le.bc.GetVarsUsed(reservedVariables);
  5821. re.bc.GetVarsUsed(reservedVariables);
  5822. int offset = AllocateVariable(temp.dataType, true, false);
  5823. reservedVariables.SetLength(l);
  5824. temp.SetVariable(temp.dataType, offset, true);
  5825. // TODO: copy: Use copy constructor if available. See PrepareTemporaryObject()
  5826. CallDefaultConstructor(temp.dataType, offset, IsVariableOnHeap(offset), &ctx->bc, expr);
  5827. // Put the code for the condition expression on the output
  5828. MergeExprBytecode(ctx, &e);
  5829. // Add the branch decision
  5830. ctx->type = e.type;
  5831. ConvertToVariable(ctx);
  5832. ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset);
  5833. ctx->bc.Instr(asBC_ClrHi);
  5834. ctx->bc.InstrDWORD(asBC_JZ, elseLabel);
  5835. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5836. // Assign the result of the left expression to the temporary variable
  5837. asCTypeInfo rtemp;
  5838. rtemp = temp;
  5839. if( rtemp.dataType.IsObjectHandle() )
  5840. rtemp.isExplicitHandle = true;
  5841. PrepareForAssignment(&rtemp.dataType, &le, cexpr->next, true);
  5842. MergeExprBytecode(ctx, &le);
  5843. if( !rtemp.dataType.IsPrimitive() )
  5844. {
  5845. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  5846. rtemp.dataType.MakeReference(IsVariableOnHeap(offset));
  5847. }
  5848. asCTypeInfo result;
  5849. result = rtemp;
  5850. PerformAssignment(&result, &le.type, &ctx->bc, cexpr->next);
  5851. if( !result.dataType.IsPrimitive() )
  5852. ctx->bc.Instr(asBC_PopPtr); // Pop the original value (always a pointer)
  5853. // Release the old temporary variable
  5854. ReleaseTemporaryVariable(le.type, &ctx->bc);
  5855. ctx->bc.InstrINT(asBC_JMP, afterLabel);
  5856. // Start of the right expression
  5857. ctx->bc.Label((short)elseLabel);
  5858. // Copy the result to the same temporary variable
  5859. PrepareForAssignment(&rtemp.dataType, &re, cexpr->next, true);
  5860. MergeExprBytecode(ctx, &re);
  5861. if( !rtemp.dataType.IsPrimitive() )
  5862. {
  5863. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  5864. rtemp.dataType.MakeReference(IsVariableOnHeap(offset));
  5865. }
  5866. result = rtemp;
  5867. PerformAssignment(&result, &re.type, &ctx->bc, cexpr->next);
  5868. if( !result.dataType.IsPrimitive() )
  5869. ctx->bc.Instr(asBC_PopPtr); // Pop the original value (always a pointer)
  5870. // Release the old temporary variable
  5871. ReleaseTemporaryVariable(re.type, &ctx->bc);
  5872. ctx->bc.Label((short)afterLabel);
  5873. // Make sure both expressions have the same type
  5874. if( !le.type.dataType.IsEqualExceptConst(re.type.dataType) )
  5875. Error(TXT_BOTH_MUST_BE_SAME, expr);
  5876. // Set the temporary variable as output
  5877. ctx->type = rtemp;
  5878. ctx->type.isExplicitHandle = isExplicitHandle;
  5879. if( !ctx->type.dataType.IsPrimitive() )
  5880. {
  5881. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  5882. ctx->type.dataType.MakeReference(IsVariableOnHeap(offset));
  5883. }
  5884. // Make sure the output isn't marked as being a literal constant
  5885. ctx->type.isConstant = false;
  5886. }
  5887. }
  5888. else
  5889. {
  5890. ctx->type.SetDummy();
  5891. return -1;
  5892. }
  5893. }
  5894. else
  5895. return CompileExpression(cexpr, ctx);
  5896. return 0;
  5897. }
  5898. int asCCompiler::CompileExpression(asCScriptNode *expr, asSExprContext *ctx)
  5899. {
  5900. asASSERT(expr->nodeType == snExpression);
  5901. // Convert to polish post fix, i.e: a+b => ab+
  5902. // The algorithm that I've implemented here is similar to
  5903. // Djikstra's Shunting Yard algorithm, though I didn't know it at the time.
  5904. // ref: http://en.wikipedia.org/wiki/Shunting-yard_algorithm
  5905. // Count the nodes in order to preallocate the buffers
  5906. int count = 0;
  5907. asCScriptNode *node = expr->firstChild;
  5908. while( node )
  5909. {
  5910. count++;
  5911. node = node->next;
  5912. }
  5913. asCArray<asCScriptNode *> stack(count);
  5914. asCArray<asCScriptNode *> stack2(count);
  5915. node = expr->firstChild;
  5916. while( node )
  5917. {
  5918. int precedence = GetPrecedence(node);
  5919. while( stack.GetLength() > 0 &&
  5920. precedence <= GetPrecedence(stack[stack.GetLength()-1]) )
  5921. stack2.PushLast(stack.PopLast());
  5922. stack.PushLast(node);
  5923. node = node->next;
  5924. }
  5925. while( stack.GetLength() > 0 )
  5926. stack2.PushLast(stack.PopLast());
  5927. // Compile the postfix formatted expression
  5928. return CompilePostFixExpression(&stack2, ctx);
  5929. }
  5930. int asCCompiler::CompilePostFixExpression(asCArray<asCScriptNode *> *postfix, asSExprContext *ctx)
  5931. {
  5932. // Shouldn't send any byte code
  5933. asASSERT(ctx->bc.GetLastInstr() == -1);
  5934. // Set the context to a dummy type to avoid further
  5935. // errors in case the expression fails to compile
  5936. ctx->type.SetDummy();
  5937. // Evaluate the operands and operators
  5938. asCArray<asSExprContext*> free;
  5939. asCArray<asSExprContext*> expr;
  5940. int ret = 0;
  5941. for( asUINT n = 0; ret == 0 && n < postfix->GetLength(); n++ )
  5942. {
  5943. asCScriptNode *node = (*postfix)[n];
  5944. if( node->nodeType == snExprTerm )
  5945. {
  5946. asSExprContext *e = free.GetLength() ? free.PopLast() : asNEW(asSExprContext)(engine);
  5947. expr.PushLast(e);
  5948. e->exprNode = node;
  5949. ret = CompileExpressionTerm(node, e);
  5950. }
  5951. else
  5952. {
  5953. asSExprContext *r = expr.PopLast();
  5954. asSExprContext *l = expr.PopLast();
  5955. // Now compile the operator
  5956. asSExprContext *e = free.GetLength() ? free.PopLast() : asNEW(asSExprContext)(engine);
  5957. ret = CompileOperator(node, l, r, e);
  5958. expr.PushLast(e);
  5959. // Free the operands
  5960. l->Clear();
  5961. free.PushLast(l);
  5962. r->Clear();
  5963. free.PushLast(r);
  5964. }
  5965. }
  5966. if( ret == 0 )
  5967. {
  5968. asASSERT(expr.GetLength() == 1);
  5969. // The final result should be moved to the output context
  5970. MergeExprBytecodeAndType(ctx, expr[0]);
  5971. }
  5972. // Clean up
  5973. for( asUINT e = 0; e < expr.GetLength(); e++ )
  5974. asDELETE(expr[e], asSExprContext);
  5975. for( asUINT f = 0; f < free.GetLength(); f++ )
  5976. asDELETE(free[f], asSExprContext);
  5977. return ret;
  5978. }
  5979. int asCCompiler::CompileExpressionTerm(asCScriptNode *node, asSExprContext *ctx)
  5980. {
  5981. // Shouldn't send any byte code
  5982. asASSERT(ctx->bc.GetLastInstr() == -1);
  5983. // Set the type as a dummy by default, in case of any compiler errors
  5984. ctx->type.SetDummy();
  5985. // Compile the value node
  5986. asCScriptNode *vnode = node->firstChild;
  5987. while( vnode->nodeType != snExprValue )
  5988. vnode = vnode->next;
  5989. asSExprContext v(engine);
  5990. int r = CompileExpressionValue(vnode, &v); if( r < 0 ) return r;
  5991. // Compile post fix operators
  5992. asCScriptNode *pnode = vnode->next;
  5993. while( pnode )
  5994. {
  5995. r = CompileExpressionPostOp(pnode, &v); if( r < 0 ) return r;
  5996. pnode = pnode->next;
  5997. }
  5998. // Compile pre fix operators
  5999. pnode = vnode->prev;
  6000. while( pnode )
  6001. {
  6002. r = CompileExpressionPreOp(pnode, &v); if( r < 0 ) return r;
  6003. pnode = pnode->prev;
  6004. }
  6005. // Return the byte code and final type description
  6006. MergeExprBytecodeAndType(ctx, &v);
  6007. return 0;
  6008. }
  6009. int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &scope, asSExprContext *ctx, asCScriptNode *errNode, bool isOptional, bool noFunction, bool noGlobal, asCObjectType *objType)
  6010. {
  6011. bool found = false;
  6012. // It is a local variable or parameter?
  6013. // This is not accessible by default arg expressions
  6014. sVariable *v = 0;
  6015. if( !isCompilingDefaultArg && scope == "" && !objType && variables )
  6016. v = variables->GetVariable(name.AddressOf());
  6017. if( v )
  6018. {
  6019. found = true;
  6020. if( v->isPureConstant )
  6021. ctx->type.SetConstantQW(v->type, v->constantValue);
  6022. else if( v->type.IsPrimitive() )
  6023. {
  6024. if( v->type.IsReference() )
  6025. {
  6026. // Copy the reference into the register
  6027. ctx->bc.InstrSHORT(asBC_PshVPtr, (short)v->stackOffset);
  6028. ctx->bc.Instr(asBC_PopRPtr);
  6029. ctx->type.Set(v->type);
  6030. }
  6031. else
  6032. ctx->type.SetVariable(v->type, v->stackOffset, false);
  6033. ctx->type.isLValue = true;
  6034. }
  6035. else
  6036. {
  6037. ctx->bc.InstrSHORT(asBC_PSF, (short)v->stackOffset);
  6038. ctx->type.SetVariable(v->type, v->stackOffset, false);
  6039. // If the variable is allocated on the heap we have a reference,
  6040. // otherwise the actual object pointer is pushed on the stack.
  6041. if( v->onHeap || v->type.IsObjectHandle() ) ctx->type.dataType.MakeReference(true);
  6042. // Implicitly dereference handle parameters sent by reference
  6043. if( v->type.IsReference() && (!v->type.IsObject() || v->type.IsObjectHandle()) )
  6044. ctx->bc.Instr(asBC_RDSPtr);
  6045. ctx->type.isLValue = true;
  6046. }
  6047. }
  6048. // Is it a class member?
  6049. // This is not accessible by default arg expressions
  6050. if( !isCompilingDefaultArg && !found && ((objType) || (outFunc && outFunc->objectType && scope == "")) )
  6051. {
  6052. if( name == THIS_TOKEN && !objType )
  6053. {
  6054. asCDataType dt = asCDataType::CreateObject(outFunc->objectType, outFunc->isReadOnly);
  6055. // The object pointer is located at stack position 0
  6056. ctx->bc.InstrSHORT(asBC_PSF, 0);
  6057. ctx->type.SetVariable(dt, 0, false);
  6058. ctx->type.dataType.MakeReference(true);
  6059. ctx->type.isLValue = true;
  6060. found = true;
  6061. }
  6062. if( !found )
  6063. {
  6064. // See if there are any matching property accessors
  6065. asSExprContext access(engine);
  6066. if( objType )
  6067. access.type.Set(asCDataType::CreateObject(objType, false));
  6068. else
  6069. access.type.Set(asCDataType::CreateObject(outFunc->objectType, outFunc->isReadOnly));
  6070. access.type.dataType.MakeReference(true);
  6071. int r = 0;
  6072. if( errNode->next && errNode->next->tokenType == ttOpenBracket )
  6073. {
  6074. // This is an index access, check if there is a property accessor that takes an index arg
  6075. asSExprContext dummyArg(engine);
  6076. r = FindPropertyAccessor(name, &access, &dummyArg, errNode, 0, true);
  6077. }
  6078. if( r == 0 )
  6079. {
  6080. // Normal property access
  6081. r = FindPropertyAccessor(name, &access, errNode, 0, true);
  6082. }
  6083. if( r < 0 ) return -1;
  6084. if( access.property_get || access.property_set )
  6085. {
  6086. if( !objType )
  6087. {
  6088. // Prepare the bytecode for the member access
  6089. // This is only done when accessing through the implicit this pointer
  6090. ctx->bc.InstrSHORT(asBC_PSF, 0);
  6091. }
  6092. MergeExprBytecodeAndType(ctx, &access);
  6093. found = true;
  6094. }
  6095. }
  6096. if( !found )
  6097. {
  6098. asCDataType dt;
  6099. if( objType )
  6100. dt = asCDataType::CreateObject(objType, false);
  6101. else
  6102. dt = asCDataType::CreateObject(outFunc->objectType, false);
  6103. asCObjectProperty *prop = builder->GetObjectProperty(dt, name.AddressOf());
  6104. if( prop )
  6105. {
  6106. if( !objType )
  6107. {
  6108. // The object pointer is located at stack position 0
  6109. // This is only done when accessing through the implicit this pointer
  6110. ctx->bc.InstrSHORT(asBC_PSF, 0);
  6111. ctx->type.SetVariable(dt, 0, false);
  6112. ctx->type.dataType.MakeReference(true);
  6113. Dereference(ctx, true);
  6114. }
  6115. // TODO: This is the same as what is in CompileExpressionPostOp
  6116. // Put the offset on the stack
  6117. ctx->bc.InstrSHORT_DW(asBC_ADDSi, (short)prop->byteOffset, engine->GetTypeIdFromDataType(dt));
  6118. if( prop->type.IsReference() )
  6119. ctx->bc.Instr(asBC_RDSPtr);
  6120. // Reference to primitive must be stored in the temp register
  6121. if( prop->type.IsPrimitive() )
  6122. {
  6123. // TODO: runtime optimize: The ADD offset command should store the reference in the register directly
  6124. ctx->bc.Instr(asBC_PopRPtr);
  6125. }
  6126. // Set the new type (keeping info about temp variable)
  6127. ctx->type.dataType = prop->type;
  6128. ctx->type.dataType.MakeReference(true);
  6129. ctx->type.isVariable = false;
  6130. ctx->type.isLValue = true;
  6131. if( ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle() )
  6132. {
  6133. // Objects that are members are not references
  6134. ctx->type.dataType.MakeReference(false);
  6135. }
  6136. // If the object reference is const, the property will also be const
  6137. ctx->type.dataType.MakeReadOnly(outFunc->isReadOnly);
  6138. found = true;
  6139. }
  6140. else if( outFunc->objectType )
  6141. {
  6142. // If it is not a property, it may still be the name of a method which can be used to create delegates
  6143. asCObjectType *ot = outFunc->objectType;
  6144. asCScriptFunction *func = 0;
  6145. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  6146. {
  6147. if( engine->scriptFunctions[ot->methods[n]]->name == name )
  6148. {
  6149. func = engine->scriptFunctions[ot->methods[n]];
  6150. break;
  6151. }
  6152. }
  6153. if( func )
  6154. {
  6155. // An object method was found. Keep the name of the method in the expression, but
  6156. // don't actually modify the bytecode at this point since it is not yet known what
  6157. // the method will be used for, or even what overloaded method should be used.
  6158. ctx->methodName = name;
  6159. // Place the object pointer on the stack, as if the expression was this.func
  6160. if( !objType )
  6161. {
  6162. // The object pointer is located at stack position 0
  6163. // This is only done when accessing through the implicit this pointer
  6164. ctx->bc.InstrSHORT(asBC_PSF, 0);
  6165. ctx->type.SetVariable(asCDataType::CreateObject(outFunc->objectType, false), 0, false);
  6166. ctx->type.dataType.MakeReference(true);
  6167. Dereference(ctx, true);
  6168. }
  6169. found = true;
  6170. }
  6171. }
  6172. }
  6173. }
  6174. // Recursively search parent namespaces for global entities
  6175. asCString currScope = scope;
  6176. if( scope == "" )
  6177. currScope = outFunc->nameSpace->name;
  6178. while( !found && !noGlobal && !objType )
  6179. {
  6180. asSNameSpace *ns = DetermineNameSpace(currScope);
  6181. // Is it a global property?
  6182. if( !found && ns )
  6183. {
  6184. // See if there are any matching global property accessors
  6185. asSExprContext access(engine);
  6186. int r = 0;
  6187. if( errNode->next && errNode->next->tokenType == ttOpenBracket )
  6188. {
  6189. // This is an index access, check if there is a property accessor that takes an index arg
  6190. asSExprContext dummyArg(engine);
  6191. r = FindPropertyAccessor(name, &access, &dummyArg, errNode, ns);
  6192. }
  6193. if( r == 0 )
  6194. {
  6195. // Normal property access
  6196. r = FindPropertyAccessor(name, &access, errNode, ns);
  6197. }
  6198. if( r < 0 ) return -1;
  6199. if( access.property_get || access.property_set )
  6200. {
  6201. // Prepare the bytecode for the function call
  6202. MergeExprBytecodeAndType(ctx, &access);
  6203. found = true;
  6204. }
  6205. // See if there is any matching global property
  6206. if( !found )
  6207. {
  6208. bool isCompiled = true;
  6209. bool isPureConstant = false;
  6210. bool isAppProp = false;
  6211. asQWORD constantValue = 0;
  6212. asCGlobalProperty *prop = builder->GetGlobalProperty(name.AddressOf(), ns, &isCompiled, &isPureConstant, &constantValue, &isAppProp);
  6213. if( prop )
  6214. {
  6215. found = true;
  6216. // Verify that the global property has been compiled already
  6217. if( isCompiled )
  6218. {
  6219. if( ctx->type.dataType.GetObjectType() && (ctx->type.dataType.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE) )
  6220. {
  6221. ctx->type.dataType.MakeHandle(true);
  6222. ctx->type.isExplicitHandle = true;
  6223. }
  6224. // If the global property is a pure constant
  6225. // we can allow the compiler to optimize it. Pure
  6226. // constants are global constant variables that were
  6227. // initialized by literal constants.
  6228. if( isPureConstant )
  6229. ctx->type.SetConstantQW(prop->type, constantValue);
  6230. else
  6231. {
  6232. // A shared type must not access global vars, unless they
  6233. // too are shared, e.g. application registered vars
  6234. if( outFunc->IsShared() )
  6235. {
  6236. if( !isAppProp )
  6237. {
  6238. asCString str;
  6239. str.Format(TXT_SHARED_CANNOT_ACCESS_NON_SHARED_VAR_s, prop->name.AddressOf());
  6240. Error(str, errNode);
  6241. // Allow the compilation to continue to catch other problems
  6242. }
  6243. }
  6244. ctx->type.Set(prop->type);
  6245. ctx->type.isLValue = true;
  6246. if( ctx->type.dataType.IsPrimitive() )
  6247. {
  6248. // Load the address of the variable into the register
  6249. ctx->bc.InstrPTR(asBC_LDG, prop->GetAddressOfValue());
  6250. ctx->type.dataType.MakeReference(true);
  6251. }
  6252. else
  6253. {
  6254. // Push the address of the variable on the stack
  6255. ctx->bc.InstrPTR(asBC_PGA, prop->GetAddressOfValue());
  6256. // If the object is a value type or a non-handle variable to a reference type,
  6257. // then we must validate the existance as it could potentially be accessed
  6258. // before it is initialized.
  6259. if( (ctx->type.dataType.GetObjectType()->flags & asOBJ_VALUE) ||
  6260. !ctx->type.dataType.IsObjectHandle() )
  6261. {
  6262. // TODO: runtime optimize: This is not necessary for application registered properties
  6263. ctx->bc.Instr(asBC_ChkRefS);
  6264. }
  6265. // If the address pushed on the stack is to a value type or an object
  6266. // handle, then mark the expression as a reference. Addresses to a reference
  6267. // type aren't marked as references to get correct behaviour
  6268. if( (ctx->type.dataType.GetObjectType()->flags & asOBJ_VALUE) ||
  6269. ctx->type.dataType.IsObjectHandle() )
  6270. {
  6271. ctx->type.dataType.MakeReference(true);
  6272. }
  6273. else
  6274. {
  6275. asASSERT( (ctx->type.dataType.GetObjectType()->flags & asOBJ_REF) && !ctx->type.dataType.IsObjectHandle() );
  6276. // It's necessary to dereference the pointer so the pointer on the stack will point to the actual object
  6277. ctx->bc.Instr(asBC_RDSPtr);
  6278. }
  6279. }
  6280. }
  6281. }
  6282. else
  6283. {
  6284. asCString str;
  6285. str.Format(TXT_UNINITIALIZED_GLOBAL_VAR_s, prop->name.AddressOf());
  6286. Error(str, errNode);
  6287. return -1;
  6288. }
  6289. }
  6290. }
  6291. }
  6292. // Is it the name of a global function?
  6293. if( !noFunction && !found && ns )
  6294. {
  6295. asCArray<int> funcs;
  6296. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  6297. if( funcs.GetLength() > 0 )
  6298. {
  6299. found = true;
  6300. // Defer the evaluation of which function until it is actually used
  6301. // Store the namespace and name of the function for later
  6302. ctx->type.SetUndefinedFuncHandle(engine);
  6303. ctx->methodName = ns ? ns->name + "::" + name : name;
  6304. }
  6305. }
  6306. // Is it an enum value?
  6307. if( !found )
  6308. {
  6309. // The enum type may be declared in a namespace too
  6310. asCObjectType *scopeType = 0;
  6311. if( currScope != "" && currScope != "::" )
  6312. {
  6313. // Use the last scope name as the enum type
  6314. asCString enumType = currScope;
  6315. asCString nsScope;
  6316. int p = currScope.FindLast("::");
  6317. if( p != -1 )
  6318. {
  6319. enumType = currScope.SubString(p+2);
  6320. nsScope = currScope.SubString(0, p);
  6321. }
  6322. asSNameSpace *ns = engine->FindNameSpace(nsScope.AddressOf());
  6323. if( ns )
  6324. scopeType = builder->GetObjectType(enumType.AddressOf(), ns);
  6325. }
  6326. asDWORD value = 0;
  6327. asCDataType dt;
  6328. if( scopeType && builder->GetEnumValueFromObjectType(scopeType, name.AddressOf(), dt, value) )
  6329. {
  6330. // scoped enum value found
  6331. found = true;
  6332. }
  6333. else if( !engine->ep.requireEnumScope )
  6334. {
  6335. // Look for the enum value without explicitly informing the enum type
  6336. asSNameSpace *ns = DetermineNameSpace(currScope);
  6337. int e = 0;
  6338. if( ns )
  6339. e = builder->GetEnumValue(name.AddressOf(), dt, value, ns);
  6340. if( e )
  6341. {
  6342. found = true;
  6343. if( e == 2 )
  6344. {
  6345. Error(TXT_FOUND_MULTIPLE_ENUM_VALUES, errNode);
  6346. }
  6347. }
  6348. }
  6349. if( found )
  6350. {
  6351. // Even if the enum type is not shared, and we're compiling a shared object,
  6352. // the use of the values are still allowed, since they are treated as constants.
  6353. // an enum value was resolved
  6354. ctx->type.SetConstantDW(dt, value);
  6355. }
  6356. else
  6357. {
  6358. // If nothing was found because the scope doesn't match a namespace or an enum
  6359. // then this should be reported as an error and the search interrupted
  6360. if( !ns && !scopeType )
  6361. {
  6362. ctx->type.SetDummy();
  6363. asCString str;
  6364. str.Format(TXT_UNKNOWN_SCOPE_s, currScope.AddressOf());
  6365. Error(str, errNode);
  6366. return -1;
  6367. }
  6368. }
  6369. }
  6370. if( !found )
  6371. {
  6372. if( currScope == "" || currScope == "::" )
  6373. break;
  6374. // Move up to parent namespace
  6375. int pos = currScope.FindLast("::");
  6376. if( pos >= 0 )
  6377. currScope = currScope.SubString(0, pos);
  6378. else
  6379. currScope = "::";
  6380. }
  6381. }
  6382. // The name doesn't match any variable
  6383. if( !found )
  6384. {
  6385. // Give dummy value
  6386. ctx->type.SetDummy();
  6387. if( !isOptional )
  6388. {
  6389. // Prepend the scope to the name for the error message
  6390. asCString ename;
  6391. if( scope != "" && scope != "::" )
  6392. ename = scope + "::";
  6393. else
  6394. ename = scope;
  6395. ename += name;
  6396. asCString str;
  6397. str.Format(TXT_s_NOT_DECLARED, ename.AddressOf());
  6398. Error(str, errNode);
  6399. // Declare the variable now so that it will not be reported again
  6400. variables->DeclareVariable(name.AddressOf(), asCDataType::CreatePrimitive(ttInt, false), 0x7FFF, true);
  6401. // Mark the variable as initialized so that the user will not be bother by it again
  6402. sVariable *v = variables->GetVariable(name.AddressOf());
  6403. asASSERT(v);
  6404. if( v ) v->isInitialized = true;
  6405. }
  6406. // Return -1 to signal that the variable wasn't found
  6407. return -1;
  6408. }
  6409. return 0;
  6410. }
  6411. int asCCompiler::CompileExpressionValue(asCScriptNode *node, asSExprContext *ctx)
  6412. {
  6413. // Shouldn't receive any byte code
  6414. asASSERT(ctx->bc.GetLastInstr() == -1);
  6415. asCScriptNode *vnode = node->firstChild;
  6416. ctx->exprNode = vnode;
  6417. if( vnode->nodeType == snVariableAccess )
  6418. {
  6419. // Determine the scope resolution of the variable
  6420. asCString scope = builder->GetScopeFromNode(vnode->firstChild, script, &vnode);
  6421. // Determine the name of the variable
  6422. asASSERT(vnode->nodeType == snIdentifier );
  6423. asCString name(&script->code[vnode->tokenPos], vnode->tokenLength);
  6424. return CompileVariableAccess(name, scope, ctx, node);
  6425. }
  6426. else if( vnode->nodeType == snConstant )
  6427. {
  6428. if( vnode->tokenType == ttIntConstant )
  6429. {
  6430. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  6431. asQWORD val = asStringScanUInt64(value.AddressOf(), 10, 0);
  6432. // Do we need 64 bits?
  6433. // If the 31st bit is set we'll treat the value as a signed 64bit number to avoid
  6434. // incorrect warnings about changing signs if the value is assigned to a 64bit variable
  6435. if( val>>31 )
  6436. {
  6437. // Only if the value uses the last bit of a 64bit word do we consider the number unsigned
  6438. if( val>>63 )
  6439. ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), val);
  6440. else
  6441. ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), val);
  6442. }
  6443. else
  6444. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), asDWORD(val));
  6445. }
  6446. else if( vnode->tokenType == ttBitsConstant )
  6447. {
  6448. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  6449. // Let the function determine the radix from the prefix 0x = 16, 0d = 10, 0o = 8, or 0b = 2
  6450. // TODO: Check for overflow
  6451. asQWORD val = asStringScanUInt64(value.AddressOf(), 0, 0);
  6452. // Do we need 64 bits?
  6453. if( val>>32 )
  6454. ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), val);
  6455. else
  6456. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), asDWORD(val));
  6457. }
  6458. else if( vnode->tokenType == ttFloatConstant )
  6459. {
  6460. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  6461. // TODO: Check for overflow
  6462. size_t numScanned;
  6463. float v = float(asStringScanDouble(value.AddressOf(), &numScanned));
  6464. ctx->type.SetConstantF(asCDataType::CreatePrimitive(ttFloat, true), v);
  6465. #ifndef AS_USE_DOUBLE_AS_FLOAT
  6466. // Don't check this if we have double as float, because then the whole token would be scanned (i.e. no f suffix)
  6467. asASSERT(numScanned == vnode->tokenLength - 1);
  6468. #endif
  6469. }
  6470. else if( vnode->tokenType == ttDoubleConstant )
  6471. {
  6472. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  6473. // TODO: Check for overflow
  6474. size_t numScanned;
  6475. double v = asStringScanDouble(value.AddressOf(), &numScanned);
  6476. ctx->type.SetConstantD(asCDataType::CreatePrimitive(ttDouble, true), v);
  6477. asASSERT(numScanned == vnode->tokenLength);
  6478. }
  6479. else if( vnode->tokenType == ttTrue ||
  6480. vnode->tokenType == ttFalse )
  6481. {
  6482. #if AS_SIZEOF_BOOL == 1
  6483. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), vnode->tokenType == ttTrue ? VALUE_OF_BOOLEAN_TRUE : 0);
  6484. #else
  6485. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), vnode->tokenType == ttTrue ? VALUE_OF_BOOLEAN_TRUE : 0);
  6486. #endif
  6487. }
  6488. else if( vnode->tokenType == ttStringConstant ||
  6489. vnode->tokenType == ttMultilineStringConstant ||
  6490. vnode->tokenType == ttHeredocStringConstant )
  6491. {
  6492. asCString str;
  6493. asCScriptNode *snode = vnode->firstChild;
  6494. if( script->code[snode->tokenPos] == '\'' && engine->ep.useCharacterLiterals )
  6495. {
  6496. // Treat the single quoted string as a single character literal
  6497. str.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2);
  6498. asDWORD val = 0;
  6499. if( str.GetLength() && (unsigned char)str[0] > 127 && engine->ep.scanner == 1 )
  6500. {
  6501. // This is the start of a UTF8 encoded character. We need to decode it
  6502. val = asStringDecodeUTF8(str.AddressOf(), 0);
  6503. if( val == (asDWORD)-1 )
  6504. Error(TXT_INVALID_CHAR_LITERAL, vnode);
  6505. }
  6506. else
  6507. {
  6508. val = ProcessStringConstant(str, snode);
  6509. if( val == (asDWORD)-1 )
  6510. Error(TXT_INVALID_CHAR_LITERAL, vnode);
  6511. }
  6512. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), val);
  6513. }
  6514. else
  6515. {
  6516. // Process the string constants
  6517. while( snode )
  6518. {
  6519. asCString cat;
  6520. if( snode->tokenType == ttStringConstant )
  6521. {
  6522. cat.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2);
  6523. ProcessStringConstant(cat, snode);
  6524. }
  6525. else if( snode->tokenType == ttMultilineStringConstant )
  6526. {
  6527. if( !engine->ep.allowMultilineStrings )
  6528. Error(TXT_MULTILINE_STRINGS_NOT_ALLOWED, snode);
  6529. cat.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2);
  6530. ProcessStringConstant(cat, snode);
  6531. }
  6532. else if( snode->tokenType == ttHeredocStringConstant )
  6533. {
  6534. cat.Assign(&script->code[snode->tokenPos+3], snode->tokenLength-6);
  6535. ProcessHeredocStringConstant(cat, snode);
  6536. }
  6537. str += cat;
  6538. snode = snode->next;
  6539. }
  6540. // Call the string factory function to create a string object
  6541. asCScriptFunction *descr = engine->stringFactory;
  6542. if( descr == 0 )
  6543. {
  6544. // Error
  6545. Error(TXT_STRINGS_NOT_RECOGNIZED, vnode);
  6546. // Give dummy value
  6547. ctx->type.SetDummy();
  6548. return -1;
  6549. }
  6550. else
  6551. {
  6552. // Register the constant string with the engine
  6553. int id = engine->AddConstantString(str.AddressOf(), str.GetLength());
  6554. ctx->bc.InstrWORD(asBC_STR, (asWORD)id);
  6555. bool useVariable = false;
  6556. int stackOffset = 0;
  6557. if( descr->DoesReturnOnStack() )
  6558. {
  6559. useVariable = true;
  6560. stackOffset = AllocateVariable(descr->returnType, true);
  6561. ctx->bc.InstrSHORT(asBC_PSF, short(stackOffset));
  6562. }
  6563. PerformFunctionCall(descr->id, ctx, false, 0, 0, useVariable, stackOffset);
  6564. }
  6565. }
  6566. }
  6567. else if( vnode->tokenType == ttNull )
  6568. {
  6569. ctx->bc.Instr(asBC_PshNull);
  6570. ctx->type.SetNullConstant();
  6571. }
  6572. else
  6573. asASSERT(false);
  6574. }
  6575. else if( vnode->nodeType == snFunctionCall )
  6576. {
  6577. // Determine the scope resolution
  6578. asCString scope = builder->GetScopeFromNode(vnode->firstChild, script);
  6579. return CompileFunctionCall(vnode, ctx, 0, false, scope);
  6580. }
  6581. else if( vnode->nodeType == snConstructCall )
  6582. {
  6583. CompileConstructCall(vnode, ctx);
  6584. }
  6585. else if( vnode->nodeType == snAssignment )
  6586. {
  6587. asSExprContext e(engine);
  6588. int r = CompileAssignment(vnode, &e);
  6589. if( r < 0 )
  6590. {
  6591. ctx->type.SetDummy();
  6592. return r;
  6593. }
  6594. MergeExprBytecodeAndType(ctx, &e);
  6595. }
  6596. else if( vnode->nodeType == snCast )
  6597. {
  6598. // Implement the cast operator
  6599. CompileConversion(vnode, ctx);
  6600. }
  6601. else if( vnode->nodeType == snUndefined && vnode->tokenType == ttVoid )
  6602. {
  6603. // This is a void expression
  6604. ctx->type.SetVoidExpression();
  6605. }
  6606. else
  6607. asASSERT(false);
  6608. return 0;
  6609. }
  6610. asUINT asCCompiler::ProcessStringConstant(asCString &cstr, asCScriptNode *node, bool processEscapeSequences)
  6611. {
  6612. int charLiteral = -1;
  6613. // Process escape sequences
  6614. asCArray<char> str((int)cstr.GetLength());
  6615. for( asUINT n = 0; n < cstr.GetLength(); n++ )
  6616. {
  6617. #ifdef AS_DOUBLEBYTE_CHARSET
  6618. // Double-byte charset is only allowed for ASCII and not UTF16 encoded strings
  6619. if( (cstr[n] & 0x80) && engine->ep.scanner == 0 && engine->ep.stringEncoding != 1 )
  6620. {
  6621. // This is the lead character of a double byte character
  6622. // include the trail character without checking it's value.
  6623. str.PushLast(cstr[n]);
  6624. n++;
  6625. str.PushLast(cstr[n]);
  6626. continue;
  6627. }
  6628. #endif
  6629. asUINT val;
  6630. if( processEscapeSequences && cstr[n] == '\\' )
  6631. {
  6632. ++n;
  6633. if( n == cstr.GetLength() )
  6634. {
  6635. if( charLiteral == -1 ) charLiteral = 0;
  6636. return charLiteral;
  6637. }
  6638. // Hexadecimal escape sequences will allow the construction of
  6639. // invalid unicode sequences, but the string should also work as
  6640. // a bytearray so we must support this. The code for working with
  6641. // unicode text must be prepared to handle invalid unicode sequences
  6642. if( cstr[n] == 'x' || cstr[n] == 'X' )
  6643. {
  6644. ++n;
  6645. if( n == cstr.GetLength() ) break;
  6646. val = 0;
  6647. int c = engine->ep.stringEncoding == 1 ? 4 : 2;
  6648. for( ; c > 0 && n < cstr.GetLength(); c--, n++ )
  6649. {
  6650. if( cstr[n] >= '0' && cstr[n] <= '9' )
  6651. val = val*16 + cstr[n] - '0';
  6652. else if( cstr[n] >= 'a' && cstr[n] <= 'f' )
  6653. val = val*16 + cstr[n] - 'a' + 10;
  6654. else if( cstr[n] >= 'A' && cstr[n] <= 'F' )
  6655. val = val*16 + cstr[n] - 'A' + 10;
  6656. else
  6657. break;
  6658. }
  6659. // Rewind one, since the loop will increment it again
  6660. n--;
  6661. // Hexadecimal escape sequences produce exact value, even if it is not proper unicode chars
  6662. if( engine->ep.stringEncoding == 0 )
  6663. {
  6664. str.PushLast((asBYTE)val);
  6665. }
  6666. else
  6667. {
  6668. #ifndef AS_BIG_ENDIAN
  6669. str.PushLast((asBYTE)val);
  6670. str.PushLast((asBYTE)(val>>8));
  6671. #else
  6672. str.PushLast((asBYTE)(val>>8));
  6673. str.PushLast((asBYTE)val);
  6674. #endif
  6675. }
  6676. if( charLiteral == -1 ) charLiteral = val;
  6677. continue;
  6678. }
  6679. else if( cstr[n] == 'u' || cstr[n] == 'U' )
  6680. {
  6681. // \u expects 4 hex digits
  6682. // \U expects 8 hex digits
  6683. bool expect2 = cstr[n] == 'u';
  6684. int c = expect2 ? 4 : 8;
  6685. val = 0;
  6686. for( ; c > 0; c-- )
  6687. {
  6688. ++n;
  6689. if( n == cstr.GetLength() ) break;
  6690. if( cstr[n] >= '0' && cstr[n] <= '9' )
  6691. val = val*16 + cstr[n] - '0';
  6692. else if( cstr[n] >= 'a' && cstr[n] <= 'f' )
  6693. val = val*16 + cstr[n] - 'a' + 10;
  6694. else if( cstr[n] >= 'A' && cstr[n] <= 'F' )
  6695. val = val*16 + cstr[n] - 'A' + 10;
  6696. else
  6697. break;
  6698. }
  6699. if( c != 0 )
  6700. {
  6701. // Give warning about invalid code point
  6702. // TODO: Need code position for warning
  6703. asCString msg;
  6704. msg.Format(TXT_INVALID_UNICODE_FORMAT_EXPECTED_d, expect2 ? 4 : 8);
  6705. Warning(msg, node);
  6706. continue;
  6707. }
  6708. }
  6709. else
  6710. {
  6711. if( cstr[n] == '"' )
  6712. val = '"';
  6713. else if( cstr[n] == '\'' )
  6714. val = '\'';
  6715. else if( cstr[n] == 'n' )
  6716. val = '\n';
  6717. else if( cstr[n] == 'r' )
  6718. val = '\r';
  6719. else if( cstr[n] == 't' )
  6720. val = '\t';
  6721. else if( cstr[n] == '0' )
  6722. val = '\0';
  6723. else if( cstr[n] == '\\' )
  6724. val = '\\';
  6725. else
  6726. {
  6727. // Invalid escape sequence
  6728. Warning(TXT_INVALID_ESCAPE_SEQUENCE, node);
  6729. continue;
  6730. }
  6731. }
  6732. }
  6733. else
  6734. {
  6735. if( engine->ep.scanner == 1 && (cstr[n] & 0x80) )
  6736. {
  6737. unsigned int len;
  6738. val = asStringDecodeUTF8(&cstr[n], &len);
  6739. if( val == 0xFFFFFFFF )
  6740. {
  6741. // Incorrect UTF8 encoding. Use only the first byte
  6742. // TODO: Need code position for warning
  6743. Warning(TXT_INVALID_UNICODE_SEQUENCE_IN_SRC, node);
  6744. val = (unsigned char)cstr[n];
  6745. }
  6746. else
  6747. n += len-1;
  6748. }
  6749. else
  6750. val = (unsigned char)cstr[n];
  6751. }
  6752. // Add the character to the final string
  6753. char encodedValue[5];
  6754. int len;
  6755. if( engine->ep.scanner == 1 && engine->ep.stringEncoding == 0 )
  6756. {
  6757. // Convert to UTF8 encoded
  6758. len = asStringEncodeUTF8(val, encodedValue);
  6759. }
  6760. else if( engine->ep.stringEncoding == 1 )
  6761. {
  6762. // Convert to 16bit wide character string (even if the script is scanned as ASCII)
  6763. len = asStringEncodeUTF16(val, encodedValue);
  6764. }
  6765. else
  6766. {
  6767. // Do not convert ASCII characters
  6768. encodedValue[0] = (asBYTE)val;
  6769. len = 1;
  6770. }
  6771. if( len < 0 )
  6772. {
  6773. // Give warning about invalid code point
  6774. // TODO: Need code position for warning
  6775. Warning(TXT_INVALID_UNICODE_VALUE, node);
  6776. }
  6777. else
  6778. {
  6779. // Add the encoded value to the final string
  6780. str.Concatenate(encodedValue, len);
  6781. if( charLiteral == -1 ) charLiteral = val;
  6782. }
  6783. }
  6784. cstr.Assign(str.AddressOf(), str.GetLength());
  6785. return charLiteral;
  6786. }
  6787. void asCCompiler::ProcessHeredocStringConstant(asCString &str, asCScriptNode *node)
  6788. {
  6789. // Remove first line if it only contains whitespace
  6790. int start;
  6791. for( start = 0; start < (int)str.GetLength(); start++ )
  6792. {
  6793. if( str[start] == '\n' )
  6794. {
  6795. // Remove the linebreak as well
  6796. start++;
  6797. break;
  6798. }
  6799. if( str[start] != ' ' &&
  6800. str[start] != '\t' &&
  6801. str[start] != '\r' )
  6802. {
  6803. // Don't remove anything
  6804. start = 0;
  6805. break;
  6806. }
  6807. }
  6808. // Remove the line after the last line break if it only contains whitespaces
  6809. int end;
  6810. for( end = (int)str.GetLength() - 1; end >= 0; end-- )
  6811. {
  6812. if( str[end] == '\n' )
  6813. {
  6814. // Don't remove the last line break
  6815. end++;
  6816. break;
  6817. }
  6818. if( str[end] != ' ' &&
  6819. str[end] != '\t' &&
  6820. str[end] != '\r' )
  6821. {
  6822. // Don't remove anything
  6823. end = (int)str.GetLength();
  6824. break;
  6825. }
  6826. }
  6827. if( end < 0 ) end = 0;
  6828. asCString tmp;
  6829. if( end > start )
  6830. tmp.Assign(&str[start], end-start);
  6831. ProcessStringConstant(tmp, node, false);
  6832. str = tmp;
  6833. }
  6834. void asCCompiler::CompileConversion(asCScriptNode *node, asSExprContext *ctx)
  6835. {
  6836. asSExprContext expr(engine);
  6837. asCDataType to;
  6838. bool anyErrors = false;
  6839. EImplicitConv convType;
  6840. if( node->nodeType == snConstructCall )
  6841. {
  6842. convType = asIC_EXPLICIT_VAL_CAST;
  6843. // Verify that there is only one argument
  6844. if( node->lastChild->firstChild == 0 ||
  6845. node->lastChild->firstChild != node->lastChild->lastChild )
  6846. {
  6847. Error(TXT_ONLY_ONE_ARGUMENT_IN_CAST, node->lastChild);
  6848. expr.type.SetDummy();
  6849. anyErrors = true;
  6850. }
  6851. else
  6852. {
  6853. // Compile the expression
  6854. int r = CompileAssignment(node->lastChild->firstChild, &expr);
  6855. if( r < 0 )
  6856. anyErrors = true;
  6857. }
  6858. // Determine the requested type
  6859. to = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace);
  6860. to.MakeReadOnly(true); // Default to const
  6861. asASSERT(to.IsPrimitive());
  6862. }
  6863. else
  6864. {
  6865. convType = asIC_EXPLICIT_REF_CAST;
  6866. // Compile the expression
  6867. int r = CompileAssignment(node->lastChild, &expr);
  6868. if( r < 0 )
  6869. anyErrors = true;
  6870. // Determine the requested type
  6871. to = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace);
  6872. to = builder->ModifyDataTypeFromNode(to, node->firstChild->next, script, 0, 0);
  6873. // If the type support object handles, then use it
  6874. if( to.SupportHandles() )
  6875. {
  6876. to.MakeHandle(true);
  6877. }
  6878. else if( !to.IsObjectHandle() )
  6879. {
  6880. // The cast<type> operator can only be used for reference casts
  6881. Error(TXT_ILLEGAL_TARGET_TYPE_FOR_REF_CAST, node->firstChild);
  6882. anyErrors = true;
  6883. }
  6884. }
  6885. // Do not allow casting to non shared type if we're compiling a shared method
  6886. if( outFunc->IsShared() &&
  6887. to.GetObjectType() && !to.GetObjectType()->IsShared() )
  6888. {
  6889. asCString msg;
  6890. msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, to.GetObjectType()->name.AddressOf());
  6891. Error(msg, node);
  6892. anyErrors = true;
  6893. }
  6894. if( anyErrors )
  6895. {
  6896. // Assume that the error can be fixed and allow the compilation to continue
  6897. ctx->type.SetConstantDW(to, 0);
  6898. return;
  6899. }
  6900. ProcessPropertyGetAccessor(&expr, node);
  6901. // Don't allow any operators on expressions that take address of class method
  6902. if( expr.IsClassMethod() )
  6903. {
  6904. Error(TXT_INVALID_OP_ON_METHOD, node);
  6905. return;
  6906. }
  6907. // We don't want a reference for conversion casts
  6908. if( convType == asIC_EXPLICIT_VAL_CAST && expr.type.dataType.IsReference() )
  6909. {
  6910. if( expr.type.dataType.IsObject() )
  6911. Dereference(&expr, true);
  6912. else
  6913. ConvertToVariable(&expr);
  6914. }
  6915. ImplicitConversion(&expr, to, node, convType);
  6916. IsVariableInitialized(&expr.type, node);
  6917. // If no type conversion is really tried ignore it
  6918. if( to == expr.type.dataType )
  6919. {
  6920. // This will keep information about constant type
  6921. MergeExprBytecode(ctx, &expr);
  6922. ctx->type = expr.type;
  6923. return;
  6924. }
  6925. if( to.IsEqualExceptConst(expr.type.dataType) && to.IsPrimitive() )
  6926. {
  6927. MergeExprBytecode(ctx, &expr);
  6928. ctx->type = expr.type;
  6929. ctx->type.dataType.MakeReadOnly(true);
  6930. return;
  6931. }
  6932. // The implicit conversion already does most of the conversions permitted,
  6933. // here we'll only treat those conversions that require an explicit cast.
  6934. bool conversionOK = false;
  6935. if( !expr.type.isConstant && expr.type.dataType != asCDataType::CreatePrimitive(ttVoid, false) )
  6936. {
  6937. if( !expr.type.dataType.IsObject() )
  6938. ConvertToTempVariable(&expr);
  6939. if( to.IsObjectHandle() &&
  6940. expr.type.dataType.IsObjectHandle() &&
  6941. !(!to.IsHandleToConst() && expr.type.dataType.IsHandleToConst()) )
  6942. {
  6943. conversionOK = CompileRefCast(&expr, to, true, node);
  6944. MergeExprBytecode(ctx, &expr);
  6945. ctx->type = expr.type;
  6946. }
  6947. }
  6948. if( conversionOK )
  6949. return;
  6950. // Conversion not available
  6951. ctx->type.SetDummy();
  6952. asCString strTo, strFrom;
  6953. strTo = to.Format();
  6954. strFrom = expr.type.dataType.Format();
  6955. asCString msg;
  6956. msg.Format(TXT_NO_CONVERSION_s_TO_s, strFrom.AddressOf(), strTo.AddressOf());
  6957. Error(msg, node);
  6958. }
  6959. void asCCompiler::AfterFunctionCall(int funcID, asCArray<asSExprContext*> &args, asSExprContext *ctx, bool deferAll)
  6960. {
  6961. asCScriptFunction *descr = builder->GetFunctionDescription(funcID);
  6962. // Parameters that are sent by reference should be assigned
  6963. // to the evaluated expression if it is an lvalue
  6964. // Evaluate the arguments from last to first
  6965. int n = (int)descr->parameterTypes.GetLength() - 1;
  6966. for( ; n >= 0; n-- )
  6967. {
  6968. if( (descr->parameterTypes[n].IsReference() && (descr->inOutFlags[n] & asTM_OUTREF)) ||
  6969. (descr->parameterTypes[n].IsObject() && deferAll) )
  6970. {
  6971. asASSERT( !(descr->parameterTypes[n].IsReference() && (descr->inOutFlags[n] == asTM_OUTREF)) || args[n]->origExpr );
  6972. // For &inout, only store the argument if it is for a temporary variable
  6973. if( engine->ep.allowUnsafeReferences ||
  6974. descr->inOutFlags[n] != asTM_INOUTREF || args[n]->type.isTemporary )
  6975. {
  6976. // Store the argument for later processing
  6977. asSDeferredParam outParam;
  6978. outParam.argNode = args[n]->exprNode;
  6979. outParam.argType = args[n]->type;
  6980. outParam.argInOutFlags = descr->inOutFlags[n];
  6981. outParam.origExpr = args[n]->origExpr;
  6982. ctx->deferredParams.PushLast(outParam);
  6983. }
  6984. }
  6985. else
  6986. {
  6987. // Release the temporary variable now
  6988. ReleaseTemporaryVariable(args[n]->type, &ctx->bc);
  6989. }
  6990. // Move the argument's deferred expressions over to the final expression
  6991. for( asUINT m = 0; m < args[n]->deferredParams.GetLength(); m++ )
  6992. {
  6993. ctx->deferredParams.PushLast(args[n]->deferredParams[m]);
  6994. args[n]->deferredParams[m].origExpr = 0;
  6995. }
  6996. args[n]->deferredParams.SetLength(0);
  6997. }
  6998. }
  6999. void asCCompiler::ProcessDeferredParams(asSExprContext *ctx)
  7000. {
  7001. if( isProcessingDeferredParams ) return;
  7002. isProcessingDeferredParams = true;
  7003. for( asUINT n = 0; n < ctx->deferredParams.GetLength(); n++ )
  7004. {
  7005. asSDeferredParam outParam = ctx->deferredParams[n];
  7006. if( outParam.argInOutFlags < asTM_OUTREF ) // &in, or not reference
  7007. {
  7008. // Just release the variable
  7009. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  7010. }
  7011. else if( outParam.argInOutFlags == asTM_OUTREF )
  7012. {
  7013. asSExprContext *expr = outParam.origExpr;
  7014. outParam.origExpr = 0;
  7015. if( outParam.argType.dataType.IsObjectHandle() )
  7016. {
  7017. // Implicitly convert the value to a handle
  7018. if( expr->type.dataType.IsObjectHandle() )
  7019. expr->type.isExplicitHandle = true;
  7020. }
  7021. // Verify that the expression result in a lvalue, or a property accessor
  7022. if( IsLValue(expr->type) || expr->property_get || expr->property_set )
  7023. {
  7024. asSExprContext rctx(engine);
  7025. rctx.type = outParam.argType;
  7026. if( rctx.type.dataType.IsPrimitive() )
  7027. rctx.type.dataType.MakeReference(false);
  7028. else
  7029. {
  7030. rctx.bc.InstrSHORT(asBC_PSF, outParam.argType.stackOffset);
  7031. rctx.type.dataType.MakeReference(IsVariableOnHeap(outParam.argType.stackOffset));
  7032. if( expr->type.isExplicitHandle )
  7033. rctx.type.isExplicitHandle = true;
  7034. }
  7035. asSExprContext o(engine);
  7036. DoAssignment(&o, expr, &rctx, outParam.argNode, outParam.argNode, ttAssignment, outParam.argNode);
  7037. if( !o.type.dataType.IsPrimitive() ) o.bc.Instr(asBC_PopPtr);
  7038. // The assignment may itself have resulted in a new temporary variable, e.g. if
  7039. // the opAssign returns a non-reference. We must release this temporary variable
  7040. // since it won't be used
  7041. ReleaseTemporaryVariable(o.type, &o.bc);
  7042. MergeExprBytecode(ctx, &o);
  7043. }
  7044. else
  7045. {
  7046. // We must still evaluate the expression
  7047. MergeExprBytecode(ctx, expr);
  7048. if( !expr->type.IsVoidExpression() && (!expr->type.isConstant || expr->type.IsNullConstant()) )
  7049. ctx->bc.Instr(asBC_PopPtr);
  7050. // Give a warning, except if the argument is void, null or 0 which indicate the argument is really to be ignored
  7051. if( !expr->type.IsVoidExpression() && !expr->type.IsNullConstant() && !(expr->type.isConstant && expr->type.qwordValue == 0) )
  7052. Warning(TXT_ARG_NOT_LVALUE, outParam.argNode);
  7053. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  7054. }
  7055. ReleaseTemporaryVariable(expr->type, &ctx->bc);
  7056. // Delete the original expression context
  7057. asDELETE(expr,asSExprContext);
  7058. }
  7059. else // &inout
  7060. {
  7061. if( outParam.argType.isTemporary )
  7062. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  7063. else if( !outParam.argType.isVariable )
  7064. {
  7065. if( outParam.argType.dataType.IsObject() &&
  7066. ((outParam.argType.dataType.GetBehaviour()->addref &&
  7067. outParam.argType.dataType.GetBehaviour()->release) ||
  7068. (outParam.argType.dataType.GetObjectType()->flags & asOBJ_NOCOUNT)) )
  7069. {
  7070. // Release the object handle that was taken to guarantee the reference
  7071. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  7072. }
  7073. }
  7074. }
  7075. }
  7076. ctx->deferredParams.SetLength(0);
  7077. isProcessingDeferredParams = false;
  7078. }
  7079. void asCCompiler::CompileConstructCall(asCScriptNode *node, asSExprContext *ctx)
  7080. {
  7081. // The first node is a datatype node
  7082. asCString name;
  7083. asCTypeInfo tempObj;
  7084. bool onHeap = true;
  7085. asCArray<int> funcs;
  7086. // It is possible that the name is really a constructor
  7087. asCDataType dt;
  7088. dt = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace);
  7089. if( dt.IsPrimitive() )
  7090. {
  7091. // This is a cast to a primitive type
  7092. CompileConversion(node, ctx);
  7093. return;
  7094. }
  7095. // Do not allow constructing non-shared types in shared functions
  7096. if( outFunc->IsShared() &&
  7097. dt.GetObjectType() && !dt.GetObjectType()->IsShared() )
  7098. {
  7099. asCString msg;
  7100. msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, dt.GetObjectType()->name.AddressOf());
  7101. Error(msg, node);
  7102. }
  7103. // Compile the arguments
  7104. asCArray<asSExprContext *> args;
  7105. asCArray<asCTypeInfo> temporaryVariables;
  7106. if( CompileArgumentList(node->lastChild, args) >= 0 )
  7107. {
  7108. // Check for a value cast behaviour
  7109. if( args.GetLength() == 1 && args[0]->type.dataType.GetObjectType() )
  7110. {
  7111. asSExprContext conv(engine);
  7112. conv.type = args[0]->type;
  7113. ImplicitConversion(&conv, dt, node->lastChild, asIC_EXPLICIT_VAL_CAST, false);
  7114. if( conv.type.dataType.IsEqualExceptRef(dt) )
  7115. {
  7116. ImplicitConversion(args[0], dt, node->lastChild, asIC_EXPLICIT_VAL_CAST);
  7117. ctx->bc.AddCode(&args[0]->bc);
  7118. ctx->type = args[0]->type;
  7119. asDELETE(args[0],asSExprContext);
  7120. return;
  7121. }
  7122. }
  7123. // Check for possible constructor/factory
  7124. name = dt.Format();
  7125. asSTypeBehaviour *beh = dt.GetBehaviour();
  7126. if( !(dt.GetObjectType()->flags & asOBJ_REF) )
  7127. {
  7128. funcs = beh->constructors;
  7129. // Value types and script types are allocated through the constructor
  7130. tempObj.dataType = dt;
  7131. tempObj.stackOffset = (short)AllocateVariable(dt, true);
  7132. tempObj.dataType.MakeReference(true);
  7133. tempObj.isTemporary = true;
  7134. tempObj.isVariable = true;
  7135. onHeap = IsVariableOnHeap(tempObj.stackOffset);
  7136. // Push the address of the object on the stack
  7137. if( onHeap )
  7138. ctx->bc.InstrSHORT(asBC_VAR, tempObj.stackOffset);
  7139. }
  7140. else
  7141. {
  7142. funcs = beh->factories;
  7143. }
  7144. // Special case: Allow calling func(void) with a void expression.
  7145. if( args.GetLength() == 1 && args[0]->type.dataType == asCDataType::CreatePrimitive(ttVoid, false) )
  7146. {
  7147. // Evaluate the expression before the function call
  7148. MergeExprBytecode(ctx, args[0]);
  7149. asDELETE(args[0],asSExprContext);
  7150. args.SetLength(0);
  7151. }
  7152. // Special case: If this is an object constructor and there are no arguments use the default constructor.
  7153. // If none has been registered, just allocate the variable and push it on the stack.
  7154. if( args.GetLength() == 0 )
  7155. {
  7156. asSTypeBehaviour *beh = tempObj.dataType.GetBehaviour();
  7157. if( beh && beh->construct == 0 && !(dt.GetObjectType()->flags & asOBJ_REF) )
  7158. {
  7159. // Call the default constructor
  7160. ctx->type = tempObj;
  7161. if( onHeap )
  7162. {
  7163. asASSERT(ctx->bc.GetLastInstr() == asBC_VAR);
  7164. ctx->bc.RemoveLastInstr();
  7165. }
  7166. CallDefaultConstructor(tempObj.dataType, tempObj.stackOffset, IsVariableOnHeap(tempObj.stackOffset), &ctx->bc, node);
  7167. // Push the reference on the stack
  7168. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  7169. return;
  7170. }
  7171. }
  7172. // Special case: If this is a construction of a delegate and the expression names an object method
  7173. if( dt.GetFuncDef() && args.GetLength() == 1 && args[0]->methodName != "" )
  7174. {
  7175. // TODO: delegate: It is possible that the argument returns a function pointer already, in which
  7176. // case no object delegate will be created, but instead a delegate for a function pointer
  7177. // In theory a simple cast would be good in this case, but this is a construct call so it
  7178. // is expected that a new object is created.
  7179. dt.MakeHandle(true);
  7180. ctx->type.Set(dt);
  7181. // The delegate must be able to hold on to a reference to the object
  7182. if( !args[0]->type.dataType.SupportHandles() )
  7183. Error(TXT_CANNOT_CREATE_DELEGATE_FOR_NOREF_TYPES, node);
  7184. else
  7185. {
  7186. // Filter the available object methods to find the one that matches the func def
  7187. asCObjectType *type = args[0]->type.dataType.GetObjectType();
  7188. asCScriptFunction *bestMethod = 0;
  7189. for( asUINT n = 0; n < type->methods.GetLength(); n++ )
  7190. {
  7191. asCScriptFunction *func = engine->scriptFunctions[type->methods[n]];
  7192. if( func->name != args[0]->methodName )
  7193. continue;
  7194. // If the expression is for a const object, then only const methods should be accepted
  7195. if( args[0]->type.dataType.IsReadOnly() && !func->IsReadOnly() )
  7196. continue;
  7197. if( func->IsSignatureExceptNameAndObjectTypeEqual(dt.GetFuncDef()) )
  7198. {
  7199. bestMethod = func;
  7200. // If the expression is non-const the non-const overloaded method has priority
  7201. if( args[0]->type.dataType.IsReadOnly() == func->IsReadOnly() )
  7202. break;
  7203. }
  7204. }
  7205. if( bestMethod )
  7206. {
  7207. // The object pointer is already on the stack
  7208. MergeExprBytecode(ctx, args[0]);
  7209. // Push the function pointer as an additional argument
  7210. ctx->bc.InstrPTR(asBC_FuncPtr, bestMethod);
  7211. // Call the factory function for the delegate
  7212. asCArray<int> funcs;
  7213. builder->GetFunctionDescriptions(DELEGATE_FACTORY, funcs, engine->nameSpaces[0]);
  7214. asASSERT( funcs.GetLength() == 1 );
  7215. ctx->bc.Call(asBC_CALLSYS , funcs[0], 2*AS_PTR_SIZE);
  7216. // Store the returned delegate in a temporary variable
  7217. int returnOffset = AllocateVariable(dt, true, false);
  7218. dt.MakeReference(true);
  7219. ctx->type.SetVariable(dt, returnOffset, true);
  7220. ctx->bc.InstrSHORT(asBC_STOREOBJ, (short)returnOffset);
  7221. // Push a reference to the temporary variable on the stack
  7222. ctx->bc.InstrSHORT(asBC_PSF, (short)returnOffset);
  7223. }
  7224. else
  7225. {
  7226. asCString msg;
  7227. msg.Format(TXT_NO_MATCHING_SIGNATURES_TO_s, dt.GetFuncDef()->GetDeclaration());
  7228. Error(msg.AddressOf(), node);
  7229. }
  7230. }
  7231. // Clean-up arg
  7232. asDELETE(args[0],asSExprContext);
  7233. return;
  7234. }
  7235. MatchFunctions(funcs, args, node, name.AddressOf(), NULL, false);
  7236. if( funcs.GetLength() != 1 )
  7237. {
  7238. // The error was reported by MatchFunctions()
  7239. // Dummy value
  7240. ctx->type.SetDummy();
  7241. }
  7242. else
  7243. {
  7244. int r = asSUCCESS;
  7245. // Add the default values for arguments not explicitly supplied
  7246. asCScriptFunction *func = (funcs[0] & FUNC_IMPORTED) == 0 ? engine->scriptFunctions[funcs[0]] : 0;
  7247. if( func && args.GetLength() < (asUINT)func->GetParamCount() )
  7248. r = CompileDefaultArgs(node, args, func);
  7249. if( r == asSUCCESS )
  7250. {
  7251. asCByteCode objBC(engine);
  7252. PrepareFunctionCall(funcs[0], &ctx->bc, args);
  7253. MoveArgsToStack(funcs[0], &ctx->bc, args, false);
  7254. if( !(dt.GetObjectType()->flags & asOBJ_REF) )
  7255. {
  7256. // If the object is allocated on the stack, then call the constructor as a normal function
  7257. if( onHeap )
  7258. {
  7259. int offset = 0;
  7260. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]);
  7261. for( asUINT n = 0; n < args.GetLength(); n++ )
  7262. offset += descr->parameterTypes[n].GetSizeOnStackDWords();
  7263. ctx->bc.InstrWORD(asBC_GETREF, (asWORD)offset);
  7264. }
  7265. else
  7266. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  7267. PerformFunctionCall(funcs[0], ctx, onHeap, &args, tempObj.dataType.GetObjectType());
  7268. // Add tag that the object has been initialized
  7269. ctx->bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT);
  7270. // The constructor doesn't return anything,
  7271. // so we have to manually inform the type of
  7272. // the return value
  7273. ctx->type = tempObj;
  7274. if( !onHeap )
  7275. ctx->type.dataType.MakeReference(false);
  7276. // Push the address of the object on the stack again
  7277. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  7278. }
  7279. else
  7280. {
  7281. // Call the factory to create the reference type
  7282. PerformFunctionCall(funcs[0], ctx, false, &args);
  7283. }
  7284. }
  7285. }
  7286. }
  7287. else
  7288. {
  7289. // Failed to compile the argument list, set the result to the dummy type
  7290. ctx->type.SetDummy();
  7291. }
  7292. // Cleanup
  7293. for( asUINT n = 0; n < args.GetLength(); n++ )
  7294. if( args[n] )
  7295. {
  7296. asDELETE(args[n],asSExprContext);
  7297. }
  7298. }
  7299. int asCCompiler::CompileFunctionCall(asCScriptNode *node, asSExprContext *ctx, asCObjectType *objectType, bool objIsConst, const asCString &scope)
  7300. {
  7301. asCString name;
  7302. asCTypeInfo tempObj;
  7303. asCArray<int> funcs;
  7304. int localVar = -1;
  7305. bool initializeMembers = false;
  7306. asCScriptNode *nm = node->lastChild->prev;
  7307. name.Assign(&script->code[nm->tokenPos], nm->tokenLength);
  7308. // First check for a local variable of a function type as it would take precedence
  7309. // Must not allow function names, nor global variables to be returned in this instance
  7310. // If objectType is set then this is a post op expression and we shouldn't look for local variables
  7311. asSExprContext funcPtr(engine);
  7312. if( objectType == 0 )
  7313. {
  7314. localVar = CompileVariableAccess(name, scope, &funcPtr, node, true, true, true);
  7315. if( localVar >= 0 && !funcPtr.type.dataType.GetFuncDef() && funcPtr.methodName == "" )
  7316. {
  7317. // The variable is not a function
  7318. asCString msg;
  7319. msg.Format(TXT_NOT_A_FUNC_s_IS_VAR, name.AddressOf());
  7320. Error(msg, node);
  7321. return -1;
  7322. }
  7323. // If the name matches a method name, then reset the indicator that nothing was found
  7324. if( funcPtr.methodName != "" )
  7325. localVar = -1;
  7326. }
  7327. if( localVar < 0 )
  7328. {
  7329. // If this is an expression post op, or if a class method is
  7330. // being compiled, then we should look for matching class methods
  7331. if( objectType || (outFunc && outFunc->objectType && scope != "::") )
  7332. {
  7333. // If we're compiling a constructor and the name of the function is super then
  7334. // the constructor of the base class is being called.
  7335. // super cannot be prefixed with a scope operator
  7336. if( scope == "" && m_isConstructor && name == SUPER_TOKEN )
  7337. {
  7338. // If the class is not derived from anyone else, calling super should give an error
  7339. if( outFunc && outFunc->objectType->derivedFrom )
  7340. funcs = outFunc->objectType->derivedFrom->beh.constructors;
  7341. // Must not allow calling base class' constructor multiple times
  7342. if( continueLabels.GetLength() > 0 )
  7343. {
  7344. // If a continue label is set we are in a loop
  7345. Error(TXT_CANNOT_CALL_CONSTRUCTOR_IN_LOOPS, node);
  7346. }
  7347. else if( breakLabels.GetLength() > 0 )
  7348. {
  7349. // TODO: inheritance: Should eventually allow constructors in switch statements
  7350. // If a break label is set we are either in a loop or a switch statements
  7351. Error(TXT_CANNOT_CALL_CONSTRUCTOR_IN_SWITCH, node);
  7352. }
  7353. else if( m_isConstructorCalled )
  7354. {
  7355. Error(TXT_CANNOT_CALL_CONSTRUCTOR_TWICE, node);
  7356. }
  7357. m_isConstructorCalled = true;
  7358. // We need to initialize the class members, but only after all the deferred arguments have been completed
  7359. initializeMembers = true;
  7360. }
  7361. else
  7362. {
  7363. // The scope is can be used to specify the base class
  7364. builder->GetObjectMethodDescriptions(name.AddressOf(), objectType ? objectType : outFunc->objectType, funcs, objIsConst, scope);
  7365. }
  7366. // It is still possible that there is a class member of a function type
  7367. if( funcs.GetLength() == 0 )
  7368. {
  7369. int r = CompileVariableAccess(name, scope, &funcPtr, node, true, true, true, objectType);
  7370. if( r >= 0 && !funcPtr.type.dataType.GetFuncDef() && funcPtr.methodName == "" )
  7371. {
  7372. // The variable is not a function
  7373. asCString msg;
  7374. msg.Format(TXT_NOT_A_FUNC_s_IS_VAR, name.AddressOf());
  7375. Error(msg, node);
  7376. return -1;
  7377. }
  7378. }
  7379. // If a class method is being called implicitly, then add the this pointer for the call
  7380. if( funcs.GetLength() && !objectType )
  7381. {
  7382. objectType = outFunc->objectType;
  7383. asCDataType dt = asCDataType::CreateObject(objectType, false);
  7384. // The object pointer is located at stack position 0
  7385. ctx->bc.InstrSHORT(asBC_PSF, 0);
  7386. ctx->type.SetVariable(dt, 0, false);
  7387. ctx->type.dataType.MakeReference(true);
  7388. Dereference(ctx, true);
  7389. }
  7390. }
  7391. // If it is not a class method or member function pointer,
  7392. // then look for global functions or global function pointers,
  7393. // unless this is an expression post op, incase only member
  7394. // functions are expected
  7395. if( objectType == 0 && funcs.GetLength() == 0 && funcPtr.type.dataType.GetFuncDef() == 0 )
  7396. {
  7397. // The scope is used to define the namespace
  7398. asSNameSpace *ns = DetermineNameSpace(scope);
  7399. if( ns )
  7400. {
  7401. // Search recursively in parent namespaces
  7402. while( ns && funcs.GetLength() == 0 && funcPtr.type.dataType.GetFuncDef() == 0 )
  7403. {
  7404. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  7405. if( funcs.GetLength() == 0 )
  7406. {
  7407. int r = CompileVariableAccess(name, scope, &funcPtr, node, true, true);
  7408. if( r >= 0 && !funcPtr.type.dataType.GetFuncDef() )
  7409. {
  7410. // The variable is not a function
  7411. asCString msg;
  7412. msg.Format(TXT_NOT_A_FUNC_s_IS_VAR, name.AddressOf());
  7413. Error(msg, node);
  7414. return -1;
  7415. }
  7416. }
  7417. ns = builder->GetParentNameSpace(ns);
  7418. }
  7419. }
  7420. else
  7421. {
  7422. asCString msg;
  7423. msg.Format(TXT_NAMESPACE_s_DOESNT_EXIST, scope.AddressOf());
  7424. Error(msg, node);
  7425. return -1;
  7426. }
  7427. }
  7428. }
  7429. if( funcs.GetLength() == 0 && funcPtr.type.dataType.GetFuncDef() )
  7430. {
  7431. funcs.PushLast(funcPtr.type.dataType.GetFuncDef()->id);
  7432. }
  7433. // Compile the arguments
  7434. asCArray<asSExprContext *> args;
  7435. asCArray<asCTypeInfo> temporaryVariables;
  7436. if( CompileArgumentList(node->lastChild, args) >= 0 )
  7437. {
  7438. // Special case: Allow calling func(void) with an expression that evaluates to no datatype, but isn't exactly 'void'
  7439. if( args.GetLength() == 1 && args[0]->type.dataType == asCDataType::CreatePrimitive(ttVoid, false) && !args[0]->type.IsVoidExpression() )
  7440. {
  7441. // Evaluate the expression before the function call
  7442. MergeExprBytecode(ctx, args[0]);
  7443. asDELETE(args[0],asSExprContext);
  7444. args.SetLength(0);
  7445. }
  7446. MatchFunctions(funcs, args, node, name.AddressOf(), objectType, objIsConst, false, true, scope);
  7447. if( funcs.GetLength() != 1 )
  7448. {
  7449. // The error was reported by MatchFunctions()
  7450. // Dummy value
  7451. ctx->type.SetDummy();
  7452. }
  7453. else
  7454. {
  7455. int r = asSUCCESS;
  7456. // Add the default values for arguments not explicitly supplied
  7457. asCScriptFunction *func = builder->GetFunctionDescription(funcs[0]);
  7458. if( func && args.GetLength() < (asUINT)func->GetParamCount() )
  7459. r = CompileDefaultArgs(node, args, func);
  7460. // TODO: funcdef: Do we have to make sure the handle is stored in a temporary variable, or
  7461. // is it enough to make sure it is in a local variable?
  7462. // For function pointer we must guarantee that the function is safe, i.e.
  7463. // by first storing the function pointer in a local variable (if it isn't already in one)
  7464. if( r == asSUCCESS )
  7465. {
  7466. if( func->funcType == asFUNC_FUNCDEF )
  7467. {
  7468. if( objectType && funcPtr.property_get <= 0 )
  7469. {
  7470. Dereference(ctx, true); // Dereference the object pointer to access the member
  7471. // The actual function should be called as if a global function
  7472. objectType = 0;
  7473. }
  7474. if( funcPtr.property_get > 0 )
  7475. {
  7476. ProcessPropertyGetAccessor(&funcPtr, node);
  7477. Dereference(&funcPtr, true);
  7478. // The function call will be made directly from the local variable so the function pointer shouldn't be on the stack
  7479. funcPtr.bc.Instr(asBC_PopPtr);
  7480. }
  7481. else
  7482. {
  7483. Dereference(&funcPtr, true);
  7484. ConvertToVariable(&funcPtr);
  7485. // The function call will be made directly from the local variable so the function pointer shouldn't be on the stack
  7486. if( !funcPtr.type.isTemporary )
  7487. funcPtr.bc.Instr(asBC_PopPtr);
  7488. }
  7489. MergeExprBytecodeAndType(ctx, &funcPtr);
  7490. }
  7491. MakeFunctionCall(ctx, funcs[0], objectType, args, node, false, 0, funcPtr.type.stackOffset);
  7492. // If the function pointer was copied to a local variable for the call, then
  7493. // release it again (temporary local variable)
  7494. if( (funcs[0] & FUNC_IMPORTED) == 0 && engine->scriptFunctions[funcs[0]]->funcType == asFUNC_FUNCDEF )
  7495. {
  7496. ReleaseTemporaryVariable(funcPtr.type, &ctx->bc);
  7497. }
  7498. }
  7499. }
  7500. }
  7501. else
  7502. {
  7503. // Failed to compile the argument list, set the dummy type and continue compilation
  7504. ctx->type.SetDummy();
  7505. }
  7506. // Cleanup
  7507. for( asUINT n = 0; n < args.GetLength(); n++ )
  7508. if( args[n] )
  7509. {
  7510. asDELETE(args[n],asSExprContext);
  7511. }
  7512. if( initializeMembers )
  7513. {
  7514. asASSERT( m_isConstructor );
  7515. // Need to initialize members here, as they may use the properties of the base class
  7516. // If there are multiple paths that call super(), then there will also be multiple
  7517. // locations with initializations of the members. It is not possible to consolidate
  7518. // these in one place, as the expressions for the initialization are evaluated where
  7519. // they are compiled, which means that they may access different variables depending
  7520. // on the scope where super() is called.
  7521. // Members that don't have an explicit initialization expression will be initialized
  7522. // beginning of the constructor as they are guaranteed not to use at the any
  7523. // members of the base class.
  7524. CompileMemberInitialization(&ctx->bc, false);
  7525. }
  7526. return 0;
  7527. }
  7528. asSNameSpace *asCCompiler::DetermineNameSpace(const asCString &scope)
  7529. {
  7530. asSNameSpace *ns;
  7531. if( scope == "" )
  7532. {
  7533. if( outFunc->nameSpace->name != "" )
  7534. ns = outFunc->nameSpace;
  7535. else if( outFunc->objectType && outFunc->objectType->nameSpace->name != "" )
  7536. ns = outFunc->objectType->nameSpace;
  7537. else
  7538. ns = engine->nameSpaces[0];
  7539. }
  7540. else if( scope == "::" )
  7541. ns = engine->nameSpaces[0];
  7542. else
  7543. ns = engine->FindNameSpace(scope.AddressOf());
  7544. return ns;
  7545. }
  7546. int asCCompiler::CompileExpressionPreOp(asCScriptNode *node, asSExprContext *ctx)
  7547. {
  7548. int op = node->tokenType;
  7549. // Don't allow any prefix operators except handle on expressions that take address of class method
  7550. if( ctx->IsClassMethod() && op != ttHandle )
  7551. {
  7552. Error(TXT_INVALID_OP_ON_METHOD, node);
  7553. return -1;
  7554. }
  7555. // Don't allow any operators on void expressions
  7556. if( ctx->type.IsVoidExpression() )
  7557. {
  7558. Error(TXT_VOID_CANT_BE_OPERAND, node);
  7559. return -1;
  7560. }
  7561. IsVariableInitialized(&ctx->type, node);
  7562. if( op == ttHandle )
  7563. {
  7564. if( ctx->methodName != "" )
  7565. {
  7566. // Don't allow taking the handle of a handle
  7567. if( ctx->type.isExplicitHandle )
  7568. {
  7569. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node);
  7570. return -1;
  7571. }
  7572. }
  7573. else
  7574. {
  7575. // Don't allow taking handle of a handle, i.e. @@
  7576. if( ctx->type.isExplicitHandle )
  7577. {
  7578. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node);
  7579. return -1;
  7580. }
  7581. // @null is allowed even though it is implicit
  7582. if( !ctx->type.IsNullConstant() )
  7583. {
  7584. // Verify that the type allow its handle to be taken
  7585. if( !ctx->type.dataType.IsObject() ||
  7586. !(((ctx->type.dataType.GetObjectType()->beh.addref && ctx->type.dataType.GetObjectType()->beh.release) || (ctx->type.dataType.GetObjectType()->flags & asOBJ_NOCOUNT)) ||
  7587. (ctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE)) )
  7588. {
  7589. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node);
  7590. return -1;
  7591. }
  7592. // Objects that are not local variables are not references
  7593. // Objects allocated on the stack are also not marked as references
  7594. if( !ctx->type.dataType.IsReference() &&
  7595. !(ctx->type.dataType.IsObject() && !ctx->type.isVariable) &&
  7596. !(ctx->type.isVariable && !IsVariableOnHeap(ctx->type.stackOffset)) )
  7597. {
  7598. Error(TXT_NOT_VALID_REFERENCE, node);
  7599. return -1;
  7600. }
  7601. // Convert the expression to a handle
  7602. if( !ctx->type.dataType.IsObjectHandle() && !(ctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE) )
  7603. {
  7604. asCDataType to = ctx->type.dataType;
  7605. to.MakeHandle(true);
  7606. to.MakeReference(true);
  7607. to.MakeHandleToConst(ctx->type.dataType.IsReadOnly());
  7608. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV, true, false);
  7609. asASSERT( ctx->type.dataType.IsObjectHandle() );
  7610. }
  7611. else if( ctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE )
  7612. {
  7613. // For the ASHANDLE type we'll simply set the expression as a handle
  7614. ctx->type.dataType.MakeHandle(true);
  7615. }
  7616. }
  7617. }
  7618. // Mark the expression as an explicit handle to avoid implicit conversions to non-handle expressions
  7619. ctx->type.isExplicitHandle = true;
  7620. }
  7621. else if( (op == ttMinus || op == ttPlus || op == ttBitNot || op == ttInc || op == ttDec) && ctx->type.dataType.IsObject() )
  7622. {
  7623. // Look for the appropriate method
  7624. // There is no overloadable operator for unary plus
  7625. const char *opName = 0;
  7626. switch( op )
  7627. {
  7628. case ttMinus: opName = "opNeg"; break;
  7629. case ttBitNot: opName = "opCom"; break;
  7630. case ttInc: opName = "opPreInc"; break;
  7631. case ttDec: opName = "opPreDec"; break;
  7632. }
  7633. if( opName )
  7634. {
  7635. // TODO: Should convert this to something similar to CompileOverloadedDualOperator2
  7636. ProcessPropertyGetAccessor(ctx, node);
  7637. // Is it a const value?
  7638. bool isConst = false;
  7639. if( ctx->type.dataType.IsObjectHandle() )
  7640. isConst = ctx->type.dataType.IsHandleToConst();
  7641. else
  7642. isConst = ctx->type.dataType.IsReadOnly();
  7643. // 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
  7644. // Find the correct method
  7645. asCArray<int> funcs;
  7646. asCObjectType *ot = ctx->type.dataType.GetObjectType();
  7647. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  7648. {
  7649. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  7650. if( func->name == opName &&
  7651. func->parameterTypes.GetLength() == 0 &&
  7652. (!isConst || func->isReadOnly) )
  7653. {
  7654. funcs.PushLast(func->id);
  7655. }
  7656. }
  7657. // Did we find the method?
  7658. if( funcs.GetLength() == 1 )
  7659. {
  7660. asCTypeInfo objType = ctx->type;
  7661. asCArray<asSExprContext *> args;
  7662. MakeFunctionCall(ctx, funcs[0], objType.dataType.GetObjectType(), args, node);
  7663. ReleaseTemporaryVariable(objType, &ctx->bc);
  7664. return 0;
  7665. }
  7666. else if( funcs.GetLength() == 0 )
  7667. {
  7668. asCString str;
  7669. str = asCString(opName) + "()";
  7670. if( isConst )
  7671. str += " const";
  7672. str.Format(TXT_FUNCTION_s_NOT_FOUND, str.AddressOf());
  7673. Error(str, node);
  7674. ctx->type.SetDummy();
  7675. return -1;
  7676. }
  7677. else if( funcs.GetLength() > 1 )
  7678. {
  7679. Error(TXT_MORE_THAN_ONE_MATCHING_OP, node);
  7680. PrintMatchingFuncs(funcs, node);
  7681. ctx->type.SetDummy();
  7682. return -1;
  7683. }
  7684. }
  7685. else if( op == ttPlus )
  7686. {
  7687. Error(TXT_ILLEGAL_OPERATION, node);
  7688. ctx->type.SetDummy();
  7689. return -1;
  7690. }
  7691. }
  7692. else if( op == ttPlus || op == ttMinus )
  7693. {
  7694. // This is only for primitives. Objects are treated in the above block
  7695. // Make sure the type is a math type
  7696. if( !(ctx->type.dataType.IsIntegerType() ||
  7697. ctx->type.dataType.IsUnsignedType() ||
  7698. ctx->type.dataType.IsFloatType() ||
  7699. ctx->type.dataType.IsDoubleType() ) )
  7700. {
  7701. Error(TXT_ILLEGAL_OPERATION, node);
  7702. return -1;
  7703. }
  7704. ProcessPropertyGetAccessor(ctx, node);
  7705. asCDataType to = ctx->type.dataType;
  7706. // TODO: The case -2147483648 gives an unecessary warning of changed sign for implicit conversion
  7707. if( ctx->type.dataType.IsUnsignedType() )
  7708. {
  7709. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  7710. to = asCDataType::CreatePrimitive(ttInt8, false);
  7711. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  7712. to = asCDataType::CreatePrimitive(ttInt16, false);
  7713. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 )
  7714. to = asCDataType::CreatePrimitive(ttInt, false);
  7715. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 8 )
  7716. to = asCDataType::CreatePrimitive(ttInt64, false);
  7717. else
  7718. {
  7719. Error(TXT_INVALID_TYPE, node);
  7720. return -1;
  7721. }
  7722. }
  7723. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  7724. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV);
  7725. if( !ctx->type.isConstant )
  7726. {
  7727. ConvertToTempVariable(ctx);
  7728. asASSERT(!ctx->type.isLValue);
  7729. if( op == ttMinus )
  7730. {
  7731. if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  7732. ctx->bc.InstrSHORT(asBC_NEGi, ctx->type.stackOffset);
  7733. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  7734. ctx->bc.InstrSHORT(asBC_NEGi64, ctx->type.stackOffset);
  7735. else if( ctx->type.dataType.IsFloatType() )
  7736. ctx->bc.InstrSHORT(asBC_NEGf, ctx->type.stackOffset);
  7737. else if( ctx->type.dataType.IsDoubleType() )
  7738. ctx->bc.InstrSHORT(asBC_NEGd, ctx->type.stackOffset);
  7739. else
  7740. {
  7741. Error(TXT_ILLEGAL_OPERATION, node);
  7742. return -1;
  7743. }
  7744. return 0;
  7745. }
  7746. }
  7747. else
  7748. {
  7749. if( op == ttMinus )
  7750. {
  7751. if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  7752. ctx->type.intValue = -ctx->type.intValue;
  7753. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  7754. ctx->type.qwordValue = -(asINT64)ctx->type.qwordValue;
  7755. else if( ctx->type.dataType.IsFloatType() )
  7756. ctx->type.floatValue = -ctx->type.floatValue;
  7757. else if( ctx->type.dataType.IsDoubleType() )
  7758. ctx->type.doubleValue = -ctx->type.doubleValue;
  7759. else
  7760. {
  7761. Error(TXT_ILLEGAL_OPERATION, node);
  7762. return -1;
  7763. }
  7764. return 0;
  7765. }
  7766. }
  7767. }
  7768. else if( op == ttNot )
  7769. {
  7770. if( ctx->type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  7771. {
  7772. if( ctx->type.isConstant )
  7773. {
  7774. ctx->type.dwordValue = (ctx->type.dwordValue == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  7775. return 0;
  7776. }
  7777. ProcessPropertyGetAccessor(ctx, node);
  7778. ConvertToTempVariable(ctx);
  7779. asASSERT(!ctx->type.isLValue);
  7780. ctx->bc.InstrSHORT(asBC_NOT, ctx->type.stackOffset);
  7781. }
  7782. else
  7783. {
  7784. Error(TXT_ILLEGAL_OPERATION, node);
  7785. return -1;
  7786. }
  7787. }
  7788. else if( op == ttBitNot )
  7789. {
  7790. ProcessPropertyGetAccessor(ctx, node);
  7791. asCDataType to = ctx->type.dataType;
  7792. if( ctx->type.dataType.IsIntegerType() )
  7793. {
  7794. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  7795. to = asCDataType::CreatePrimitive(ttUInt8, false);
  7796. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  7797. to = asCDataType::CreatePrimitive(ttUInt16, false);
  7798. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 )
  7799. to = asCDataType::CreatePrimitive(ttUInt, false);
  7800. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 8 )
  7801. to = asCDataType::CreatePrimitive(ttUInt64, false);
  7802. else
  7803. {
  7804. Error(TXT_INVALID_TYPE, node);
  7805. return -1;
  7806. }
  7807. }
  7808. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  7809. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV);
  7810. if( ctx->type.dataType.IsUnsignedType() )
  7811. {
  7812. if( ctx->type.isConstant )
  7813. {
  7814. ctx->type.qwordValue = ~ctx->type.qwordValue;
  7815. return 0;
  7816. }
  7817. ConvertToTempVariable(ctx);
  7818. asASSERT(!ctx->type.isLValue);
  7819. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  7820. ctx->bc.InstrSHORT(asBC_BNOT, ctx->type.stackOffset);
  7821. else
  7822. ctx->bc.InstrSHORT(asBC_BNOT64, ctx->type.stackOffset);
  7823. }
  7824. else
  7825. {
  7826. Error(TXT_ILLEGAL_OPERATION, node);
  7827. return -1;
  7828. }
  7829. }
  7830. else if( op == ttInc || op == ttDec )
  7831. {
  7832. // Need a reference to the primitive that will be updated
  7833. // The result of this expression is the same reference as before
  7834. // Make sure the reference isn't a temporary variable
  7835. if( ctx->type.isTemporary )
  7836. {
  7837. Error(TXT_REF_IS_TEMP, node);
  7838. return -1;
  7839. }
  7840. if( ctx->type.dataType.IsReadOnly() )
  7841. {
  7842. Error(TXT_REF_IS_READ_ONLY, node);
  7843. return -1;
  7844. }
  7845. if( ctx->property_get || ctx->property_set )
  7846. {
  7847. Error(TXT_INVALID_REF_PROP_ACCESS, node);
  7848. return -1;
  7849. }
  7850. if( !ctx->type.isLValue )
  7851. {
  7852. Error(TXT_NOT_LVALUE, node);
  7853. return -1;
  7854. }
  7855. if( ctx->type.isVariable && !ctx->type.dataType.IsReference() )
  7856. ConvertToReference(ctx);
  7857. else if( !ctx->type.dataType.IsReference() )
  7858. {
  7859. Error(TXT_NOT_VALID_REFERENCE, node);
  7860. return -1;
  7861. }
  7862. if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt64, false)) ||
  7863. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt64, false)) )
  7864. {
  7865. if( op == ttInc )
  7866. ctx->bc.Instr(asBC_INCi64);
  7867. else
  7868. ctx->bc.Instr(asBC_DECi64);
  7869. }
  7870. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt, false)) ||
  7871. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt, false)) )
  7872. {
  7873. if( op == ttInc )
  7874. ctx->bc.Instr(asBC_INCi);
  7875. else
  7876. ctx->bc.Instr(asBC_DECi);
  7877. }
  7878. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt16, false)) ||
  7879. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt16, false)) )
  7880. {
  7881. if( op == ttInc )
  7882. ctx->bc.Instr(asBC_INCi16);
  7883. else
  7884. ctx->bc.Instr(asBC_DECi16);
  7885. }
  7886. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt8, false)) ||
  7887. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt8, false)) )
  7888. {
  7889. if( op == ttInc )
  7890. ctx->bc.Instr(asBC_INCi8);
  7891. else
  7892. ctx->bc.Instr(asBC_DECi8);
  7893. }
  7894. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttFloat, false)) )
  7895. {
  7896. if( op == ttInc )
  7897. ctx->bc.Instr(asBC_INCf);
  7898. else
  7899. ctx->bc.Instr(asBC_DECf);
  7900. }
  7901. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttDouble, false)) )
  7902. {
  7903. if( op == ttInc )
  7904. ctx->bc.Instr(asBC_INCd);
  7905. else
  7906. ctx->bc.Instr(asBC_DECd);
  7907. }
  7908. else
  7909. {
  7910. Error(TXT_ILLEGAL_OPERATION, node);
  7911. return -1;
  7912. }
  7913. }
  7914. else
  7915. {
  7916. // Unknown operator
  7917. asASSERT(false);
  7918. return -1;
  7919. }
  7920. return 0;
  7921. }
  7922. void asCCompiler::ConvertToReference(asSExprContext *ctx)
  7923. {
  7924. if( ctx->type.isVariable && !ctx->type.dataType.IsReference() )
  7925. {
  7926. ctx->bc.InstrSHORT(asBC_LDV, ctx->type.stackOffset);
  7927. ctx->type.dataType.MakeReference(true);
  7928. ctx->type.SetVariable(ctx->type.dataType, ctx->type.stackOffset, ctx->type.isTemporary);
  7929. }
  7930. }
  7931. int asCCompiler::FindPropertyAccessor(const asCString &name, asSExprContext *ctx, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess)
  7932. {
  7933. return FindPropertyAccessor(name, ctx, 0, node, ns, isThisAccess);
  7934. }
  7935. int asCCompiler::FindPropertyAccessor(const asCString &name, asSExprContext *ctx, asSExprContext *arg, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess)
  7936. {
  7937. if( engine->ep.propertyAccessorMode == 0 )
  7938. {
  7939. // Property accessors have been disabled by the application
  7940. return 0;
  7941. }
  7942. int getId = 0, setId = 0;
  7943. asCString getName = "get_" + name;
  7944. asCString setName = "set_" + name;
  7945. asCArray<int> multipleGetFuncs, multipleSetFuncs;
  7946. if( ctx->type.dataType.IsObject() )
  7947. {
  7948. asASSERT( ns == 0 );
  7949. // Don't look for property accessors in script classes if the script
  7950. // property accessors have been disabled by the application
  7951. if( !(ctx->type.dataType.GetObjectType()->flags & asOBJ_SCRIPT_OBJECT) ||
  7952. engine->ep.propertyAccessorMode == 2 )
  7953. {
  7954. // Check if the object has any methods with the corresponding accessor name(s)
  7955. asCObjectType *ot = ctx->type.dataType.GetObjectType();
  7956. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  7957. {
  7958. asCScriptFunction *f = engine->scriptFunctions[ot->methods[n]];
  7959. // TODO: The type of the parameter should match the argument (unless the arg is a dummy)
  7960. if( f->name == getName && (int)f->parameterTypes.GetLength() == (arg?1:0) )
  7961. {
  7962. if( getId == 0 )
  7963. getId = ot->methods[n];
  7964. else
  7965. {
  7966. if( multipleGetFuncs.GetLength() == 0 )
  7967. multipleGetFuncs.PushLast(getId);
  7968. multipleGetFuncs.PushLast(ot->methods[n]);
  7969. }
  7970. }
  7971. // TODO: getset: If the parameter is a reference, it must not be an out reference. Should we allow inout ref?
  7972. if( f->name == setName && (int)f->parameterTypes.GetLength() == (arg?2:1) )
  7973. {
  7974. if( setId == 0 )
  7975. setId = ot->methods[n];
  7976. else
  7977. {
  7978. if( multipleSetFuncs.GetLength() == 0 )
  7979. multipleSetFuncs.PushLast(setId);
  7980. multipleSetFuncs.PushLast(ot->methods[n]);
  7981. }
  7982. }
  7983. }
  7984. }
  7985. }
  7986. else
  7987. {
  7988. asASSERT( ns != 0 );
  7989. // Look for appropriate global functions.
  7990. asCArray<int> funcs;
  7991. asUINT n;
  7992. builder->GetFunctionDescriptions(getName.AddressOf(), funcs, ns);
  7993. for( n = 0; n < funcs.GetLength(); n++ )
  7994. {
  7995. asCScriptFunction *f = builder->GetFunctionDescription(funcs[n]);
  7996. // TODO: The type of the parameter should match the argument (unless the arg is a dummy)
  7997. if( (int)f->parameterTypes.GetLength() == (arg?1:0) )
  7998. {
  7999. if( getId == 0 )
  8000. getId = funcs[n];
  8001. else
  8002. {
  8003. if( multipleGetFuncs.GetLength() == 0 )
  8004. multipleGetFuncs.PushLast(getId);
  8005. multipleGetFuncs.PushLast(funcs[n]);
  8006. }
  8007. }
  8008. }
  8009. funcs.SetLength(0);
  8010. builder->GetFunctionDescriptions(setName.AddressOf(), funcs, ns);
  8011. for( n = 0; n < funcs.GetLength(); n++ )
  8012. {
  8013. asCScriptFunction *f = builder->GetFunctionDescription(funcs[n]);
  8014. // TODO: getset: If the parameter is a reference, it must not be an out reference. Should we allow inout ref?
  8015. if( (int)f->parameterTypes.GetLength() == (arg?2:1) )
  8016. {
  8017. if( setId == 0 )
  8018. setId = funcs[n];
  8019. else
  8020. {
  8021. if( multipleSetFuncs.GetLength() == 0 )
  8022. multipleSetFuncs.PushLast(getId);
  8023. multipleSetFuncs.PushLast(funcs[n]);
  8024. }
  8025. }
  8026. }
  8027. }
  8028. bool isConst = false;
  8029. if( ctx->type.dataType.IsObjectHandle() )
  8030. isConst = ctx->type.dataType.IsHandleToConst();
  8031. else
  8032. isConst = ctx->type.dataType.IsReadOnly();
  8033. // Check for multiple matches
  8034. if( multipleGetFuncs.GetLength() > 0 )
  8035. {
  8036. // Filter the list by constness
  8037. FilterConst(multipleGetFuncs, !isConst);
  8038. if( multipleGetFuncs.GetLength() > 1 )
  8039. {
  8040. asCString str;
  8041. str.Format(TXT_MULTIPLE_PROP_GET_ACCESSOR_FOR_s, name.AddressOf());
  8042. Error(str, node);
  8043. PrintMatchingFuncs(multipleGetFuncs, node);
  8044. return -1;
  8045. }
  8046. else
  8047. {
  8048. // The id may have changed
  8049. getId = multipleGetFuncs[0];
  8050. }
  8051. }
  8052. if( multipleSetFuncs.GetLength() > 0 )
  8053. {
  8054. // Filter the list by constness
  8055. FilterConst(multipleSetFuncs, !isConst);
  8056. if( multipleSetFuncs.GetLength() > 1 )
  8057. {
  8058. asCString str;
  8059. str.Format(TXT_MULTIPLE_PROP_SET_ACCESSOR_FOR_s, name.AddressOf());
  8060. Error(str, node);
  8061. PrintMatchingFuncs(multipleSetFuncs, node);
  8062. return -1;
  8063. }
  8064. else
  8065. {
  8066. // The id may have changed
  8067. setId = multipleSetFuncs[0];
  8068. }
  8069. }
  8070. // Check for type compatibility between get and set accessor
  8071. if( getId && setId )
  8072. {
  8073. asCScriptFunction *getFunc = builder->GetFunctionDescription(getId);
  8074. asCScriptFunction *setFunc = builder->GetFunctionDescription(setId);
  8075. // It is permitted for a getter to return a handle and the setter to take a reference
  8076. int idx = (arg?1:0);
  8077. if( !getFunc->returnType.IsEqualExceptRefAndConst(setFunc->parameterTypes[idx]) &&
  8078. !((getFunc->returnType.IsObjectHandle() && !setFunc->parameterTypes[idx].IsObjectHandle()) &&
  8079. (getFunc->returnType.GetObjectType() == setFunc->parameterTypes[idx].GetObjectType())) )
  8080. {
  8081. asCString str;
  8082. str.Format(TXT_GET_SET_ACCESSOR_TYPE_MISMATCH_FOR_s, name.AddressOf());
  8083. Error(str, node);
  8084. asCArray<int> funcs;
  8085. funcs.PushLast(getId);
  8086. funcs.PushLast(setId);
  8087. PrintMatchingFuncs(funcs, node);
  8088. return -1;
  8089. }
  8090. }
  8091. // Check if we are within one of the accessors
  8092. int realGetId = getId;
  8093. int realSetId = setId;
  8094. if( outFunc->objectType && isThisAccess )
  8095. {
  8096. // The property accessors would be virtual functions, so we need to find the real implementation
  8097. asCScriptFunction *getFunc = getId ? builder->GetFunctionDescription(getId) : 0;
  8098. if( getFunc &&
  8099. getFunc->funcType == asFUNC_VIRTUAL &&
  8100. outFunc->objectType->DerivesFrom(getFunc->objectType) )
  8101. realGetId = outFunc->objectType->virtualFunctionTable[getFunc->vfTableIdx]->id;
  8102. asCScriptFunction *setFunc = setId ? builder->GetFunctionDescription(setId) : 0;
  8103. if( setFunc &&
  8104. setFunc->funcType == asFUNC_VIRTUAL &&
  8105. outFunc->objectType->DerivesFrom(setFunc->objectType) )
  8106. realSetId = outFunc->objectType->virtualFunctionTable[setFunc->vfTableIdx]->id;
  8107. }
  8108. // Avoid recursive call, by not treating this as a property accessor call.
  8109. // This will also allow having the real property with the same name as the accessors.
  8110. if( (isThisAccess || outFunc->objectType == 0) &&
  8111. ((realGetId && realGetId == outFunc->id) ||
  8112. (realSetId && realSetId == outFunc->id)) )
  8113. {
  8114. getId = 0;
  8115. setId = 0;
  8116. }
  8117. // Check if the application has disabled script written property accessors
  8118. if( engine->ep.propertyAccessorMode == 1 )
  8119. {
  8120. if( getId && builder->GetFunctionDescription(getId)->funcType != asFUNC_SYSTEM )
  8121. getId = 0;
  8122. if( setId && builder->GetFunctionDescription(setId)->funcType != asFUNC_SYSTEM )
  8123. setId = 0;
  8124. }
  8125. if( getId || setId )
  8126. {
  8127. // Property accessors were found, but we don't know which is to be used yet, so
  8128. // we just prepare the bytecode for the method call, and then store the function ids
  8129. // so that the right one can be used when we get there.
  8130. ctx->property_get = getId;
  8131. ctx->property_set = setId;
  8132. if( ctx->type.dataType.IsObject() )
  8133. {
  8134. // If the object is read-only then we need to remember that
  8135. if( (!ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReadOnly()) ||
  8136. (ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsHandleToConst()) )
  8137. ctx->property_const = true;
  8138. else
  8139. ctx->property_const = false;
  8140. // If the object is a handle then we need to remember that
  8141. ctx->property_handle = ctx->type.dataType.IsObjectHandle();
  8142. ctx->property_ref = ctx->type.dataType.IsReference();
  8143. }
  8144. // The setter's parameter type is used as the property type,
  8145. // unless only the getter is available
  8146. asCDataType dt;
  8147. if( setId )
  8148. dt = builder->GetFunctionDescription(setId)->parameterTypes[(arg?1:0)];
  8149. else
  8150. dt = builder->GetFunctionDescription(getId)->returnType;
  8151. // Just change the type, the context must still maintain information
  8152. // about previous variable offset and the indicator of temporary variable.
  8153. int offset = ctx->type.stackOffset;
  8154. bool isTemp = ctx->type.isTemporary;
  8155. ctx->type.Set(dt);
  8156. ctx->type.stackOffset = (short)offset;
  8157. ctx->type.isTemporary = isTemp;
  8158. ctx->exprNode = node;
  8159. // Store the argument for later use
  8160. if( arg )
  8161. {
  8162. ctx->property_arg = asNEW(asSExprContext)(engine);
  8163. if( ctx->property_arg == 0 )
  8164. {
  8165. // Out of memory
  8166. return -1;
  8167. }
  8168. MergeExprBytecodeAndType(ctx->property_arg, arg);
  8169. }
  8170. return 1;
  8171. }
  8172. // No accessor was found
  8173. return 0;
  8174. }
  8175. int asCCompiler::ProcessPropertySetAccessor(asSExprContext *ctx, asSExprContext *arg, asCScriptNode *node)
  8176. {
  8177. // TODO: A lot of this code is similar to ProcessPropertyGetAccessor. Can we unify them?
  8178. if( !ctx->property_set )
  8179. {
  8180. Error(TXT_PROPERTY_HAS_NO_SET_ACCESSOR, node);
  8181. return -1;
  8182. }
  8183. asCTypeInfo objType = ctx->type;
  8184. asCScriptFunction *func = builder->GetFunctionDescription(ctx->property_set);
  8185. // Make sure the arg match the property
  8186. asCArray<int> funcs;
  8187. funcs.PushLast(ctx->property_set);
  8188. asCArray<asSExprContext *> args;
  8189. if( ctx->property_arg )
  8190. args.PushLast(ctx->property_arg);
  8191. args.PushLast(arg);
  8192. MatchFunctions(funcs, args, node, func->GetName(), func->objectType, ctx->property_const);
  8193. if( funcs.GetLength() == 0 )
  8194. {
  8195. // MatchFunctions already reported the error
  8196. if( ctx->property_arg )
  8197. {
  8198. asDELETE(ctx->property_arg, asSExprContext);
  8199. ctx->property_arg = 0;
  8200. }
  8201. return -1;
  8202. }
  8203. if( func->objectType )
  8204. {
  8205. // Setup the context with the original type so the method call gets built correctly
  8206. ctx->type.dataType = asCDataType::CreateObject(func->objectType, ctx->property_const);
  8207. if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
  8208. if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
  8209. // Don't allow the call if the object is read-only and the property accessor is not const
  8210. if( ctx->property_const && !func->isReadOnly )
  8211. {
  8212. Error(TXT_NON_CONST_METHOD_ON_CONST_OBJ, node);
  8213. asCArray<int> funcs;
  8214. funcs.PushLast(ctx->property_set);
  8215. PrintMatchingFuncs(funcs, node);
  8216. }
  8217. }
  8218. // Call the accessor
  8219. MakeFunctionCall(ctx, ctx->property_set, func->objectType, args, node);
  8220. if( func->objectType )
  8221. {
  8222. // TODO: This is from CompileExpressionPostOp, can we unify the code?
  8223. if( !objType.isTemporary ||
  8224. !ctx->type.dataType.IsReference() ||
  8225. ctx->type.isVariable ) // If the resulting type is a variable, then the reference is not a member
  8226. {
  8227. // As the method didn't return a reference to a member
  8228. // we can safely release the original object now
  8229. ReleaseTemporaryVariable(objType, &ctx->bc);
  8230. }
  8231. }
  8232. ctx->property_get = 0;
  8233. ctx->property_set = 0;
  8234. if( ctx->property_arg )
  8235. {
  8236. asDELETE(ctx->property_arg, asSExprContext);
  8237. ctx->property_arg = 0;
  8238. }
  8239. return 0;
  8240. }
  8241. void asCCompiler::ProcessPropertyGetAccessor(asSExprContext *ctx, asCScriptNode *node)
  8242. {
  8243. // If no property accessor has been prepared then don't do anything
  8244. if( !ctx->property_get && !ctx->property_set )
  8245. return;
  8246. if( !ctx->property_get )
  8247. {
  8248. // Raise error on missing accessor
  8249. Error(TXT_PROPERTY_HAS_NO_GET_ACCESSOR, node);
  8250. ctx->type.SetDummy();
  8251. return;
  8252. }
  8253. asCTypeInfo objType = ctx->type;
  8254. asCScriptFunction *func = builder->GetFunctionDescription(ctx->property_get);
  8255. // Make sure the arg match the property
  8256. asCArray<int> funcs;
  8257. funcs.PushLast(ctx->property_get);
  8258. asCArray<asSExprContext *> args;
  8259. if( ctx->property_arg )
  8260. args.PushLast(ctx->property_arg);
  8261. MatchFunctions(funcs, args, node, func->GetName(), func->objectType, ctx->property_const);
  8262. if( funcs.GetLength() == 0 )
  8263. {
  8264. // MatchFunctions already reported the error
  8265. if( ctx->property_arg )
  8266. {
  8267. asDELETE(ctx->property_arg, asSExprContext);
  8268. ctx->property_arg = 0;
  8269. }
  8270. ctx->type.SetDummy();
  8271. return;
  8272. }
  8273. if( func->objectType )
  8274. {
  8275. // Setup the context with the original type so the method call gets built correctly
  8276. ctx->type.dataType = asCDataType::CreateObject(func->objectType, ctx->property_const);
  8277. if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
  8278. if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
  8279. // Don't allow the call if the object is read-only and the property accessor is not const
  8280. if( ctx->property_const && !func->isReadOnly )
  8281. {
  8282. Error(TXT_NON_CONST_METHOD_ON_CONST_OBJ, node);
  8283. asCArray<int> funcs;
  8284. funcs.PushLast(ctx->property_get);
  8285. PrintMatchingFuncs(funcs, node);
  8286. }
  8287. }
  8288. // Call the accessor
  8289. MakeFunctionCall(ctx, ctx->property_get, func->objectType, args, node);
  8290. if( func->objectType )
  8291. {
  8292. // TODO: This is from CompileExpressionPostOp, can we unify the code?
  8293. // If the method returned a reference, then we can't release the original
  8294. // object yet, because the reference may be to a member of it
  8295. if( !objType.isTemporary ||
  8296. !(ctx->type.dataType.IsReference() || (ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle())) ||
  8297. ctx->type.isVariable ) // If the resulting type is a variable, then the reference is not a member
  8298. {
  8299. // As the method didn't return a reference to a member
  8300. // we can safely release the original object now
  8301. ReleaseTemporaryVariable(objType, &ctx->bc);
  8302. }
  8303. }
  8304. ctx->property_get = 0;
  8305. ctx->property_set = 0;
  8306. if( ctx->property_arg )
  8307. {
  8308. asDELETE(ctx->property_arg, asSExprContext);
  8309. ctx->property_arg = 0;
  8310. }
  8311. }
  8312. int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ctx)
  8313. {
  8314. // Don't allow any postfix operators on expressions that take address of class method
  8315. if( ctx->IsClassMethod() )
  8316. {
  8317. Error(TXT_INVALID_OP_ON_METHOD, node);
  8318. return -1;
  8319. }
  8320. // Don't allow any operators on void expressions
  8321. if( ctx->type.IsVoidExpression() )
  8322. {
  8323. Error(TXT_VOID_CANT_BE_OPERAND, node);
  8324. return -1;
  8325. }
  8326. // Check if the variable is initialized (if it indeed is a variable)
  8327. IsVariableInitialized(&ctx->type, node);
  8328. int op = node->tokenType;
  8329. if( (op == ttInc || op == ttDec) && ctx->type.dataType.IsObject() )
  8330. {
  8331. const char *opName = 0;
  8332. switch( op )
  8333. {
  8334. case ttInc: opName = "opPostInc"; break;
  8335. case ttDec: opName = "opPostDec"; break;
  8336. }
  8337. if( opName )
  8338. {
  8339. // TODO: Should convert this to something similar to CompileOverloadedDualOperator2
  8340. ProcessPropertyGetAccessor(ctx, node);
  8341. // Is it a const value?
  8342. bool isConst = false;
  8343. if( ctx->type.dataType.IsObjectHandle() )
  8344. isConst = ctx->type.dataType.IsHandleToConst();
  8345. else
  8346. isConst = ctx->type.dataType.IsReadOnly();
  8347. // 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
  8348. // Find the correct method
  8349. asCArray<int> funcs;
  8350. asCObjectType *ot = ctx->type.dataType.GetObjectType();
  8351. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  8352. {
  8353. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  8354. if( func->name == opName &&
  8355. func->parameterTypes.GetLength() == 0 &&
  8356. (!isConst || func->isReadOnly) )
  8357. {
  8358. funcs.PushLast(func->id);
  8359. }
  8360. }
  8361. // Did we find the method?
  8362. if( funcs.GetLength() == 1 )
  8363. {
  8364. asCTypeInfo objType = ctx->type;
  8365. asCArray<asSExprContext *> args;
  8366. MakeFunctionCall(ctx, funcs[0], objType.dataType.GetObjectType(), args, node);
  8367. ReleaseTemporaryVariable(objType, &ctx->bc);
  8368. return 0;
  8369. }
  8370. else if( funcs.GetLength() == 0 )
  8371. {
  8372. asCString str;
  8373. str = asCString(opName) + "()";
  8374. if( isConst )
  8375. str += " const";
  8376. str.Format(TXT_FUNCTION_s_NOT_FOUND, str.AddressOf());
  8377. Error(str, node);
  8378. ctx->type.SetDummy();
  8379. return -1;
  8380. }
  8381. else if( funcs.GetLength() > 1 )
  8382. {
  8383. Error(TXT_MORE_THAN_ONE_MATCHING_OP, node);
  8384. PrintMatchingFuncs(funcs, node);
  8385. ctx->type.SetDummy();
  8386. return -1;
  8387. }
  8388. }
  8389. }
  8390. else if( op == ttInc || op == ttDec )
  8391. {
  8392. // Make sure the reference isn't a temporary variable
  8393. if( ctx->type.isTemporary )
  8394. {
  8395. Error(TXT_REF_IS_TEMP, node);
  8396. return -1;
  8397. }
  8398. if( ctx->type.dataType.IsReadOnly() )
  8399. {
  8400. Error(TXT_REF_IS_READ_ONLY, node);
  8401. return -1;
  8402. }
  8403. if( ctx->property_get || ctx->property_set )
  8404. {
  8405. Error(TXT_INVALID_REF_PROP_ACCESS, node);
  8406. return -1;
  8407. }
  8408. if( !ctx->type.isLValue )
  8409. {
  8410. Error(TXT_NOT_LVALUE, node);
  8411. return -1;
  8412. }
  8413. if( ctx->type.isVariable && !ctx->type.dataType.IsReference() )
  8414. ConvertToReference(ctx);
  8415. else if( !ctx->type.dataType.IsReference() )
  8416. {
  8417. Error(TXT_NOT_VALID_REFERENCE, node);
  8418. return -1;
  8419. }
  8420. // Copy the value to a temp before changing it
  8421. ConvertToTempVariable(ctx);
  8422. asASSERT(!ctx->type.isLValue);
  8423. // Increment the value pointed to by the reference still in the register
  8424. asEBCInstr iInc = asBC_INCi, iDec = asBC_DECi;
  8425. if( ctx->type.dataType.IsDoubleType() )
  8426. {
  8427. iInc = asBC_INCd;
  8428. iDec = asBC_DECd;
  8429. }
  8430. else if( ctx->type.dataType.IsFloatType() )
  8431. {
  8432. iInc = asBC_INCf;
  8433. iDec = asBC_DECf;
  8434. }
  8435. else if( ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType() )
  8436. {
  8437. if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt16, false)) ||
  8438. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt16, false)) )
  8439. {
  8440. iInc = asBC_INCi16;
  8441. iDec = asBC_DECi16;
  8442. }
  8443. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt8, false)) ||
  8444. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt8, false)) )
  8445. {
  8446. iInc = asBC_INCi8;
  8447. iDec = asBC_DECi8;
  8448. }
  8449. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt64, false)) ||
  8450. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt64, false)) )
  8451. {
  8452. iInc = asBC_INCi64;
  8453. iDec = asBC_DECi64;
  8454. }
  8455. }
  8456. else
  8457. {
  8458. Error(TXT_ILLEGAL_OPERATION, node);
  8459. return -1;
  8460. }
  8461. if( op == ttInc ) ctx->bc.Instr(iInc); else ctx->bc.Instr(iDec);
  8462. }
  8463. else if( op == ttDot )
  8464. {
  8465. if( node->firstChild->nodeType == snIdentifier )
  8466. {
  8467. ProcessPropertyGetAccessor(ctx, node);
  8468. // Get the property name
  8469. asCString name(&script->code[node->firstChild->tokenPos], node->firstChild->tokenLength);
  8470. if( ctx->type.dataType.IsObject() )
  8471. {
  8472. // We need to look for get/set property accessors.
  8473. // If found, the context stores information on the get/set accessors
  8474. // until it is known which is to be used.
  8475. int r = 0;
  8476. if( node->next && node->next->tokenType == ttOpenBracket )
  8477. {
  8478. // The property accessor should take an index arg
  8479. asSExprContext dummyArg(engine);
  8480. r = FindPropertyAccessor(name, ctx, &dummyArg, node, 0);
  8481. }
  8482. if( r == 0 )
  8483. r = FindPropertyAccessor(name, ctx, node, 0);
  8484. if( r != 0 )
  8485. return r;
  8486. if( !ctx->type.dataType.IsPrimitive() )
  8487. Dereference(ctx, true);
  8488. if( ctx->type.dataType.IsObjectHandle() )
  8489. {
  8490. // Convert the handle to a normal object
  8491. asCDataType dt = ctx->type.dataType;
  8492. dt.MakeHandle(false);
  8493. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV);
  8494. // The handle may not have been an lvalue, but the dereferenced object is
  8495. ctx->type.isLValue = true;
  8496. }
  8497. bool isConst = ctx->type.dataType.IsReadOnly();
  8498. asCObjectProperty *prop = builder->GetObjectProperty(ctx->type.dataType, name.AddressOf());
  8499. if( prop )
  8500. {
  8501. // Is the property access allowed?
  8502. if( prop->isPrivate && (!outFunc || outFunc->objectType != ctx->type.dataType.GetObjectType()) )
  8503. {
  8504. asCString msg;
  8505. msg.Format(TXT_PRIVATE_PROP_ACCESS_s, name.AddressOf());
  8506. Error(msg, node);
  8507. }
  8508. // Put the offset on the stack
  8509. ctx->bc.InstrSHORT_DW(asBC_ADDSi, (short)prop->byteOffset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(ctx->type.dataType.GetObjectType(), false)));
  8510. if( prop->type.IsReference() )
  8511. ctx->bc.Instr(asBC_RDSPtr);
  8512. // Reference to primitive must be stored in the temp register
  8513. if( prop->type.IsPrimitive() )
  8514. {
  8515. ctx->bc.Instr(asBC_PopRPtr);
  8516. }
  8517. // Keep information about temporary variables as deferred expression
  8518. if( ctx->type.isTemporary )
  8519. {
  8520. // Add the release of this reference, as a deferred expression
  8521. asSDeferredParam deferred;
  8522. deferred.origExpr = 0;
  8523. deferred.argInOutFlags = asTM_INREF;
  8524. deferred.argNode = 0;
  8525. deferred.argType.SetVariable(ctx->type.dataType, ctx->type.stackOffset, true);
  8526. ctx->deferredParams.PushLast(deferred);
  8527. }
  8528. // Set the new type and make sure it is not treated as a variable anymore
  8529. ctx->type.dataType = prop->type;
  8530. ctx->type.dataType.MakeReference(true);
  8531. ctx->type.isVariable = false;
  8532. ctx->type.isTemporary = false;
  8533. if( ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle() )
  8534. {
  8535. // Objects that are members are not references
  8536. ctx->type.dataType.MakeReference(false);
  8537. }
  8538. ctx->type.dataType.MakeReadOnly(isConst ? true : prop->type.IsReadOnly());
  8539. }
  8540. else
  8541. {
  8542. // If the name is not a property, the compiler must check if the name matches
  8543. // a method, which can be used for constructing delegates
  8544. asIScriptFunction *func = 0;
  8545. asCObjectType *ot = ctx->type.dataType.GetObjectType();
  8546. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  8547. {
  8548. if( engine->scriptFunctions[ot->methods[n]]->name == name )
  8549. {
  8550. func = engine->scriptFunctions[ot->methods[n]];
  8551. break;
  8552. }
  8553. }
  8554. if( func )
  8555. {
  8556. // An object method was found. Keep the name of the method in the expression, but
  8557. // don't actually modify the bytecode at this point since it is not yet known what
  8558. // the method will be used for, or even what overloaded method should be used.
  8559. ctx->methodName = name;
  8560. }
  8561. else
  8562. {
  8563. asCString str;
  8564. str.Format(TXT_s_NOT_MEMBER_OF_s, name.AddressOf(), ctx->type.dataType.Format().AddressOf());
  8565. Error(str, node);
  8566. return -1;
  8567. }
  8568. }
  8569. }
  8570. else
  8571. {
  8572. asCString str;
  8573. str.Format(TXT_s_NOT_MEMBER_OF_s, name.AddressOf(), ctx->type.dataType.Format().AddressOf());
  8574. Error(str, node);
  8575. return -1;
  8576. }
  8577. }
  8578. else
  8579. {
  8580. // Make sure it is an object we are accessing
  8581. if( !ctx->type.dataType.IsObject() )
  8582. {
  8583. asCString str;
  8584. str.Format(TXT_ILLEGAL_OPERATION_ON_s, ctx->type.dataType.Format().AddressOf());
  8585. Error(str, node);
  8586. return -1;
  8587. }
  8588. // Process the get property accessor
  8589. ProcessPropertyGetAccessor(ctx, node);
  8590. bool isConst = false;
  8591. if( ctx->type.dataType.IsObjectHandle() )
  8592. isConst = ctx->type.dataType.IsHandleToConst();
  8593. else
  8594. isConst = ctx->type.dataType.IsReadOnly();
  8595. asCObjectType *trueObj = ctx->type.dataType.GetObjectType();
  8596. asCTypeInfo objType = ctx->type;
  8597. // Compile function call
  8598. int r = CompileFunctionCall(node->firstChild, ctx, trueObj, isConst);
  8599. if( r < 0 ) return r;
  8600. // If the method returned a reference, then we can't release the original
  8601. // object yet, because the reference may be to a member of it
  8602. if( !objType.isTemporary ||
  8603. !(ctx->type.dataType.IsReference() || (ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle())) ||
  8604. ctx->type.isVariable ) // If the resulting type is a variable, then the reference is not a member
  8605. {
  8606. // As the method didn't return a reference to a member
  8607. // we can safely release the original object now
  8608. ReleaseTemporaryVariable(objType, &ctx->bc);
  8609. }
  8610. }
  8611. }
  8612. else if( op == ttOpenBracket )
  8613. {
  8614. // If the property access takes an index arg and the argument hasn't been evaluated yet,
  8615. // then we should use that instead of processing it now. If the argument has already been
  8616. // evaluated, then we should process the property accessor as a get access now as the new
  8617. // index operator is on the result of that accessor.
  8618. asCString propertyName;
  8619. asSNameSpace *ns = 0;
  8620. if( ((ctx->property_get && builder->GetFunctionDescription(ctx->property_get)->GetParamCount() == 1) ||
  8621. (ctx->property_set && builder->GetFunctionDescription(ctx->property_set)->GetParamCount() == 2)) &&
  8622. (ctx->property_arg && ctx->property_arg->type.dataType.GetTokenType() == ttUnrecognizedToken) )
  8623. {
  8624. // Determine the name of the property accessor
  8625. asCScriptFunction *func = 0;
  8626. if( ctx->property_get )
  8627. func = builder->GetFunctionDescription(ctx->property_get);
  8628. else
  8629. func = builder->GetFunctionDescription(ctx->property_set);
  8630. propertyName = func->GetName();
  8631. propertyName = propertyName.SubString(4);
  8632. // Set the original type of the expression so we can re-evaluate the property accessor
  8633. if( func->objectType )
  8634. {
  8635. ctx->type.dataType = asCDataType::CreateObject(func->objectType, ctx->property_const);
  8636. if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
  8637. if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
  8638. }
  8639. else
  8640. {
  8641. // Store the namespace where the function is declared
  8642. // so the same function can be found later
  8643. ctx->type.SetDummy();
  8644. ns = func->nameSpace;
  8645. }
  8646. ctx->property_get = ctx->property_set = 0;
  8647. if( ctx->property_arg )
  8648. {
  8649. asDELETE(ctx->property_arg, asSExprContext);
  8650. ctx->property_arg = 0;
  8651. }
  8652. }
  8653. else
  8654. {
  8655. if( !ctx->type.dataType.IsObject() )
  8656. {
  8657. asCString str;
  8658. str.Format(TXT_OBJECT_DOESNT_SUPPORT_INDEX_OP, ctx->type.dataType.Format().AddressOf());
  8659. Error(str, node);
  8660. return -1;
  8661. }
  8662. ProcessPropertyGetAccessor(ctx, node);
  8663. }
  8664. Dereference(ctx, true);
  8665. // Compile the expression
  8666. asSExprContext expr(engine);
  8667. CompileAssignment(node->firstChild, &expr);
  8668. // Check for the existence of the opIndex method
  8669. asSExprContext lctx(engine);
  8670. MergeExprBytecodeAndType(&lctx, ctx);
  8671. int r = 0;
  8672. if( propertyName == "" )
  8673. r = CompileOverloadedDualOperator2(node, "opIndex", &lctx, &expr, ctx);
  8674. if( r == 0 )
  8675. {
  8676. // Check for accessors methods for the opIndex
  8677. r = FindPropertyAccessor(propertyName == "" ? "opIndex" : propertyName.AddressOf(), &lctx, &expr, node, ns);
  8678. if( r == 0 )
  8679. {
  8680. asCString str;
  8681. str.Format(TXT_OBJECT_DOESNT_SUPPORT_INDEX_OP, ctx->type.dataType.Format().AddressOf());
  8682. Error(str, node);
  8683. return -1;
  8684. }
  8685. else if( r < 0 )
  8686. return -1;
  8687. MergeExprBytecodeAndType(ctx, &lctx);
  8688. }
  8689. }
  8690. else if( op == ttOpenParanthesis )
  8691. {
  8692. // TODO: Most of this is already done by CompileFunctionCall(). Can we share the code?
  8693. // Make sure the expression is a funcdef
  8694. if( !ctx->type.dataType.GetFuncDef() )
  8695. {
  8696. Error(TXT_EXPR_DOESNT_EVAL_TO_FUNC, node);
  8697. return -1;
  8698. }
  8699. // Compile arguments
  8700. asCArray<asSExprContext *> args;
  8701. if( CompileArgumentList(node->lastChild, args) >= 0 )
  8702. {
  8703. // Match arguments with the funcdef
  8704. asCArray<int> funcs;
  8705. funcs.PushLast(ctx->type.dataType.GetFuncDef()->id);
  8706. MatchFunctions(funcs, args, node, ctx->type.dataType.GetFuncDef()->name.AddressOf());
  8707. if( funcs.GetLength() != 1 )
  8708. {
  8709. // The error was reported by MatchFunctions()
  8710. // Dummy value
  8711. ctx->type.SetDummy();
  8712. }
  8713. else
  8714. {
  8715. int r = asSUCCESS;
  8716. // Add the default values for arguments not explicitly supplied
  8717. asCScriptFunction *func = (funcs[0] & FUNC_IMPORTED) == 0 ? engine->scriptFunctions[funcs[0]] : 0;
  8718. if( func && args.GetLength() < (asUINT)func->GetParamCount() )
  8719. r = CompileDefaultArgs(node, args, func);
  8720. // TODO: funcdef: Do we have to make sure the handle is stored in a temporary variable, or
  8721. // is it enough to make sure it is in a local variable?
  8722. // For function pointer we must guarantee that the function is safe, i.e.
  8723. // by first storing the function pointer in a local variable (if it isn't already in one)
  8724. if( r == asSUCCESS )
  8725. {
  8726. Dereference(ctx, true);
  8727. if( !ctx->type.isVariable )
  8728. ConvertToVariable(ctx);
  8729. else
  8730. {
  8731. // Remove the reference from the stack as the asBC_CALLPTR instruction takes the variable as argument
  8732. ctx->bc.Instr(asBC_PopPtr);
  8733. }
  8734. asCTypeInfo t = ctx->type;
  8735. MakeFunctionCall(ctx, funcs[0], 0, args, node, false, 0, ctx->type.stackOffset);
  8736. ReleaseTemporaryVariable(t, &ctx->bc);
  8737. }
  8738. }
  8739. }
  8740. else
  8741. ctx->type.SetDummy();
  8742. // Cleanup
  8743. for( asUINT n = 0; n < args.GetLength(); n++ )
  8744. if( args[n] )
  8745. {
  8746. asDELETE(args[n],asSExprContext);
  8747. }
  8748. }
  8749. return 0;
  8750. }
  8751. int asCCompiler::GetPrecedence(asCScriptNode *op)
  8752. {
  8753. // x * y, x / y, x % y
  8754. // x + y, x - y
  8755. // x <= y, x < y, x >= y, x > y
  8756. // x = =y, x != y, x xor y, x is y, x !is y
  8757. // x and y
  8758. // x or y
  8759. // The following are not used in this function,
  8760. // but should have lower precedence than the above
  8761. // x ? y : z
  8762. // x = y
  8763. // The expression term have the highest precedence
  8764. if( op->nodeType == snExprTerm )
  8765. return 1;
  8766. // Evaluate operators by token
  8767. int tokenType = op->tokenType;
  8768. if( tokenType == ttStar || tokenType == ttSlash || tokenType == ttPercent )
  8769. return 0;
  8770. if( tokenType == ttPlus || tokenType == ttMinus )
  8771. return -1;
  8772. if( tokenType == ttBitShiftLeft ||
  8773. tokenType == ttBitShiftRight ||
  8774. tokenType == ttBitShiftRightArith )
  8775. return -2;
  8776. if( tokenType == ttAmp )
  8777. return -3;
  8778. if( tokenType == ttBitXor )
  8779. return -4;
  8780. if( tokenType == ttBitOr )
  8781. return -5;
  8782. if( tokenType == ttLessThanOrEqual ||
  8783. tokenType == ttLessThan ||
  8784. tokenType == ttGreaterThanOrEqual ||
  8785. tokenType == ttGreaterThan )
  8786. return -6;
  8787. if( tokenType == ttEqual || tokenType == ttNotEqual || tokenType == ttXor || tokenType == ttIs || tokenType == ttNotIs )
  8788. return -7;
  8789. if( tokenType == ttAnd )
  8790. return -8;
  8791. if( tokenType == ttOr )
  8792. return -9;
  8793. // Unknown operator
  8794. asASSERT(false);
  8795. return 0;
  8796. }
  8797. asUINT asCCompiler::MatchArgument(asCArray<int> &funcs, asCArray<asSOverloadCandidate> &matches, const asSExprContext *argExpr, int paramNum, bool allowObjectConstruct)
  8798. {
  8799. matches.SetLength(0);
  8800. for( asUINT n = 0; n < funcs.GetLength(); n++ )
  8801. {
  8802. asCScriptFunction *desc = builder->GetFunctionDescription(funcs[n]);
  8803. // Does the function have arguments enough?
  8804. if( (int)desc->parameterTypes.GetLength() <= paramNum )
  8805. continue;
  8806. // void expressions can match any out parameter, but nothing else
  8807. if( argExpr->type.IsVoidExpression() )
  8808. {
  8809. if( desc->inOutFlags[paramNum] == asTM_OUTREF )
  8810. matches.PushLast(asSOverloadCandidate(funcs[n], 0));
  8811. continue;
  8812. }
  8813. // Can we make the match by implicit conversion?
  8814. asSExprContext ti(engine);
  8815. ti.type = argExpr->type;
  8816. ti.methodName = argExpr->methodName;
  8817. if( argExpr->type.dataType.IsPrimitive() ) ti.type.dataType.MakeReference(false);
  8818. asUINT cost = ImplicitConversion(&ti, desc->parameterTypes[paramNum], 0, asIC_IMPLICIT_CONV, false, allowObjectConstruct);
  8819. // If the function parameter is an inout-reference then it must not be possible to call the
  8820. // function with an incorrect argument type, even though the type can normally be converted.
  8821. if( desc->parameterTypes[paramNum].IsReference() &&
  8822. desc->inOutFlags[paramNum] == asTM_INOUTREF &&
  8823. desc->parameterTypes[paramNum].GetTokenType() != ttQuestion )
  8824. {
  8825. // Observe, that the below checks are only necessary for when unsafe references have been
  8826. // enabled by the application. Without this the &inout reference form wouldn't be allowed
  8827. // for these value types.
  8828. // Don't allow a primitive to be converted to a reference of another primitive type
  8829. if( desc->parameterTypes[paramNum].IsPrimitive() &&
  8830. desc->parameterTypes[paramNum].GetTokenType() != argExpr->type.dataType.GetTokenType() )
  8831. {
  8832. asASSERT( engine->ep.allowUnsafeReferences );
  8833. continue;
  8834. }
  8835. // Don't allow an enum to be converted to a reference of another enum type
  8836. if( desc->parameterTypes[paramNum].IsEnumType() &&
  8837. desc->parameterTypes[paramNum].GetObjectType() != argExpr->type.dataType.GetObjectType() )
  8838. {
  8839. asASSERT( engine->ep.allowUnsafeReferences );
  8840. continue;
  8841. }
  8842. // Don't allow a non-handle expression to be converted to a reference to a handle
  8843. if( desc->parameterTypes[paramNum].IsObjectHandle() &&
  8844. !argExpr->type.dataType.IsObjectHandle() )
  8845. {
  8846. asASSERT( engine->ep.allowUnsafeReferences );
  8847. continue;
  8848. }
  8849. // Don't allow a value type to be converted
  8850. if( (desc->parameterTypes[paramNum].GetObjectType() && (desc->parameterTypes[paramNum].GetObjectType()->GetFlags() & asOBJ_VALUE)) &&
  8851. (desc->parameterTypes[paramNum].GetObjectType() != argExpr->type.dataType.GetObjectType()) )
  8852. {
  8853. asASSERT( engine->ep.allowUnsafeReferences );
  8854. continue;
  8855. }
  8856. }
  8857. // How well does the argument match the function parameter?
  8858. if( desc->parameterTypes[paramNum].IsEqualExceptRef(ti.type.dataType) )
  8859. matches.PushLast(asSOverloadCandidate(funcs[n], cost));
  8860. }
  8861. return (asUINT)matches.GetLength();
  8862. }
  8863. void asCCompiler::PrepareArgument2(asSExprContext *ctx, asSExprContext *arg, asCDataType *paramType, bool isFunction, int refType, bool isMakingCopy)
  8864. {
  8865. // Reference parameters whose value won't be used don't evaluate the expression
  8866. if( paramType->IsReference() && !(refType & asTM_INREF) )
  8867. {
  8868. // Store the original bytecode so that it can be reused when processing the deferred output parameter
  8869. asSExprContext *orig = asNEW(asSExprContext)(engine);
  8870. if( orig == 0 )
  8871. {
  8872. // Out of memory
  8873. return;
  8874. }
  8875. MergeExprBytecodeAndType(orig, arg);
  8876. arg->origExpr = orig;
  8877. }
  8878. PrepareArgument(paramType, arg, arg->exprNode, isFunction, refType, isMakingCopy);
  8879. // arg still holds the original expression for output parameters
  8880. ctx->bc.AddCode(&arg->bc);
  8881. }
  8882. bool asCCompiler::CompileOverloadedDualOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  8883. {
  8884. DetermineSingleFunc(lctx, node);
  8885. DetermineSingleFunc(rctx, node);
  8886. ctx->exprNode = node;
  8887. // What type of operator is it?
  8888. int token = node->tokenType;
  8889. if( token == ttUnrecognizedToken )
  8890. {
  8891. // This happens when the compiler is inferring an assignment
  8892. // operation from another action, for example in preparing a value
  8893. // as a function argument
  8894. token = ttAssignment;
  8895. }
  8896. // boolean operators are not overloadable
  8897. if( token == ttAnd ||
  8898. token == ttOr ||
  8899. token == ttXor )
  8900. return false;
  8901. // Dual operators can also be implemented as class methods
  8902. if( token == ttEqual ||
  8903. token == ttNotEqual )
  8904. {
  8905. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  8906. // Find the matching opEquals method
  8907. int r = CompileOverloadedDualOperator2(node, "opEquals", lctx, rctx, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  8908. if( r == 0 )
  8909. {
  8910. // Try again by switching the order of the operands
  8911. r = CompileOverloadedDualOperator2(node, "opEquals", rctx, lctx, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  8912. }
  8913. if( r == 1 )
  8914. {
  8915. if( token == ttNotEqual )
  8916. ctx->bc.InstrSHORT(asBC_NOT, ctx->type.stackOffset);
  8917. // Success, don't continue
  8918. return true;
  8919. }
  8920. else if( r < 0 )
  8921. {
  8922. // Compiler error, don't continue
  8923. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  8924. return true;
  8925. }
  8926. }
  8927. if( token == ttEqual ||
  8928. token == ttNotEqual ||
  8929. token == ttLessThan ||
  8930. token == ttLessThanOrEqual ||
  8931. token == ttGreaterThan ||
  8932. token == ttGreaterThanOrEqual )
  8933. {
  8934. bool swappedOrder = false;
  8935. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  8936. // Find the matching opCmp method
  8937. int r = CompileOverloadedDualOperator2(node, "opCmp", lctx, rctx, ctx, true, asCDataType::CreatePrimitive(ttInt, false));
  8938. if( r == 0 )
  8939. {
  8940. // Try again by switching the order of the operands
  8941. swappedOrder = true;
  8942. r = CompileOverloadedDualOperator2(node, "opCmp", rctx, lctx, ctx, true, asCDataType::CreatePrimitive(ttInt, false));
  8943. }
  8944. if( r == 1 )
  8945. {
  8946. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  8947. int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, false), true);
  8948. ctx->bc.InstrW_DW(asBC_CMPIi, ctx->type.stackOffset, 0);
  8949. if( token == ttEqual )
  8950. ctx->bc.Instr(asBC_TZ);
  8951. else if( token == ttNotEqual )
  8952. ctx->bc.Instr(asBC_TNZ);
  8953. else if( (token == ttLessThan && !swappedOrder) ||
  8954. (token == ttGreaterThan && swappedOrder) )
  8955. ctx->bc.Instr(asBC_TS);
  8956. else if( (token == ttLessThanOrEqual && !swappedOrder) ||
  8957. (token == ttGreaterThanOrEqual && swappedOrder) )
  8958. ctx->bc.Instr(asBC_TNP);
  8959. else if( (token == ttGreaterThan && !swappedOrder) ||
  8960. (token == ttLessThan && swappedOrder) )
  8961. ctx->bc.Instr(asBC_TP);
  8962. else if( (token == ttGreaterThanOrEqual && !swappedOrder) ||
  8963. (token == ttLessThanOrEqual && swappedOrder) )
  8964. ctx->bc.Instr(asBC_TNS);
  8965. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  8966. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, false), a, true);
  8967. // Success, don't continue
  8968. return true;
  8969. }
  8970. else if( r < 0 )
  8971. {
  8972. // Compiler error, don't continue
  8973. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  8974. return true;
  8975. }
  8976. }
  8977. // The rest of the operators are not commutative, and doesn't require specific return type
  8978. const char *op = 0, *op_r = 0;
  8979. switch( token )
  8980. {
  8981. case ttPlus: op = "opAdd"; op_r = "opAdd_r"; break;
  8982. case ttMinus: op = "opSub"; op_r = "opSub_r"; break;
  8983. case ttStar: op = "opMul"; op_r = "opMul_r"; break;
  8984. case ttSlash: op = "opDiv"; op_r = "opDiv_r"; break;
  8985. case ttPercent: op = "opMod"; op_r = "opMod_r"; break;
  8986. case ttBitOr: op = "opOr"; op_r = "opOr_r"; break;
  8987. case ttAmp: op = "opAnd"; op_r = "opAnd_r"; break;
  8988. case ttBitXor: op = "opXor"; op_r = "opXor_r"; break;
  8989. case ttBitShiftLeft: op = "opShl"; op_r = "opShl_r"; break;
  8990. case ttBitShiftRight: op = "opShr"; op_r = "opShr_r"; break;
  8991. case ttBitShiftRightArith: op = "opUShr"; op_r = "opUShr_r"; break;
  8992. }
  8993. // TODO: Might be interesting to support a concatenation operator, e.g. ~
  8994. if( op && op_r )
  8995. {
  8996. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  8997. // Find the matching operator method
  8998. int r = CompileOverloadedDualOperator2(node, op, lctx, rctx, ctx);
  8999. if( r == 0 )
  9000. {
  9001. // Try again by switching the order of the operands, and using the reversed operator
  9002. r = CompileOverloadedDualOperator2(node, op_r, rctx, lctx, ctx);
  9003. }
  9004. if( r == 1 )
  9005. {
  9006. // Success, don't continue
  9007. return true;
  9008. }
  9009. else if( r < 0 )
  9010. {
  9011. // Compiler error, don't continue
  9012. ctx->type.SetDummy();
  9013. return true;
  9014. }
  9015. }
  9016. // Assignment operators
  9017. op = 0;
  9018. switch( token )
  9019. {
  9020. case ttAssignment: op = "opAssign"; break;
  9021. case ttAddAssign: op = "opAddAssign"; break;
  9022. case ttSubAssign: op = "opSubAssign"; break;
  9023. case ttMulAssign: op = "opMulAssign"; break;
  9024. case ttDivAssign: op = "opDivAssign"; break;
  9025. case ttModAssign: op = "opModAssign"; break;
  9026. case ttOrAssign: op = "opOrAssign"; break;
  9027. case ttAndAssign: op = "opAndAssign"; break;
  9028. case ttXorAssign: op = "opXorAssign"; break;
  9029. case ttShiftLeftAssign: op = "opShlAssign"; break;
  9030. case ttShiftRightLAssign: op = "opShrAssign"; break;
  9031. case ttShiftRightAAssign: op = "opUShrAssign"; break;
  9032. }
  9033. if( op )
  9034. {
  9035. if( builder->engine->ep.disallowValueAssignForRefType &&
  9036. lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->flags & asOBJ_REF) && !(lctx->type.dataType.GetObjectType()->flags & asOBJ_SCOPED) )
  9037. {
  9038. if( token == ttAssignment )
  9039. Error(TXT_DISALLOW_ASSIGN_ON_REF_TYPE, node);
  9040. else
  9041. Error(TXT_DISALLOW_COMPOUND_ASSIGN_ON_REF_TYPE, node);
  9042. // Set a dummy output
  9043. ctx->type.Set(lctx->type.dataType);
  9044. return true;
  9045. }
  9046. // TODO: Shouldn't accept const lvalue with the assignment operators
  9047. // Find the matching operator method
  9048. int r = CompileOverloadedDualOperator2(node, op, lctx, rctx, ctx);
  9049. if( r == 1 )
  9050. {
  9051. // Success, don't continue
  9052. return true;
  9053. }
  9054. else if( r < 0 )
  9055. {
  9056. // Compiler error, don't continue
  9057. ctx->type.SetDummy();
  9058. return true;
  9059. }
  9060. }
  9061. // No suitable operator was found
  9062. return false;
  9063. }
  9064. // Returns negative on compile error
  9065. // zero on no matching operator
  9066. // one on matching operator
  9067. int asCCompiler::CompileOverloadedDualOperator2(asCScriptNode *node, const char *methodName, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx, bool specificReturn, const asCDataType &returnType)
  9068. {
  9069. // Find the matching method
  9070. if( lctx->type.dataType.IsObject() &&
  9071. (!lctx->type.isExplicitHandle ||
  9072. lctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE) )
  9073. {
  9074. asUINT n;
  9075. // Is the left value a const?
  9076. bool isConst = false;
  9077. if( lctx->type.dataType.IsObjectHandle() )
  9078. isConst = lctx->type.dataType.IsHandleToConst();
  9079. else
  9080. isConst = lctx->type.dataType.IsReadOnly();
  9081. asCArray<int> funcs;
  9082. asCObjectType *ot = lctx->type.dataType.GetObjectType();
  9083. for( n = 0; n < ot->methods.GetLength(); n++ )
  9084. {
  9085. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  9086. if( func->name == methodName &&
  9087. (!specificReturn || func->returnType == returnType) &&
  9088. func->parameterTypes.GetLength() == 1 &&
  9089. (!isConst || func->isReadOnly) )
  9090. {
  9091. // Make sure the method is accessible by the module
  9092. if( builder->module->accessMask & func->accessMask )
  9093. {
  9094. funcs.PushLast(func->id);
  9095. }
  9096. }
  9097. }
  9098. // Which is the best matching function?
  9099. asCArray<asSOverloadCandidate> tempFuncs;
  9100. MatchArgument(funcs, tempFuncs, rctx, 0);
  9101. // Find the lowest cost operator(s)
  9102. asCArray<int> ops;
  9103. asUINT bestCost = asUINT(-1);
  9104. for( n = 0; n < tempFuncs.GetLength(); ++n )
  9105. {
  9106. asUINT cost = tempFuncs[n].cost;
  9107. if( cost < bestCost )
  9108. {
  9109. ops.SetLength(0);
  9110. bestCost = cost;
  9111. }
  9112. if( cost == bestCost )
  9113. ops.PushLast(tempFuncs[n].funcId);
  9114. }
  9115. // If the object is not const, then we need to prioritize non-const methods
  9116. if( !isConst )
  9117. FilterConst(ops);
  9118. // Did we find an operator?
  9119. if( ops.GetLength() == 1 )
  9120. {
  9121. // Process the lctx expression as get accessor
  9122. ProcessPropertyGetAccessor(lctx, node);
  9123. // Merge the bytecode so that it forms lvalue.methodName(rvalue)
  9124. asCTypeInfo objType = lctx->type;
  9125. asCArray<asSExprContext *> args;
  9126. args.PushLast(rctx);
  9127. MergeExprBytecode(ctx, lctx);
  9128. ctx->type = lctx->type;
  9129. MakeFunctionCall(ctx, ops[0], objType.dataType.GetObjectType(), args, node);
  9130. // If the method returned a reference, then we can't release the original
  9131. // object yet, because the reference may be to a member of it
  9132. if( !objType.isTemporary ||
  9133. !(ctx->type.dataType.IsReference() || (ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle())) ||
  9134. ctx->type.isVariable ) // If the resulting type is a variable, then the reference is not to a member
  9135. {
  9136. // As the index operator didn't return a reference to a
  9137. // member we can release the original object now
  9138. ReleaseTemporaryVariable(objType, &ctx->bc);
  9139. }
  9140. // Found matching operator
  9141. return 1;
  9142. }
  9143. else if( ops.GetLength() > 1 )
  9144. {
  9145. Error(TXT_MORE_THAN_ONE_MATCHING_OP, node);
  9146. PrintMatchingFuncs(ops, node);
  9147. ctx->type.SetDummy();
  9148. // Compiler error
  9149. return -1;
  9150. }
  9151. }
  9152. // No matching operator
  9153. return 0;
  9154. }
  9155. void asCCompiler::MakeFunctionCall(asSExprContext *ctx, int funcId, asCObjectType *objectType, asCArray<asSExprContext*> &args, asCScriptNode * /*node*/, bool useVariable, int stackOffset, int funcPtrVar)
  9156. {
  9157. if( objectType )
  9158. {
  9159. Dereference(ctx, true);
  9160. // This following warning was removed as there may be valid reasons
  9161. // for calling non-const methods on temporary objects, and we shouldn't
  9162. // warn when there is no way of removing the warning.
  9163. /*
  9164. // Warn if the method is non-const and the object is temporary
  9165. // since the changes will be lost when the object is destroyed.
  9166. // If the object is accessed through a handle, then it is assumed
  9167. // the object is not temporary, even though the handle is.
  9168. if( ctx->type.isTemporary &&
  9169. !ctx->type.dataType.IsObjectHandle() &&
  9170. !engine->scriptFunctions[funcId]->isReadOnly )
  9171. {
  9172. Warning("A non-const method is called on temporary object. Changes to the object may be lost.", node);
  9173. Information(engine->scriptFunctions[funcId]->GetDeclaration(), node);
  9174. }
  9175. */ }
  9176. asCByteCode objBC(engine);
  9177. objBC.AddCode(&ctx->bc);
  9178. PrepareFunctionCall(funcId, &ctx->bc, args);
  9179. // Verify if any of the args variable offsets are used in the other code.
  9180. // If they are exchange the offset for a new one
  9181. asUINT n;
  9182. for( n = 0; n < args.GetLength(); n++ )
  9183. {
  9184. if( args[n]->type.isTemporary && objBC.IsVarUsed(args[n]->type.stackOffset) )
  9185. {
  9186. // Release the current temporary variable
  9187. ReleaseTemporaryVariable(args[n]->type, 0);
  9188. asCDataType dt = args[n]->type.dataType;
  9189. dt.MakeReference(false);
  9190. int l = int(reservedVariables.GetLength());
  9191. objBC.GetVarsUsed(reservedVariables);
  9192. ctx->bc.GetVarsUsed(reservedVariables);
  9193. int newOffset = AllocateVariable(dt, true, IsVariableOnHeap(args[n]->type.stackOffset));
  9194. reservedVariables.SetLength(l);
  9195. asASSERT( IsVariableOnHeap(args[n]->type.stackOffset) == IsVariableOnHeap(newOffset) );
  9196. ctx->bc.ExchangeVar(args[n]->type.stackOffset, newOffset);
  9197. args[n]->type.stackOffset = (short)newOffset;
  9198. args[n]->type.isTemporary = true;
  9199. args[n]->type.isVariable = true;
  9200. }
  9201. }
  9202. // If the function will return a value type on the stack, then we must allocate space
  9203. // for that here and push the address on the stack as a hidden argument to the function
  9204. asCScriptFunction *func = builder->GetFunctionDescription(funcId);
  9205. if( func->DoesReturnOnStack() )
  9206. {
  9207. asASSERT(!useVariable);
  9208. useVariable = true;
  9209. stackOffset = AllocateVariable(func->returnType, true);
  9210. ctx->bc.InstrSHORT(asBC_PSF, short(stackOffset));
  9211. }
  9212. ctx->bc.AddCode(&objBC);
  9213. MoveArgsToStack(funcId, &ctx->bc, args, objectType ? true : false);
  9214. PerformFunctionCall(funcId, ctx, false, &args, 0, useVariable, stackOffset, funcPtrVar);
  9215. }
  9216. int asCCompiler::CompileOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  9217. {
  9218. // Don't allow any operators on expressions that take address of class method, but allow it on global functions
  9219. if( (lctx->IsClassMethod()) || (rctx->IsClassMethod()) )
  9220. {
  9221. Error(TXT_INVALID_OP_ON_METHOD, node);
  9222. return -1;
  9223. }
  9224. // Don't allow any operators on void expressions
  9225. if( lctx->type.IsVoidExpression() || rctx->type.IsVoidExpression() )
  9226. {
  9227. Error(TXT_VOID_CANT_BE_OPERAND, node);
  9228. return -1;
  9229. }
  9230. IsVariableInitialized(&lctx->type, node);
  9231. IsVariableInitialized(&rctx->type, node);
  9232. if( lctx->type.isExplicitHandle || rctx->type.isExplicitHandle ||
  9233. lctx->type.IsNullConstant() || rctx->type.IsNullConstant() ||
  9234. node->tokenType == ttIs || node->tokenType == ttNotIs )
  9235. {
  9236. CompileOperatorOnHandles(node, lctx, rctx, ctx);
  9237. return 0;
  9238. }
  9239. else
  9240. {
  9241. // Compile an overloaded operator for the two operands
  9242. if( CompileOverloadedDualOperator(node, lctx, rctx, ctx) )
  9243. return 0;
  9244. // If both operands are objects, then we shouldn't continue
  9245. if( lctx->type.dataType.IsObject() && rctx->type.dataType.IsObject() )
  9246. {
  9247. asCString str;
  9248. str.Format(TXT_NO_MATCHING_OP_FOUND_FOR_TYPES_s_AND_s, lctx->type.dataType.Format().AddressOf(), rctx->type.dataType.Format().AddressOf());
  9249. Error(str, node);
  9250. ctx->type.SetDummy();
  9251. return -1;
  9252. }
  9253. // Process the property get accessors (if any)
  9254. ProcessPropertyGetAccessor(lctx, node);
  9255. ProcessPropertyGetAccessor(rctx, node);
  9256. // Make sure we have two variables or constants
  9257. if( lctx->type.dataType.IsReference() ) ConvertToVariableNotIn(lctx, rctx);
  9258. if( rctx->type.dataType.IsReference() ) ConvertToVariableNotIn(rctx, lctx);
  9259. // Make sure lctx doesn't end up with a variable used in rctx
  9260. if( lctx->type.isTemporary && rctx->bc.IsVarUsed(lctx->type.stackOffset) )
  9261. {
  9262. int offset = AllocateVariableNotIn(lctx->type.dataType, true, false, rctx);
  9263. rctx->bc.ExchangeVar(lctx->type.stackOffset, offset);
  9264. ReleaseTemporaryVariable(offset, 0);
  9265. }
  9266. // Math operators
  9267. // + - * / % += -= *= /= %=
  9268. int op = node->tokenType;
  9269. if( op == ttPlus || op == ttAddAssign ||
  9270. op == ttMinus || op == ttSubAssign ||
  9271. op == ttStar || op == ttMulAssign ||
  9272. op == ttSlash || op == ttDivAssign ||
  9273. op == ttPercent || op == ttModAssign )
  9274. {
  9275. CompileMathOperator(node, lctx, rctx, ctx);
  9276. return 0;
  9277. }
  9278. // Bitwise operators
  9279. // << >> >>> & | ^ <<= >>= >>>= &= |= ^=
  9280. if( op == ttAmp || op == ttAndAssign ||
  9281. op == ttBitOr || op == ttOrAssign ||
  9282. op == ttBitXor || op == ttXorAssign ||
  9283. op == ttBitShiftLeft || op == ttShiftLeftAssign ||
  9284. op == ttBitShiftRight || op == ttShiftRightLAssign ||
  9285. op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  9286. {
  9287. CompileBitwiseOperator(node, lctx, rctx, ctx);
  9288. return 0;
  9289. }
  9290. // Comparison operators
  9291. // == != < > <= >=
  9292. if( op == ttEqual || op == ttNotEqual ||
  9293. op == ttLessThan || op == ttLessThanOrEqual ||
  9294. op == ttGreaterThan || op == ttGreaterThanOrEqual )
  9295. {
  9296. CompileComparisonOperator(node, lctx, rctx, ctx);
  9297. return 0;
  9298. }
  9299. // Boolean operators
  9300. // && || ^^
  9301. if( op == ttAnd || op == ttOr || op == ttXor )
  9302. {
  9303. CompileBooleanOperator(node, lctx, rctx, ctx);
  9304. return 0;
  9305. }
  9306. }
  9307. asASSERT(false);
  9308. return -1;
  9309. }
  9310. void asCCompiler::ConvertToTempVariableNotIn(asSExprContext *ctx, asSExprContext *exclude)
  9311. {
  9312. int l = int(reservedVariables.GetLength());
  9313. if( exclude ) exclude->bc.GetVarsUsed(reservedVariables);
  9314. ConvertToTempVariable(ctx);
  9315. reservedVariables.SetLength(l);
  9316. }
  9317. void asCCompiler::ConvertToTempVariable(asSExprContext *ctx)
  9318. {
  9319. // This is only used for primitive types and null handles
  9320. asASSERT( ctx->type.dataType.IsPrimitive() || ctx->type.dataType.IsNullHandle() );
  9321. ConvertToVariable(ctx);
  9322. if( !ctx->type.isTemporary )
  9323. {
  9324. if( ctx->type.dataType.IsPrimitive() )
  9325. {
  9326. // Copy the variable to a temporary variable
  9327. int offset = AllocateVariable(ctx->type.dataType, true);
  9328. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  9329. ctx->bc.InstrW_W(asBC_CpyVtoV4, offset, ctx->type.stackOffset);
  9330. else
  9331. ctx->bc.InstrW_W(asBC_CpyVtoV8, offset, ctx->type.stackOffset);
  9332. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  9333. }
  9334. else
  9335. {
  9336. // We should never get here
  9337. asASSERT(false);
  9338. }
  9339. }
  9340. }
  9341. void asCCompiler::ConvertToVariable(asSExprContext *ctx)
  9342. {
  9343. // We should never get here while the context is still an unprocessed property accessor
  9344. asASSERT(ctx->property_get == 0 && ctx->property_set == 0);
  9345. int offset;
  9346. if( !ctx->type.isVariable &&
  9347. (ctx->type.dataType.IsObjectHandle() ||
  9348. (ctx->type.dataType.IsObject() && ctx->type.dataType.SupportHandles())) )
  9349. {
  9350. offset = AllocateVariable(ctx->type.dataType, true);
  9351. if( ctx->type.IsNullConstant() )
  9352. {
  9353. if( ctx->bc.GetLastInstr() == asBC_PshNull )
  9354. ctx->bc.Instr(asBC_PopPtr); // Pop the null constant pushed onto the stack
  9355. ctx->bc.InstrSHORT(asBC_ClrVPtr, (short)offset);
  9356. }
  9357. else
  9358. {
  9359. // Copy the object handle to a variable
  9360. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  9361. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetObjectType());
  9362. ctx->bc.Instr(asBC_PopPtr);
  9363. }
  9364. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  9365. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  9366. ctx->type.dataType.MakeHandle(true);
  9367. }
  9368. else if( (!ctx->type.isVariable || ctx->type.dataType.IsReference()) &&
  9369. ctx->type.dataType.IsPrimitive() )
  9370. {
  9371. if( ctx->type.isConstant )
  9372. {
  9373. offset = AllocateVariable(ctx->type.dataType, true);
  9374. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  9375. ctx->bc.InstrSHORT_B(asBC_SetV1, (short)offset, ctx->type.byteValue);
  9376. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  9377. ctx->bc.InstrSHORT_W(asBC_SetV2, (short)offset, ctx->type.wordValue);
  9378. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 )
  9379. ctx->bc.InstrSHORT_DW(asBC_SetV4, (short)offset, ctx->type.dwordValue);
  9380. else
  9381. ctx->bc.InstrSHORT_QW(asBC_SetV8, (short)offset, ctx->type.qwordValue);
  9382. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  9383. return;
  9384. }
  9385. else
  9386. {
  9387. asASSERT(ctx->type.dataType.IsPrimitive());
  9388. asASSERT(ctx->type.dataType.IsReference());
  9389. ctx->type.dataType.MakeReference(false);
  9390. offset = AllocateVariable(ctx->type.dataType, true);
  9391. // Read the value from the address in the register directly into the variable
  9392. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  9393. ctx->bc.InstrSHORT(asBC_RDR1, (short)offset);
  9394. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  9395. ctx->bc.InstrSHORT(asBC_RDR2, (short)offset);
  9396. else if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  9397. ctx->bc.InstrSHORT(asBC_RDR4, (short)offset);
  9398. else
  9399. ctx->bc.InstrSHORT(asBC_RDR8, (short)offset);
  9400. }
  9401. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  9402. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  9403. }
  9404. }
  9405. void asCCompiler::ConvertToVariableNotIn(asSExprContext *ctx, asSExprContext *exclude)
  9406. {
  9407. int l = int(reservedVariables.GetLength());
  9408. if( exclude ) exclude->bc.GetVarsUsed(reservedVariables);
  9409. ConvertToVariable(ctx);
  9410. reservedVariables.SetLength(l);
  9411. }
  9412. void asCCompiler::CompileMathOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  9413. {
  9414. // TODO: If a constant is only using 32bits, then a 32bit operation is preferred
  9415. // TODO: clean up: This initial part is identical to CompileComparisonOperator. Make a common function out of it
  9416. // Implicitly convert the operands to a number type
  9417. asCDataType to;
  9418. // If either operand is a non-primitive then use the primitive type
  9419. if( !lctx->type.dataType.IsPrimitive() )
  9420. to.SetTokenType(rctx->type.dataType.GetTokenType());
  9421. else if( !rctx->type.dataType.IsPrimitive() )
  9422. to.SetTokenType(lctx->type.dataType.GetTokenType());
  9423. else if( lctx->type.dataType.IsDoubleType() || rctx->type.dataType.IsDoubleType() )
  9424. to.SetTokenType(ttDouble);
  9425. else if( lctx->type.dataType.IsFloatType() || rctx->type.dataType.IsFloatType() )
  9426. to.SetTokenType(ttFloat);
  9427. else if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 || rctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  9428. {
  9429. // Convert to int64 if both are signed or if one is non-constant and signed
  9430. if( (lctx->type.dataType.IsIntegerType() && rctx->type.dataType.IsIntegerType()) ||
  9431. (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) ||
  9432. (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) )
  9433. to.SetTokenType(ttInt64);
  9434. else
  9435. to.SetTokenType(ttUInt64);
  9436. }
  9437. else
  9438. {
  9439. // Convert to int32 if both are signed or if one is non-constant and signed
  9440. if( (lctx->type.dataType.IsIntegerType() && rctx->type.dataType.IsIntegerType()) ||
  9441. (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) ||
  9442. (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) )
  9443. to.SetTokenType(ttInt);
  9444. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  9445. to.SetTokenType(ttUInt);
  9446. else if( lctx->type.dataType.IsBooleanType() || rctx->type.dataType.IsBooleanType() )
  9447. to.SetTokenType(ttBool);
  9448. }
  9449. // If doing an operation with double constant and float variable, the constant should be converted to float
  9450. if( (lctx->type.isConstant && lctx->type.dataType.IsDoubleType() && !rctx->type.isConstant && rctx->type.dataType.IsFloatType()) ||
  9451. (rctx->type.isConstant && rctx->type.dataType.IsDoubleType() && !lctx->type.isConstant && lctx->type.dataType.IsFloatType()) )
  9452. to.SetTokenType(ttFloat);
  9453. // Do the actual conversion
  9454. int l = int(reservedVariables.GetLength());
  9455. rctx->bc.GetVarsUsed(reservedVariables);
  9456. lctx->bc.GetVarsUsed(reservedVariables);
  9457. if( lctx->type.dataType.IsReference() )
  9458. ConvertToVariable(lctx);
  9459. if( rctx->type.dataType.IsReference() )
  9460. ConvertToVariable(rctx);
  9461. if( to.IsPrimitive() )
  9462. {
  9463. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true);
  9464. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true);
  9465. }
  9466. reservedVariables.SetLength(l);
  9467. // Verify that the conversion was successful
  9468. if( !lctx->type.dataType.IsIntegerType() &&
  9469. !lctx->type.dataType.IsUnsignedType() &&
  9470. !lctx->type.dataType.IsFloatType() &&
  9471. !lctx->type.dataType.IsDoubleType() )
  9472. {
  9473. asCString str;
  9474. str.Format(TXT_NO_CONVERSION_s_TO_MATH_TYPE, lctx->type.dataType.Format().AddressOf());
  9475. Error(str, node);
  9476. ctx->type.SetDummy();
  9477. return;
  9478. }
  9479. if( !rctx->type.dataType.IsIntegerType() &&
  9480. !rctx->type.dataType.IsUnsignedType() &&
  9481. !rctx->type.dataType.IsFloatType() &&
  9482. !rctx->type.dataType.IsDoubleType() )
  9483. {
  9484. asCString str;
  9485. str.Format(TXT_NO_CONVERSION_s_TO_MATH_TYPE, rctx->type.dataType.Format().AddressOf());
  9486. Error(str, node);
  9487. ctx->type.SetDummy();
  9488. return;
  9489. }
  9490. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  9491. // Verify if we are dividing with a constant zero
  9492. int op = node->tokenType;
  9493. if( rctx->type.isConstant && rctx->type.qwordValue == 0 &&
  9494. (op == ttSlash || op == ttDivAssign ||
  9495. op == ttPercent || op == ttModAssign) )
  9496. {
  9497. Error(TXT_DIVIDE_BY_ZERO, node);
  9498. }
  9499. if( !isConstant )
  9500. {
  9501. ConvertToVariableNotIn(lctx, rctx);
  9502. ConvertToVariableNotIn(rctx, lctx);
  9503. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  9504. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  9505. if( op == ttAddAssign || op == ttSubAssign ||
  9506. op == ttMulAssign || op == ttDivAssign ||
  9507. op == ttModAssign )
  9508. {
  9509. // Merge the operands in the different order so that they are evaluated correctly
  9510. MergeExprBytecode(ctx, rctx);
  9511. MergeExprBytecode(ctx, lctx);
  9512. // We must not process the deferred parameters yet, as
  9513. // it may overwrite the lvalue kept in the register
  9514. }
  9515. else
  9516. {
  9517. MergeExprBytecode(ctx, lctx);
  9518. MergeExprBytecode(ctx, rctx);
  9519. ProcessDeferredParams(ctx);
  9520. }
  9521. asEBCInstr instruction = asBC_ADDi;
  9522. if( lctx->type.dataType.IsIntegerType() ||
  9523. lctx->type.dataType.IsUnsignedType() )
  9524. {
  9525. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  9526. {
  9527. if( op == ttPlus || op == ttAddAssign )
  9528. instruction = asBC_ADDi;
  9529. else if( op == ttMinus || op == ttSubAssign )
  9530. instruction = asBC_SUBi;
  9531. else if( op == ttStar || op == ttMulAssign )
  9532. instruction = asBC_MULi;
  9533. else if( op == ttSlash || op == ttDivAssign )
  9534. {
  9535. if( lctx->type.dataType.IsIntegerType() )
  9536. instruction = asBC_DIVi;
  9537. else
  9538. instruction = asBC_DIVu;
  9539. }
  9540. else if( op == ttPercent || op == ttModAssign )
  9541. {
  9542. if( lctx->type.dataType.IsIntegerType() )
  9543. instruction = asBC_MODi;
  9544. else
  9545. instruction = asBC_MODu;
  9546. }
  9547. }
  9548. else
  9549. {
  9550. if( op == ttPlus || op == ttAddAssign )
  9551. instruction = asBC_ADDi64;
  9552. else if( op == ttMinus || op == ttSubAssign )
  9553. instruction = asBC_SUBi64;
  9554. else if( op == ttStar || op == ttMulAssign )
  9555. instruction = asBC_MULi64;
  9556. else if( op == ttSlash || op == ttDivAssign )
  9557. {
  9558. if( lctx->type.dataType.IsIntegerType() )
  9559. instruction = asBC_DIVi64;
  9560. else
  9561. instruction = asBC_DIVu64;
  9562. }
  9563. else if( op == ttPercent || op == ttModAssign )
  9564. {
  9565. if( lctx->type.dataType.IsIntegerType() )
  9566. instruction = asBC_MODi64;
  9567. else
  9568. instruction = asBC_MODu64;
  9569. }
  9570. }
  9571. }
  9572. else if( lctx->type.dataType.IsFloatType() )
  9573. {
  9574. if( op == ttPlus || op == ttAddAssign )
  9575. instruction = asBC_ADDf;
  9576. else if( op == ttMinus || op == ttSubAssign )
  9577. instruction = asBC_SUBf;
  9578. else if( op == ttStar || op == ttMulAssign )
  9579. instruction = asBC_MULf;
  9580. else if( op == ttSlash || op == ttDivAssign )
  9581. instruction = asBC_DIVf;
  9582. else if( op == ttPercent || op == ttModAssign )
  9583. instruction = asBC_MODf;
  9584. }
  9585. else if( lctx->type.dataType.IsDoubleType() )
  9586. {
  9587. if( op == ttPlus || op == ttAddAssign )
  9588. instruction = asBC_ADDd;
  9589. else if( op == ttMinus || op == ttSubAssign )
  9590. instruction = asBC_SUBd;
  9591. else if( op == ttStar || op == ttMulAssign )
  9592. instruction = asBC_MULd;
  9593. else if( op == ttSlash || op == ttDivAssign )
  9594. instruction = asBC_DIVd;
  9595. else if( op == ttPercent || op == ttModAssign )
  9596. instruction = asBC_MODd;
  9597. }
  9598. else
  9599. {
  9600. // Shouldn't be possible
  9601. asASSERT(false);
  9602. }
  9603. // Do the operation
  9604. int a = AllocateVariable(lctx->type.dataType, true);
  9605. int b = lctx->type.stackOffset;
  9606. int c = rctx->type.stackOffset;
  9607. ctx->bc.InstrW_W_W(instruction, a, b, c);
  9608. ctx->type.SetVariable(lctx->type.dataType, a, true);
  9609. }
  9610. else
  9611. {
  9612. // Both values are constants
  9613. if( lctx->type.dataType.IsIntegerType() ||
  9614. lctx->type.dataType.IsUnsignedType() )
  9615. {
  9616. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  9617. {
  9618. int v = 0;
  9619. if( op == ttPlus )
  9620. v = lctx->type.intValue + rctx->type.intValue;
  9621. else if( op == ttMinus )
  9622. v = lctx->type.intValue - rctx->type.intValue;
  9623. else if( op == ttStar )
  9624. v = lctx->type.intValue * rctx->type.intValue;
  9625. else if( op == ttSlash )
  9626. {
  9627. // TODO: Should probably report an error, rather than silently convert the value to 0
  9628. if( rctx->type.intValue == 0 || (rctx->type.intValue == -1 && lctx->type.dwordValue == 0x80000000) )
  9629. v = 0;
  9630. else
  9631. if( lctx->type.dataType.IsIntegerType() )
  9632. v = lctx->type.intValue / rctx->type.intValue;
  9633. else
  9634. v = lctx->type.dwordValue / rctx->type.dwordValue;
  9635. }
  9636. else if( op == ttPercent )
  9637. {
  9638. // TODO: Should probably report an error, rather than silently convert the value to 0
  9639. if( rctx->type.intValue == 0 || (rctx->type.intValue == -1 && lctx->type.dwordValue == 0x80000000) )
  9640. v = 0;
  9641. else
  9642. if( lctx->type.dataType.IsIntegerType() )
  9643. v = lctx->type.intValue % rctx->type.intValue;
  9644. else
  9645. v = lctx->type.dwordValue % rctx->type.dwordValue;
  9646. }
  9647. ctx->type.SetConstantDW(lctx->type.dataType, v);
  9648. // If the right value is greater than the left value in a minus operation, then we need to convert the type to int
  9649. if( lctx->type.dataType.GetTokenType() == ttUInt && op == ttMinus && lctx->type.intValue < rctx->type.intValue )
  9650. ctx->type.dataType.SetTokenType(ttInt);
  9651. }
  9652. else
  9653. {
  9654. asQWORD v = 0;
  9655. if( op == ttPlus )
  9656. v = lctx->type.qwordValue + rctx->type.qwordValue;
  9657. else if( op == ttMinus )
  9658. v = lctx->type.qwordValue - rctx->type.qwordValue;
  9659. else if( op == ttStar )
  9660. v = lctx->type.qwordValue * rctx->type.qwordValue;
  9661. else if( op == ttSlash )
  9662. {
  9663. // TODO: Should probably report an error, rather than silently convert the value to 0
  9664. if( rctx->type.qwordValue == 0 || (rctx->type.qwordValue == asQWORD(-1) && lctx->type.qwordValue == (asQWORD(1)<<63)) )
  9665. v = 0;
  9666. else
  9667. if( lctx->type.dataType.IsIntegerType() )
  9668. v = asINT64(lctx->type.qwordValue) / asINT64(rctx->type.qwordValue);
  9669. else
  9670. v = lctx->type.qwordValue / rctx->type.qwordValue;
  9671. }
  9672. else if( op == ttPercent )
  9673. {
  9674. // TODO: Should probably report an error, rather than silently convert the value to 0
  9675. if( rctx->type.qwordValue == 0 || (rctx->type.qwordValue == asQWORD(-1) && lctx->type.qwordValue == (asQWORD(1)<<63)) )
  9676. v = 0;
  9677. else
  9678. if( lctx->type.dataType.IsIntegerType() )
  9679. v = asINT64(lctx->type.qwordValue) % asINT64(rctx->type.qwordValue);
  9680. else
  9681. v = lctx->type.qwordValue % rctx->type.qwordValue;
  9682. }
  9683. ctx->type.SetConstantQW(lctx->type.dataType, v);
  9684. // If the right value is greater than the left value in a minus operation, then we need to convert the type to int
  9685. if( lctx->type.dataType.GetTokenType() == ttUInt64 && op == ttMinus && lctx->type.qwordValue < rctx->type.qwordValue )
  9686. ctx->type.dataType.SetTokenType(ttInt64);
  9687. }
  9688. }
  9689. else if( lctx->type.dataType.IsFloatType() )
  9690. {
  9691. float v = 0.0f;
  9692. if( op == ttPlus )
  9693. v = lctx->type.floatValue + rctx->type.floatValue;
  9694. else if( op == ttMinus )
  9695. v = lctx->type.floatValue - rctx->type.floatValue;
  9696. else if( op == ttStar )
  9697. v = lctx->type.floatValue * rctx->type.floatValue;
  9698. else if( op == ttSlash )
  9699. {
  9700. if( rctx->type.floatValue == 0 )
  9701. v = 0;
  9702. else
  9703. v = lctx->type.floatValue / rctx->type.floatValue;
  9704. }
  9705. else if( op == ttPercent )
  9706. {
  9707. if( rctx->type.floatValue == 0 )
  9708. v = 0;
  9709. else
  9710. v = fmodf(lctx->type.floatValue, rctx->type.floatValue);
  9711. }
  9712. ctx->type.SetConstantF(lctx->type.dataType, v);
  9713. }
  9714. else if( lctx->type.dataType.IsDoubleType() )
  9715. {
  9716. double v = 0.0;
  9717. if( op == ttPlus )
  9718. v = lctx->type.doubleValue + rctx->type.doubleValue;
  9719. else if( op == ttMinus )
  9720. v = lctx->type.doubleValue - rctx->type.doubleValue;
  9721. else if( op == ttStar )
  9722. v = lctx->type.doubleValue * rctx->type.doubleValue;
  9723. else if( op == ttSlash )
  9724. {
  9725. if( rctx->type.doubleValue == 0 )
  9726. v = 0;
  9727. else
  9728. v = lctx->type.doubleValue / rctx->type.doubleValue;
  9729. }
  9730. else if( op == ttPercent )
  9731. {
  9732. if( rctx->type.doubleValue == 0 )
  9733. v = 0;
  9734. else
  9735. v = fmod(lctx->type.doubleValue, rctx->type.doubleValue);
  9736. }
  9737. ctx->type.SetConstantD(lctx->type.dataType, v);
  9738. }
  9739. else
  9740. {
  9741. // Shouldn't be possible
  9742. asASSERT(false);
  9743. }
  9744. }
  9745. }
  9746. void asCCompiler::CompileBitwiseOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  9747. {
  9748. // TODO: If a constant is only using 32bits, then a 32bit operation is preferred
  9749. int op = node->tokenType;
  9750. if( op == ttAmp || op == ttAndAssign ||
  9751. op == ttBitOr || op == ttOrAssign ||
  9752. op == ttBitXor || op == ttXorAssign )
  9753. {
  9754. // Convert left hand operand to integer if it's not already one
  9755. asCDataType to;
  9756. if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 ||
  9757. rctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  9758. to.SetTokenType(ttUInt64);
  9759. else
  9760. to.SetTokenType(ttUInt);
  9761. // Do the actual conversion
  9762. int l = int(reservedVariables.GetLength());
  9763. rctx->bc.GetVarsUsed(reservedVariables);
  9764. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true);
  9765. reservedVariables.SetLength(l);
  9766. // Verify that the conversion was successful
  9767. if( !lctx->type.dataType.IsUnsignedType() )
  9768. {
  9769. asCString str;
  9770. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  9771. Error(str, node);
  9772. }
  9773. // Convert right hand operand to same type as left hand operand
  9774. l = int(reservedVariables.GetLength());
  9775. lctx->bc.GetVarsUsed(reservedVariables);
  9776. ImplicitConversion(rctx, lctx->type.dataType, node, asIC_IMPLICIT_CONV, true);
  9777. reservedVariables.SetLength(l);
  9778. if( !rctx->type.dataType.IsEqualExceptRef(lctx->type.dataType) )
  9779. {
  9780. asCString str;
  9781. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format().AddressOf(), lctx->type.dataType.Format().AddressOf());
  9782. Error(str, node);
  9783. }
  9784. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  9785. if( !isConstant )
  9786. {
  9787. ConvertToVariableNotIn(lctx, rctx);
  9788. ConvertToVariableNotIn(rctx, lctx);
  9789. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  9790. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  9791. if( op == ttAndAssign || op == ttOrAssign || op == ttXorAssign )
  9792. {
  9793. // Compound assignments execute the right hand value first
  9794. MergeExprBytecode(ctx, rctx);
  9795. MergeExprBytecode(ctx, lctx);
  9796. }
  9797. else
  9798. {
  9799. MergeExprBytecode(ctx, lctx);
  9800. MergeExprBytecode(ctx, rctx);
  9801. }
  9802. ProcessDeferredParams(ctx);
  9803. asEBCInstr instruction = asBC_BAND;
  9804. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  9805. {
  9806. if( op == ttAmp || op == ttAndAssign )
  9807. instruction = asBC_BAND;
  9808. else if( op == ttBitOr || op == ttOrAssign )
  9809. instruction = asBC_BOR;
  9810. else if( op == ttBitXor || op == ttXorAssign )
  9811. instruction = asBC_BXOR;
  9812. }
  9813. else
  9814. {
  9815. if( op == ttAmp || op == ttAndAssign )
  9816. instruction = asBC_BAND64;
  9817. else if( op == ttBitOr || op == ttOrAssign )
  9818. instruction = asBC_BOR64;
  9819. else if( op == ttBitXor || op == ttXorAssign )
  9820. instruction = asBC_BXOR64;
  9821. }
  9822. // Do the operation
  9823. int a = AllocateVariable(lctx->type.dataType, true);
  9824. int b = lctx->type.stackOffset;
  9825. int c = rctx->type.stackOffset;
  9826. ctx->bc.InstrW_W_W(instruction, a, b, c);
  9827. ctx->type.SetVariable(lctx->type.dataType, a, true);
  9828. }
  9829. else
  9830. {
  9831. if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  9832. {
  9833. asQWORD v = 0;
  9834. if( op == ttAmp )
  9835. v = lctx->type.qwordValue & rctx->type.qwordValue;
  9836. else if( op == ttBitOr )
  9837. v = lctx->type.qwordValue | rctx->type.qwordValue;
  9838. else if( op == ttBitXor )
  9839. v = lctx->type.qwordValue ^ rctx->type.qwordValue;
  9840. // Remember the result
  9841. ctx->type.SetConstantQW(lctx->type.dataType, v);
  9842. }
  9843. else
  9844. {
  9845. asDWORD v = 0;
  9846. if( op == ttAmp )
  9847. v = lctx->type.dwordValue & rctx->type.dwordValue;
  9848. else if( op == ttBitOr )
  9849. v = lctx->type.dwordValue | rctx->type.dwordValue;
  9850. else if( op == ttBitXor )
  9851. v = lctx->type.dwordValue ^ rctx->type.dwordValue;
  9852. // Remember the result
  9853. ctx->type.SetConstantDW(lctx->type.dataType, v);
  9854. }
  9855. }
  9856. }
  9857. else if( op == ttBitShiftLeft || op == ttShiftLeftAssign ||
  9858. op == ttBitShiftRight || op == ttShiftRightLAssign ||
  9859. op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  9860. {
  9861. // Don't permit object to primitive conversion, since we don't know which integer type is the correct one
  9862. if( lctx->type.dataType.IsObject() )
  9863. {
  9864. asCString str;
  9865. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format().AddressOf());
  9866. Error(str, node);
  9867. // Set an integer value and allow the compiler to continue
  9868. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), 0);
  9869. return;
  9870. }
  9871. // Convert left hand operand to integer if it's not already one
  9872. asCDataType to = lctx->type.dataType;
  9873. if( lctx->type.dataType.IsUnsignedType() &&
  9874. lctx->type.dataType.GetSizeInMemoryBytes() < 4 )
  9875. {
  9876. to = asCDataType::CreatePrimitive(ttUInt, false);
  9877. }
  9878. else if( !lctx->type.dataType.IsUnsignedType() )
  9879. {
  9880. asCDataType to;
  9881. if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  9882. to.SetTokenType(ttInt64);
  9883. else
  9884. to.SetTokenType(ttInt);
  9885. }
  9886. // Do the actual conversion
  9887. int l = int(reservedVariables.GetLength());
  9888. rctx->bc.GetVarsUsed(reservedVariables);
  9889. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true);
  9890. reservedVariables.SetLength(l);
  9891. // Verify that the conversion was successful
  9892. if( lctx->type.dataType != to )
  9893. {
  9894. asCString str;
  9895. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  9896. Error(str, node);
  9897. }
  9898. // Right operand must be 32bit uint
  9899. l = int(reservedVariables.GetLength());
  9900. lctx->bc.GetVarsUsed(reservedVariables);
  9901. ImplicitConversion(rctx, asCDataType::CreatePrimitive(ttUInt, true), node, asIC_IMPLICIT_CONV, true);
  9902. reservedVariables.SetLength(l);
  9903. if( !rctx->type.dataType.IsUnsignedType() )
  9904. {
  9905. asCString str;
  9906. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format().AddressOf(), "uint");
  9907. Error(str, node);
  9908. }
  9909. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  9910. if( !isConstant )
  9911. {
  9912. ConvertToVariableNotIn(lctx, rctx);
  9913. ConvertToVariableNotIn(rctx, lctx);
  9914. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  9915. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  9916. if( op == ttShiftLeftAssign || op == ttShiftRightLAssign || op == ttShiftRightAAssign )
  9917. {
  9918. // Compound assignments execute the right hand value first
  9919. MergeExprBytecode(ctx, rctx);
  9920. MergeExprBytecode(ctx, lctx);
  9921. }
  9922. else
  9923. {
  9924. MergeExprBytecode(ctx, lctx);
  9925. MergeExprBytecode(ctx, rctx);
  9926. }
  9927. ProcessDeferredParams(ctx);
  9928. asEBCInstr instruction = asBC_BSLL;
  9929. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  9930. {
  9931. if( op == ttBitShiftLeft || op == ttShiftLeftAssign )
  9932. instruction = asBC_BSLL;
  9933. else if( op == ttBitShiftRight || op == ttShiftRightLAssign )
  9934. instruction = asBC_BSRL;
  9935. else if( op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  9936. instruction = asBC_BSRA;
  9937. }
  9938. else
  9939. {
  9940. if( op == ttBitShiftLeft || op == ttShiftLeftAssign )
  9941. instruction = asBC_BSLL64;
  9942. else if( op == ttBitShiftRight || op == ttShiftRightLAssign )
  9943. instruction = asBC_BSRL64;
  9944. else if( op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  9945. instruction = asBC_BSRA64;
  9946. }
  9947. // Do the operation
  9948. int a = AllocateVariable(lctx->type.dataType, true);
  9949. int b = lctx->type.stackOffset;
  9950. int c = rctx->type.stackOffset;
  9951. ctx->bc.InstrW_W_W(instruction, a, b, c);
  9952. ctx->type.SetVariable(lctx->type.dataType, a, true);
  9953. }
  9954. else
  9955. {
  9956. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  9957. {
  9958. asDWORD v = 0;
  9959. if( op == ttBitShiftLeft )
  9960. v = lctx->type.dwordValue << rctx->type.dwordValue;
  9961. else if( op == ttBitShiftRight )
  9962. v = lctx->type.dwordValue >> rctx->type.dwordValue;
  9963. else if( op == ttBitShiftRightArith )
  9964. v = lctx->type.intValue >> rctx->type.dwordValue;
  9965. ctx->type.SetConstantDW(lctx->type.dataType, v);
  9966. }
  9967. else
  9968. {
  9969. asQWORD v = 0;
  9970. if( op == ttBitShiftLeft )
  9971. v = lctx->type.qwordValue << rctx->type.dwordValue;
  9972. else if( op == ttBitShiftRight )
  9973. v = lctx->type.qwordValue >> rctx->type.dwordValue;
  9974. else if( op == ttBitShiftRightArith )
  9975. v = asINT64(lctx->type.qwordValue) >> rctx->type.dwordValue;
  9976. ctx->type.SetConstantQW(lctx->type.dataType, v);
  9977. }
  9978. }
  9979. }
  9980. }
  9981. void asCCompiler::CompileComparisonOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  9982. {
  9983. // Both operands must be of the same type
  9984. // Implicitly convert the operands to a number type
  9985. asCDataType to;
  9986. // If either operand is a non-primitive then use the primitive type
  9987. if( !lctx->type.dataType.IsPrimitive() )
  9988. to.SetTokenType(rctx->type.dataType.GetTokenType());
  9989. else if( !rctx->type.dataType.IsPrimitive() )
  9990. to.SetTokenType(lctx->type.dataType.GetTokenType());
  9991. else if( lctx->type.dataType.IsDoubleType() || rctx->type.dataType.IsDoubleType() )
  9992. to.SetTokenType(ttDouble);
  9993. else if( lctx->type.dataType.IsFloatType() || rctx->type.dataType.IsFloatType() )
  9994. to.SetTokenType(ttFloat);
  9995. else if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 || rctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  9996. {
  9997. // Convert to int64 if both are signed or if one is non-constant and signed
  9998. if( (lctx->type.dataType.IsIntegerType() && rctx->type.dataType.IsIntegerType()) ||
  9999. (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) ||
  10000. (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) )
  10001. to.SetTokenType(ttInt64);
  10002. else
  10003. to.SetTokenType(ttUInt64);
  10004. }
  10005. else
  10006. {
  10007. // Convert to int32 if both are signed or if one is non-constant and signed
  10008. if( (lctx->type.dataType.IsIntegerType() && rctx->type.dataType.IsIntegerType()) ||
  10009. (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) ||
  10010. (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) )
  10011. to.SetTokenType(ttInt);
  10012. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  10013. to.SetTokenType(ttUInt);
  10014. else if( lctx->type.dataType.IsBooleanType() || rctx->type.dataType.IsBooleanType() )
  10015. to.SetTokenType(ttBool);
  10016. }
  10017. // If doing an operation with double constant and float variable, the constant should be converted to float
  10018. if( (lctx->type.isConstant && lctx->type.dataType.IsDoubleType() && !rctx->type.isConstant && rctx->type.dataType.IsFloatType()) ||
  10019. (rctx->type.isConstant && rctx->type.dataType.IsDoubleType() && !lctx->type.isConstant && lctx->type.dataType.IsFloatType()) )
  10020. to.SetTokenType(ttFloat);
  10021. asASSERT( to.GetTokenType() != ttUnrecognizedToken );
  10022. // Do we have a mismatch between the sign of the operand?
  10023. bool signMismatch = false;
  10024. for( int n = 0; !signMismatch && n < 2; n++ )
  10025. {
  10026. asSExprContext *op = n ? rctx : lctx;
  10027. if( op->type.dataType.IsUnsignedType() != to.IsUnsignedType() )
  10028. {
  10029. // We have a mismatch, unless the value is a literal constant and the conversion won't affect its value
  10030. signMismatch = true;
  10031. if( op->type.isConstant )
  10032. {
  10033. if( op->type.dataType.GetTokenType() == ttUInt64 || op->type.dataType.GetTokenType() == ttInt64 )
  10034. {
  10035. if( !(op->type.qwordValue & (asQWORD(1)<<63)) )
  10036. signMismatch = false;
  10037. }
  10038. else
  10039. {
  10040. if( !(op->type.dwordValue & (1<<31)) )
  10041. signMismatch = false;
  10042. }
  10043. // It's not necessary to check for floats or double, because if
  10044. // it was then the types for the conversion will never be unsigned
  10045. }
  10046. }
  10047. }
  10048. // Check for signed/unsigned mismatch
  10049. if( signMismatch )
  10050. Warning(TXT_SIGNED_UNSIGNED_MISMATCH, node);
  10051. // Do the actual conversion
  10052. int l = int(reservedVariables.GetLength());
  10053. rctx->bc.GetVarsUsed(reservedVariables);
  10054. if( lctx->type.dataType.IsReference() )
  10055. ConvertToVariable(lctx);
  10056. if( rctx->type.dataType.IsReference() )
  10057. ConvertToVariable(rctx);
  10058. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV);
  10059. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV);
  10060. reservedVariables.SetLength(l);
  10061. // Verify that the conversion was successful
  10062. bool ok = true;
  10063. if( !lctx->type.dataType.IsEqualExceptConst(to) )
  10064. {
  10065. asCString str;
  10066. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  10067. Error(str, node);
  10068. ok = false;
  10069. }
  10070. if( !rctx->type.dataType.IsEqualExceptConst(to) )
  10071. {
  10072. asCString str;
  10073. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  10074. Error(str, node);
  10075. ok = false;
  10076. }
  10077. if( !ok )
  10078. {
  10079. // It wasn't possible to get two valid operands, so we just return
  10080. // a boolean result and let the compiler continue.
  10081. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  10082. return;
  10083. }
  10084. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  10085. int op = node->tokenType;
  10086. if( !isConstant )
  10087. {
  10088. if( to.IsBooleanType() )
  10089. {
  10090. int op = node->tokenType;
  10091. if( op == ttEqual || op == ttNotEqual )
  10092. {
  10093. // Must convert to temporary variable, because we are changing the value before comparison
  10094. ConvertToTempVariableNotIn(lctx, rctx);
  10095. ConvertToTempVariableNotIn(rctx, lctx);
  10096. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  10097. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  10098. // Make sure they are equal if not false
  10099. lctx->bc.InstrWORD(asBC_NOT, lctx->type.stackOffset);
  10100. rctx->bc.InstrWORD(asBC_NOT, rctx->type.stackOffset);
  10101. MergeExprBytecode(ctx, lctx);
  10102. MergeExprBytecode(ctx, rctx);
  10103. ProcessDeferredParams(ctx);
  10104. int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, true), true);
  10105. int b = lctx->type.stackOffset;
  10106. int c = rctx->type.stackOffset;
  10107. if( op == ttEqual )
  10108. {
  10109. ctx->bc.InstrW_W(asBC_CMPi,b,c);
  10110. ctx->bc.Instr(asBC_TZ);
  10111. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  10112. }
  10113. else if( op == ttNotEqual )
  10114. {
  10115. ctx->bc.InstrW_W(asBC_CMPi,b,c);
  10116. ctx->bc.Instr(asBC_TNZ);
  10117. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  10118. }
  10119. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  10120. }
  10121. else
  10122. {
  10123. // TODO: Use TXT_ILLEGAL_OPERATION_ON
  10124. Error(TXT_ILLEGAL_OPERATION, node);
  10125. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), 0);
  10126. }
  10127. }
  10128. else
  10129. {
  10130. ConvertToVariableNotIn(lctx, rctx);
  10131. ConvertToVariableNotIn(rctx, lctx);
  10132. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  10133. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  10134. MergeExprBytecode(ctx, lctx);
  10135. MergeExprBytecode(ctx, rctx);
  10136. ProcessDeferredParams(ctx);
  10137. asEBCInstr iCmp = asBC_CMPi, iT = asBC_TZ;
  10138. if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  10139. iCmp = asBC_CMPi;
  10140. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  10141. iCmp = asBC_CMPu;
  10142. else if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  10143. iCmp = asBC_CMPi64;
  10144. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  10145. iCmp = asBC_CMPu64;
  10146. else if( lctx->type.dataType.IsFloatType() )
  10147. iCmp = asBC_CMPf;
  10148. else if( lctx->type.dataType.IsDoubleType() )
  10149. iCmp = asBC_CMPd;
  10150. else
  10151. asASSERT(false);
  10152. if( op == ttEqual )
  10153. iT = asBC_TZ;
  10154. else if( op == ttNotEqual )
  10155. iT = asBC_TNZ;
  10156. else if( op == ttLessThan )
  10157. iT = asBC_TS;
  10158. else if( op == ttLessThanOrEqual )
  10159. iT = asBC_TNP;
  10160. else if( op == ttGreaterThan )
  10161. iT = asBC_TP;
  10162. else if( op == ttGreaterThanOrEqual )
  10163. iT = asBC_TNS;
  10164. int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, true), true);
  10165. int b = lctx->type.stackOffset;
  10166. int c = rctx->type.stackOffset;
  10167. ctx->bc.InstrW_W(iCmp, b, c);
  10168. ctx->bc.Instr(iT);
  10169. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  10170. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  10171. }
  10172. }
  10173. else
  10174. {
  10175. if( to.IsBooleanType() )
  10176. {
  10177. int op = node->tokenType;
  10178. if( op == ttEqual || op == ttNotEqual )
  10179. {
  10180. // Make sure they are equal if not false
  10181. if( lctx->type.dwordValue != 0 ) lctx->type.dwordValue = VALUE_OF_BOOLEAN_TRUE;
  10182. if( rctx->type.dwordValue != 0 ) rctx->type.dwordValue = VALUE_OF_BOOLEAN_TRUE;
  10183. asDWORD v = 0;
  10184. if( op == ttEqual )
  10185. {
  10186. v = lctx->type.intValue - rctx->type.intValue;
  10187. if( v == 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  10188. }
  10189. else if( op == ttNotEqual )
  10190. {
  10191. v = lctx->type.intValue - rctx->type.intValue;
  10192. if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  10193. }
  10194. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), v);
  10195. }
  10196. else
  10197. {
  10198. // TODO: Use TXT_ILLEGAL_OPERATION_ON
  10199. Error(TXT_ILLEGAL_OPERATION, node);
  10200. }
  10201. }
  10202. else
  10203. {
  10204. int i = 0;
  10205. if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  10206. {
  10207. int v = lctx->type.intValue - rctx->type.intValue;
  10208. if( v < 0 ) i = -1;
  10209. if( v > 0 ) i = 1;
  10210. }
  10211. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  10212. {
  10213. asDWORD v1 = lctx->type.dwordValue;
  10214. asDWORD v2 = rctx->type.dwordValue;
  10215. if( v1 < v2 ) i = -1;
  10216. if( v1 > v2 ) i = 1;
  10217. }
  10218. else if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  10219. {
  10220. asINT64 v = asINT64(lctx->type.qwordValue) - asINT64(rctx->type.qwordValue);
  10221. if( v < 0 ) i = -1;
  10222. if( v > 0 ) i = 1;
  10223. }
  10224. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  10225. {
  10226. asQWORD v1 = lctx->type.qwordValue;
  10227. asQWORD v2 = rctx->type.qwordValue;
  10228. if( v1 < v2 ) i = -1;
  10229. if( v1 > v2 ) i = 1;
  10230. }
  10231. else if( lctx->type.dataType.IsFloatType() )
  10232. {
  10233. float v = lctx->type.floatValue - rctx->type.floatValue;
  10234. if( v < 0 ) i = -1;
  10235. if( v > 0 ) i = 1;
  10236. }
  10237. else if( lctx->type.dataType.IsDoubleType() )
  10238. {
  10239. double v = lctx->type.doubleValue - rctx->type.doubleValue;
  10240. if( v < 0 ) i = -1;
  10241. if( v > 0 ) i = 1;
  10242. }
  10243. if( op == ttEqual )
  10244. i = (i == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  10245. else if( op == ttNotEqual )
  10246. i = (i != 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  10247. else if( op == ttLessThan )
  10248. i = (i < 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  10249. else if( op == ttLessThanOrEqual )
  10250. i = (i <= 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  10251. else if( op == ttGreaterThan )
  10252. i = (i > 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  10253. else if( op == ttGreaterThanOrEqual )
  10254. i = (i >= 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  10255. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), i);
  10256. }
  10257. }
  10258. }
  10259. void asCCompiler::PushVariableOnStack(asSExprContext *ctx, bool asReference)
  10260. {
  10261. // Put the result on the stack
  10262. if( asReference )
  10263. {
  10264. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  10265. ctx->type.dataType.MakeReference(true);
  10266. }
  10267. else
  10268. {
  10269. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  10270. ctx->bc.InstrSHORT(asBC_PshV4, ctx->type.stackOffset);
  10271. else
  10272. ctx->bc.InstrSHORT(asBC_PshV8, ctx->type.stackOffset);
  10273. }
  10274. }
  10275. void asCCompiler::CompileBooleanOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  10276. {
  10277. // Both operands must be booleans
  10278. asCDataType to;
  10279. to.SetTokenType(ttBool);
  10280. // Do the actual conversion
  10281. int l = int(reservedVariables.GetLength());
  10282. rctx->bc.GetVarsUsed(reservedVariables);
  10283. lctx->bc.GetVarsUsed(reservedVariables);
  10284. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV);
  10285. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV);
  10286. reservedVariables.SetLength(l);
  10287. // Verify that the conversion was successful
  10288. if( !lctx->type.dataType.IsBooleanType() )
  10289. {
  10290. asCString str;
  10291. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format().AddressOf(), "bool");
  10292. Error(str, node);
  10293. // Force the conversion to allow compilation to proceed
  10294. lctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  10295. }
  10296. if( !rctx->type.dataType.IsBooleanType() )
  10297. {
  10298. asCString str;
  10299. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format().AddressOf(), "bool");
  10300. Error(str, node);
  10301. // Force the conversion to allow compilation to proceed
  10302. rctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  10303. }
  10304. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  10305. ctx->type.Set(asCDataType::CreatePrimitive(ttBool, true));
  10306. // What kind of operator is it?
  10307. int op = node->tokenType;
  10308. if( op == ttXor )
  10309. {
  10310. if( !isConstant )
  10311. {
  10312. // Must convert to temporary variable, because we are changing the value before comparison
  10313. ConvertToTempVariableNotIn(lctx, rctx);
  10314. ConvertToTempVariableNotIn(rctx, lctx);
  10315. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  10316. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  10317. // Make sure they are equal if not false
  10318. lctx->bc.InstrWORD(asBC_NOT, lctx->type.stackOffset);
  10319. rctx->bc.InstrWORD(asBC_NOT, rctx->type.stackOffset);
  10320. MergeExprBytecode(ctx, lctx);
  10321. MergeExprBytecode(ctx, rctx);
  10322. ProcessDeferredParams(ctx);
  10323. int a = AllocateVariable(ctx->type.dataType, true);
  10324. int b = lctx->type.stackOffset;
  10325. int c = rctx->type.stackOffset;
  10326. ctx->bc.InstrW_W_W(asBC_BXOR,a,b,c);
  10327. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  10328. }
  10329. else
  10330. {
  10331. // Make sure they are equal if not false
  10332. #if AS_SIZEOF_BOOL == 1
  10333. if( lctx->type.byteValue != 0 ) lctx->type.byteValue = VALUE_OF_BOOLEAN_TRUE;
  10334. if( rctx->type.byteValue != 0 ) rctx->type.byteValue = VALUE_OF_BOOLEAN_TRUE;
  10335. asBYTE v = 0;
  10336. v = lctx->type.byteValue - rctx->type.byteValue;
  10337. if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  10338. ctx->type.isConstant = true;
  10339. ctx->type.byteValue = v;
  10340. #else
  10341. if( lctx->type.dwordValue != 0 ) lctx->type.dwordValue = VALUE_OF_BOOLEAN_TRUE;
  10342. if( rctx->type.dwordValue != 0 ) rctx->type.dwordValue = VALUE_OF_BOOLEAN_TRUE;
  10343. asDWORD v = 0;
  10344. v = lctx->type.intValue - rctx->type.intValue;
  10345. if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  10346. ctx->type.isConstant = true;
  10347. ctx->type.dwordValue = v;
  10348. #endif
  10349. }
  10350. }
  10351. else if( op == ttAnd ||
  10352. op == ttOr )
  10353. {
  10354. if( !isConstant )
  10355. {
  10356. // If or-operator and first value is 1 the second value shouldn't be calculated
  10357. // if and-operator and first value is 0 the second value shouldn't be calculated
  10358. ConvertToVariable(lctx);
  10359. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  10360. MergeExprBytecode(ctx, lctx);
  10361. int offset = AllocateVariable(asCDataType::CreatePrimitive(ttBool, false), true);
  10362. int label1 = nextLabel++;
  10363. int label2 = nextLabel++;
  10364. ctx->bc.InstrSHORT(asBC_CpyVtoR4, lctx->type.stackOffset);
  10365. ctx->bc.Instr(asBC_ClrHi);
  10366. if( op == ttAnd )
  10367. {
  10368. ctx->bc.InstrDWORD(asBC_JNZ, label1);
  10369. ctx->bc.InstrW_DW(asBC_SetV4, (asWORD)offset, 0);
  10370. ctx->bc.InstrINT(asBC_JMP, label2);
  10371. }
  10372. else if( op == ttOr )
  10373. {
  10374. ctx->bc.InstrDWORD(asBC_JZ, label1);
  10375. #if AS_SIZEOF_BOOL == 1
  10376. ctx->bc.InstrSHORT_B(asBC_SetV1, (short)offset, VALUE_OF_BOOLEAN_TRUE);
  10377. #else
  10378. ctx->bc.InstrSHORT_DW(asBC_SetV4, (short)offset, VALUE_OF_BOOLEAN_TRUE);
  10379. #endif
  10380. ctx->bc.InstrINT(asBC_JMP, label2);
  10381. }
  10382. ctx->bc.Label((short)label1);
  10383. ConvertToVariable(rctx);
  10384. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  10385. rctx->bc.InstrW_W(asBC_CpyVtoV4, offset, rctx->type.stackOffset);
  10386. MergeExprBytecode(ctx, rctx);
  10387. ctx->bc.Label((short)label2);
  10388. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, false), offset, true);
  10389. }
  10390. else
  10391. {
  10392. #if AS_SIZEOF_BOOL == 1
  10393. asBYTE v = 0;
  10394. if( op == ttAnd )
  10395. v = lctx->type.byteValue && rctx->type.byteValue;
  10396. else if( op == ttOr )
  10397. v = lctx->type.byteValue || rctx->type.byteValue;
  10398. // Remember the result
  10399. ctx->type.isConstant = true;
  10400. ctx->type.byteValue = v;
  10401. #else
  10402. asDWORD v = 0;
  10403. if( op == ttAnd )
  10404. v = lctx->type.dwordValue && rctx->type.dwordValue;
  10405. else if( op == ttOr )
  10406. v = lctx->type.dwordValue || rctx->type.dwordValue;
  10407. // Remember the result
  10408. ctx->type.isConstant = true;
  10409. ctx->type.dwordValue = v;
  10410. #endif
  10411. }
  10412. }
  10413. }
  10414. void asCCompiler::CompileOperatorOnHandles(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  10415. {
  10416. // Process the property accessor as get
  10417. ProcessPropertyGetAccessor(lctx, node);
  10418. ProcessPropertyGetAccessor(rctx, node);
  10419. DetermineSingleFunc(lctx, node);
  10420. DetermineSingleFunc(rctx, node);
  10421. // Make sure lctx doesn't end up with a variable used in rctx
  10422. if( lctx->type.isTemporary && rctx->bc.IsVarUsed(lctx->type.stackOffset) )
  10423. {
  10424. asCArray<int> vars;
  10425. rctx->bc.GetVarsUsed(vars);
  10426. int offset = AllocateVariable(lctx->type.dataType, true);
  10427. rctx->bc.ExchangeVar(lctx->type.stackOffset, offset);
  10428. ReleaseTemporaryVariable(offset, 0);
  10429. }
  10430. // Warn if not both operands are explicit handles or null handles
  10431. if( (node->tokenType == ttEqual || node->tokenType == ttNotEqual) &&
  10432. ((!(lctx->type.isExplicitHandle || lctx->type.IsNullConstant()) && !(lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE))) ||
  10433. (!(rctx->type.isExplicitHandle || rctx->type.IsNullConstant()) && !(rctx->type.dataType.GetObjectType() && (rctx->type.dataType.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE)))) )
  10434. {
  10435. Warning(TXT_HANDLE_COMPARISON, node);
  10436. }
  10437. // If one of the operands is a value type used as handle, we should look for the opEquals method
  10438. if( ((lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE)) ||
  10439. (rctx->type.dataType.GetObjectType() && (rctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE))) &&
  10440. (node->tokenType == ttEqual || node->tokenType == ttIs ||
  10441. node->tokenType == ttNotEqual || node->tokenType == ttNotIs) )
  10442. {
  10443. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  10444. // Find the matching opEquals method
  10445. int r = CompileOverloadedDualOperator2(node, "opEquals", lctx, rctx, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  10446. if( r == 0 )
  10447. {
  10448. // Try again by switching the order of the operands
  10449. r = CompileOverloadedDualOperator2(node, "opEquals", rctx, lctx, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  10450. }
  10451. if( r == 1 )
  10452. {
  10453. if( node->tokenType == ttNotEqual || node->tokenType == ttNotIs )
  10454. ctx->bc.InstrSHORT(asBC_NOT, ctx->type.stackOffset);
  10455. // Success, don't continue
  10456. return;
  10457. }
  10458. else if( r == 0 )
  10459. {
  10460. // Couldn't find opEquals method
  10461. Error(TXT_NO_APPROPRIATE_OPEQUALS, node);
  10462. }
  10463. // Compiler error, don't continue
  10464. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  10465. return;
  10466. }
  10467. // Implicitly convert null to the other type
  10468. asCDataType to;
  10469. if( lctx->type.IsNullConstant() )
  10470. to = rctx->type.dataType;
  10471. else if( rctx->type.IsNullConstant() )
  10472. to = lctx->type.dataType;
  10473. else
  10474. {
  10475. // TODO: Use the common base type
  10476. to = lctx->type.dataType;
  10477. }
  10478. // Need to pop the value if it is a null constant
  10479. if( lctx->type.IsNullConstant() )
  10480. lctx->bc.Instr(asBC_PopPtr);
  10481. if( rctx->type.IsNullConstant() )
  10482. rctx->bc.Instr(asBC_PopPtr);
  10483. // Convert both sides to explicit handles
  10484. to.MakeHandle(true);
  10485. to.MakeReference(false);
  10486. if( !to.IsObjectHandle() )
  10487. {
  10488. // Compiler error, don't continue
  10489. Error(TXT_OPERANDS_MUST_BE_HANDLES, node);
  10490. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  10491. return;
  10492. }
  10493. // Do the conversion
  10494. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV);
  10495. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV);
  10496. // Both operands must be of the same type
  10497. // Verify that the conversion was successful
  10498. if( !lctx->type.dataType.IsEqualExceptConst(to) )
  10499. {
  10500. asCString str;
  10501. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  10502. Error(str, node);
  10503. }
  10504. if( !rctx->type.dataType.IsEqualExceptConst(to) )
  10505. {
  10506. asCString str;
  10507. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  10508. Error(str, node);
  10509. }
  10510. // Make sure it really is handles that are being compared
  10511. if( !lctx->type.dataType.IsObjectHandle() )
  10512. {
  10513. Error(TXT_OPERANDS_MUST_BE_HANDLES, node);
  10514. }
  10515. ctx->type.Set(asCDataType::CreatePrimitive(ttBool, true));
  10516. int op = node->tokenType;
  10517. if( op == ttEqual || op == ttNotEqual || op == ttIs || op == ttNotIs )
  10518. {
  10519. // If the object handle already is in a variable we must manually pop it from the stack
  10520. if( lctx->type.isVariable )
  10521. lctx->bc.Instr(asBC_PopPtr);
  10522. if( rctx->type.isVariable )
  10523. rctx->bc.Instr(asBC_PopPtr);
  10524. // TODO: runtime optimize: don't do REFCPY
  10525. ConvertToVariableNotIn(lctx, rctx);
  10526. ConvertToVariable(rctx);
  10527. MergeExprBytecode(ctx, lctx);
  10528. MergeExprBytecode(ctx, rctx);
  10529. int a = AllocateVariable(ctx->type.dataType, true);
  10530. int b = lctx->type.stackOffset;
  10531. int c = rctx->type.stackOffset;
  10532. ctx->bc.InstrW_W(asBC_CmpPtr, b, c);
  10533. if( op == ttEqual || op == ttIs )
  10534. ctx->bc.Instr(asBC_TZ);
  10535. else if( op == ttNotEqual || op == ttNotIs )
  10536. ctx->bc.Instr(asBC_TNZ);
  10537. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  10538. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  10539. ReleaseTemporaryVariable(lctx->type, &ctx->bc);
  10540. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  10541. ProcessDeferredParams(ctx);
  10542. }
  10543. else
  10544. {
  10545. // TODO: Use TXT_ILLEGAL_OPERATION_ON
  10546. Error(TXT_ILLEGAL_OPERATION, node);
  10547. }
  10548. }
  10549. void asCCompiler::PerformFunctionCall(int funcId, asSExprContext *ctx, bool isConstructor, asCArray<asSExprContext*> *args, asCObjectType *objType, bool useVariable, int varOffset, int funcPtrVar)
  10550. {
  10551. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  10552. // A shared object may not call non-shared functions
  10553. if( outFunc->IsShared() && !descr->IsShared() )
  10554. {
  10555. asCString msg;
  10556. msg.Format(TXT_SHARED_CANNOT_CALL_NON_SHARED_FUNC_s, descr->GetDeclarationStr().AddressOf());
  10557. Error(msg, ctx->exprNode);
  10558. }
  10559. // Check if the function is private
  10560. if( descr->isPrivate && descr->GetObjectType() != outFunc->GetObjectType() )
  10561. {
  10562. asCString msg;
  10563. msg.Format(TXT_PRIVATE_METHOD_CALL_s, descr->GetDeclarationStr().AddressOf());
  10564. Error(msg, ctx->exprNode);
  10565. }
  10566. int argSize = descr->GetSpaceNeededForArguments();
  10567. if( descr->objectType && descr->returnType.IsReference() &&
  10568. !(ctx->type.isVariable || ctx->type.isTemporary) &&
  10569. (ctx->type.dataType.IsObjectHandle() || ctx->type.dataType.SupportHandles()) &&
  10570. !(ctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_SCOPED) &&
  10571. !(ctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_ASHANDLE) )
  10572. {
  10573. // The class method we're calling is returning a reference, which may be to a member of the object.
  10574. // In order to guarantee the lifetime of the reference, we must hold a local reference to the object.
  10575. // TODO: runtime optimize: This can be avoided for local variables (non-handles) as they have a well defined life time
  10576. int tempRef = AllocateVariable(ctx->type.dataType, true);
  10577. ctx->bc.InstrSHORT(asBC_PSF, (short)tempRef);
  10578. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetObjectType());
  10579. // Add the release of this reference, as a deferred expression
  10580. asSDeferredParam deferred;
  10581. deferred.origExpr = 0;
  10582. deferred.argInOutFlags = asTM_INREF;
  10583. deferred.argNode = 0;
  10584. deferred.argType.SetVariable(ctx->type.dataType, tempRef, true);
  10585. ctx->deferredParams.PushLast(deferred);
  10586. // Forget the current type
  10587. ctx->type.SetDummy();
  10588. }
  10589. if( isConstructor )
  10590. {
  10591. // Sometimes the value types are allocated on the heap,
  10592. // which is when this way of constructing them is used.
  10593. asASSERT(useVariable == false);
  10594. ctx->bc.Alloc(asBC_ALLOC, objType, descr->id, argSize+AS_PTR_SIZE);
  10595. // The instruction has already moved the returned object to the variable
  10596. ctx->type.Set(asCDataType::CreatePrimitive(ttVoid, false));
  10597. ctx->type.isLValue = false;
  10598. // Clean up arguments
  10599. if( args )
  10600. AfterFunctionCall(funcId, *args, ctx, false);
  10601. ProcessDeferredParams(ctx);
  10602. return;
  10603. }
  10604. else
  10605. {
  10606. if( descr->objectType )
  10607. argSize += AS_PTR_SIZE;
  10608. // If the function returns an object by value the address of the location
  10609. // where the value should be stored is passed as an argument too
  10610. if( descr->DoesReturnOnStack() )
  10611. {
  10612. argSize += AS_PTR_SIZE;
  10613. }
  10614. // TODO: runtime optimize: If it is known that a class method cannot be overridden the call
  10615. // should be made with asBC_CALL as it is faster. Examples where this
  10616. // is known is for example finalled methods where the class doesn't derive
  10617. // from any other, or even non-finalled methods but where it is known
  10618. // at compile time the true type of the object. The first should be
  10619. // quite easy to determine, but the latter will be quite complex and possibly
  10620. // not worth it.
  10621. if( descr->funcType == asFUNC_IMPORTED )
  10622. ctx->bc.Call(asBC_CALLBND , descr->id, argSize);
  10623. // TODO: Maybe we need two different byte codes
  10624. else if( descr->funcType == asFUNC_INTERFACE || descr->funcType == asFUNC_VIRTUAL )
  10625. ctx->bc.Call(asBC_CALLINTF, descr->id, argSize);
  10626. else if( descr->funcType == asFUNC_SCRIPT )
  10627. ctx->bc.Call(asBC_CALL , descr->id, argSize);
  10628. else if( descr->funcType == asFUNC_SYSTEM )
  10629. ctx->bc.Call(asBC_CALLSYS , descr->id, argSize);
  10630. else if( descr->funcType == asFUNC_FUNCDEF )
  10631. ctx->bc.CallPtr(asBC_CallPtr, funcPtrVar, argSize);
  10632. }
  10633. if( descr->returnType.IsObject() && !descr->returnType.IsReference() )
  10634. {
  10635. int returnOffset = 0;
  10636. if( descr->DoesReturnOnStack() )
  10637. {
  10638. asASSERT( useVariable );
  10639. // The variable was allocated before the function was called
  10640. returnOffset = varOffset;
  10641. ctx->type.SetVariable(descr->returnType, returnOffset, true);
  10642. // The variable was initialized by the function, so we need to mark it as initialized here
  10643. ctx->bc.ObjInfo(varOffset, asOBJ_INIT);
  10644. }
  10645. else
  10646. {
  10647. if( useVariable )
  10648. {
  10649. // Use the given variable
  10650. returnOffset = varOffset;
  10651. ctx->type.SetVariable(descr->returnType, returnOffset, false);
  10652. }
  10653. else
  10654. {
  10655. // Allocate a temporary variable for the returned object
  10656. // The returned object will actually be allocated on the heap, so
  10657. // we must force the allocation of the variable to do the same
  10658. returnOffset = AllocateVariable(descr->returnType, true, !descr->returnType.IsObjectHandle());
  10659. ctx->type.SetVariable(descr->returnType, returnOffset, true);
  10660. }
  10661. // Move the pointer from the object register to the temporary variable
  10662. ctx->bc.InstrSHORT(asBC_STOREOBJ, (short)returnOffset);
  10663. }
  10664. ctx->type.dataType.MakeReference(IsVariableOnHeap(returnOffset));
  10665. ctx->type.isLValue = false; // It is a reference, but not an lvalue
  10666. // Clean up arguments
  10667. if( args )
  10668. AfterFunctionCall(funcId, *args, ctx, false);
  10669. ProcessDeferredParams(ctx);
  10670. ctx->bc.InstrSHORT(asBC_PSF, (short)returnOffset);
  10671. }
  10672. else if( descr->returnType.IsReference() )
  10673. {
  10674. asASSERT(useVariable == false);
  10675. // We cannot clean up the arguments yet, because the
  10676. // reference might be pointing to one of them.
  10677. if( args )
  10678. AfterFunctionCall(funcId, *args, ctx, true);
  10679. // Do not process the output parameters yet, because it
  10680. // might invalidate the returned reference
  10681. // If the context holds a variable that needs cleanup
  10682. // store it as a deferred parameter so it will be cleaned up
  10683. // afterwards.
  10684. if( ctx->type.isTemporary )
  10685. {
  10686. asSDeferredParam defer;
  10687. defer.argNode = 0;
  10688. defer.argType = ctx->type;
  10689. defer.argInOutFlags = asTM_INOUTREF;
  10690. defer.origExpr = 0;
  10691. ctx->deferredParams.PushLast(defer);
  10692. }
  10693. ctx->type.Set(descr->returnType);
  10694. if( !descr->returnType.IsPrimitive() )
  10695. {
  10696. ctx->bc.Instr(asBC_PshRPtr);
  10697. if( descr->returnType.IsObject() &&
  10698. !descr->returnType.IsObjectHandle() )
  10699. {
  10700. // We are getting the pointer to the object
  10701. // not a pointer to a object variable
  10702. ctx->type.dataType.MakeReference(false);
  10703. }
  10704. }
  10705. // A returned reference can be used as lvalue
  10706. ctx->type.isLValue = true;
  10707. }
  10708. else
  10709. {
  10710. asASSERT(useVariable == false);
  10711. if( descr->returnType.GetSizeInMemoryBytes() )
  10712. {
  10713. // Allocate a temporary variable to hold the value, but make sure
  10714. // the temporary variable isn't used in any of the deferred arguments
  10715. int l = int(reservedVariables.GetLength());
  10716. for( asUINT n = 0; args && n < args->GetLength(); n++ )
  10717. {
  10718. asSExprContext *expr = (*args)[n]->origExpr;
  10719. if( expr )
  10720. expr->bc.GetVarsUsed(reservedVariables);
  10721. }
  10722. int offset = AllocateVariable(descr->returnType, true);
  10723. reservedVariables.SetLength(l);
  10724. ctx->type.SetVariable(descr->returnType, offset, true);
  10725. // Move the value from the return register to the variable
  10726. if( descr->returnType.GetSizeOnStackDWords() == 1 )
  10727. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)offset);
  10728. else if( descr->returnType.GetSizeOnStackDWords() == 2 )
  10729. ctx->bc.InstrSHORT(asBC_CpyRtoV8, (short)offset);
  10730. }
  10731. else
  10732. ctx->type.Set(descr->returnType);
  10733. ctx->type.isLValue = false;
  10734. // Clean up arguments
  10735. if( args )
  10736. AfterFunctionCall(funcId, *args, ctx, false);
  10737. ProcessDeferredParams(ctx);
  10738. }
  10739. }
  10740. // This only merges the bytecode, but doesn't modify the type of the final context
  10741. void asCCompiler::MergeExprBytecode(asSExprContext *before, asSExprContext *after)
  10742. {
  10743. before->bc.AddCode(&after->bc);
  10744. for( asUINT n = 0; n < after->deferredParams.GetLength(); n++ )
  10745. {
  10746. before->deferredParams.PushLast(after->deferredParams[n]);
  10747. after->deferredParams[n].origExpr = 0;
  10748. }
  10749. after->deferredParams.SetLength(0);
  10750. }
  10751. // This merges both bytecode and the type of the final context
  10752. void asCCompiler::MergeExprBytecodeAndType(asSExprContext *before, asSExprContext *after)
  10753. {
  10754. MergeExprBytecode(before, after);
  10755. before->type = after->type;
  10756. before->property_get = after->property_get;
  10757. before->property_set = after->property_set;
  10758. before->property_const = after->property_const;
  10759. before->property_handle = after->property_handle;
  10760. before->property_ref = after->property_ref;
  10761. before->property_arg = after->property_arg;
  10762. before->exprNode = after->exprNode;
  10763. before->methodName = after->methodName;
  10764. after->property_arg = 0;
  10765. // Do not copy the origExpr member
  10766. }
  10767. void asCCompiler::FilterConst(asCArray<int> &funcs, bool removeConst)
  10768. {
  10769. if( funcs.GetLength() == 0 ) return;
  10770. // This is only done for object methods
  10771. asCScriptFunction *desc = builder->GetFunctionDescription(funcs[0]);
  10772. if( desc->objectType == 0 ) return;
  10773. // Check if there are any non-const matches
  10774. asUINT n;
  10775. bool foundNonConst = false;
  10776. for( n = 0; n < funcs.GetLength(); n++ )
  10777. {
  10778. desc = builder->GetFunctionDescription(funcs[n]);
  10779. if( desc->isReadOnly != removeConst )
  10780. {
  10781. foundNonConst = true;
  10782. break;
  10783. }
  10784. }
  10785. if( foundNonConst )
  10786. {
  10787. // Remove all const methods
  10788. for( n = 0; n < funcs.GetLength(); n++ )
  10789. {
  10790. desc = builder->GetFunctionDescription(funcs[n]);
  10791. if( desc->isReadOnly == removeConst )
  10792. {
  10793. if( n == funcs.GetLength() - 1 )
  10794. funcs.PopLast();
  10795. else
  10796. funcs[n] = funcs.PopLast();
  10797. n--;
  10798. }
  10799. }
  10800. }
  10801. }
  10802. END_AS_NAMESPACE
  10803. #endif // AS_NO_COMPILER