as_compiler.cpp 386 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871987298739874987598769877987898799880988198829883988498859886988798889889989098919892989398949895989698979898989999009901990299039904990599069907990899099910991199129913991499159916991799189919992099219922992399249925992699279928992999309931993299339934993599369937993899399940994199429943994499459946994799489949995099519952995399549955995699579958995999609961996299639964996599669967996899699970997199729973997499759976997799789979998099819982998399849985998699879988998999909991999299939994999599969997999899991000010001100021000310004100051000610007100081000910010100111001210013100141001510016100171001810019100201002110022100231002410025100261002710028100291003010031100321003310034100351003610037100381003910040100411004210043100441004510046100471004810049100501005110052100531005410055100561005710058100591006010061100621006310064100651006610067100681006910070100711007210073100741007510076100771007810079100801008110082100831008410085100861008710088100891009010091100921009310094100951009610097100981009910100101011010210103101041010510106101071010810109101101011110112101131011410115101161011710118101191012010121101221012310124101251012610127101281012910130101311013210133101341013510136101371013810139101401014110142101431014410145101461014710148101491015010151101521015310154101551015610157101581015910160101611016210163101641016510166101671016810169101701017110172101731017410175101761017710178101791018010181101821018310184101851018610187101881018910190101911019210193101941019510196101971019810199102001020110202102031020410205102061020710208102091021010211102121021310214102151021610217102181021910220102211022210223102241022510226102271022810229102301023110232102331023410235102361023710238102391024010241102421024310244102451024610247102481024910250102511025210253102541025510256102571025810259102601026110262102631026410265102661026710268102691027010271102721027310274102751027610277102781027910280102811028210283102841028510286102871028810289102901029110292102931029410295102961029710298102991030010301103021030310304103051030610307103081030910310103111031210313103141031510316103171031810319103201032110322103231032410325103261032710328103291033010331103321033310334103351033610337103381033910340103411034210343103441034510346103471034810349103501035110352103531035410355103561035710358103591036010361103621036310364103651036610367103681036910370103711037210373103741037510376103771037810379103801038110382103831038410385103861038710388103891039010391103921039310394103951039610397103981039910400104011040210403104041040510406104071040810409104101041110412104131041410415104161041710418104191042010421104221042310424104251042610427104281042910430104311043210433104341043510436104371043810439104401044110442104431044410445104461044710448104491045010451104521045310454104551045610457104581045910460104611046210463104641046510466104671046810469104701047110472104731047410475104761047710478104791048010481104821048310484104851048610487104881048910490104911049210493104941049510496104971049810499105001050110502105031050410505105061050710508105091051010511105121051310514105151051610517105181051910520105211052210523105241052510526105271052810529105301053110532105331053410535105361053710538105391054010541105421054310544105451054610547105481054910550105511055210553105541055510556105571055810559105601056110562105631056410565105661056710568105691057010571105721057310574105751057610577105781057910580105811058210583105841058510586105871058810589105901059110592105931059410595105961059710598105991060010601106021060310604106051060610607106081060910610106111061210613106141061510616106171061810619106201062110622106231062410625106261062710628106291063010631106321063310634106351063610637106381063910640106411064210643106441064510646106471064810649106501065110652106531065410655106561065710658106591066010661106621066310664106651066610667106681066910670106711067210673106741067510676106771067810679106801068110682106831068410685106861068710688106891069010691106921069310694106951069610697106981069910700107011070210703107041070510706107071070810709107101071110712107131071410715107161071710718107191072010721107221072310724107251072610727107281072910730107311073210733107341073510736107371073810739107401074110742107431074410745107461074710748107491075010751107521075310754107551075610757107581075910760107611076210763107641076510766107671076810769107701077110772107731077410775107761077710778107791078010781107821078310784107851078610787107881078910790107911079210793107941079510796107971079810799108001080110802108031080410805108061080710808108091081010811108121081310814108151081610817108181081910820108211082210823108241082510826108271082810829108301083110832108331083410835108361083710838108391084010841108421084310844108451084610847108481084910850108511085210853108541085510856108571085810859108601086110862108631086410865108661086710868108691087010871108721087310874108751087610877108781087910880108811088210883108841088510886108871088810889108901089110892108931089410895108961089710898108991090010901109021090310904109051090610907109081090910910109111091210913109141091510916109171091810919109201092110922109231092410925109261092710928109291093010931109321093310934109351093610937109381093910940109411094210943109441094510946109471094810949109501095110952109531095410955109561095710958109591096010961109621096310964109651096610967109681096910970109711097210973109741097510976109771097810979109801098110982109831098410985109861098710988109891099010991109921099310994109951099610997109981099911000110011100211003110041100511006110071100811009110101101111012110131101411015110161101711018110191102011021110221102311024110251102611027110281102911030110311103211033110341103511036110371103811039110401104111042110431104411045110461104711048110491105011051110521105311054110551105611057110581105911060110611106211063110641106511066110671106811069110701107111072110731107411075110761107711078110791108011081110821108311084110851108611087110881108911090110911109211093110941109511096110971109811099111001110111102111031110411105111061110711108111091111011111111121111311114111151111611117111181111911120111211112211123111241112511126111271112811129111301113111132111331113411135111361113711138111391114011141111421114311144111451114611147111481114911150111511115211153111541115511156111571115811159111601116111162111631116411165111661116711168111691117011171111721117311174111751117611177111781117911180111811118211183111841118511186111871118811189111901119111192111931119411195111961119711198111991120011201112021120311204112051120611207112081120911210112111121211213112141121511216112171121811219112201122111222112231122411225112261122711228112291123011231112321123311234112351123611237112381123911240112411124211243112441124511246112471124811249112501125111252112531125411255112561125711258112591126011261112621126311264112651126611267112681126911270112711127211273112741127511276112771127811279112801128111282112831128411285112861128711288112891129011291112921129311294112951129611297112981129911300113011130211303113041130511306113071130811309113101131111312113131131411315113161131711318113191132011321113221132311324113251132611327113281132911330113311133211333113341133511336113371133811339113401134111342113431134411345113461134711348113491135011351113521135311354113551135611357113581135911360113611136211363113641136511366113671136811369113701137111372113731137411375113761137711378113791138011381113821138311384113851138611387113881138911390113911139211393113941139511396113971139811399114001140111402114031140411405114061140711408114091141011411114121141311414114151141611417114181141911420114211142211423114241142511426114271142811429114301143111432114331143411435114361143711438114391144011441114421144311444114451144611447114481144911450114511145211453114541145511456114571145811459114601146111462114631146411465114661146711468114691147011471114721147311474114751147611477114781147911480114811148211483114841148511486114871148811489114901149111492114931149411495114961149711498114991150011501115021150311504115051150611507115081150911510115111151211513115141151511516115171151811519115201152111522115231152411525115261152711528115291153011531115321153311534115351153611537115381153911540115411154211543115441154511546115471154811549115501155111552115531155411555115561155711558115591156011561115621156311564115651156611567115681156911570115711157211573115741157511576115771157811579115801158111582115831158411585115861158711588115891159011591115921159311594115951159611597115981159911600116011160211603116041160511606116071160811609116101161111612116131161411615116161161711618116191162011621116221162311624116251162611627116281162911630116311163211633116341163511636116371163811639116401164111642116431164411645116461164711648116491165011651116521165311654116551165611657116581165911660116611166211663116641166511666116671166811669116701167111672116731167411675116761167711678116791168011681116821168311684116851168611687116881168911690116911169211693116941169511696116971169811699117001170111702117031170411705117061170711708117091171011711117121171311714117151171611717117181171911720117211172211723117241172511726117271172811729117301173111732117331173411735117361173711738117391174011741117421174311744117451174611747117481174911750117511175211753117541175511756117571175811759117601176111762117631176411765117661176711768117691177011771117721177311774117751177611777117781177911780117811178211783117841178511786117871178811789117901179111792117931179411795117961179711798117991180011801118021180311804118051180611807118081180911810118111181211813118141181511816118171181811819118201182111822118231182411825118261182711828118291183011831118321183311834118351183611837118381183911840118411184211843118441184511846118471184811849118501185111852118531185411855118561185711858118591186011861118621186311864118651186611867118681186911870118711187211873118741187511876118771187811879118801188111882118831188411885118861188711888118891189011891118921189311894118951189611897118981189911900119011190211903119041190511906119071190811909119101191111912119131191411915119161191711918119191192011921119221192311924119251192611927119281192911930119311193211933119341193511936119371193811939119401194111942119431194411945119461194711948119491195011951119521195311954119551195611957119581195911960119611196211963119641196511966119671196811969119701197111972119731197411975119761197711978119791198011981119821198311984119851198611987119881198911990119911199211993119941199511996119971199811999120001200112002120031200412005120061200712008120091201012011120121201312014120151201612017120181201912020120211202212023120241202512026120271202812029120301203112032120331203412035120361203712038120391204012041120421204312044120451204612047120481204912050120511205212053120541205512056120571205812059120601206112062120631206412065120661206712068120691207012071120721207312074120751207612077120781207912080120811208212083120841208512086120871208812089120901209112092120931209412095120961209712098120991210012101121021210312104121051210612107121081210912110121111211212113121141211512116121171211812119121201212112122121231212412125121261212712128121291213012131121321213312134121351213612137121381213912140121411214212143121441214512146121471214812149121501215112152121531215412155121561215712158121591216012161121621216312164121651216612167121681216912170121711217212173121741217512176121771217812179121801218112182121831218412185121861218712188121891219012191121921219312194121951219612197121981219912200122011220212203122041220512206122071220812209122101221112212122131221412215122161221712218122191222012221122221222312224122251222612227122281222912230122311223212233122341223512236122371223812239122401224112242122431224412245122461224712248122491225012251122521225312254122551225612257122581225912260122611226212263122641226512266122671226812269122701227112272122731227412275122761227712278122791228012281122821228312284122851228612287122881228912290122911229212293122941229512296122971229812299123001230112302123031230412305123061230712308123091231012311123121231312314
  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->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->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. asUINT n;
  201. // Finalize the bytecode
  202. byteCode.Finalize(tempVariableOffsets);
  203. byteCode.ExtractObjectVariableInfo(outFunc);
  204. // Compile the list of object variables for the exception handler
  205. // Start with the variables allocated on the heap, and then the ones allocated on the stack
  206. for( n = 0; n < variableAllocations.GetLength(); n++ )
  207. {
  208. if( variableAllocations[n].IsObject() && !variableAllocations[n].IsReference() )
  209. {
  210. if( variableIsOnHeap[n] )
  211. {
  212. outFunc->objVariableTypes.PushLast(variableAllocations[n].GetObjectType());
  213. outFunc->funcVariableTypes.PushLast(variableAllocations[n].GetFuncDef());
  214. outFunc->objVariablePos.PushLast(GetVariableOffset(n));
  215. }
  216. }
  217. }
  218. outFunc->objVariablesOnHeap = asUINT(outFunc->objVariablePos.GetLength());
  219. for( n = 0; n < variableAllocations.GetLength(); n++ )
  220. {
  221. if( variableAllocations[n].IsObject() && !variableAllocations[n].IsReference() )
  222. {
  223. if( !variableIsOnHeap[n] )
  224. {
  225. outFunc->objVariableTypes.PushLast(variableAllocations[n].GetObjectType());
  226. outFunc->funcVariableTypes.PushLast(variableAllocations[n].GetFuncDef());
  227. outFunc->objVariablePos.PushLast(GetVariableOffset(n));
  228. }
  229. }
  230. }
  231. // Copy byte code to the function
  232. asASSERT( outFunc->byteCode.GetLength() == 0 );
  233. outFunc->byteCode.SetLength(byteCode.GetSize());
  234. byteCode.Output(outFunc->byteCode.AddressOf());
  235. outFunc->AddReferences();
  236. outFunc->stackNeeded = byteCode.largestStackUsed + outFunc->variableSpace;
  237. outFunc->lineNumbers = byteCode.lineNumbers;
  238. // Extract the script section indexes too if there are any entries that are different from the function's script section
  239. int lastIdx = outFunc->scriptSectionIdx;
  240. for( n = 0; n < byteCode.sectionIdxs.GetLength(); n++ )
  241. {
  242. if( byteCode.sectionIdxs[n] != lastIdx )
  243. {
  244. lastIdx = byteCode.sectionIdxs[n];
  245. outFunc->sectionIdxs.PushLast(byteCode.lineNumbers[n*2]);
  246. outFunc->sectionIdxs.PushLast(lastIdx);
  247. }
  248. }
  249. }
  250. // internal
  251. int asCCompiler::SetupParametersAndReturnVariable(asCArray<asCString> &parameterNames, asCScriptNode *func)
  252. {
  253. int stackPos = 0;
  254. if( outFunc->objectType )
  255. stackPos = -AS_PTR_SIZE; // The first parameter is the pointer to the object
  256. // Add the first variable scope, which the parameters and
  257. // variables declared in the outermost statement block is
  258. // part of.
  259. AddVariableScope();
  260. bool isDestructor = false;
  261. asCDataType returnType;
  262. // Examine return type
  263. returnType = outFunc->returnType;
  264. // Check if this is a constructor or destructor
  265. if( returnType.GetTokenType() == ttVoid && outFunc->objectType )
  266. {
  267. if( outFunc->name[0] == '~' )
  268. isDestructor = true;
  269. else if( outFunc->objectType->name == outFunc->name )
  270. m_isConstructor = true;
  271. }
  272. // Is the return type allowed?
  273. if( (!returnType.CanBeInstanciated() && returnType != asCDataType::CreatePrimitive(ttVoid, false)) ||
  274. (returnType.IsReference() && !returnType.CanBeInstanciated()) )
  275. {
  276. // TODO: Hasn't this been validated by the builder already?
  277. asCString str;
  278. str.Format(TXT_RETURN_CANT_BE_s, returnType.Format().AddressOf());
  279. Error(str, func);
  280. }
  281. // If the return type is a value type returned by value the address of the
  282. // location where the value will be stored is pushed on the stack before
  283. // the arguments
  284. if( !(isDestructor || m_isConstructor) && outFunc->DoesReturnOnStack() )
  285. stackPos -= AS_PTR_SIZE;
  286. asCVariableScope vs(0);
  287. // Declare parameters
  288. asUINT n;
  289. for( n = 0; n < parameterNames.GetLength(); n++ )
  290. {
  291. // Get the parameter type
  292. asCDataType &type = outFunc->parameterTypes[n];
  293. asETypeModifiers inoutFlag = outFunc->inOutFlags[n];
  294. // Is the data type allowed?
  295. // TODO: Hasn't this been validated by the builder already?
  296. if( (type.IsReference() && inoutFlag != asTM_INOUTREF && !type.CanBeInstanciated()) ||
  297. (!type.IsReference() && !type.CanBeInstanciated()) )
  298. {
  299. asCString parm = type.Format();
  300. if( inoutFlag == asTM_INREF )
  301. parm += "in";
  302. else if( inoutFlag == asTM_OUTREF )
  303. parm += "out";
  304. asCString str;
  305. str.Format(TXT_PARAMETER_CANT_BE_s, parm.AddressOf());
  306. Error(str, func);
  307. }
  308. // If the parameter has a name then declare it as variable
  309. if( parameterNames[n] != "" )
  310. {
  311. asCString &name = parameterNames[n];
  312. if( vs.DeclareVariable(name.AddressOf(), type, stackPos, true) < 0 )
  313. {
  314. // TODO: It might be an out-of-memory too
  315. Error(TXT_PARAMETER_ALREADY_DECLARED, func);
  316. }
  317. // Add marker for variable declaration
  318. byteCode.VarDecl((int)outFunc->variables.GetLength());
  319. outFunc->AddVariable(name, type, stackPos);
  320. }
  321. else
  322. vs.DeclareVariable("", type, stackPos, true);
  323. // Move to next parameter
  324. stackPos -= type.GetSizeOnStackDWords();
  325. }
  326. for( n = asUINT(vs.variables.GetLength()); n-- > 0; )
  327. variables->DeclareVariable(vs.variables[n]->name.AddressOf(), vs.variables[n]->type, vs.variables[n]->stackOffset, vs.variables[n]->onHeap);
  328. variables->DeclareVariable("return", returnType, stackPos, true);
  329. return stackPos;
  330. }
  331. void asCCompiler::CompileMemberInitialization(asCByteCode *byteCode, bool onlyDefaults)
  332. {
  333. asASSERT( m_classDecl );
  334. // Initialize each member in the order they were declared
  335. for( asUINT n = 0; n < outFunc->objectType->properties.GetLength(); n++ )
  336. {
  337. asCObjectProperty *prop = outFunc->objectType->properties[n];
  338. // Check if the property has an initialization expression
  339. asCScriptNode *declNode = 0;
  340. asCScriptNode *initNode = 0;
  341. asCScriptCode *initScript = 0;
  342. for( asUINT m = 0; m < m_classDecl->propInits.GetLength(); m++ )
  343. {
  344. if( m_classDecl->propInits[m].name == prop->name )
  345. {
  346. declNode = m_classDecl->propInits[m].declNode;
  347. initNode = m_classDecl->propInits[m].initNode;
  348. initScript = m_classDecl->propInits[m].file;
  349. break;
  350. }
  351. }
  352. // If declNode is null, the property was inherited in which case
  353. // it was already initialized by the base class' constructor
  354. if( declNode )
  355. {
  356. if( initNode )
  357. {
  358. if( onlyDefaults )
  359. continue;
  360. #ifdef AS_NO_MEMBER_INIT
  361. // Give an error as the initialization in the declaration has been disabled
  362. asCScriptCode *origScript = script;
  363. script = initScript;
  364. Error("Initialization of members in declaration is not supported", initNode);
  365. script = origScript;
  366. // Clear the initialization node
  367. initNode = 0;
  368. initScript = script;
  369. #else
  370. // Re-parse the initialization expression as the parser now knows the types, which it didn't earlier
  371. asCParser parser(builder);
  372. int r = parser.ParseVarInit(initScript, initNode);
  373. if( r < 0 )
  374. continue;
  375. initNode = parser.GetScriptNode();
  376. #endif
  377. }
  378. else
  379. {
  380. if( !onlyDefaults )
  381. continue;
  382. }
  383. #ifdef AS_NO_MEMBER_INIT
  384. // The initialization will be done in the asCScriptObject constructor, so
  385. // here we should just validate that the member has a default constructor
  386. if( prop->type.IsObject() &&
  387. !prop->type.IsObjectHandle() &&
  388. (((prop->type.GetObjectType()->flags & asOBJ_REF) &&
  389. prop->type.GetBehaviour()->factory == 0) ||
  390. ((prop->type.GetObjectType()->flags & asOBJ_VALUE) &&
  391. prop->type.GetBehaviour()->construct == 0 &&
  392. !(prop->type.GetObjectType()->flags & asOBJ_POD))) )
  393. {
  394. // Class has no default factory/constructor.
  395. asCString str;
  396. // TODO: funcdef: asCDataType should have a GetTypeName()
  397. if( prop->type.GetFuncDef() )
  398. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, prop->type.GetFuncDef()->GetName());
  399. else
  400. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, prop->type.GetObjectType()->GetName());
  401. Error(str, declNode);
  402. }
  403. #else
  404. // Temporarily set the script that is being compiled to where the member initialization is declared.
  405. // The script can be different when including mixin classes from a different script section
  406. asCScriptCode *origScript = script;
  407. script = initScript;
  408. // Add a line instruction with the position of the declaration
  409. LineInstr(byteCode, declNode->tokenPos);
  410. // Compile the initialization
  411. asQWORD constantValue;
  412. asCByteCode bc(engine);
  413. CompileInitialization(initNode, &bc, prop->type, declNode, prop->byteOffset, &constantValue, 2);
  414. byteCode->AddCode(&bc);
  415. script = origScript;
  416. #endif
  417. }
  418. }
  419. }
  420. // Entry
  421. int asCCompiler::CompileFunction(asCBuilder *builder, asCScriptCode *script, asCArray<asCString> &parameterNames, asCScriptNode *func, asCScriptFunction *outFunc, sClassDeclaration *classDecl)
  422. {
  423. TimeIt("asCCompiler::CompileFunction");
  424. Reset(builder, script, outFunc);
  425. int buildErrors = builder->numErrors;
  426. int stackPos = SetupParametersAndReturnVariable(parameterNames, func);
  427. //--------------------------------------------
  428. // Compile the statement block
  429. if( m_isConstructor )
  430. m_classDecl = classDecl;
  431. // We need to parse the statement block now
  432. asCScriptNode *blockBegin;
  433. // If the function signature was implicit, e.g. virtual property
  434. // accessor, then the received node already is the statement block
  435. if( func->nodeType != snStatementBlock )
  436. blockBegin = func->lastChild;
  437. else
  438. blockBegin = func;
  439. // TODO: memory: We can parse the statement block one statement at a time, thus save even more memory
  440. // 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
  441. asCParser parser(builder);
  442. int r = parser.ParseStatementBlock(script, blockBegin);
  443. if( r < 0 ) return -1;
  444. asCScriptNode *block = parser.GetScriptNode();
  445. // Reserve a label for the cleanup code
  446. nextLabel++;
  447. bool hasReturn;
  448. asCByteCode bc(engine);
  449. LineInstr(&bc, blockBegin->tokenPos);
  450. CompileStatementBlock(block, false, &hasReturn, &bc);
  451. LineInstr(&bc, blockBegin->tokenPos + blockBegin->tokenLength);
  452. // Make sure there is a return in all paths (if not return type is void)
  453. // Don't bother with this check if there are compiler errors, e.g. Unreachable code
  454. if( !hasCompileErrors && outFunc->returnType != asCDataType::CreatePrimitive(ttVoid, false) )
  455. {
  456. if( hasReturn == false )
  457. Error(TXT_NOT_ALL_PATHS_RETURN, blockBegin);
  458. }
  459. //------------------------------------------------
  460. // Concatenate the bytecode
  461. // Insert a JitEntry at the start of the function for JIT compilers
  462. byteCode.InstrPTR(asBC_JitEntry, 0);
  463. if( outFunc->objectType )
  464. {
  465. if( m_isConstructor )
  466. {
  467. if( outFunc->objectType->derivedFrom )
  468. {
  469. // Call the base class' default constructor unless called manually in the code
  470. if( !m_isConstructorCalled )
  471. {
  472. if( outFunc->objectType->derivedFrom->beh.construct )
  473. {
  474. // Initialize members without explicit expression first
  475. CompileMemberInitialization(&byteCode, true);
  476. // Call base class' constructor
  477. asCByteCode tmpBC(engine);
  478. tmpBC.InstrSHORT(asBC_PSF, 0);
  479. tmpBC.Instr(asBC_RDSPtr);
  480. tmpBC.Call(asBC_CALL, outFunc->objectType->derivedFrom->beh.construct, AS_PTR_SIZE);
  481. tmpBC.OptimizeLocally(tempVariableOffsets);
  482. byteCode.AddCode(&tmpBC);
  483. // Add the initialization of the members with explicit expressions
  484. CompileMemberInitialization(&byteCode, false);
  485. }
  486. else
  487. Error(TEXT_BASE_DOESNT_HAVE_DEF_CONSTR, blockBegin);
  488. }
  489. else
  490. {
  491. // Only initialize members that don't have an explicit expression
  492. // The members that are explicitly initialized will be initialized after the call to base class' constructor
  493. CompileMemberInitialization(&byteCode, true);
  494. }
  495. }
  496. else
  497. {
  498. // Add the initialization of the members
  499. CompileMemberInitialization(&byteCode, true);
  500. CompileMemberInitialization(&byteCode, false);
  501. }
  502. }
  503. // Increase the reference for the object pointer, so that it is guaranteed to live during the entire call
  504. if( !m_isConstructor && !outFunc->returnType.IsReference() )
  505. {
  506. // TODO: runtime optimize: If the function is trivial, i.e. doesn't access any outside functions,
  507. // then this is not necessary. If I implement this, then the function needs
  508. // to set a flag so the exception handler doesn't try to release the handle.
  509. // It is not necessary to do this for constructors, as they have no outside references that can be released anyway
  510. // It is not necessary to do this for methods that return references, as the caller is guaranteed to hold a reference to the object
  511. asCByteCode tmpBC(engine);
  512. tmpBC.InstrSHORT(asBC_PSF, 0);
  513. tmpBC.Instr(asBC_RDSPtr);
  514. tmpBC.Call(asBC_CALLSYS, outFunc->objectType->beh.addref, AS_PTR_SIZE);
  515. tmpBC.OptimizeLocally(tempVariableOffsets);
  516. byteCode.AddCode(&tmpBC);
  517. }
  518. }
  519. // Add the code for the statement block
  520. byteCode.AddCode(&bc);
  521. // Count total variable size
  522. int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1;
  523. outFunc->variableSpace = varSize;
  524. // Deallocate all local variables
  525. int n;
  526. for( n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  527. {
  528. sVariable *v = variables->variables[n];
  529. if( v->stackOffset > 0 )
  530. {
  531. // Call variables destructors
  532. if( v->name != "return" && v->name != "return address" )
  533. CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode);
  534. DeallocateVariable(v->stackOffset);
  535. }
  536. }
  537. // This is the label that return statements jump to
  538. // in order to exit the function
  539. byteCode.Label(0);
  540. // Call destructors for function parameters
  541. for( n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  542. {
  543. sVariable *v = variables->variables[n];
  544. if( v->stackOffset <= 0 )
  545. {
  546. // Call variable destructors here, for variables not yet destroyed
  547. if( v->name != "return" && v->name != "return address" )
  548. CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode);
  549. }
  550. // Do not deallocate parameters
  551. }
  552. // Release the object pointer again
  553. if( outFunc->objectType && !m_isConstructor && !outFunc->returnType.IsReference() )
  554. byteCode.InstrW_PTR(asBC_FREE, 0, outFunc->objectType);
  555. // Check if the number of labels in the functions isn't too many to be handled
  556. if( nextLabel >= (1<<15) )
  557. Error(TXT_TOO_MANY_JUMP_LABELS, func);
  558. // If there are compile errors, there is no reason to build the final code
  559. if( hasCompileErrors || builder->numErrors != buildErrors )
  560. return -1;
  561. // At this point there should be no variables allocated
  562. asASSERT(variableAllocations.GetLength() == freeVariables.GetLength());
  563. // Remove the variable scope
  564. RemoveVariableScope();
  565. byteCode.Ret(-stackPos);
  566. FinalizeFunction();
  567. #ifdef AS_DEBUG
  568. // DEBUG: output byte code
  569. if( outFunc->objectType )
  570. byteCode.DebugOutput(("__" + outFunc->objectType->name + "_" + outFunc->name + ".txt").AddressOf(), engine, outFunc);
  571. else
  572. byteCode.DebugOutput(("__" + outFunc->name + ".txt").AddressOf(), engine, outFunc);
  573. #endif
  574. return 0;
  575. }
  576. int asCCompiler::CallCopyConstructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asSExprContext *arg, asCScriptNode *node, bool isGlobalVar, bool derefDest)
  577. {
  578. if( !type.IsObject() )
  579. return 0;
  580. // CallCopyConstructor should not be called for object handles.
  581. asASSERT( !type.IsObjectHandle() );
  582. asCArray<asSExprContext*> args;
  583. args.PushLast(arg);
  584. // The reference parameter must be pushed on the stack
  585. asASSERT( arg->type.dataType.GetObjectType() == type.GetObjectType() );
  586. // Since we're calling the copy constructor, we have to trust the function to not do
  587. // anything stupid otherwise we will just enter a loop, as we try to make temporary
  588. // copies of the argument in order to guarantee safety.
  589. if( type.GetObjectType()->flags & asOBJ_REF )
  590. {
  591. asSExprContext ctx(engine);
  592. int func = 0;
  593. asSTypeBehaviour *beh = type.GetBehaviour();
  594. if( beh ) func = beh->copyfactory;
  595. if( func > 0 )
  596. {
  597. if( !isGlobalVar )
  598. {
  599. // Call factory and store the handle in the given variable
  600. PerformFunctionCall(func, &ctx, false, &args, type.GetObjectType(), true, offset);
  601. // Pop the reference left by the function call
  602. ctx.bc.Instr(asBC_PopPtr);
  603. }
  604. else
  605. {
  606. // Call factory
  607. PerformFunctionCall(func, &ctx, false, &args, type.GetObjectType());
  608. // Store the returned handle in the global variable
  609. ctx.bc.Instr(asBC_RDSPtr);
  610. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  611. ctx.bc.InstrPTR(asBC_REFCPY, type.GetObjectType());
  612. ctx.bc.Instr(asBC_PopPtr);
  613. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  614. }
  615. bc->AddCode(&ctx.bc);
  616. return 0;
  617. }
  618. }
  619. else
  620. {
  621. asSTypeBehaviour *beh = type.GetBehaviour();
  622. int func = beh ? beh->copyconstruct : 0;
  623. if( func > 0 )
  624. {
  625. // Push the address where the object will be stored on the stack, before the argument
  626. // TODO: When the context is serializable this probably has to be changed, since this
  627. // pointer can remain on the stack while the context is suspended. There is no
  628. // risk the pointer becomes invalid though, there is just no easy way to serialize it.
  629. asCByteCode tmp(engine);
  630. if( isGlobalVar )
  631. tmp.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  632. else if( isObjectOnHeap )
  633. tmp.InstrSHORT(asBC_PSF, (short)offset);
  634. tmp.AddCode(bc);
  635. bc->AddCode(&tmp);
  636. // When the object is allocated on the stack the object pointer
  637. // must be pushed on the stack after the arguments
  638. if( !isObjectOnHeap )
  639. {
  640. asASSERT( !isGlobalVar );
  641. bc->InstrSHORT(asBC_PSF, (short)offset);
  642. if( derefDest )
  643. {
  644. // The variable is a reference to the real location, so we need to dereference it
  645. bc->Instr(asBC_RDSPtr);
  646. }
  647. }
  648. asSExprContext ctx(engine);
  649. PerformFunctionCall(func, &ctx, isObjectOnHeap, &args, type.GetObjectType());
  650. bc->AddCode(&ctx.bc);
  651. // TODO: value on stack: This probably needs to be done in PerformFunctionCall
  652. // Mark the object as initialized
  653. if( !isObjectOnHeap )
  654. bc->ObjInfo(offset, asOBJ_INIT);
  655. return 0;
  656. }
  657. }
  658. // Class has no copy constructor/factory.
  659. asCString str;
  660. str.Format(TXT_NO_COPY_CONSTRUCTOR_FOR_s, type.GetObjectType()->GetName());
  661. Error(str, node);
  662. return -1;
  663. }
  664. int asCCompiler::CallDefaultConstructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asCScriptNode *node, int isVarGlobOrMem, bool deferDest)
  665. {
  666. if( !type.IsObject() || type.IsObjectHandle() )
  667. return 0;
  668. if( type.GetObjectType()->flags & asOBJ_REF )
  669. {
  670. asSExprContext ctx(engine);
  671. ctx.exprNode = node;
  672. int func = 0;
  673. asSTypeBehaviour *beh = type.GetBehaviour();
  674. if( beh ) func = beh->factory;
  675. if( func > 0 )
  676. {
  677. if( isVarGlobOrMem == 0 )
  678. {
  679. // Call factory and store the handle in the given variable
  680. PerformFunctionCall(func, &ctx, false, 0, type.GetObjectType(), true, offset);
  681. // Pop the reference left by the function call
  682. ctx.bc.Instr(asBC_PopPtr);
  683. }
  684. else
  685. {
  686. // Call factory
  687. PerformFunctionCall(func, &ctx, false, 0, type.GetObjectType());
  688. // TODO: runtime optimize: Should have a way of storing the object pointer directly to the destination
  689. // instead of first storing it in a local variable and then copying it to the
  690. // destination.
  691. if( !(type.GetObjectType()->flags & asOBJ_SCOPED) )
  692. {
  693. // Only dereference the variable if not a scoped type
  694. ctx.bc.Instr(asBC_RDSPtr);
  695. }
  696. if( isVarGlobOrMem == 1 )
  697. {
  698. // Store the returned handle in the global variable
  699. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  700. }
  701. else
  702. {
  703. // Store the returned handle in the class member
  704. ctx.bc.InstrSHORT(asBC_PSF, 0);
  705. ctx.bc.Instr(asBC_RDSPtr);
  706. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
  707. }
  708. if( type.GetObjectType()->flags & asOBJ_SCOPED )
  709. {
  710. // For scoped typed we must move the reference from the local
  711. // variable rather than copy it as there is no AddRef behaviour
  712. ctx.bc.InstrSHORT_DW(asBC_COPY, AS_PTR_SIZE, asTYPEID_OBJHANDLE | engine->GetTypeIdFromDataType(type));
  713. // Clear the local variable so the reference isn't released
  714. ctx.bc.InstrSHORT(asBC_ClrVPtr, ctx.type.stackOffset);
  715. }
  716. else
  717. {
  718. ctx.bc.InstrPTR(asBC_REFCPY, type.GetObjectType());
  719. }
  720. ctx.bc.Instr(asBC_PopPtr);
  721. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  722. }
  723. bc->AddCode(&ctx.bc);
  724. return 0;
  725. }
  726. }
  727. else
  728. {
  729. asSTypeBehaviour *beh = type.GetBehaviour();
  730. int func = 0;
  731. if( beh ) func = beh->construct;
  732. // Allocate and initialize with the default constructor
  733. if( func != 0 || (type.GetObjectType()->flags & asOBJ_POD) )
  734. {
  735. if( !isObjectOnHeap )
  736. {
  737. asASSERT( isVarGlobOrMem == 0 );
  738. // There is nothing to do if there is no function,
  739. // as the memory is already allocated on the stack
  740. if( func )
  741. {
  742. // Call the constructor as a normal function
  743. bc->InstrSHORT(asBC_PSF, (short)offset);
  744. if( deferDest )
  745. bc->Instr(asBC_RDSPtr);
  746. asSExprContext ctx(engine);
  747. PerformFunctionCall(func, &ctx, false, 0, type.GetObjectType());
  748. bc->AddCode(&ctx.bc);
  749. // TODO: value on stack: This probably needs to be done in PerformFunctionCall
  750. // Mark the object as initialized
  751. bc->ObjInfo(offset, asOBJ_INIT);
  752. }
  753. }
  754. else
  755. {
  756. if( isVarGlobOrMem == 0 )
  757. bc->InstrSHORT(asBC_PSF, (short)offset);
  758. else if( isVarGlobOrMem == 1 )
  759. bc->InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  760. else
  761. {
  762. bc->InstrSHORT(asBC_PSF, 0);
  763. bc->Instr(asBC_RDSPtr);
  764. bc->InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
  765. }
  766. bc->Alloc(asBC_ALLOC, type.GetObjectType(), func, AS_PTR_SIZE);
  767. }
  768. return 0;
  769. }
  770. }
  771. // Class has no default factory/constructor.
  772. asCString str;
  773. // TODO: funcdef: asCDataType should have a GetTypeName()
  774. if( type.GetFuncDef() )
  775. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, type.GetFuncDef()->GetName());
  776. else
  777. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, type.GetObjectType()->GetName());
  778. Error(str, node);
  779. return -1;
  780. }
  781. void asCCompiler::CallDestructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc)
  782. {
  783. if( !type.IsReference() )
  784. {
  785. // Call destructor for the data type
  786. if( type.IsObject() )
  787. {
  788. if( isObjectOnHeap || type.IsObjectHandle() )
  789. {
  790. // Free the memory
  791. bc->InstrW_PTR(asBC_FREE, (short)offset, type.GetObjectType());
  792. }
  793. else
  794. {
  795. asASSERT( type.GetObjectType()->GetFlags() & asOBJ_VALUE );
  796. if( type.GetBehaviour()->destruct )
  797. {
  798. // Call the destructor as a regular function
  799. asSExprContext ctx(engine);
  800. ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
  801. PerformFunctionCall(type.GetBehaviour()->destruct, &ctx);
  802. ctx.bc.OptimizeLocally(tempVariableOffsets);
  803. bc->AddCode(&ctx.bc);
  804. }
  805. // TODO: Value on stack: This probably needs to be done in PerformFunctionCall
  806. // Mark the object as destroyed
  807. bc->ObjInfo(offset, asOBJ_UNINIT);
  808. }
  809. }
  810. }
  811. }
  812. void asCCompiler::LineInstr(asCByteCode *bc, size_t pos)
  813. {
  814. int r, c;
  815. script->ConvertPosToRowCol(pos, &r, &c);
  816. bc->Line(r, c, script->idx);
  817. }
  818. void asCCompiler::CompileStatementBlock(asCScriptNode *block, bool ownVariableScope, bool *hasReturn, asCByteCode *bc)
  819. {
  820. *hasReturn = false;
  821. bool isFinished = false;
  822. bool hasUnreachableCode = false;
  823. bool hasReturnBefore = false;
  824. if( ownVariableScope )
  825. {
  826. bc->Block(true);
  827. AddVariableScope();
  828. }
  829. asCScriptNode *node = block->firstChild;
  830. while( node )
  831. {
  832. if( !hasUnreachableCode && (*hasReturn || isFinished) )
  833. {
  834. // Empty statements don't count
  835. if( node->nodeType != snExpressionStatement || node->firstChild )
  836. {
  837. hasUnreachableCode = true;
  838. Warning(TXT_UNREACHABLE_CODE, node);
  839. }
  840. if( *hasReturn )
  841. hasReturnBefore = true;
  842. }
  843. if( node->nodeType == snBreak || node->nodeType == snContinue )
  844. isFinished = true;
  845. asCByteCode statement(engine);
  846. if( node->nodeType == snDeclaration )
  847. CompileDeclaration(node, &statement);
  848. else
  849. CompileStatement(node, hasReturn, &statement);
  850. // Ignore missing returns in unreachable code paths
  851. if( !(*hasReturn) && hasReturnBefore )
  852. *hasReturn = true;
  853. LineInstr(bc, node->tokenPos);
  854. bc->AddCode(&statement);
  855. if( !hasCompileErrors )
  856. {
  857. asASSERT( tempVariables.GetLength() == 0 );
  858. asASSERT( reservedVariables.GetLength() == 0 );
  859. }
  860. node = node->next;
  861. }
  862. if( ownVariableScope )
  863. {
  864. // Deallocate variables in this block, in reverse order
  865. for( int n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  866. {
  867. sVariable *v = variables->variables[n];
  868. // Call variable destructors here, for variables not yet destroyed
  869. // If the block is terminated with a break, continue, or
  870. // return the variables are already destroyed
  871. if( !isFinished && !*hasReturn )
  872. CallDestructor(v->type, v->stackOffset, v->onHeap, bc);
  873. // Don't deallocate function parameters
  874. if( v->stackOffset > 0 )
  875. DeallocateVariable(v->stackOffset);
  876. }
  877. RemoveVariableScope();
  878. bc->Block(false);
  879. }
  880. }
  881. // Entry
  882. int asCCompiler::CompileGlobalVariable(asCBuilder *builder, asCScriptCode *script, asCScriptNode *node, sGlobalVariableDescription *gvar, asCScriptFunction *outFunc)
  883. {
  884. Reset(builder, script, outFunc);
  885. // Add a variable scope (even though variables can't be declared)
  886. AddVariableScope();
  887. gvar->isPureConstant = false;
  888. // Parse the initialization nodes
  889. asCParser parser(builder);
  890. if( node )
  891. {
  892. int r = parser.ParseVarInit(script, node);
  893. if( r < 0 )
  894. return r;
  895. node = parser.GetScriptNode();
  896. }
  897. // Compile the expression
  898. asSExprContext ctx(engine);
  899. asQWORD constantValue;
  900. if( CompileInitialization(node, &ctx.bc, gvar->datatype, gvar->idNode, gvar->index, &constantValue, 1) )
  901. {
  902. // Should the variable be marked as pure constant?
  903. if( gvar->datatype.IsPrimitive() && gvar->datatype.IsReadOnly() )
  904. {
  905. gvar->isPureConstant = true;
  906. gvar->constantValue = constantValue;
  907. }
  908. }
  909. // Concatenate the bytecode
  910. int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1;
  911. // Add information on the line number for the global variable
  912. size_t pos = 0;
  913. if( gvar->idNode )
  914. pos = gvar->idNode->tokenPos;
  915. else if( gvar->nextNode )
  916. pos = gvar->nextNode->tokenPos;
  917. LineInstr(&byteCode, pos);
  918. // Reserve space for all local variables
  919. outFunc->variableSpace = varSize;
  920. ctx.bc.OptimizeLocally(tempVariableOffsets);
  921. byteCode.AddCode(&ctx.bc);
  922. // Deallocate variables in this block, in reverse order
  923. for( int n = (int)variables->variables.GetLength() - 1; n >= 0; --n )
  924. {
  925. sVariable *v = variables->variables[n];
  926. // Call variable destructors here, for variables not yet destroyed
  927. CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode);
  928. DeallocateVariable(v->stackOffset);
  929. }
  930. if( hasCompileErrors ) return -1;
  931. // At this point there should be no variables allocated
  932. asASSERT(variableAllocations.GetLength() == freeVariables.GetLength());
  933. // Remove the variable scope again
  934. RemoveVariableScope();
  935. byteCode.Ret(0);
  936. FinalizeFunction();
  937. #ifdef AS_DEBUG
  938. // DEBUG: output byte code
  939. byteCode.DebugOutput(("___init_" + gvar->name + ".txt").AddressOf(), engine, outFunc);
  940. #endif
  941. return 0;
  942. }
  943. void asCCompiler::DetermineSingleFunc(asSExprContext *ctx, asCScriptNode *node)
  944. {
  945. // Don't do anything if this is not a deferred global function
  946. if( ctx->methodName == "" || ctx->type.dataType.GetObjectType() != 0 )
  947. return;
  948. // Determine the namespace
  949. asSNameSpace *ns = 0;
  950. asCString name = "";
  951. int pos = ctx->methodName.FindLast("::");
  952. if( pos >= 0 )
  953. {
  954. asCString nsName = ctx->methodName.SubString(0, pos+2);
  955. ns = DetermineNameSpace(nsName);
  956. name = ctx->methodName.SubString(pos+2);
  957. }
  958. else
  959. {
  960. DetermineNameSpace("");
  961. name = ctx->methodName;
  962. }
  963. asCArray<int> funcs;
  964. if( ns )
  965. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  966. // CompileVariableAccess should guarantee that at least one function is exists
  967. asASSERT( funcs.GetLength() > 0 );
  968. if( funcs.GetLength() > 1 )
  969. {
  970. asCString str;
  971. str.Format(TXT_MULTIPLE_MATCHING_SIGNATURES_TO_s, ctx->methodName.AddressOf());
  972. Error(str, node);
  973. // Fall through so the compiler can continue as if only one function was matching
  974. }
  975. // A shared object may not access global functions unless they too are shared (e.g. registered functions)
  976. if( !builder->GetFunctionDescription(funcs[0])->IsShared() &&
  977. outFunc->IsShared() )
  978. {
  979. asCString msg;
  980. msg.Format(TXT_SHARED_CANNOT_CALL_NON_SHARED_FUNC_s, builder->GetFunctionDescription(funcs[0])->GetDeclaration());
  981. Error(msg, node);
  982. // Fall through so the compiler can continue anyway
  983. }
  984. // Push the function pointer on the stack
  985. ctx->bc.InstrPTR(asBC_FuncPtr, builder->GetFunctionDescription(funcs[0]));
  986. ctx->type.Set(asCDataType::CreateFuncDef(builder->GetFunctionDescription(funcs[0])));
  987. ctx->type.dataType.MakeHandle(true);
  988. ctx->type.isExplicitHandle = true;
  989. ctx->methodName = "";
  990. }
  991. void asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, asCScriptNode *node, bool isFunction, int refType, bool isMakingCopy)
  992. {
  993. asCDataType param = *paramType;
  994. if( paramType->GetTokenType() == ttQuestion )
  995. {
  996. // The function is expecting a var type. If the argument is a function name, we must now decide which function it is
  997. DetermineSingleFunc(ctx, node);
  998. // Since the function is expecting a var type ?, then we don't want to convert the argument to anything else
  999. param = ctx->type.dataType;
  1000. param.MakeHandle(ctx->type.isExplicitHandle);
  1001. // Reference types will always be passed as handles to ? parameters
  1002. if( builder->engine->ep.disallowValueAssignForRefType &&
  1003. ctx->type.dataType.GetObjectType() && (ctx->type.dataType.GetObjectType()->flags & asOBJ_REF) && !(ctx->type.dataType.GetObjectType()->flags & asOBJ_SCOPED) )
  1004. {
  1005. param.MakeHandle(true);
  1006. }
  1007. param.MakeReference(paramType->IsReference());
  1008. param.MakeReadOnly(paramType->IsReadOnly());
  1009. }
  1010. else
  1011. param = *paramType;
  1012. asCDataType dt = param;
  1013. // Need to protect arguments by reference
  1014. if( isFunction && dt.IsReference() )
  1015. {
  1016. // Allocate a temporary variable of the same type as the argument
  1017. dt.MakeReference(false);
  1018. dt.MakeReadOnly(false);
  1019. int offset;
  1020. if( refType == 1 ) // &in
  1021. {
  1022. ProcessPropertyGetAccessor(ctx, node);
  1023. // Add the type id as hidden arg if the parameter is a ? type
  1024. if( paramType->GetTokenType() == ttQuestion )
  1025. {
  1026. asCByteCode tmpBC(engine);
  1027. // Place the type id on the stack as a hidden parameter
  1028. tmpBC.InstrDWORD(asBC_TYPEID, engine->GetTypeIdFromDataType(param));
  1029. // Insert the code before the expression code
  1030. tmpBC.AddCode(&ctx->bc);
  1031. ctx->bc.AddCode(&tmpBC);
  1032. }
  1033. // If the reference is const, then it is not necessary to make a copy if the value already is a variable
  1034. // Even if the same variable is passed in another argument as non-const then there is no problem
  1035. if( dt.IsPrimitive() || dt.IsNullHandle() )
  1036. {
  1037. IsVariableInitialized(&ctx->type, node);
  1038. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  1039. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true);
  1040. if( !(param.IsReadOnly() && ctx->type.isVariable) )
  1041. ConvertToTempVariable(ctx);
  1042. PushVariableOnStack(ctx, true);
  1043. ctx->type.dataType.MakeReadOnly(param.IsReadOnly());
  1044. }
  1045. else
  1046. {
  1047. IsVariableInitialized(&ctx->type, node);
  1048. if( !isMakingCopy )
  1049. {
  1050. ImplicitConversion(ctx, param, node, asIC_IMPLICIT_CONV, true);
  1051. if( !ctx->type.dataType.IsEqualExceptRef(param) )
  1052. {
  1053. asCString str;
  1054. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), param.Format().AddressOf());
  1055. Error(str, node);
  1056. ctx->type.Set(param);
  1057. }
  1058. }
  1059. // If the argument already is a temporary
  1060. // variable we don't need to allocate another
  1061. // If the parameter is read-only and the object already is a local
  1062. // variable then it is not necessary to make a copy either
  1063. if( !ctx->type.isTemporary && !(param.IsReadOnly() && ctx->type.isVariable) && !isMakingCopy )
  1064. {
  1065. // Make sure the variable is not used in the expression
  1066. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1067. // TODO: copy: Use copy constructor if available. See PrepareTemporaryObject()
  1068. // Allocate and construct the temporary object
  1069. asCByteCode tmpBC(engine);
  1070. CallDefaultConstructor(dt, offset, IsVariableOnHeap(offset), &tmpBC, node);
  1071. // Insert the code before the expression code
  1072. tmpBC.AddCode(&ctx->bc);
  1073. ctx->bc.AddCode(&tmpBC);
  1074. // Assign the evaluated expression to the temporary variable
  1075. PrepareForAssignment(&dt, ctx, node, true);
  1076. dt.MakeReference(IsVariableOnHeap(offset));
  1077. asCTypeInfo type;
  1078. type.Set(dt);
  1079. type.isTemporary = true;
  1080. type.stackOffset = (short)offset;
  1081. if( dt.IsObjectHandle() )
  1082. type.isExplicitHandle = true;
  1083. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  1084. PerformAssignment(&type, &ctx->type, &ctx->bc, node);
  1085. ctx->bc.Instr(asBC_PopPtr);
  1086. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  1087. ctx->type = type;
  1088. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  1089. if( dt.IsObject() && !dt.IsObjectHandle() )
  1090. ctx->bc.Instr(asBC_RDSPtr);
  1091. if( paramType->IsReadOnly() )
  1092. ctx->type.dataType.MakeReadOnly(true);
  1093. }
  1094. else if( isMakingCopy )
  1095. {
  1096. // We must guarantee that the address to the value is on the stack
  1097. if( ctx->type.dataType.IsObject() &&
  1098. !ctx->type.dataType.IsObjectHandle() &&
  1099. ctx->type.dataType.IsReference() )
  1100. Dereference(ctx, true);
  1101. }
  1102. }
  1103. }
  1104. else if( refType == 2 ) // &out
  1105. {
  1106. // Add the type id as hidden arg if the parameter is a ? type
  1107. if( paramType->GetTokenType() == ttQuestion )
  1108. {
  1109. asCByteCode tmpBC(engine);
  1110. // Place the type id on the stack as a hidden parameter
  1111. tmpBC.InstrDWORD(asBC_TYPEID, engine->GetTypeIdFromDataType(param));
  1112. // Insert the code before the expression code
  1113. tmpBC.AddCode(&ctx->bc);
  1114. ctx->bc.AddCode(&tmpBC);
  1115. }
  1116. // Make sure the variable is not used in the expression
  1117. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1118. if( dt.IsPrimitive() )
  1119. {
  1120. ctx->type.SetVariable(dt, offset, true);
  1121. PushVariableOnStack(ctx, true);
  1122. }
  1123. else
  1124. {
  1125. // Allocate and construct the temporary object
  1126. asCByteCode tmpBC(engine);
  1127. CallDefaultConstructor(dt, offset, IsVariableOnHeap(offset), &tmpBC, node);
  1128. // Insert the code before the expression code
  1129. tmpBC.AddCode(&ctx->bc);
  1130. ctx->bc.AddCode(&tmpBC);
  1131. dt.MakeReference((!dt.IsObject() || dt.IsObjectHandle()));
  1132. asCTypeInfo type;
  1133. type.Set(dt);
  1134. type.isTemporary = true;
  1135. type.stackOffset = (short)offset;
  1136. ctx->type = type;
  1137. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  1138. if( dt.IsObject() && !dt.IsObjectHandle() )
  1139. ctx->bc.Instr(asBC_RDSPtr);
  1140. }
  1141. // After the function returns the temporary variable will
  1142. // be assigned to the expression, if it is a valid lvalue
  1143. }
  1144. else if( refType == asTM_INOUTREF )
  1145. {
  1146. ProcessPropertyGetAccessor(ctx, node);
  1147. // Add the type id as hidden arg if the parameter is a ? type
  1148. if( paramType->GetTokenType() == ttQuestion )
  1149. {
  1150. asCByteCode tmpBC(engine);
  1151. // Place the type id on the stack as a hidden parameter
  1152. tmpBC.InstrDWORD(asBC_TYPEID, engine->GetTypeIdFromDataType(param));
  1153. // Insert the code before the expression code
  1154. tmpBC.AddCode(&ctx->bc);
  1155. ctx->bc.AddCode(&tmpBC);
  1156. }
  1157. // Literal constants cannot be passed to inout ref arguments
  1158. if( !ctx->type.isVariable && ctx->type.isConstant )
  1159. {
  1160. Error(TXT_NOT_VALID_REFERENCE, node);
  1161. }
  1162. // Only objects that support object handles
  1163. // can be guaranteed to be safe. Local variables are
  1164. // already safe, so there is no need to add an extra
  1165. // references
  1166. if( !engine->ep.allowUnsafeReferences &&
  1167. !ctx->type.isVariable &&
  1168. ctx->type.dataType.IsObject() &&
  1169. !ctx->type.dataType.IsObjectHandle() &&
  1170. ((ctx->type.dataType.GetBehaviour()->addref &&
  1171. ctx->type.dataType.GetBehaviour()->release) ||
  1172. (ctx->type.dataType.GetObjectType()->flags & asOBJ_NOCOUNT)) )
  1173. {
  1174. // Store a handle to the object as local variable
  1175. asSExprContext tmp(engine);
  1176. asCDataType dt = ctx->type.dataType;
  1177. dt.MakeHandle(true);
  1178. dt.MakeReference(false);
  1179. offset = AllocateVariableNotIn(dt, true, false, ctx);
  1180. // Copy the handle
  1181. if( !ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReference() )
  1182. ctx->bc.Instr(asBC_RDSPtr);
  1183. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1184. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetObjectType());
  1185. ctx->bc.Instr(asBC_PopPtr);
  1186. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1187. dt.MakeHandle(false);
  1188. dt.MakeReference(true);
  1189. // Release previous temporary variable stored in the context (if any)
  1190. if( ctx->type.isTemporary )
  1191. {
  1192. ReleaseTemporaryVariable(ctx->type.stackOffset, &ctx->bc);
  1193. }
  1194. ctx->type.SetVariable(dt, offset, true);
  1195. }
  1196. // Make sure the reference to the value is on the stack
  1197. // For objects, the reference needs to be dereferenced so the pointer on the stack is to the actual object
  1198. // For handles, the reference shouldn't be changed because the pointer on the stack should be to the handle
  1199. if( ctx->type.dataType.IsObject() && ctx->type.dataType.IsReference() && !paramType->IsObjectHandle() )
  1200. Dereference(ctx, true);
  1201. else if( ctx->type.isVariable && !ctx->type.dataType.IsObject() )
  1202. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  1203. else if( ctx->type.dataType.IsPrimitive() )
  1204. ctx->bc.Instr(asBC_PshRPtr);
  1205. else if( ctx->type.dataType.IsObjectHandle() && !ctx->type.dataType.IsReference() )
  1206. ImplicitConversion(ctx, param, node, asIC_IMPLICIT_CONV, true, false);
  1207. }
  1208. }
  1209. else
  1210. {
  1211. ProcessPropertyGetAccessor(ctx, node);
  1212. if( dt.IsPrimitive() )
  1213. {
  1214. IsVariableInitialized(&ctx->type, node);
  1215. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  1216. // Implicitly convert primitives to the parameter type
  1217. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV);
  1218. if( ctx->type.isVariable )
  1219. {
  1220. PushVariableOnStack(ctx, dt.IsReference());
  1221. }
  1222. else if( ctx->type.isConstant )
  1223. {
  1224. ConvertToVariable(ctx);
  1225. PushVariableOnStack(ctx, dt.IsReference());
  1226. }
  1227. }
  1228. else
  1229. {
  1230. IsVariableInitialized(&ctx->type, node);
  1231. // Implicitly convert primitives to the parameter type
  1232. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV);
  1233. // Was the conversion successful?
  1234. if( !ctx->type.dataType.IsEqualExceptRef(dt) )
  1235. {
  1236. asCString str;
  1237. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), dt.Format().AddressOf());
  1238. Error(str, node);
  1239. ctx->type.Set(dt);
  1240. }
  1241. if( dt.IsObjectHandle() )
  1242. ctx->type.isExplicitHandle = true;
  1243. if( dt.IsObject() )
  1244. {
  1245. if( !dt.IsReference() )
  1246. {
  1247. // Objects passed by value must be placed in temporary variables
  1248. // so that they are guaranteed to not be referenced anywhere else.
  1249. // The object must also be allocated on the heap, as the memory will
  1250. // be deleted by in as_callfunc_xxx.
  1251. // TODO: value on stack: How can we avoid this unnecessary allocation?
  1252. // Local variables doesn't need to be copied into
  1253. // a temp if we're already compiling an assignment
  1254. if( !isMakingCopy || !ctx->type.dataType.IsObjectHandle() || !ctx->type.isVariable )
  1255. PrepareTemporaryObject(node, ctx, true);
  1256. // The implicit conversion shouldn't convert the object to
  1257. // non-reference yet. It will be dereferenced just before the call.
  1258. // Otherwise the object might be missed by the exception handler.
  1259. dt.MakeReference(true);
  1260. }
  1261. else
  1262. {
  1263. // An object passed by reference should place the pointer to
  1264. // the object on the stack.
  1265. dt.MakeReference(false);
  1266. }
  1267. }
  1268. }
  1269. }
  1270. // Don't put any pointer on the stack yet
  1271. if( param.IsReference() || param.IsObject() )
  1272. {
  1273. // &inout parameter may leave the reference on the stack already
  1274. if( refType != 3 )
  1275. {
  1276. asASSERT( ctx->type.isVariable || ctx->type.isTemporary || isMakingCopy );
  1277. if( ctx->type.isVariable || ctx->type.isTemporary )
  1278. {
  1279. ctx->bc.Instr(asBC_PopPtr);
  1280. ctx->bc.InstrSHORT(asBC_VAR, ctx->type.stackOffset);
  1281. ProcessDeferredParams(ctx);
  1282. }
  1283. }
  1284. }
  1285. }
  1286. void asCCompiler::PrepareFunctionCall(int funcId, asCByteCode *bc, asCArray<asSExprContext *> &args)
  1287. {
  1288. // When a match has been found, compile the final byte code using correct parameter types
  1289. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  1290. // If the function being called is the opAssign or copy constructor for the same type
  1291. // as the argument, then we should avoid making temporary copy of the argument
  1292. bool makingCopy = false;
  1293. if( descr->parameterTypes.GetLength() == 1 &&
  1294. descr->parameterTypes[0].IsEqualExceptRefAndConst(args[0]->type.dataType) &&
  1295. ((descr->name == "opAssign" && descr->objectType && descr->objectType == args[0]->type.dataType.GetObjectType()) ||
  1296. (args[0]->type.dataType.GetObjectType() && descr->name == args[0]->type.dataType.GetObjectType()->name)) )
  1297. makingCopy = true;
  1298. // Add code for arguments
  1299. asSExprContext e(engine);
  1300. for( int n = (int)args.GetLength()-1; n >= 0; n-- )
  1301. {
  1302. // Make sure PrepareArgument doesn't use any variable that is already
  1303. // being used by any of the following argument expressions
  1304. int l = int(reservedVariables.GetLength());
  1305. for( int m = n-1; m >= 0; m-- )
  1306. args[m]->bc.GetVarsUsed(reservedVariables);
  1307. PrepareArgument2(&e, args[n], &descr->parameterTypes[n], true, descr->inOutFlags[n], makingCopy);
  1308. reservedVariables.SetLength(l);
  1309. }
  1310. bc->AddCode(&e.bc);
  1311. }
  1312. void asCCompiler::MoveArgsToStack(int funcId, asCByteCode *bc, asCArray<asSExprContext *> &args, bool addOneToOffset)
  1313. {
  1314. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  1315. int offset = 0;
  1316. if( addOneToOffset )
  1317. offset += AS_PTR_SIZE;
  1318. // The address of where the return value should be stored is push on top of the arguments
  1319. if( descr->DoesReturnOnStack() )
  1320. offset += AS_PTR_SIZE;
  1321. #ifdef AS_DEBUG
  1322. // If the function being called is the opAssign or copy constructor for the same type
  1323. // as the argument, then we should avoid making temporary copy of the argument
  1324. bool makingCopy = false;
  1325. if( descr->parameterTypes.GetLength() == 1 &&
  1326. descr->parameterTypes[0].IsEqualExceptRefAndConst(args[0]->type.dataType) &&
  1327. ((descr->name == "opAssign" && descr->objectType && descr->objectType == args[0]->type.dataType.GetObjectType()) ||
  1328. (args[0]->type.dataType.GetObjectType() && descr->name == args[0]->type.dataType.GetObjectType()->name)) )
  1329. makingCopy = true;
  1330. #endif
  1331. // Move the objects that are sent by value to the stack just before the call
  1332. for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ )
  1333. {
  1334. if( descr->parameterTypes[n].IsReference() )
  1335. {
  1336. if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() )
  1337. {
  1338. if( descr->inOutFlags[n] != asTM_INOUTREF )
  1339. {
  1340. #ifdef AS_DEBUG
  1341. asASSERT( args[n]->type.isVariable || args[n]->type.isTemporary || makingCopy );
  1342. #endif
  1343. if( (args[n]->type.isVariable || args[n]->type.isTemporary) )
  1344. {
  1345. if( !IsVariableOnHeap(args[n]->type.stackOffset) )
  1346. // TODO: runtime optimize: Actually the reference can be pushed on the stack directly
  1347. // as the value allocated on the stack is guaranteed to be safe
  1348. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1349. else
  1350. bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset);
  1351. }
  1352. }
  1353. if( args[n]->type.dataType.IsObjectHandle() )
  1354. bc->InstrWORD(asBC_ChkNullS, (asWORD)offset);
  1355. }
  1356. else if( descr->inOutFlags[n] != asTM_INOUTREF )
  1357. {
  1358. if( descr->parameterTypes[n].GetTokenType() == ttQuestion &&
  1359. args[n]->type.dataType.IsObject() && !args[n]->type.dataType.IsObjectHandle() )
  1360. {
  1361. // Send the object as a reference to the object,
  1362. // and not to the variable holding the object
  1363. if( !IsVariableOnHeap(args[n]->type.stackOffset) )
  1364. // TODO: runtime optimize: Actually the reference can be pushed on the stack directly
  1365. // as the value allocated on the stack is guaranteed to be safe
  1366. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1367. else
  1368. bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset);
  1369. }
  1370. else
  1371. {
  1372. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1373. }
  1374. }
  1375. }
  1376. else if( descr->parameterTypes[n].IsObject() )
  1377. {
  1378. // TODO: value on stack: What can we do to avoid this unnecessary allocation?
  1379. // The object must be allocated on the heap, because this memory will be deleted in as_callfunc_xxx
  1380. asASSERT(IsVariableOnHeap(args[n]->type.stackOffset));
  1381. bc->InstrWORD(asBC_GETOBJ, (asWORD)offset);
  1382. // The temporary variable must not be freed as it will no longer hold an object
  1383. DeallocateVariable(args[n]->type.stackOffset);
  1384. args[n]->type.isTemporary = false;
  1385. }
  1386. offset += descr->parameterTypes[n].GetSizeOnStackDWords();
  1387. }
  1388. }
  1389. int asCCompiler::CompileArgumentList(asCScriptNode *node, asCArray<asSExprContext*> &args)
  1390. {
  1391. asASSERT(node->nodeType == snArgList);
  1392. // Count arguments
  1393. asCScriptNode *arg = node->firstChild;
  1394. int argCount = 0;
  1395. while( arg )
  1396. {
  1397. argCount++;
  1398. arg = arg->next;
  1399. }
  1400. // Prepare the arrays
  1401. args.SetLength(argCount);
  1402. int n;
  1403. for( n = 0; n < argCount; n++ )
  1404. args[n] = 0;
  1405. n = argCount-1;
  1406. // Compile the arguments in reverse order (as they will be pushed on the stack)
  1407. bool anyErrors = false;
  1408. arg = node->lastChild;
  1409. while( arg )
  1410. {
  1411. asSExprContext expr(engine);
  1412. int r = CompileAssignment(arg, &expr);
  1413. if( r < 0 ) anyErrors = true;
  1414. args[n] = asNEW(asSExprContext)(engine);
  1415. if( args[n] == 0 )
  1416. {
  1417. // Out of memory
  1418. return -1;
  1419. }
  1420. MergeExprBytecodeAndType(args[n], &expr);
  1421. n--;
  1422. arg = arg->prev;
  1423. }
  1424. return anyErrors ? -1 : 0;
  1425. }
  1426. int asCCompiler::CompileDefaultArgs(asCScriptNode *node, asCArray<asSExprContext*> &args, asCScriptFunction *func)
  1427. {
  1428. bool anyErrors = false;
  1429. asCArray<int> varsUsed;
  1430. int explicitArgs = (int)args.GetLength();
  1431. for( int p = 0; p < explicitArgs; p++ )
  1432. args[p]->bc.GetVarsUsed(varsUsed);
  1433. // Compile the arguments in reverse order (as they will be pushed on the stack)
  1434. args.SetLength(func->parameterTypes.GetLength());
  1435. for( asUINT c = explicitArgs; c < args.GetLength(); c++ )
  1436. args[c] = 0;
  1437. for( int n = (int)func->parameterTypes.GetLength() - 1; n >= explicitArgs; n-- )
  1438. {
  1439. if( func->defaultArgs[n] == 0 ) { anyErrors = true; continue; }
  1440. // Parse the default arg string
  1441. asCParser parser(builder);
  1442. asCScriptCode code;
  1443. code.SetCode("default arg", func->defaultArgs[n]->AddressOf(), false);
  1444. int r = parser.ParseExpression(&code);
  1445. if( r < 0 )
  1446. {
  1447. asCString msg;
  1448. msg.Format(TXT_FAILED_TO_COMPILE_DEF_ARG_d_IN_FUNC_s, n, func->GetDeclaration());
  1449. Error(msg, node);
  1450. anyErrors = true;
  1451. continue;
  1452. }
  1453. asCScriptNode *arg = parser.GetScriptNode();
  1454. // Temporarily set the script code to the default arg expression
  1455. asCScriptCode *origScript = script;
  1456. script = &code;
  1457. // Don't allow the expression to access local variables
  1458. // TODO: namespace: The default arg should see the symbols declared in the same scope as the function that is called
  1459. isCompilingDefaultArg = true;
  1460. asSExprContext expr(engine);
  1461. r = CompileExpression(arg, &expr);
  1462. // Don't allow address of class method
  1463. if( expr.methodName != "" )
  1464. {
  1465. // TODO: Improve error message
  1466. Error(TXT_DEF_ARG_TYPE_DOESNT_MATCH, arg);
  1467. r = -1;
  1468. }
  1469. // Make sure the expression can be implicitly converted to the parameter type
  1470. if( r >= 0 )
  1471. {
  1472. asCArray<int> funcs;
  1473. funcs.PushLast(func->id);
  1474. asCArray<asSOverloadCandidate> matches;
  1475. if( MatchArgument(funcs, matches, &expr, n) == 0 )
  1476. {
  1477. Error(TXT_DEF_ARG_TYPE_DOESNT_MATCH, arg);
  1478. r = -1;
  1479. }
  1480. }
  1481. isCompilingDefaultArg = false;
  1482. script = origScript;
  1483. if( r < 0 )
  1484. {
  1485. asCString msg;
  1486. msg.Format(TXT_FAILED_TO_COMPILE_DEF_ARG_d_IN_FUNC_s, n, func->GetDeclaration());
  1487. Error(msg, node);
  1488. anyErrors = true;
  1489. continue;
  1490. }
  1491. args[n] = asNEW(asSExprContext)(engine);
  1492. if( args[n] == 0 )
  1493. {
  1494. // Out of memory
  1495. return -1;
  1496. }
  1497. MergeExprBytecodeAndType(args[n], &expr);
  1498. // Make sure the default arg expression doesn't end up
  1499. // with a variable that is used in a previous expression
  1500. if( args[n]->type.isVariable )
  1501. {
  1502. int offset = args[n]->type.stackOffset;
  1503. if( varsUsed.Exists(offset) )
  1504. {
  1505. // Release the current temporary variable
  1506. ReleaseTemporaryVariable(args[n]->type, 0);
  1507. asCDataType dt = args[n]->type.dataType;
  1508. dt.MakeReference(false);
  1509. // Reserve all variables already used in the expression so none of them will be used
  1510. asCArray<int> used;
  1511. args[n]->bc.GetVarsUsed(used);
  1512. size_t prevReserved = reservedVariables.GetLength();
  1513. reservedVariables.Concatenate(used);
  1514. int newOffset = AllocateVariable(dt, true, IsVariableOnHeap(offset));
  1515. asASSERT( IsVariableOnHeap(offset) == IsVariableOnHeap(newOffset) );
  1516. reservedVariables.SetLength(prevReserved);
  1517. // Replace the variable in the expression
  1518. args[n]->bc.ExchangeVar(offset, newOffset);
  1519. args[n]->type.stackOffset = (short)newOffset;
  1520. args[n]->type.isTemporary = true;
  1521. args[n]->type.isVariable = true;
  1522. }
  1523. }
  1524. }
  1525. return anyErrors ? -1 : 0;
  1526. }
  1527. 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)
  1528. {
  1529. asCArray<int> origFuncs = funcs; // Keep the original list for error message
  1530. asUINT cost = 0;
  1531. asUINT n;
  1532. if( funcs.GetLength() > 0 )
  1533. {
  1534. // Check the number of parameters in the found functions
  1535. for( n = 0; n < funcs.GetLength(); ++n )
  1536. {
  1537. asCScriptFunction *desc = builder->GetFunctionDescription(funcs[n]);
  1538. if( desc->parameterTypes.GetLength() != args.GetLength() )
  1539. {
  1540. bool noMatch = true;
  1541. if( args.GetLength() < desc->parameterTypes.GetLength() )
  1542. {
  1543. // Count the number of default args
  1544. asUINT defaultArgs = 0;
  1545. for( asUINT d = 0; d < desc->defaultArgs.GetLength(); d++ )
  1546. if( desc->defaultArgs[d] )
  1547. defaultArgs++;
  1548. if( args.GetLength() >= desc->parameterTypes.GetLength() - defaultArgs )
  1549. noMatch = false;
  1550. }
  1551. if( noMatch )
  1552. {
  1553. // remove it from the list
  1554. if( n == funcs.GetLength()-1 )
  1555. funcs.PopLast();
  1556. else
  1557. funcs[n] = funcs.PopLast();
  1558. n--;
  1559. }
  1560. }
  1561. }
  1562. // Match functions with the parameters, and discard those that do not match
  1563. asCArray<asSOverloadCandidate> matchingFuncs;
  1564. matchingFuncs.SetLengthNoConstruct( funcs.GetLength() );
  1565. for ( n = 0; n < funcs.GetLength(); ++n )
  1566. {
  1567. matchingFuncs[n].funcId = funcs[n];
  1568. matchingFuncs[n].cost = 0;
  1569. }
  1570. for( n = 0; n < args.GetLength(); ++n )
  1571. {
  1572. asCArray<asSOverloadCandidate> tempFuncs;
  1573. MatchArgument(funcs, tempFuncs, args[n], n, allowObjectConstruct);
  1574. // Intersect the found functions with the list of matching functions
  1575. for( asUINT f = 0; f < matchingFuncs.GetLength(); f++ )
  1576. {
  1577. asUINT c;
  1578. for( c = 0; c < tempFuncs.GetLength(); c++ )
  1579. {
  1580. if( matchingFuncs[f].funcId == tempFuncs[c].funcId )
  1581. {
  1582. // Sum argument cost
  1583. matchingFuncs[f].cost += tempFuncs[c].cost;
  1584. break;
  1585. } // End if match
  1586. }
  1587. // Was the function a match?
  1588. if( c == tempFuncs.GetLength() )
  1589. {
  1590. // No, remove it from the list
  1591. if( f == matchingFuncs.GetLength()-1 )
  1592. matchingFuncs.PopLast();
  1593. else
  1594. matchingFuncs[f] = matchingFuncs.PopLast();
  1595. f--;
  1596. }
  1597. }
  1598. }
  1599. // Select the overload(s) with the lowest overall cost
  1600. funcs.SetLength(0);
  1601. asUINT bestCost = asUINT(-1);
  1602. for( n = 0; n < matchingFuncs.GetLength(); ++n )
  1603. {
  1604. cost = matchingFuncs[n].cost;
  1605. if( cost < bestCost )
  1606. {
  1607. funcs.SetLength(0);
  1608. bestCost = cost;
  1609. }
  1610. if( cost == bestCost )
  1611. funcs.PushLast( matchingFuncs[n].funcId );
  1612. }
  1613. // Cost returned is equivalent to the best cost discovered
  1614. cost = bestCost;
  1615. }
  1616. if( !isConstMethod )
  1617. FilterConst(funcs);
  1618. if( funcs.GetLength() != 1 && !silent )
  1619. {
  1620. // Build a readable string of the function with parameter types
  1621. asCString str;
  1622. if( scope != "" )
  1623. {
  1624. if( scope == "::" )
  1625. str = scope;
  1626. else
  1627. str = scope + "::";
  1628. }
  1629. str += name;
  1630. str += "(";
  1631. if( args.GetLength() )
  1632. {
  1633. if( args[0]->methodName != "" )
  1634. str += args[0]->methodName;
  1635. else
  1636. str += args[0]->type.dataType.Format();
  1637. }
  1638. for( n = 1; n < args.GetLength(); n++ )
  1639. {
  1640. str += ", ";
  1641. if( args[n]->methodName != "" )
  1642. str += args[n]->methodName;
  1643. else
  1644. str += args[n]->type.dataType.Format();
  1645. }
  1646. str += ")";
  1647. if( isConstMethod )
  1648. str += " const";
  1649. if( objectType && scope == "" )
  1650. str = objectType->name + "::" + str;
  1651. if( funcs.GetLength() == 0 )
  1652. {
  1653. str.Format(TXT_NO_MATCHING_SIGNATURES_TO_s, str.AddressOf());
  1654. Error(str, node);
  1655. // Print the list of candidates
  1656. if( origFuncs.GetLength() > 0 )
  1657. {
  1658. int r = 0, c = 0;
  1659. asASSERT( node );
  1660. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  1661. builder->WriteInfo(script->name.AddressOf(), TXT_CANDIDATES_ARE, r, c, false);
  1662. PrintMatchingFuncs(origFuncs, node);
  1663. }
  1664. }
  1665. else
  1666. {
  1667. str.Format(TXT_MULTIPLE_MATCHING_SIGNATURES_TO_s, str.AddressOf());
  1668. Error(str, node);
  1669. PrintMatchingFuncs(funcs, node);
  1670. }
  1671. }
  1672. return cost;
  1673. }
  1674. void asCCompiler::CompileDeclaration(asCScriptNode *decl, asCByteCode *bc)
  1675. {
  1676. // Get the data type
  1677. asCDataType type = builder->CreateDataTypeFromNode(decl->firstChild, script, outFunc->nameSpace);
  1678. // Declare all variables in this declaration
  1679. asCScriptNode *node = decl->firstChild->next;
  1680. while( node )
  1681. {
  1682. // Is the type allowed?
  1683. if( !type.CanBeInstanciated() )
  1684. {
  1685. asCString str;
  1686. // TODO: Change to "'type' cannot be declared as variable"
  1687. str.Format(TXT_DATA_TYPE_CANT_BE_s, type.Format().AddressOf());
  1688. Error(str, node);
  1689. // Use int instead to avoid further problems
  1690. type = asCDataType::CreatePrimitive(ttInt, false);
  1691. }
  1692. // A shared object may not declare variables of non-shared types
  1693. if( outFunc->IsShared() )
  1694. {
  1695. asCObjectType *ot = type.GetObjectType();
  1696. if( ot && !ot->IsShared() )
  1697. {
  1698. asCString msg;
  1699. msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, ot->name.AddressOf());
  1700. Error(msg, decl);
  1701. }
  1702. }
  1703. // Get the name of the identifier
  1704. asCString name(&script->code[node->tokenPos], node->tokenLength);
  1705. // Verify that the name isn't used by a dynamic data type
  1706. if( engine->GetObjectType(name.AddressOf(), outFunc->nameSpace) != 0 )
  1707. {
  1708. asCString str;
  1709. str.Format(TXT_ILLEGAL_VARIABLE_NAME_s, name.AddressOf());
  1710. Error(str, node);
  1711. }
  1712. int offset = AllocateVariable(type, false);
  1713. if( variables->DeclareVariable(name.AddressOf(), type, offset, IsVariableOnHeap(offset)) < 0 )
  1714. {
  1715. // TODO: It might be an out-of-memory too
  1716. asCString str;
  1717. str.Format(TXT_s_ALREADY_DECLARED, name.AddressOf());
  1718. Error(str, node);
  1719. // Don't continue after this error, as it will just
  1720. // lead to more errors that are likely false
  1721. return;
  1722. }
  1723. // Add marker that the variable has been declared
  1724. bc->VarDecl((int)outFunc->variables.GetLength());
  1725. outFunc->AddVariable(name, type, offset);
  1726. // Keep the node for the variable decl
  1727. asCScriptNode *varNode = node;
  1728. node = node->next;
  1729. if( node == 0 || node->nodeType == snIdentifier )
  1730. {
  1731. // Initialize with default constructor
  1732. CompileInitialization(0, bc, type, varNode, offset, 0, 0);
  1733. }
  1734. else
  1735. {
  1736. // Compile the initialization expression
  1737. asQWORD constantValue = 0;
  1738. if( CompileInitialization(node, bc, type, varNode, offset, &constantValue, 0) )
  1739. {
  1740. // Check if the variable should be marked as pure constant
  1741. if( type.IsPrimitive() && type.IsReadOnly() )
  1742. {
  1743. sVariable *v = variables->GetVariable(name.AddressOf());
  1744. v->isPureConstant = true;
  1745. v->constantValue = constantValue;
  1746. }
  1747. }
  1748. node = node->next;
  1749. }
  1750. }
  1751. bc->OptimizeLocally(tempVariableOffsets);
  1752. }
  1753. bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, asCDataType &type, asCScriptNode *errNode, int offset, asQWORD *constantValue, int isVarGlobOrMem)
  1754. {
  1755. bool isConstantExpression = false;
  1756. if( node && node->nodeType == snArgList )
  1757. {
  1758. // Make sure it is an object and not a handle
  1759. if( type.GetObjectType() == 0 || type.IsObjectHandle() )
  1760. {
  1761. Error(TXT_MUST_BE_OBJECT, node);
  1762. }
  1763. else
  1764. {
  1765. // Compile the arguments
  1766. asCArray<asSExprContext *> args;
  1767. if( CompileArgumentList(node, args) >= 0 )
  1768. {
  1769. // Find all constructors
  1770. asCArray<int> funcs;
  1771. asSTypeBehaviour *beh = type.GetBehaviour();
  1772. if( beh )
  1773. {
  1774. if( type.GetObjectType()->flags & asOBJ_REF )
  1775. funcs = beh->factories;
  1776. else
  1777. funcs = beh->constructors;
  1778. }
  1779. asCString str = type.Format();
  1780. MatchFunctions(funcs, args, node, str.AddressOf());
  1781. if( funcs.GetLength() == 1 )
  1782. {
  1783. int r = asSUCCESS;
  1784. // Add the default values for arguments not explicitly supplied
  1785. asCScriptFunction *func = (funcs[0] & FUNC_IMPORTED) == 0 ? engine->scriptFunctions[funcs[0]] : 0;
  1786. if( func && args.GetLength() < (asUINT)func->GetParamCount() )
  1787. r = CompileDefaultArgs(node, args, func);
  1788. if( r == asSUCCESS )
  1789. {
  1790. asSExprContext ctx(engine);
  1791. if( type.GetObjectType() && (type.GetObjectType()->flags & asOBJ_REF) )
  1792. {
  1793. if( isVarGlobOrMem == 0 )
  1794. MakeFunctionCall(&ctx, funcs[0], 0, args, node, true, offset);
  1795. else
  1796. {
  1797. MakeFunctionCall(&ctx, funcs[0], 0, args, node);
  1798. ctx.bc.Instr(asBC_RDSPtr);
  1799. if( isVarGlobOrMem == 1 )
  1800. {
  1801. // Store the returned handle in the global variable
  1802. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  1803. }
  1804. else
  1805. {
  1806. // Store the returned handle in the member
  1807. ctx.bc.InstrSHORT(asBC_PSF, 0);
  1808. ctx.bc.Instr(asBC_RDSPtr);
  1809. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
  1810. }
  1811. ctx.bc.InstrPTR(asBC_REFCPY, type.GetObjectType());
  1812. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  1813. }
  1814. // Pop the reference left by the function call
  1815. ctx.bc.Instr(asBC_PopPtr);
  1816. }
  1817. else
  1818. {
  1819. bool onHeap = false;
  1820. if( isVarGlobOrMem == 0 )
  1821. {
  1822. // When the object is allocated on the heap, the address where the
  1823. // reference will be stored must be pushed on the stack before the
  1824. // arguments. This reference on the stack is safe, even if the script
  1825. // is suspended during the evaluation of the arguments.
  1826. onHeap = IsVariableOnHeap(offset);
  1827. if( onHeap )
  1828. ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
  1829. }
  1830. else
  1831. {
  1832. // Push the address of the location where the variable will be stored on the stack.
  1833. // This reference is safe, because the addresses of the global variables cannot change.
  1834. // TODO: When serialization of the context is implemented this will probably have to change,
  1835. // because this pointer may be on the stack while the context is suspended, and may
  1836. // be difficult to serialize as the context doesn't know that the value represents a
  1837. // pointer.
  1838. onHeap = true;
  1839. if( isVarGlobOrMem == 1 )
  1840. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  1841. else
  1842. {
  1843. ctx.bc.InstrSHORT(asBC_PSF, 0);
  1844. ctx.bc.Instr(asBC_RDSPtr);
  1845. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
  1846. }
  1847. }
  1848. PrepareFunctionCall(funcs[0], &ctx.bc, args);
  1849. MoveArgsToStack(funcs[0], &ctx.bc, args, false);
  1850. // When the object is allocated on the stack, the address to the
  1851. // object is pushed on the stack after the arguments as the object pointer
  1852. if( !onHeap )
  1853. ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
  1854. PerformFunctionCall(funcs[0], &ctx, onHeap, &args, type.GetObjectType());
  1855. if( isVarGlobOrMem == 0 )
  1856. {
  1857. // Mark the object in the local variable as initialized
  1858. ctx.bc.ObjInfo(offset, asOBJ_INIT);
  1859. }
  1860. }
  1861. bc->AddCode(&ctx.bc);
  1862. }
  1863. }
  1864. }
  1865. // Cleanup
  1866. for( asUINT n = 0; n < args.GetLength(); n++ )
  1867. if( args[n] )
  1868. {
  1869. asDELETE(args[n],asSExprContext);
  1870. }
  1871. }
  1872. }
  1873. else if( node && node->nodeType == snInitList )
  1874. {
  1875. asCTypeInfo ti;
  1876. ti.Set(type);
  1877. ti.isVariable = (isVarGlobOrMem == 0);
  1878. ti.isTemporary = false;
  1879. ti.stackOffset = (short)offset;
  1880. ti.isLValue = true;
  1881. CompileInitList(&ti, node, bc, isVarGlobOrMem);
  1882. }
  1883. else if( node && node->nodeType == snAssignment )
  1884. {
  1885. asSExprContext ctx(engine);
  1886. // TODO: copy: Here we should look for the best matching constructor, instead of
  1887. // just the copy constructor. Only if no appropriate constructor is
  1888. // available should the assignment operator be used.
  1889. // Call the default constructor here
  1890. if( isVarGlobOrMem == 0 )
  1891. CallDefaultConstructor(type, offset, IsVariableOnHeap(offset), &ctx.bc, errNode);
  1892. else
  1893. CallDefaultConstructor(type, offset, true, &ctx.bc, errNode, isVarGlobOrMem);
  1894. // Compile the expression
  1895. asSExprContext expr(engine);
  1896. int r = CompileAssignment(node, &expr);
  1897. if( r >= 0 )
  1898. {
  1899. if( type.IsPrimitive() )
  1900. {
  1901. if( type.IsReadOnly() && expr.type.isConstant )
  1902. {
  1903. ImplicitConversion(&expr, type, node, asIC_IMPLICIT_CONV);
  1904. // Tell caller that the expression is a constant so it can mark the variable as pure constant
  1905. isConstantExpression = true;
  1906. *constantValue = expr.type.qwordValue;
  1907. }
  1908. asSExprContext lctx(engine);
  1909. if( isVarGlobOrMem == 0 )
  1910. lctx.type.SetVariable(type, offset, false);
  1911. else if( isVarGlobOrMem == 1 )
  1912. {
  1913. lctx.type.Set(type);
  1914. lctx.type.dataType.MakeReference(true);
  1915. // If it is an enum value that is being compiled then we skip this
  1916. // as the bytecode won't be used anyway, only the constant value
  1917. if( asUINT(offset) < engine->globalProperties.GetLength() )
  1918. lctx.bc.InstrPTR(asBC_LDG, engine->globalProperties[offset]->GetAddressOfValue());
  1919. }
  1920. else
  1921. {
  1922. asASSERT( isVarGlobOrMem == 2 );
  1923. lctx.type.Set(type);
  1924. lctx.type.dataType.MakeReference(true);
  1925. // Load the reference of the primitive member into the register
  1926. lctx.bc.InstrSHORT(asBC_PSF, 0);
  1927. lctx.bc.Instr(asBC_RDSPtr);
  1928. lctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
  1929. lctx.bc.Instr(asBC_PopRPtr);
  1930. }
  1931. lctx.type.dataType.MakeReadOnly(false);
  1932. lctx.type.isLValue = true;
  1933. DoAssignment(&ctx, &lctx, &expr, node, node, ttAssignment, node);
  1934. ProcessDeferredParams(&ctx);
  1935. }
  1936. else
  1937. {
  1938. // TODO: runtime optimize: Here we should look for the best matching constructor, instead of
  1939. // just the copy constructor. Only if no appropriate constructor is
  1940. // available should the assignment operator be used.
  1941. asSExprContext lexpr(engine);
  1942. lexpr.type.Set(type);
  1943. if( isVarGlobOrMem == 0 )
  1944. lexpr.type.dataType.MakeReference(IsVariableOnHeap(offset));
  1945. else
  1946. lexpr.type.dataType.MakeReference(true);
  1947. // Allow initialization of constant variables
  1948. lexpr.type.dataType.MakeReadOnly(false);
  1949. if( type.IsObjectHandle() )
  1950. lexpr.type.isExplicitHandle = true;
  1951. if( isVarGlobOrMem == 0 )
  1952. {
  1953. lexpr.bc.InstrSHORT(asBC_PSF, (short)offset);
  1954. lexpr.type.stackOffset = (short)offset;
  1955. lexpr.type.isVariable = true;
  1956. }
  1957. else if( isVarGlobOrMem == 1 )
  1958. {
  1959. lexpr.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  1960. }
  1961. else
  1962. {
  1963. lexpr.bc.InstrSHORT(asBC_PSF, 0);
  1964. lexpr.bc.Instr(asBC_RDSPtr);
  1965. lexpr.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
  1966. lexpr.type.stackOffset = -1;
  1967. }
  1968. lexpr.type.isLValue = true;
  1969. // If left expression resolves into a registered type
  1970. // check if the assignment operator is overloaded, and check
  1971. // the type of the right hand expression. If none is found
  1972. // the default action is a direct copy if it is the same type
  1973. // and a simple assignment.
  1974. bool assigned = false;
  1975. // Even though an ASHANDLE can be an explicit handle the overloaded operator needs to be called
  1976. if( lexpr.type.dataType.IsObject() && (!lexpr.type.isExplicitHandle || (lexpr.type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE)) )
  1977. {
  1978. assigned = CompileOverloadedDualOperator(node, &lexpr, &expr, &ctx);
  1979. if( assigned )
  1980. {
  1981. // Pop the resulting value
  1982. if( !ctx.type.dataType.IsPrimitive() )
  1983. ctx.bc.Instr(asBC_PopPtr);
  1984. // Release the argument
  1985. ProcessDeferredParams(&ctx);
  1986. // Release temporary variable that may be allocated by the overloaded operator
  1987. ReleaseTemporaryVariable(ctx.type, &ctx.bc);
  1988. }
  1989. }
  1990. if( !assigned )
  1991. {
  1992. PrepareForAssignment(&lexpr.type.dataType, &expr, node, false);
  1993. // If the expression is constant and the variable also is constant
  1994. // then mark the variable as pure constant. This will allow the compiler
  1995. // to optimize expressions with this variable.
  1996. if( type.IsReadOnly() && expr.type.isConstant )
  1997. {
  1998. isConstantExpression = true;
  1999. *constantValue = expr.type.qwordValue;
  2000. }
  2001. // Add expression code to bytecode
  2002. MergeExprBytecode(&ctx, &expr);
  2003. // Add byte code for storing value of expression in variable
  2004. ctx.bc.AddCode(&lexpr.bc);
  2005. PerformAssignment(&lexpr.type, &expr.type, &ctx.bc, errNode);
  2006. // Release temporary variables used by expression
  2007. ReleaseTemporaryVariable(expr.type, &ctx.bc);
  2008. ctx.bc.Instr(asBC_PopPtr);
  2009. ProcessDeferredParams(&ctx);
  2010. }
  2011. }
  2012. }
  2013. bc->AddCode(&ctx.bc);
  2014. }
  2015. else
  2016. {
  2017. asASSERT( node == 0 );
  2018. // Call the default constructor here, as no explicit initialization is done
  2019. if( isVarGlobOrMem == 0 )
  2020. CallDefaultConstructor(type, offset, IsVariableOnHeap(offset), bc, errNode);
  2021. else
  2022. CallDefaultConstructor(type, offset, true, bc, errNode, isVarGlobOrMem);
  2023. }
  2024. bc->OptimizeLocally(tempVariableOffsets);
  2025. return isConstantExpression;
  2026. }
  2027. void asCCompiler::CompileInitList(asCTypeInfo *var, asCScriptNode *node, asCByteCode *bc, int isVarGlobOrMem)
  2028. {
  2029. // Check if the type supports initialization lists
  2030. if( var->dataType.GetObjectType() == 0 ||
  2031. var->dataType.GetBehaviour()->listFactory == 0 ||
  2032. var->dataType.IsObjectHandle() )
  2033. {
  2034. asCString str;
  2035. str.Format(TXT_INIT_LIST_CANNOT_BE_USED_WITH_s, var->dataType.Format().AddressOf());
  2036. Error(str, node);
  2037. return;
  2038. }
  2039. // Count the number of elements and initialize the array with the correct size
  2040. int countElements = 0;
  2041. asCScriptNode *el = node->firstChild;
  2042. while( el )
  2043. {
  2044. countElements++;
  2045. el = el->next;
  2046. }
  2047. // Construct the array with the size elements
  2048. // TODO: value on stack: This needs to support value types on the stack as well
  2049. // Find the list factory
  2050. // TODO: initlist: Add support for value types as well
  2051. int funcId = var->dataType.GetBehaviour()->listFactory;
  2052. asCArray<asSExprContext *> args;
  2053. asSExprContext arg1(engine);
  2054. arg1.bc.InstrDWORD(asBC_PshC4, countElements);
  2055. arg1.type.Set(asCDataType::CreatePrimitive(ttUInt, false));
  2056. args.PushLast(&arg1);
  2057. asSExprContext ctx(engine);
  2058. PrepareFunctionCall(funcId, &ctx.bc, args);
  2059. MoveArgsToStack(funcId, &ctx.bc, args, false);
  2060. if( var->isVariable )
  2061. {
  2062. asASSERT( isVarGlobOrMem == 0 );
  2063. // Call factory and store the handle in the given variable
  2064. PerformFunctionCall(funcId, &ctx, false, &args, 0, true, var->stackOffset);
  2065. ctx.bc.Instr(asBC_PopPtr);
  2066. }
  2067. else
  2068. {
  2069. PerformFunctionCall(funcId, &ctx, false, &args);
  2070. ctx.bc.Instr(asBC_RDSPtr);
  2071. if( isVarGlobOrMem == 1 )
  2072. {
  2073. // Store the returned handle in the global variable
  2074. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[var->stackOffset]->GetAddressOfValue());
  2075. }
  2076. else
  2077. {
  2078. // Store the returned handle in the member
  2079. ctx.bc.InstrSHORT(asBC_PSF, 0);
  2080. ctx.bc.Instr(asBC_RDSPtr);
  2081. ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)var->stackOffset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
  2082. }
  2083. ctx.bc.InstrPTR(asBC_REFCPY, var->dataType.GetObjectType());
  2084. ctx.bc.Instr(asBC_PopPtr);
  2085. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  2086. }
  2087. bc->AddCode(&ctx.bc);
  2088. // TODO: initlist: Should we have a special indexing operator for this? How can we support
  2089. // initialization lists with different types for different elements? Maybe
  2090. // by using the variable arguments the initialization can be done with one
  2091. // call, passing all the elements as arguments. The registered function can
  2092. // then traverse them however it wants.
  2093. // Find the indexing operator that is not read-only that will be used for all elements
  2094. asCDataType retType;
  2095. retType = var->dataType.GetSubType();
  2096. retType.MakeReference(true);
  2097. retType.MakeReadOnly(false);
  2098. funcId = 0;
  2099. for( asUINT n = 0; n < var->dataType.GetObjectType()->methods.GetLength(); n++ )
  2100. {
  2101. asCScriptFunction *desc = builder->GetFunctionDescription(var->dataType.GetObjectType()->methods[n]);
  2102. if( !desc->isReadOnly &&
  2103. desc->parameterTypes.GetLength() == 1 &&
  2104. (desc->parameterTypes[0] == asCDataType::CreatePrimitive(ttUInt, false) ||
  2105. desc->parameterTypes[0] == asCDataType::CreatePrimitive(ttInt, false)) &&
  2106. desc->returnType == retType &&
  2107. desc->name == "opIndex" )
  2108. {
  2109. funcId = var->dataType.GetObjectType()->methods[n];
  2110. break;
  2111. }
  2112. }
  2113. if( funcId == 0 )
  2114. {
  2115. Error(TXT_NO_APPROPRIATE_INDEX_OPERATOR, node);
  2116. return;
  2117. }
  2118. asUINT index = 0;
  2119. el = node->firstChild;
  2120. while( el )
  2121. {
  2122. if( el->nodeType == snAssignment || el->nodeType == snInitList )
  2123. {
  2124. asSExprContext lctx(engine);
  2125. asSExprContext rctx(engine);
  2126. if( el->nodeType == snAssignment )
  2127. {
  2128. // Compile the assignment expression
  2129. CompileAssignment(el, &rctx);
  2130. }
  2131. else if( el->nodeType == snInitList )
  2132. {
  2133. int offset = AllocateVariable(var->dataType.GetSubType(), true);
  2134. rctx.type.Set(var->dataType.GetSubType());
  2135. rctx.type.isVariable = true;
  2136. rctx.type.isTemporary = true;
  2137. rctx.type.stackOffset = (short)offset;
  2138. CompileInitList(&rctx.type, el, &rctx.bc, 0);
  2139. // Put the object on the stack
  2140. rctx.bc.InstrSHORT(asBC_PSF, rctx.type.stackOffset);
  2141. // It is a reference that we place on the stack
  2142. rctx.type.dataType.MakeReference(true);
  2143. }
  2144. // Compile the lvalue
  2145. lctx.bc.InstrDWORD(asBC_PshC4, index);
  2146. if( var->isVariable )
  2147. lctx.bc.InstrSHORT(asBC_PSF, var->stackOffset);
  2148. else
  2149. {
  2150. // TODO: runtime optimize: should copy a handle to a local variable to avoid
  2151. // accessing the global variable or class member for each element
  2152. if( isVarGlobOrMem == 1 )
  2153. lctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[var->stackOffset]->GetAddressOfValue());
  2154. else
  2155. {
  2156. lctx.bc.InstrSHORT(asBC_PSF, 0);
  2157. lctx.bc.Instr(asBC_RDSPtr);
  2158. lctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)var->stackOffset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
  2159. }
  2160. }
  2161. lctx.bc.Instr(asBC_RDSPtr);
  2162. lctx.bc.Call(asBC_CALLSYS, funcId, 1+AS_PTR_SIZE);
  2163. if( !var->dataType.GetSubType().IsPrimitive() )
  2164. lctx.bc.Instr(asBC_PshRPtr);
  2165. lctx.type.Set(var->dataType.GetSubType());
  2166. if( !lctx.type.dataType.IsObject() || lctx.type.dataType.IsObjectHandle() )
  2167. lctx.type.dataType.MakeReference(true);
  2168. // If the element type is handles, then we're expected to do handle assignments
  2169. if( lctx.type.dataType.IsObjectHandle() )
  2170. lctx.type.isExplicitHandle = true;
  2171. lctx.type.isLValue = true;
  2172. asSExprContext ctx(engine);
  2173. DoAssignment(&ctx, &lctx, &rctx, el, el, ttAssignment, el);
  2174. if( !lctx.type.dataType.IsPrimitive() )
  2175. ctx.bc.Instr(asBC_PopPtr);
  2176. // Release temporary variables used by expression
  2177. ReleaseTemporaryVariable(ctx.type, &ctx.bc);
  2178. ProcessDeferredParams(&ctx);
  2179. bc->AddCode(&ctx.bc);
  2180. }
  2181. el = el->next;
  2182. index++;
  2183. }
  2184. }
  2185. void asCCompiler::CompileStatement(asCScriptNode *statement, bool *hasReturn, asCByteCode *bc)
  2186. {
  2187. // Don't clear the hasReturn flag if this is an empty statement
  2188. // to avoid false errors of 'not all paths return'
  2189. if( statement->nodeType != snExpressionStatement || statement->firstChild )
  2190. *hasReturn = false;
  2191. if( statement->nodeType == snStatementBlock )
  2192. CompileStatementBlock(statement, true, hasReturn, bc);
  2193. else if( statement->nodeType == snIf )
  2194. CompileIfStatement(statement, hasReturn, bc);
  2195. else if( statement->nodeType == snFor )
  2196. CompileForStatement(statement, bc);
  2197. else if( statement->nodeType == snWhile )
  2198. CompileWhileStatement(statement, bc);
  2199. else if( statement->nodeType == snDoWhile )
  2200. CompileDoWhileStatement(statement, bc);
  2201. else if( statement->nodeType == snExpressionStatement )
  2202. CompileExpressionStatement(statement, bc);
  2203. else if( statement->nodeType == snBreak )
  2204. CompileBreakStatement(statement, bc);
  2205. else if( statement->nodeType == snContinue )
  2206. CompileContinueStatement(statement, bc);
  2207. else if( statement->nodeType == snSwitch )
  2208. CompileSwitchStatement(statement, hasReturn, bc);
  2209. else if( statement->nodeType == snReturn )
  2210. {
  2211. CompileReturnStatement(statement, bc);
  2212. *hasReturn = true;
  2213. }
  2214. }
  2215. void asCCompiler::CompileSwitchStatement(asCScriptNode *snode, bool *, asCByteCode *bc)
  2216. {
  2217. // TODO: inheritance: Must guarantee that all options in the switch case call a constructor, or that none call it.
  2218. // Reserve label for break statements
  2219. int breakLabel = nextLabel++;
  2220. breakLabels.PushLast(breakLabel);
  2221. // Add a variable scope that will be used by CompileBreak
  2222. // to know where to stop deallocating variables
  2223. AddVariableScope(true, false);
  2224. //---------------------------
  2225. // Compile the switch expression
  2226. //-------------------------------
  2227. // Compile the switch expression
  2228. asSExprContext expr(engine);
  2229. CompileAssignment(snode->firstChild, &expr);
  2230. // Verify that the expression is a primitive type
  2231. if( !expr.type.dataType.IsIntegerType() && !expr.type.dataType.IsUnsignedType() )
  2232. {
  2233. Error(TXT_SWITCH_MUST_BE_INTEGRAL, snode->firstChild);
  2234. return;
  2235. }
  2236. ProcessPropertyGetAccessor(&expr, snode);
  2237. // TODO: Need to support 64bit integers
  2238. // Convert the expression to a 32bit variable
  2239. asCDataType to;
  2240. if( expr.type.dataType.IsIntegerType() )
  2241. to.SetTokenType(ttInt);
  2242. else if( expr.type.dataType.IsUnsignedType() )
  2243. to.SetTokenType(ttUInt);
  2244. // Make sure the value is in a variable
  2245. if( expr.type.dataType.IsReference() )
  2246. ConvertToVariable(&expr);
  2247. ImplicitConversion(&expr, to, snode->firstChild, asIC_IMPLICIT_CONV, true);
  2248. ConvertToVariable(&expr);
  2249. int offset = expr.type.stackOffset;
  2250. ProcessDeferredParams(&expr);
  2251. //-------------------------------
  2252. // Determine case values and labels
  2253. //--------------------------------
  2254. // Remember the first label so that we can later pass the
  2255. // correct label to each CompileCase()
  2256. int firstCaseLabel = nextLabel;
  2257. int defaultLabel = 0;
  2258. asCArray<int> caseValues;
  2259. asCArray<int> caseLabels;
  2260. // Compile all case comparisons and make them jump to the right label
  2261. asCScriptNode *cnode = snode->firstChild->next;
  2262. while( cnode )
  2263. {
  2264. // Each case should have a constant expression
  2265. if( cnode->firstChild && cnode->firstChild->nodeType == snExpression )
  2266. {
  2267. // Compile expression
  2268. asSExprContext c(engine);
  2269. CompileExpression(cnode->firstChild, &c);
  2270. // Verify that the result is a constant
  2271. if( !c.type.isConstant )
  2272. Error(TXT_SWITCH_CASE_MUST_BE_CONSTANT, cnode->firstChild);
  2273. // Verify that the result is an integral number
  2274. if( !c.type.dataType.IsIntegerType() && !c.type.dataType.IsUnsignedType() )
  2275. Error(TXT_SWITCH_MUST_BE_INTEGRAL, cnode->firstChild);
  2276. ImplicitConversion(&c, to, cnode->firstChild, asIC_IMPLICIT_CONV, true);
  2277. // Has this case been declared already?
  2278. if( caseValues.IndexOf(c.type.intValue) >= 0 )
  2279. {
  2280. Error(TXT_DUPLICATE_SWITCH_CASE, cnode->firstChild);
  2281. }
  2282. // TODO: Optimize: We can insert the numbers sorted already
  2283. // Store constant for later use
  2284. caseValues.PushLast(c.type.intValue);
  2285. // Reserve label for this case
  2286. caseLabels.PushLast(nextLabel++);
  2287. }
  2288. else
  2289. {
  2290. // TODO: It shouldn't be necessary for the default case to be the last one.
  2291. // Is default the last case?
  2292. if( cnode->next )
  2293. {
  2294. Error(TXT_DEFAULT_MUST_BE_LAST, cnode);
  2295. break;
  2296. }
  2297. // Reserve label for this case
  2298. defaultLabel = nextLabel++;
  2299. }
  2300. cnode = cnode->next;
  2301. }
  2302. // check for empty switch
  2303. if (caseValues.GetLength() == 0)
  2304. {
  2305. Error(TXT_EMPTY_SWITCH, snode);
  2306. return;
  2307. }
  2308. if( defaultLabel == 0 )
  2309. defaultLabel = breakLabel;
  2310. //---------------------------------
  2311. // Output the optimized case comparisons
  2312. // with jumps to the case code
  2313. //------------------------------------
  2314. // Sort the case values by increasing value. Do the sort together with the labels
  2315. // A simple bubble sort is sufficient since we don't expect a huge number of values
  2316. for( asUINT fwd = 1; fwd < caseValues.GetLength(); fwd++ )
  2317. {
  2318. for( int bck = fwd - 1; bck >= 0; bck-- )
  2319. {
  2320. int bckp = bck + 1;
  2321. if( caseValues[bck] > caseValues[bckp] )
  2322. {
  2323. // Swap the values in both arrays
  2324. int swap = caseValues[bckp];
  2325. caseValues[bckp] = caseValues[bck];
  2326. caseValues[bck] = swap;
  2327. swap = caseLabels[bckp];
  2328. caseLabels[bckp] = caseLabels[bck];
  2329. caseLabels[bck] = swap;
  2330. }
  2331. else
  2332. break;
  2333. }
  2334. }
  2335. // Find ranges of consecutive numbers
  2336. asCArray<int> ranges;
  2337. ranges.PushLast(0);
  2338. asUINT n;
  2339. for( n = 1; n < caseValues.GetLength(); ++n )
  2340. {
  2341. // We can join numbers that are less than 5 numbers
  2342. // apart since the output code will still be smaller
  2343. if( caseValues[n] > caseValues[n-1] + 5 )
  2344. ranges.PushLast(n);
  2345. }
  2346. // If the value is larger than the largest case value, jump to default
  2347. int tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  2348. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[caseValues.GetLength()-1]);
  2349. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  2350. expr.bc.InstrDWORD(asBC_JP, defaultLabel);
  2351. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  2352. // TODO: runtime optimize: We could possibly optimize this even more by doing a
  2353. // binary search instead of a linear search through the ranges
  2354. // For each range
  2355. int range;
  2356. for( range = 0; range < (int)ranges.GetLength(); range++ )
  2357. {
  2358. // Find the largest value in this range
  2359. int maxRange = caseValues[ranges[range]];
  2360. int index = ranges[range];
  2361. for( ; (index < (int)caseValues.GetLength()) && (caseValues[index] <= maxRange + 5); index++ )
  2362. maxRange = caseValues[index];
  2363. // If there are only 2 numbers then it is better to compare them directly
  2364. if( index - ranges[range] > 2 )
  2365. {
  2366. // If the value is smaller than the smallest case value in the range, jump to default
  2367. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  2368. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[ranges[range]]);
  2369. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  2370. expr.bc.InstrDWORD(asBC_JS, defaultLabel);
  2371. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  2372. int nextRangeLabel = nextLabel++;
  2373. // If this is the last range we don't have to make this test
  2374. if( range < (int)ranges.GetLength() - 1 )
  2375. {
  2376. // If the value is larger than the largest case value in the range, jump to the next range
  2377. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  2378. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, maxRange);
  2379. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  2380. expr.bc.InstrDWORD(asBC_JP, nextRangeLabel);
  2381. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  2382. }
  2383. // Jump forward according to the value
  2384. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  2385. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[ranges[range]]);
  2386. expr.bc.InstrW_W_W(asBC_SUBi, tmpOffset, offset, tmpOffset);
  2387. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  2388. expr.bc.JmpP(tmpOffset, maxRange - caseValues[ranges[range]]);
  2389. // Add the list of jumps to the correct labels (any holes, jump to default)
  2390. index = ranges[range];
  2391. for( int n = caseValues[index]; n <= maxRange; n++ )
  2392. {
  2393. if( caseValues[index] == n )
  2394. expr.bc.InstrINT(asBC_JMP, caseLabels[index++]);
  2395. else
  2396. expr.bc.InstrINT(asBC_JMP, defaultLabel);
  2397. }
  2398. expr.bc.Label((short)nextRangeLabel);
  2399. }
  2400. else
  2401. {
  2402. // Simply make a comparison with each value
  2403. int n;
  2404. for( n = ranges[range]; n < index; ++n )
  2405. {
  2406. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  2407. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[n]);
  2408. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  2409. expr.bc.InstrDWORD(asBC_JZ, caseLabels[n]);
  2410. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  2411. }
  2412. }
  2413. }
  2414. // Catch any value that falls trough
  2415. expr.bc.InstrINT(asBC_JMP, defaultLabel);
  2416. // Release the temporary variable previously stored
  2417. ReleaseTemporaryVariable(expr.type, &expr.bc);
  2418. // TODO: optimize: Should optimize each piece individually
  2419. expr.bc.OptimizeLocally(tempVariableOffsets);
  2420. //----------------------------------
  2421. // Output case implementations
  2422. //----------------------------------
  2423. // Compile case implementations, each one with the label before it
  2424. cnode = snode->firstChild->next;
  2425. while( cnode )
  2426. {
  2427. // Each case should have a constant expression
  2428. if( cnode->firstChild && cnode->firstChild->nodeType == snExpression )
  2429. {
  2430. expr.bc.Label((short)firstCaseLabel++);
  2431. CompileCase(cnode->firstChild->next, &expr.bc);
  2432. }
  2433. else
  2434. {
  2435. expr.bc.Label((short)defaultLabel);
  2436. // Is default the last case?
  2437. if( cnode->next )
  2438. {
  2439. // We've already reported this error
  2440. break;
  2441. }
  2442. CompileCase(cnode->firstChild, &expr.bc);
  2443. }
  2444. cnode = cnode->next;
  2445. }
  2446. //--------------------------------
  2447. bc->AddCode(&expr.bc);
  2448. // Add break label
  2449. bc->Label((short)breakLabel);
  2450. breakLabels.PopLast();
  2451. RemoveVariableScope();
  2452. }
  2453. void asCCompiler::CompileCase(asCScriptNode *node, asCByteCode *bc)
  2454. {
  2455. bool isFinished = false;
  2456. bool hasReturn = false;
  2457. bool hasUnreachableCode = false;
  2458. while( node )
  2459. {
  2460. if( !hasUnreachableCode && (hasReturn || isFinished) )
  2461. {
  2462. hasUnreachableCode = true;
  2463. Warning(TXT_UNREACHABLE_CODE, node);
  2464. break;
  2465. }
  2466. if( node->nodeType == snBreak || node->nodeType == snContinue )
  2467. isFinished = true;
  2468. asCByteCode statement(engine);
  2469. if( node->nodeType == snDeclaration )
  2470. {
  2471. Error(TXT_DECL_IN_SWITCH, node);
  2472. // Compile it anyway to avoid further compiler errors
  2473. CompileDeclaration(node, &statement);
  2474. }
  2475. else
  2476. CompileStatement(node, &hasReturn, &statement);
  2477. LineInstr(bc, node->tokenPos);
  2478. bc->AddCode(&statement);
  2479. if( !hasCompileErrors )
  2480. asASSERT( tempVariables.GetLength() == 0 );
  2481. node = node->next;
  2482. }
  2483. }
  2484. void asCCompiler::CompileIfStatement(asCScriptNode *inode, bool *hasReturn, asCByteCode *bc)
  2485. {
  2486. // We will use one label for the if statement
  2487. // and possibly another for the else statement
  2488. int afterLabel = nextLabel++;
  2489. // Compile the expression
  2490. asSExprContext expr(engine);
  2491. CompileAssignment(inode->firstChild, &expr);
  2492. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  2493. {
  2494. Error(TXT_EXPR_MUST_BE_BOOL, inode->firstChild);
  2495. expr.type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), 1);
  2496. }
  2497. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  2498. ProcessDeferredParams(&expr);
  2499. if( !expr.type.isConstant )
  2500. {
  2501. ProcessPropertyGetAccessor(&expr, inode);
  2502. ConvertToVariable(&expr);
  2503. // Add a test
  2504. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  2505. expr.bc.Instr(asBC_ClrHi);
  2506. expr.bc.InstrDWORD(asBC_JZ, afterLabel);
  2507. ReleaseTemporaryVariable(expr.type, &expr.bc);
  2508. expr.bc.OptimizeLocally(tempVariableOffsets);
  2509. bc->AddCode(&expr.bc);
  2510. }
  2511. else if( expr.type.dwordValue == 0 )
  2512. {
  2513. // Jump to the else case
  2514. bc->InstrINT(asBC_JMP, afterLabel);
  2515. // TODO: Should we warn that the expression will always go to the else?
  2516. }
  2517. // Compile the if statement
  2518. bool origIsConstructorCalled = m_isConstructorCalled;
  2519. bool hasReturn1;
  2520. asCByteCode ifBC(engine);
  2521. CompileStatement(inode->firstChild->next, &hasReturn1, &ifBC);
  2522. // Add the byte code
  2523. LineInstr(bc, inode->firstChild->next->tokenPos);
  2524. bc->AddCode(&ifBC);
  2525. if( inode->firstChild->next->nodeType == snExpressionStatement && inode->firstChild->next->firstChild == 0 )
  2526. {
  2527. // Don't allow if( expr );
  2528. Error(TXT_IF_WITH_EMPTY_STATEMENT, inode->firstChild->next);
  2529. }
  2530. // If one of the statements call the constructor, the other must as well
  2531. // otherwise it is possible the constructor is never called
  2532. bool constructorCall1 = false;
  2533. bool constructorCall2 = false;
  2534. if( !origIsConstructorCalled && m_isConstructorCalled )
  2535. constructorCall1 = true;
  2536. // Do we have an else statement?
  2537. if( inode->firstChild->next != inode->lastChild )
  2538. {
  2539. // Reset the constructor called flag so the else statement can call the constructor too
  2540. m_isConstructorCalled = origIsConstructorCalled;
  2541. int afterElse = 0;
  2542. if( !hasReturn1 )
  2543. {
  2544. afterElse = nextLabel++;
  2545. // Add jump to after the else statement
  2546. bc->InstrINT(asBC_JMP, afterElse);
  2547. }
  2548. // Add label for the else statement
  2549. bc->Label((short)afterLabel);
  2550. bool hasReturn2;
  2551. asCByteCode elseBC(engine);
  2552. CompileStatement(inode->lastChild, &hasReturn2, &elseBC);
  2553. // Add byte code for the else statement
  2554. LineInstr(bc, inode->lastChild->tokenPos);
  2555. bc->AddCode(&elseBC);
  2556. if( inode->lastChild->nodeType == snExpressionStatement && inode->lastChild->firstChild == 0 )
  2557. {
  2558. // Don't allow if( expr ) {} else;
  2559. Error(TXT_ELSE_WITH_EMPTY_STATEMENT, inode->lastChild);
  2560. }
  2561. if( !hasReturn1 )
  2562. {
  2563. // Add label for the end of else statement
  2564. bc->Label((short)afterElse);
  2565. }
  2566. // The if statement only has return if both alternatives have
  2567. *hasReturn = hasReturn1 && hasReturn2;
  2568. if( !origIsConstructorCalled && m_isConstructorCalled )
  2569. constructorCall2 = true;
  2570. }
  2571. else
  2572. {
  2573. // Add label for the end of if statement
  2574. bc->Label((short)afterLabel);
  2575. *hasReturn = false;
  2576. }
  2577. // Make sure both or neither conditions call a constructor
  2578. if( (constructorCall1 && !constructorCall2) ||
  2579. (constructorCall2 && !constructorCall1) )
  2580. {
  2581. Error(TXT_BOTH_CONDITIONS_MUST_CALL_CONSTRUCTOR, inode);
  2582. }
  2583. m_isConstructorCalled = origIsConstructorCalled || constructorCall1 || constructorCall2;
  2584. }
  2585. void asCCompiler::CompileForStatement(asCScriptNode *fnode, asCByteCode *bc)
  2586. {
  2587. // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables
  2588. AddVariableScope(true, true);
  2589. // We will use three labels for the for loop
  2590. int conditionLabel = nextLabel++;
  2591. int afterLabel = nextLabel++;
  2592. int continueLabel = nextLabel++;
  2593. int insideLabel = nextLabel++;
  2594. continueLabels.PushLast(continueLabel);
  2595. breakLabels.PushLast(afterLabel);
  2596. //---------------------------------------
  2597. // Compile the initialization statement
  2598. asCByteCode initBC(engine);
  2599. LineInstr(&initBC, fnode->firstChild->tokenPos);
  2600. if( fnode->firstChild->nodeType == snDeclaration )
  2601. CompileDeclaration(fnode->firstChild, &initBC);
  2602. else
  2603. CompileExpressionStatement(fnode->firstChild, &initBC);
  2604. //-----------------------------------
  2605. // Compile the condition statement
  2606. asSExprContext expr(engine);
  2607. asCScriptNode *second = fnode->firstChild->next;
  2608. if( second->firstChild )
  2609. {
  2610. int r = CompileAssignment(second->firstChild, &expr);
  2611. if( r >= 0 )
  2612. {
  2613. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  2614. Error(TXT_EXPR_MUST_BE_BOOL, second);
  2615. else
  2616. {
  2617. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  2618. ProcessDeferredParams(&expr);
  2619. ProcessPropertyGetAccessor(&expr, second);
  2620. // If expression is false exit the loop
  2621. ConvertToVariable(&expr);
  2622. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  2623. expr.bc.Instr(asBC_ClrHi);
  2624. expr.bc.InstrDWORD(asBC_JNZ, insideLabel);
  2625. ReleaseTemporaryVariable(expr.type, &expr.bc);
  2626. expr.bc.OptimizeLocally(tempVariableOffsets);
  2627. // Prepend the line instruction for the condition
  2628. asCByteCode tmp(engine);
  2629. LineInstr(&tmp, second->firstChild->tokenPos);
  2630. tmp.AddCode(&expr.bc);
  2631. expr.bc.AddCode(&tmp);
  2632. }
  2633. }
  2634. }
  2635. //---------------------------
  2636. // Compile the increment statement
  2637. asCByteCode nextBC(engine);
  2638. asCScriptNode *third = second->next;
  2639. if( third->nodeType == snExpressionStatement )
  2640. {
  2641. LineInstr(&nextBC, third->tokenPos);
  2642. CompileExpressionStatement(third, &nextBC);
  2643. }
  2644. //------------------------------
  2645. // Compile loop statement
  2646. bool hasReturn;
  2647. asCByteCode forBC(engine);
  2648. CompileStatement(fnode->lastChild, &hasReturn, &forBC);
  2649. //-------------------------------
  2650. // Join the code pieces
  2651. bc->AddCode(&initBC);
  2652. bc->InstrDWORD(asBC_JMP, conditionLabel);
  2653. bc->Label((short)insideLabel);
  2654. // Add a suspend bytecode inside the loop to guarantee
  2655. // that the application can suspend the execution
  2656. bc->Instr(asBC_SUSPEND);
  2657. bc->InstrPTR(asBC_JitEntry, 0);
  2658. LineInstr(bc, fnode->lastChild->tokenPos);
  2659. bc->AddCode(&forBC);
  2660. bc->Label((short)continueLabel);
  2661. bc->AddCode(&nextBC);
  2662. bc->Label((short)conditionLabel);
  2663. if( expr.bc.GetLastInstr() == -1 )
  2664. // There is no condition, so we just always jump
  2665. bc->InstrDWORD(asBC_JMP, insideLabel);
  2666. else
  2667. bc->AddCode(&expr.bc);
  2668. bc->Label((short)afterLabel);
  2669. continueLabels.PopLast();
  2670. breakLabels.PopLast();
  2671. // Deallocate variables in this block, in reverse order
  2672. for( int n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  2673. {
  2674. sVariable *v = variables->variables[n];
  2675. // Call variable destructors here, for variables not yet destroyed
  2676. CallDestructor(v->type, v->stackOffset, v->onHeap, bc);
  2677. // Don't deallocate function parameters
  2678. if( v->stackOffset > 0 )
  2679. DeallocateVariable(v->stackOffset);
  2680. }
  2681. RemoveVariableScope();
  2682. }
  2683. void asCCompiler::CompileWhileStatement(asCScriptNode *wnode, asCByteCode *bc)
  2684. {
  2685. // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables
  2686. AddVariableScope(true, true);
  2687. // We will use two labels for the while loop
  2688. int beforeLabel = nextLabel++;
  2689. int afterLabel = nextLabel++;
  2690. continueLabels.PushLast(beforeLabel);
  2691. breakLabels.PushLast(afterLabel);
  2692. // Add label before the expression
  2693. bc->Label((short)beforeLabel);
  2694. // Compile expression
  2695. asSExprContext expr(engine);
  2696. CompileAssignment(wnode->firstChild, &expr);
  2697. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  2698. Error(TXT_EXPR_MUST_BE_BOOL, wnode->firstChild);
  2699. else
  2700. {
  2701. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  2702. ProcessDeferredParams(&expr);
  2703. ProcessPropertyGetAccessor(&expr, wnode);
  2704. // Add byte code for the expression
  2705. ConvertToVariable(&expr);
  2706. // Jump to end of statement if expression is false
  2707. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  2708. expr.bc.Instr(asBC_ClrHi);
  2709. expr.bc.InstrDWORD(asBC_JZ, afterLabel);
  2710. ReleaseTemporaryVariable(expr.type, &expr.bc);
  2711. expr.bc.OptimizeLocally(tempVariableOffsets);
  2712. bc->AddCode(&expr.bc);
  2713. }
  2714. // Add a suspend bytecode inside the loop to guarantee
  2715. // that the application can suspend the execution
  2716. bc->Instr(asBC_SUSPEND);
  2717. bc->InstrPTR(asBC_JitEntry, 0);
  2718. // Compile statement
  2719. bool hasReturn;
  2720. asCByteCode whileBC(engine);
  2721. CompileStatement(wnode->lastChild, &hasReturn, &whileBC);
  2722. // Add byte code for the statement
  2723. LineInstr(bc, wnode->lastChild->tokenPos);
  2724. bc->AddCode(&whileBC);
  2725. // Jump to the expression
  2726. bc->InstrINT(asBC_JMP, beforeLabel);
  2727. // Add label after the statement
  2728. bc->Label((short)afterLabel);
  2729. continueLabels.PopLast();
  2730. breakLabels.PopLast();
  2731. RemoveVariableScope();
  2732. }
  2733. void asCCompiler::CompileDoWhileStatement(asCScriptNode *wnode, asCByteCode *bc)
  2734. {
  2735. // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables
  2736. AddVariableScope(true, true);
  2737. // We will use two labels for the while loop
  2738. int beforeLabel = nextLabel++;
  2739. int beforeTest = nextLabel++;
  2740. int afterLabel = nextLabel++;
  2741. continueLabels.PushLast(beforeTest);
  2742. breakLabels.PushLast(afterLabel);
  2743. // Add label before the statement
  2744. bc->Label((short)beforeLabel);
  2745. // Compile statement
  2746. bool hasReturn;
  2747. asCByteCode whileBC(engine);
  2748. CompileStatement(wnode->firstChild, &hasReturn, &whileBC);
  2749. // Add byte code for the statement
  2750. LineInstr(bc, wnode->firstChild->tokenPos);
  2751. bc->AddCode(&whileBC);
  2752. // Add label before the expression
  2753. bc->Label((short)beforeTest);
  2754. // Add a suspend bytecode inside the loop to guarantee
  2755. // that the application can suspend the execution
  2756. bc->Instr(asBC_SUSPEND);
  2757. bc->InstrPTR(asBC_JitEntry, 0);
  2758. // Add a line instruction
  2759. LineInstr(bc, wnode->lastChild->tokenPos);
  2760. // Compile expression
  2761. asSExprContext expr(engine);
  2762. CompileAssignment(wnode->lastChild, &expr);
  2763. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  2764. Error(TXT_EXPR_MUST_BE_BOOL, wnode->firstChild);
  2765. else
  2766. {
  2767. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  2768. ProcessDeferredParams(&expr);
  2769. ProcessPropertyGetAccessor(&expr, wnode);
  2770. // Add byte code for the expression
  2771. ConvertToVariable(&expr);
  2772. // Jump to next iteration if expression is true
  2773. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  2774. expr.bc.Instr(asBC_ClrHi);
  2775. expr.bc.InstrDWORD(asBC_JNZ, beforeLabel);
  2776. ReleaseTemporaryVariable(expr.type, &expr.bc);
  2777. expr.bc.OptimizeLocally(tempVariableOffsets);
  2778. bc->AddCode(&expr.bc);
  2779. }
  2780. // Add label after the statement
  2781. bc->Label((short)afterLabel);
  2782. continueLabels.PopLast();
  2783. breakLabels.PopLast();
  2784. RemoveVariableScope();
  2785. }
  2786. void asCCompiler::CompileBreakStatement(asCScriptNode *node, asCByteCode *bc)
  2787. {
  2788. if( breakLabels.GetLength() == 0 )
  2789. {
  2790. Error(TXT_INVALID_BREAK, node);
  2791. return;
  2792. }
  2793. // Add destructor calls for all variables that will go out of scope
  2794. // Put this clean up in a block to allow exception handler to understand them
  2795. bc->Block(true);
  2796. asCVariableScope *vs = variables;
  2797. while( !vs->isBreakScope )
  2798. {
  2799. for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- )
  2800. CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc);
  2801. vs = vs->parent;
  2802. }
  2803. bc->Block(false);
  2804. bc->InstrINT(asBC_JMP, breakLabels[breakLabels.GetLength()-1]);
  2805. }
  2806. void asCCompiler::CompileContinueStatement(asCScriptNode *node, asCByteCode *bc)
  2807. {
  2808. if( continueLabels.GetLength() == 0 )
  2809. {
  2810. Error(TXT_INVALID_CONTINUE, node);
  2811. return;
  2812. }
  2813. // Add destructor calls for all variables that will go out of scope
  2814. // Put this clean up in a block to allow exception handler to understand them
  2815. bc->Block(true);
  2816. asCVariableScope *vs = variables;
  2817. while( !vs->isContinueScope )
  2818. {
  2819. for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- )
  2820. CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc);
  2821. vs = vs->parent;
  2822. }
  2823. bc->Block(false);
  2824. bc->InstrINT(asBC_JMP, continueLabels[continueLabels.GetLength()-1]);
  2825. }
  2826. void asCCompiler::CompileExpressionStatement(asCScriptNode *enode, asCByteCode *bc)
  2827. {
  2828. if( enode->firstChild )
  2829. {
  2830. // Compile the expression
  2831. asSExprContext expr(engine);
  2832. CompileAssignment(enode->firstChild, &expr);
  2833. // If we get here and there is still an unprocessed property
  2834. // accessor, then process it as a get access. Don't call if there is
  2835. // already a compile error, or we might report an error that is not valid
  2836. if( !hasCompileErrors )
  2837. ProcessPropertyGetAccessor(&expr, enode);
  2838. // Pop the value from the stack
  2839. if( !expr.type.dataType.IsPrimitive() )
  2840. expr.bc.Instr(asBC_PopPtr);
  2841. // Release temporary variables used by expression
  2842. ReleaseTemporaryVariable(expr.type, &expr.bc);
  2843. ProcessDeferredParams(&expr);
  2844. expr.bc.OptimizeLocally(tempVariableOffsets);
  2845. bc->AddCode(&expr.bc);
  2846. }
  2847. }
  2848. void asCCompiler::PrepareTemporaryObject(asCScriptNode *node, asSExprContext *ctx, bool forceOnHeap)
  2849. {
  2850. // If the object already is stored in temporary variable then nothing needs to be done
  2851. // Note, a type can be temporary without being a variable, in which case it is holding off
  2852. // on releasing a previously used object.
  2853. if( ctx->type.isTemporary && ctx->type.isVariable &&
  2854. !(forceOnHeap && !IsVariableOnHeap(ctx->type.stackOffset)) )
  2855. {
  2856. // If the temporary object is currently not a reference
  2857. // the expression needs to be reevaluated to a reference
  2858. if( !ctx->type.dataType.IsReference() )
  2859. {
  2860. ctx->bc.Instr(asBC_PopPtr);
  2861. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  2862. ctx->type.dataType.MakeReference(true);
  2863. }
  2864. return;
  2865. }
  2866. // Allocate temporary variable
  2867. asCDataType dt = ctx->type.dataType;
  2868. dt.MakeReference(false);
  2869. dt.MakeReadOnly(false);
  2870. int offset = AllocateVariable(dt, true, forceOnHeap);
  2871. // Objects stored on the stack are not considered references
  2872. dt.MakeReference(IsVariableOnHeap(offset));
  2873. asCTypeInfo lvalue;
  2874. lvalue.Set(dt);
  2875. lvalue.isTemporary = true;
  2876. lvalue.stackOffset = (short)offset;
  2877. lvalue.isVariable = true;
  2878. lvalue.isExplicitHandle = ctx->type.isExplicitHandle;
  2879. if( !dt.IsObjectHandle() &&
  2880. dt.GetObjectType() && (dt.GetBehaviour()->copyconstruct || dt.GetBehaviour()->copyfactory) )
  2881. {
  2882. PrepareForAssignment(&lvalue.dataType, ctx, node, true);
  2883. // Use the copy constructor/factory when available
  2884. CallCopyConstructor(dt, offset, IsVariableOnHeap(offset), &ctx->bc, ctx, node);
  2885. }
  2886. else
  2887. {
  2888. // Allocate and construct the temporary object
  2889. int r = CallDefaultConstructor(dt, offset, IsVariableOnHeap(offset), &ctx->bc, node);
  2890. if( r < 0 )
  2891. {
  2892. Error(TXT_FAILED_TO_CREATE_TEMP_OBJ, node);
  2893. }
  2894. else
  2895. {
  2896. // Assign the object to the temporary variable
  2897. PrepareForAssignment(&lvalue.dataType, ctx, node, true);
  2898. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  2899. r = PerformAssignment(&lvalue, &ctx->type, &ctx->bc, node);
  2900. if( r < 0 )
  2901. {
  2902. Error(TXT_FAILED_TO_CREATE_TEMP_OBJ, node);
  2903. }
  2904. // Pop the original reference
  2905. ctx->bc.Instr(asBC_PopPtr);
  2906. }
  2907. // If the expression was holding off on releasing a
  2908. // previously used object, we need to release it now
  2909. if( ctx->type.isTemporary )
  2910. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  2911. }
  2912. // Push the reference to the temporary variable on the stack
  2913. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  2914. lvalue.dataType.MakeReference(IsVariableOnHeap(offset));
  2915. ctx->type = lvalue;
  2916. }
  2917. void asCCompiler::CompileReturnStatement(asCScriptNode *rnode, asCByteCode *bc)
  2918. {
  2919. // Get return type and location
  2920. sVariable *v = variables->GetVariable("return");
  2921. // Basic validations
  2922. if( v->type.GetSizeOnStackDWords() > 0 && !rnode->firstChild )
  2923. {
  2924. Error(TXT_MUST_RETURN_VALUE, rnode);
  2925. return;
  2926. }
  2927. else if( v->type.GetSizeOnStackDWords() == 0 && rnode->firstChild )
  2928. {
  2929. Error(TXT_CANT_RETURN_VALUE, rnode);
  2930. return;
  2931. }
  2932. // Compile the expression
  2933. if( rnode->firstChild )
  2934. {
  2935. // Compile the expression
  2936. asSExprContext expr(engine);
  2937. int r = CompileAssignment(rnode->firstChild, &expr);
  2938. if( r < 0 ) return;
  2939. if( v->type.IsReference() )
  2940. {
  2941. // The expression that gives the reference must not use any of the
  2942. // variables that must be destroyed upon exit, because then it means
  2943. // reference will stay alive while the clean-up is done, which could
  2944. // potentially mean that the reference is invalidated by the clean-up.
  2945. //
  2946. // When the function is returning a reference, the clean-up of the
  2947. // variables must be done before the evaluation of the expression.
  2948. //
  2949. // A reference to a global variable, or a class member for class methods
  2950. // should be allowed to be returned.
  2951. if( !(expr.type.dataType.IsReference() ||
  2952. (expr.type.dataType.IsObject() && !expr.type.dataType.IsObjectHandle())) )
  2953. {
  2954. // Clean up the potential deferred parameters
  2955. ProcessDeferredParams(&expr);
  2956. Error(TXT_NOT_VALID_REFERENCE, rnode);
  2957. return;
  2958. }
  2959. // No references to local variables, temporary variables, or parameters
  2960. // are allowed to be returned, since they go out of scope when the function
  2961. // returns. Even reference parameters are disallowed, since it is not possible
  2962. // to know the scope of them. The exception is the 'this' pointer, which
  2963. // is treated by the compiler as a local variable, but isn't really so.
  2964. if( (expr.type.isVariable && !(expr.type.stackOffset == 0 && outFunc->objectType)) || expr.type.isTemporary )
  2965. {
  2966. // Clean up the potential deferred parameters
  2967. ProcessDeferredParams(&expr);
  2968. Error(TXT_CANNOT_RETURN_REF_TO_LOCAL, rnode);
  2969. return;
  2970. }
  2971. // The type must match exactly as we cannot convert
  2972. // the reference without loosing the original value
  2973. if( !(v->type.IsEqualExceptConst(expr.type.dataType) ||
  2974. (expr.type.dataType.IsObject() &&
  2975. !expr.type.dataType.IsObjectHandle() &&
  2976. v->type.IsEqualExceptRefAndConst(expr.type.dataType))) ||
  2977. (!v->type.IsReadOnly() && expr.type.dataType.IsReadOnly()) )
  2978. {
  2979. // Clean up the potential deferred parameters
  2980. ProcessDeferredParams(&expr);
  2981. asCString str;
  2982. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, expr.type.dataType.Format().AddressOf(), v->type.Format().AddressOf());
  2983. Error(str, rnode);
  2984. return;
  2985. }
  2986. // The expression must not have any deferred expressions, because the evaluation
  2987. // of these cannot be done without keeping the reference which is not safe
  2988. if( expr.deferredParams.GetLength() )
  2989. {
  2990. // Clean up the potential deferred parameters
  2991. ProcessDeferredParams(&expr);
  2992. Error(TXT_REF_CANT_BE_RETURNED_DEFERRED_PARAM, rnode);
  2993. return;
  2994. }
  2995. // Make sure the expression isn't using any local variables that
  2996. // will need to be cleaned up before the function completes
  2997. asCArray<int> usedVars;
  2998. expr.bc.GetVarsUsed(usedVars);
  2999. for( asUINT n = 0; n < usedVars.GetLength(); n++ )
  3000. {
  3001. int var = GetVariableSlot(usedVars[n]);
  3002. if( var != -1 )
  3003. {
  3004. asCDataType dt = variableAllocations[var];
  3005. if( dt.IsObject() )
  3006. {
  3007. ProcessDeferredParams(&expr);
  3008. Error(TXT_REF_CANT_BE_RETURNED_LOCAL_VARS, rnode);
  3009. return;
  3010. }
  3011. }
  3012. }
  3013. // All objects in the function must be cleaned up before the expression
  3014. // is evaluated, otherwise there is a possibility that the cleanup will
  3015. // invalidate the reference.
  3016. // Destroy the local variables before loading
  3017. // the reference into the register. This will
  3018. // be done before the expression is evaluated.
  3019. DestroyVariables(bc);
  3020. // For primitives the reference is already in the register,
  3021. // but for non-primitives the reference is on the stack so we
  3022. // need to load it into the register
  3023. if( !expr.type.dataType.IsPrimitive() )
  3024. {
  3025. if( !expr.type.dataType.IsObjectHandle() &&
  3026. expr.type.dataType.IsReference() )
  3027. expr.bc.Instr(asBC_RDSPtr);
  3028. expr.bc.Instr(asBC_PopRPtr);
  3029. }
  3030. // There are no temporaries to release so we're done
  3031. }
  3032. else // if( !v->type.IsReference() )
  3033. {
  3034. ProcessPropertyGetAccessor(&expr, rnode);
  3035. // Prepare the value for assignment
  3036. IsVariableInitialized(&expr.type, rnode->firstChild);
  3037. if( v->type.IsPrimitive() )
  3038. {
  3039. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  3040. // Implicitly convert the value to the return type
  3041. ImplicitConversion(&expr, v->type, rnode->firstChild, asIC_IMPLICIT_CONV);
  3042. // Verify that the conversion was successful
  3043. if( expr.type.dataType != v->type )
  3044. {
  3045. asCString str;
  3046. str.Format(TXT_NO_CONVERSION_s_TO_s, expr.type.dataType.Format().AddressOf(), v->type.Format().AddressOf());
  3047. Error(str, rnode);
  3048. return;
  3049. }
  3050. else
  3051. {
  3052. ConvertToVariable(&expr);
  3053. // Clean up the local variables and process deferred parameters
  3054. DestroyVariables(&expr.bc);
  3055. ProcessDeferredParams(&expr);
  3056. ReleaseTemporaryVariable(expr.type, &expr.bc);
  3057. // Load the variable in the register
  3058. if( v->type.GetSizeOnStackDWords() == 1 )
  3059. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  3060. else
  3061. expr.bc.InstrSHORT(asBC_CpyVtoR8, expr.type.stackOffset);
  3062. }
  3063. }
  3064. else if( v->type.IsObject() )
  3065. {
  3066. // Value types are returned on the stack, in a location
  3067. // that has been reserved by the calling function.
  3068. if( outFunc->DoesReturnOnStack() )
  3069. {
  3070. // TODO: runtime optimize: If the return type has a constructor that takes the type of the expression,
  3071. // it should be called directly instead of first converting the expression and
  3072. // then copy the value.
  3073. if( !v->type.IsEqualExceptRefAndConst(expr.type.dataType) )
  3074. {
  3075. ImplicitConversion(&expr, v->type, rnode->firstChild, asIC_IMPLICIT_CONV);
  3076. if( !v->type.IsEqualExceptRefAndConst(expr.type.dataType) )
  3077. {
  3078. asCString str;
  3079. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, expr.type.dataType.Format().AddressOf(), v->type.Format().AddressOf());
  3080. Error(str, rnode->firstChild);
  3081. return;
  3082. }
  3083. }
  3084. int offset = outFunc->objectType ? -AS_PTR_SIZE : 0;
  3085. if( v->type.GetObjectType()->beh.copyconstruct )
  3086. {
  3087. PrepareForAssignment(&v->type, &expr, rnode->firstChild, false);
  3088. CallCopyConstructor(v->type, offset, false, &expr.bc, &expr, rnode->firstChild, false, true);
  3089. }
  3090. else
  3091. {
  3092. // If the copy constructor doesn't exist, then a manual assignment needs to be done instead.
  3093. CallDefaultConstructor(v->type, offset, false, &expr.bc, rnode->firstChild, 0, true);
  3094. PrepareForAssignment(&v->type, &expr, rnode->firstChild, false);
  3095. expr.bc.InstrSHORT(asBC_PSF, (short)offset);
  3096. expr.bc.Instr(asBC_RDSPtr);
  3097. asSExprContext lexpr(engine);
  3098. lexpr.type.Set(v->type);
  3099. lexpr.type.isLValue = true;
  3100. PerformAssignment(&lexpr.type, &expr.type, &expr.bc, rnode->firstChild);
  3101. expr.bc.Instr(asBC_PopPtr);
  3102. // Release any temporary variable
  3103. ReleaseTemporaryVariable(expr.type, &expr.bc);
  3104. }
  3105. // Clean up the local variables and process deferred parameters
  3106. DestroyVariables(&expr.bc);
  3107. ProcessDeferredParams(&expr);
  3108. }
  3109. else
  3110. {
  3111. asASSERT( v->type.GetObjectType()->flags & asOBJ_REF );
  3112. // Prepare the expression to be loaded into the object
  3113. // register. This will place the reference in local variable
  3114. PrepareArgument(&v->type, &expr, rnode->firstChild, false, 0);
  3115. // Pop the reference to the temporary variable
  3116. expr.bc.Instr(asBC_PopPtr);
  3117. // Clean up the local variables and process deferred parameters
  3118. DestroyVariables(&expr.bc);
  3119. ProcessDeferredParams(&expr);
  3120. // Load the object pointer into the object register
  3121. // LOADOBJ also clears the address in the variable
  3122. expr.bc.InstrSHORT(asBC_LOADOBJ, expr.type.stackOffset);
  3123. // LOADOBJ cleared the address in the variable so the object will not be freed
  3124. // here, but the temporary variable must still be freed so the slot can be reused
  3125. // By releasing without the bytecode we do just that.
  3126. ReleaseTemporaryVariable(expr.type, 0);
  3127. }
  3128. }
  3129. }
  3130. expr.bc.OptimizeLocally(tempVariableOffsets);
  3131. bc->AddCode(&expr.bc);
  3132. }
  3133. else
  3134. {
  3135. // For functions that don't return anything
  3136. // we just detroy the local variables
  3137. DestroyVariables(bc);
  3138. }
  3139. // Jump to the end of the function
  3140. bc->InstrINT(asBC_JMP, 0);
  3141. }
  3142. void asCCompiler::DestroyVariables(asCByteCode *bc)
  3143. {
  3144. // Call destructor on all variables except for the function parameters
  3145. // Put the clean-up in a block to allow exception handler to understand this
  3146. bc->Block(true);
  3147. asCVariableScope *vs = variables;
  3148. while( vs )
  3149. {
  3150. for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- )
  3151. if( vs->variables[n]->stackOffset > 0 )
  3152. CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc);
  3153. vs = vs->parent;
  3154. }
  3155. bc->Block(false);
  3156. }
  3157. void asCCompiler::AddVariableScope(bool isBreakScope, bool isContinueScope)
  3158. {
  3159. variables = asNEW(asCVariableScope)(variables);
  3160. if( variables == 0 )
  3161. {
  3162. // Out of memory
  3163. return;
  3164. }
  3165. variables->isBreakScope = isBreakScope;
  3166. variables->isContinueScope = isContinueScope;
  3167. }
  3168. void asCCompiler::RemoveVariableScope()
  3169. {
  3170. if( variables )
  3171. {
  3172. asCVariableScope *var = variables;
  3173. variables = variables->parent;
  3174. asDELETE(var,asCVariableScope);
  3175. }
  3176. }
  3177. void asCCompiler::Error(const asCString &msg, asCScriptNode *node)
  3178. {
  3179. asCString str;
  3180. int r = 0, c = 0;
  3181. asASSERT( node );
  3182. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  3183. builder->WriteError(script->name, msg, r, c);
  3184. hasCompileErrors = true;
  3185. }
  3186. void asCCompiler::Warning(const asCString &msg, asCScriptNode *node)
  3187. {
  3188. asCString str;
  3189. int r = 0, c = 0;
  3190. asASSERT( node );
  3191. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  3192. builder->WriteWarning(script->name, msg, r, c);
  3193. }
  3194. void asCCompiler::Information(const asCString &msg, asCScriptNode *node)
  3195. {
  3196. asCString str;
  3197. int r = 0, c = 0;
  3198. asASSERT( node );
  3199. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  3200. builder->WriteInfo(script->name, msg, r, c, false);
  3201. }
  3202. void asCCompiler::PrintMatchingFuncs(asCArray<int> &funcs, asCScriptNode *node)
  3203. {
  3204. int r = 0, c = 0;
  3205. asASSERT( node );
  3206. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  3207. for( unsigned int n = 0; n < funcs.GetLength(); n++ )
  3208. {
  3209. asIScriptFunction *func = builder->GetFunctionDescription(funcs[n]);
  3210. builder->WriteInfo(script->name, func->GetDeclaration(true), r, c, false);
  3211. }
  3212. }
  3213. int asCCompiler::AllocateVariableNotIn(const asCDataType &type, bool isTemporary, bool forceOnHeap, asSExprContext *ctx)
  3214. {
  3215. int l = int(reservedVariables.GetLength());
  3216. ctx->bc.GetVarsUsed(reservedVariables);
  3217. int var = AllocateVariable(type, isTemporary, forceOnHeap);
  3218. reservedVariables.SetLength(l);
  3219. return var;
  3220. }
  3221. int asCCompiler::AllocateVariable(const asCDataType &type, bool isTemporary, bool forceOnHeap)
  3222. {
  3223. asCDataType t(type);
  3224. if( t.IsPrimitive() && t.GetSizeOnStackDWords() == 1 )
  3225. t.SetTokenType(ttInt);
  3226. if( t.IsPrimitive() && t.GetSizeOnStackDWords() == 2 )
  3227. t.SetTokenType(ttDouble);
  3228. // Only null handles have the token type unrecognized token
  3229. asASSERT( t.IsObjectHandle() || t.GetTokenType() != ttUnrecognizedToken );
  3230. bool isOnHeap = true;
  3231. if( t.IsPrimitive() ||
  3232. (t.GetObjectType() && (t.GetObjectType()->GetFlags() & asOBJ_VALUE) && !forceOnHeap) )
  3233. {
  3234. // Primitives and value types (unless overridden) are allocated on the stack
  3235. isOnHeap = false;
  3236. }
  3237. // Find a free location with the same type
  3238. for( asUINT n = 0; n < freeVariables.GetLength(); n++ )
  3239. {
  3240. int slot = freeVariables[n];
  3241. if( variableAllocations[slot].IsEqualExceptConst(t) &&
  3242. variableIsTemporary[slot] == isTemporary &&
  3243. variableIsOnHeap[slot] == isOnHeap )
  3244. {
  3245. // We can't return by slot, must count variable sizes
  3246. int offset = GetVariableOffset(slot);
  3247. // Verify that it is not in the list of reserved variables
  3248. bool isUsed = false;
  3249. if( reservedVariables.GetLength() )
  3250. isUsed = reservedVariables.Exists(offset);
  3251. if( !isUsed )
  3252. {
  3253. if( n != freeVariables.GetLength() - 1 )
  3254. freeVariables[n] = freeVariables.PopLast();
  3255. else
  3256. freeVariables.PopLast();
  3257. if( isTemporary )
  3258. tempVariables.PushLast(offset);
  3259. return offset;
  3260. }
  3261. }
  3262. }
  3263. variableAllocations.PushLast(t);
  3264. variableIsTemporary.PushLast(isTemporary);
  3265. variableIsOnHeap.PushLast(isOnHeap);
  3266. int offset = GetVariableOffset((int)variableAllocations.GetLength()-1);
  3267. if( isTemporary )
  3268. {
  3269. // Add offset to the currently allocated temporary variables
  3270. tempVariables.PushLast(offset);
  3271. // Add offset to all known offsets to temporary variables, whether allocated or not
  3272. tempVariableOffsets.PushLast(offset);
  3273. }
  3274. return offset;
  3275. }
  3276. int asCCompiler::GetVariableOffset(int varIndex)
  3277. {
  3278. // Return offset to the last dword on the stack
  3279. int varOffset = 1;
  3280. for( int n = 0; n < varIndex; n++ )
  3281. {
  3282. if( !variableIsOnHeap[n] && variableAllocations[n].IsObject() )
  3283. varOffset += variableAllocations[n].GetSizeInMemoryDWords();
  3284. else
  3285. varOffset += variableAllocations[n].GetSizeOnStackDWords();
  3286. }
  3287. if( varIndex < (int)variableAllocations.GetLength() )
  3288. {
  3289. int size;
  3290. if( !variableIsOnHeap[varIndex] && variableAllocations[varIndex].IsObject() )
  3291. size = variableAllocations[varIndex].GetSizeInMemoryDWords();
  3292. else
  3293. size = variableAllocations[varIndex].GetSizeOnStackDWords();
  3294. if( size > 1 )
  3295. varOffset += size-1;
  3296. }
  3297. return varOffset;
  3298. }
  3299. int asCCompiler::GetVariableSlot(int offset)
  3300. {
  3301. int varOffset = 1;
  3302. for( asUINT n = 0; n < variableAllocations.GetLength(); n++ )
  3303. {
  3304. if( !variableIsOnHeap[n] && variableAllocations[n].IsObject() )
  3305. varOffset += -1 + variableAllocations[n].GetSizeInMemoryDWords();
  3306. else
  3307. varOffset += -1 + variableAllocations[n].GetSizeOnStackDWords();
  3308. if( varOffset == offset )
  3309. return n;
  3310. varOffset++;
  3311. }
  3312. return -1;
  3313. }
  3314. bool asCCompiler::IsVariableOnHeap(int offset)
  3315. {
  3316. int varSlot = GetVariableSlot(offset);
  3317. if( varSlot < 0 )
  3318. {
  3319. // This happens for function arguments that are considered as on the heap
  3320. return true;
  3321. }
  3322. return variableIsOnHeap[varSlot];
  3323. }
  3324. void asCCompiler::DeallocateVariable(int offset)
  3325. {
  3326. // Remove temporary variable
  3327. int n;
  3328. for( n = 0; n < (int)tempVariables.GetLength(); n++ )
  3329. {
  3330. if( offset == tempVariables[n] )
  3331. {
  3332. if( n == (int)tempVariables.GetLength()-1 )
  3333. tempVariables.PopLast();
  3334. else
  3335. tempVariables[n] = tempVariables.PopLast();
  3336. break;
  3337. }
  3338. }
  3339. n = GetVariableSlot(offset);
  3340. if( n != -1 )
  3341. {
  3342. freeVariables.PushLast(n);
  3343. return;
  3344. }
  3345. // We might get here if the variable was implicitly declared
  3346. // because it was use before a formal declaration, in this case
  3347. // the offset is 0x7FFF
  3348. asASSERT(offset == 0x7FFF);
  3349. }
  3350. void asCCompiler::ReleaseTemporaryVariable(asCTypeInfo &t, asCByteCode *bc)
  3351. {
  3352. if( t.isTemporary )
  3353. {
  3354. ReleaseTemporaryVariable(t.stackOffset, bc);
  3355. t.isTemporary = false;
  3356. }
  3357. }
  3358. void asCCompiler::ReleaseTemporaryVariable(int offset, asCByteCode *bc)
  3359. {
  3360. if( bc )
  3361. {
  3362. // We need to call the destructor on the true variable type
  3363. int n = GetVariableSlot(offset);
  3364. asASSERT( n >= 0 );
  3365. if( n >= 0 )
  3366. {
  3367. asCDataType dt = variableAllocations[n];
  3368. bool isOnHeap = variableIsOnHeap[n];
  3369. // Call destructor
  3370. CallDestructor(dt, offset, isOnHeap, bc);
  3371. }
  3372. }
  3373. DeallocateVariable(offset);
  3374. }
  3375. void asCCompiler::Dereference(asSExprContext *ctx, bool generateCode)
  3376. {
  3377. if( ctx->type.dataType.IsReference() )
  3378. {
  3379. if( ctx->type.dataType.IsObject() )
  3380. {
  3381. ctx->type.dataType.MakeReference(false);
  3382. if( generateCode )
  3383. ctx->bc.Instr(asBC_RDSPtr);
  3384. }
  3385. else
  3386. {
  3387. // This should never happen as primitives are treated differently
  3388. asASSERT(false);
  3389. }
  3390. }
  3391. }
  3392. bool asCCompiler::IsVariableInitialized(asCTypeInfo *type, asCScriptNode *node)
  3393. {
  3394. // No need to check if there is no variable scope
  3395. if( variables == 0 ) return true;
  3396. // Temporary variables are assumed to be initialized
  3397. if( type->isTemporary ) return true;
  3398. // Verify that it is a variable
  3399. if( !type->isVariable ) return true;
  3400. // Find the variable
  3401. sVariable *v = variables->GetVariableByOffset(type->stackOffset);
  3402. // The variable isn't found if it is a constant, in which case it is guaranteed to be initialized
  3403. if( v == 0 ) return true;
  3404. if( v->isInitialized ) return true;
  3405. // Complex types don't need this test
  3406. if( v->type.IsObject() ) return true;
  3407. // Mark as initialized so that the user will not be bothered again
  3408. v->isInitialized = true;
  3409. // Write warning
  3410. asCString str;
  3411. str.Format(TXT_s_NOT_INITIALIZED, (const char *)v->name.AddressOf());
  3412. Warning(str, node);
  3413. return false;
  3414. }
  3415. void asCCompiler::PrepareOperand(asSExprContext *ctx, asCScriptNode *node)
  3416. {
  3417. // Check if the variable is initialized (if it indeed is a variable)
  3418. IsVariableInitialized(&ctx->type, node);
  3419. asCDataType to = ctx->type.dataType;
  3420. to.MakeReference(false);
  3421. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV);
  3422. ProcessDeferredParams(ctx);
  3423. }
  3424. void asCCompiler::PrepareForAssignment(asCDataType *lvalue, asSExprContext *rctx, asCScriptNode *node, bool toTemporary, asSExprContext *lvalueExpr)
  3425. {
  3426. // Reserve the temporary variables used in the lvalue expression so they won't end up being used by the rvalue too
  3427. int l = int(reservedVariables.GetLength());
  3428. if( lvalueExpr ) lvalueExpr->bc.GetVarsUsed(reservedVariables);
  3429. ProcessPropertyGetAccessor(rctx, node);
  3430. // Make sure the rvalue is initialized if it is a variable
  3431. IsVariableInitialized(&rctx->type, node);
  3432. if( lvalue->IsPrimitive() )
  3433. {
  3434. if( rctx->type.dataType.IsPrimitive() )
  3435. {
  3436. if( rctx->type.dataType.IsReference() )
  3437. {
  3438. // Cannot do implicit conversion of references so we first convert the reference to a variable
  3439. ConvertToVariableNotIn(rctx, lvalueExpr);
  3440. }
  3441. }
  3442. // Implicitly convert the value to the right type
  3443. ImplicitConversion(rctx, *lvalue, node, asIC_IMPLICIT_CONV);
  3444. // Check data type
  3445. if( !lvalue->IsEqualExceptRefAndConst(rctx->type.dataType) )
  3446. {
  3447. asCString str;
  3448. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format().AddressOf(), lvalue->Format().AddressOf());
  3449. Error(str, node);
  3450. rctx->type.SetDummy();
  3451. }
  3452. // Make sure the rvalue is a variable
  3453. if( !rctx->type.isVariable )
  3454. ConvertToVariableNotIn(rctx, lvalueExpr);
  3455. }
  3456. else
  3457. {
  3458. asCDataType to = *lvalue;
  3459. to.MakeReference(false);
  3460. // TODO: ImplicitConversion should know to do this by itself
  3461. // First convert to a handle which will do a reference cast
  3462. if( !lvalue->IsObjectHandle() &&
  3463. (lvalue->GetObjectType()->flags & asOBJ_SCRIPT_OBJECT) )
  3464. to.MakeHandle(true);
  3465. // Don't allow the implicit conversion to create an object
  3466. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true, !toTemporary);
  3467. if( !lvalue->IsObjectHandle() &&
  3468. (lvalue->GetObjectType()->flags & asOBJ_SCRIPT_OBJECT) )
  3469. {
  3470. // Then convert to a reference, which will validate the handle
  3471. to.MakeHandle(false);
  3472. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true, !toTemporary);
  3473. }
  3474. // Check data type
  3475. if( !lvalue->IsEqualExceptRefAndConst(rctx->type.dataType) )
  3476. {
  3477. asCString str;
  3478. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format().AddressOf(), lvalue->Format().AddressOf());
  3479. Error(str, node);
  3480. }
  3481. else
  3482. {
  3483. // If the assignment will be made with the copy behaviour then the rvalue must not be a reference
  3484. if( lvalue->IsObject() )
  3485. asASSERT(!rctx->type.dataType.IsReference());
  3486. }
  3487. }
  3488. // Unreserve variables
  3489. reservedVariables.SetLength(l);
  3490. }
  3491. bool asCCompiler::IsLValue(asCTypeInfo &type)
  3492. {
  3493. if( !type.isLValue ) return false;
  3494. if( type.dataType.IsReadOnly() ) return false;
  3495. if( !type.dataType.IsObject() && !type.isVariable && !type.dataType.IsReference() ) return false;
  3496. return true;
  3497. }
  3498. int asCCompiler::PerformAssignment(asCTypeInfo *lvalue, asCTypeInfo *rvalue, asCByteCode *bc, asCScriptNode *node)
  3499. {
  3500. if( lvalue->dataType.IsReadOnly() )
  3501. {
  3502. Error(TXT_REF_IS_READ_ONLY, node);
  3503. return -1;
  3504. }
  3505. if( lvalue->dataType.IsPrimitive() )
  3506. {
  3507. if( lvalue->isVariable )
  3508. {
  3509. // Copy the value between the variables directly
  3510. if( lvalue->dataType.GetSizeInMemoryDWords() == 1 )
  3511. bc->InstrW_W(asBC_CpyVtoV4, lvalue->stackOffset, rvalue->stackOffset);
  3512. else
  3513. bc->InstrW_W(asBC_CpyVtoV8, lvalue->stackOffset, rvalue->stackOffset);
  3514. // Mark variable as initialized
  3515. sVariable *v = variables->GetVariableByOffset(lvalue->stackOffset);
  3516. if( v ) v->isInitialized = true;
  3517. }
  3518. else if( lvalue->dataType.IsReference() )
  3519. {
  3520. // Copy the value of the variable to the reference in the register
  3521. int s = lvalue->dataType.GetSizeInMemoryBytes();
  3522. if( s == 1 )
  3523. bc->InstrSHORT(asBC_WRTV1, rvalue->stackOffset);
  3524. else if( s == 2 )
  3525. bc->InstrSHORT(asBC_WRTV2, rvalue->stackOffset);
  3526. else if( s == 4 )
  3527. bc->InstrSHORT(asBC_WRTV4, rvalue->stackOffset);
  3528. else if( s == 8 )
  3529. bc->InstrSHORT(asBC_WRTV8, rvalue->stackOffset);
  3530. }
  3531. else
  3532. {
  3533. Error(TXT_NOT_VALID_LVALUE, node);
  3534. return -1;
  3535. }
  3536. }
  3537. else if( !lvalue->isExplicitHandle )
  3538. {
  3539. asSExprContext ctx(engine);
  3540. ctx.type = *lvalue;
  3541. Dereference(&ctx, true);
  3542. *lvalue = ctx.type;
  3543. bc->AddCode(&ctx.bc);
  3544. // TODO: Should find the opAssign method that implements the default copy behaviour.
  3545. // The beh->copy member will be removed.
  3546. asSTypeBehaviour *beh = lvalue->dataType.GetBehaviour();
  3547. if( beh->copy )
  3548. {
  3549. // Call the copy operator
  3550. bc->Call(asBC_CALLSYS, (asDWORD)beh->copy, 2*AS_PTR_SIZE);
  3551. bc->Instr(asBC_PshRPtr);
  3552. }
  3553. else
  3554. {
  3555. // Default copy operator
  3556. if( lvalue->dataType.GetSizeInMemoryDWords() == 0 ||
  3557. !(lvalue->dataType.GetObjectType()->flags & asOBJ_POD) )
  3558. {
  3559. asCString msg;
  3560. msg.Format(TXT_NO_DEFAULT_COPY_OP_FOR_s, lvalue->dataType.GetObjectType()->name.AddressOf());
  3561. Error(msg, node);
  3562. return -1;
  3563. }
  3564. // Copy larger data types from a reference
  3565. // TODO: runtime optimize: COPY should pop both arguments and store the reference in the register.
  3566. bc->InstrSHORT_DW(asBC_COPY, (short)lvalue->dataType.GetSizeInMemoryDWords(), engine->GetTypeIdFromDataType(lvalue->dataType));
  3567. }
  3568. }
  3569. else
  3570. {
  3571. // TODO: The object handle can be stored in a variable as well
  3572. if( !lvalue->dataType.IsReference() )
  3573. {
  3574. Error(TXT_NOT_VALID_REFERENCE, node);
  3575. return -1;
  3576. }
  3577. bc->InstrPTR(asBC_REFCPY, lvalue->dataType.GetObjectType());
  3578. // Mark variable as initialized
  3579. if( variables )
  3580. {
  3581. sVariable *v = variables->GetVariableByOffset(lvalue->stackOffset);
  3582. if( v ) v->isInitialized = true;
  3583. }
  3584. }
  3585. return 0;
  3586. }
  3587. bool asCCompiler::CompileRefCast(asSExprContext *ctx, const asCDataType &to, bool isExplicit, asCScriptNode *node, bool generateCode)
  3588. {
  3589. bool conversionDone = false;
  3590. asCArray<int> ops;
  3591. asUINT n;
  3592. if( ctx->type.dataType.GetObjectType()->flags & asOBJ_SCRIPT_OBJECT )
  3593. {
  3594. // We need it to be a reference
  3595. if( !ctx->type.dataType.IsReference() )
  3596. {
  3597. asCDataType to = ctx->type.dataType;
  3598. to.MakeReference(true);
  3599. ImplicitConversion(ctx, to, 0, isExplicit ? asIC_EXPLICIT_REF_CAST : asIC_IMPLICIT_CONV, generateCode);
  3600. }
  3601. if( isExplicit )
  3602. {
  3603. // Allow dynamic cast between object handles (only for script objects).
  3604. // At run time this may result in a null handle,
  3605. // which when used will throw an exception
  3606. conversionDone = true;
  3607. if( generateCode )
  3608. {
  3609. ctx->bc.InstrDWORD(asBC_Cast, engine->GetTypeIdFromDataType(to));
  3610. // Allocate a temporary variable for the returned object
  3611. int returnOffset = AllocateVariable(to, true);
  3612. // Move the pointer from the object register to the temporary variable
  3613. ctx->bc.InstrSHORT(asBC_STOREOBJ, (short)returnOffset);
  3614. ctx->bc.InstrSHORT(asBC_PSF, (short)returnOffset);
  3615. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3616. ctx->type.SetVariable(to, returnOffset, true);
  3617. ctx->type.dataType.MakeReference(true);
  3618. }
  3619. else
  3620. {
  3621. ctx->type.dataType = to;
  3622. ctx->type.dataType.MakeReference(true);
  3623. }
  3624. }
  3625. else
  3626. {
  3627. if( ctx->type.dataType.GetObjectType()->DerivesFrom(to.GetObjectType()) )
  3628. {
  3629. conversionDone = true;
  3630. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3631. }
  3632. }
  3633. }
  3634. else
  3635. {
  3636. // Find a suitable registered behaviour
  3637. asSTypeBehaviour *beh = &ctx->type.dataType.GetObjectType()->beh;
  3638. for( n = 0; n < beh->operators.GetLength(); n+= 2 )
  3639. {
  3640. if( (isExplicit && asBEHAVE_REF_CAST == beh->operators[n]) ||
  3641. asBEHAVE_IMPLICIT_REF_CAST == beh->operators[n] )
  3642. {
  3643. int funcId = beh->operators[n+1];
  3644. // Is the operator for the output type?
  3645. asCScriptFunction *func = engine->scriptFunctions[funcId];
  3646. if( func->returnType.GetObjectType() != to.GetObjectType() )
  3647. continue;
  3648. ops.PushLast(funcId);
  3649. }
  3650. }
  3651. // It shouldn't be possible to have more than one
  3652. asASSERT( ops.GetLength() <= 1 );
  3653. // Should only have one behaviour for each output type
  3654. if( ops.GetLength() == 1 )
  3655. {
  3656. if( generateCode )
  3657. {
  3658. // TODO: runtime optimize: Instead of producing bytecode for checking if the handle is
  3659. // null, we can create a special CALLSYS instruction that checks
  3660. // if the object pointer is null and if so sets the object register
  3661. // to null directly without executing the function.
  3662. //
  3663. // Alternatively I could force the ref cast behaviours be global
  3664. // functions with 1 parameter, even though they should still be
  3665. // registered with RegisterObjectBehaviour()
  3666. // Add code to avoid calling the cast behaviour if the handle is already null,
  3667. // because that will raise a null pointer exception due to the cast behaviour
  3668. // being a class method, and the this pointer cannot be null.
  3669. if( ctx->type.isVariable )
  3670. ctx->bc.Instr(asBC_PopPtr);
  3671. else
  3672. {
  3673. Dereference(ctx, true);
  3674. ConvertToVariable(ctx);
  3675. }
  3676. // TODO: runtime optimize: should have immediate comparison for null pointer
  3677. int offset = AllocateVariable(asCDataType::CreateNullHandle(), true);
  3678. // 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)
  3679. ctx->bc.InstrSHORT(asBC_ClrVPtr, (asWORD)offset);
  3680. ctx->bc.InstrW_W(asBC_CmpPtr, ctx->type.stackOffset, offset);
  3681. DeallocateVariable(offset);
  3682. int afterLabel = nextLabel++;
  3683. ctx->bc.InstrDWORD(asBC_JZ, afterLabel);
  3684. // Call the cast operator
  3685. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  3686. ctx->bc.Instr(asBC_RDSPtr);
  3687. ctx->type.dataType.MakeReference(false);
  3688. asCTypeInfo objType = ctx->type;
  3689. asCArray<asSExprContext *> args;
  3690. MakeFunctionCall(ctx, ops[0], objType.dataType.GetObjectType(), args, node);
  3691. ctx->bc.Instr(asBC_PopPtr);
  3692. int endLabel = nextLabel++;
  3693. ctx->bc.InstrINT(asBC_JMP, endLabel);
  3694. ctx->bc.Label((short)afterLabel);
  3695. // Make a NULL pointer
  3696. ctx->bc.InstrSHORT(asBC_ClrVPtr, ctx->type.stackOffset);
  3697. ctx->bc.Label((short)endLabel);
  3698. // Since we're receiving a handle, we can release the original variable
  3699. ReleaseTemporaryVariable(objType, &ctx->bc);
  3700. // Push the reference to the handle on the stack
  3701. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  3702. }
  3703. else
  3704. {
  3705. asCScriptFunction *func = engine->scriptFunctions[ops[0]];
  3706. ctx->type.Set(func->returnType);
  3707. }
  3708. }
  3709. else if( ops.GetLength() == 0 )
  3710. {
  3711. // Check for the generic ref cast behaviour
  3712. for( n = 0; n < beh->operators.GetLength(); n+= 2 )
  3713. {
  3714. if( (isExplicit && asBEHAVE_REF_CAST == beh->operators[n]) ||
  3715. asBEHAVE_IMPLICIT_REF_CAST == beh->operators[n] )
  3716. {
  3717. int funcId = beh->operators[n+1];
  3718. // Does the operator take the ?&out parameter?
  3719. asCScriptFunction *func = engine->scriptFunctions[funcId];
  3720. if( func->parameterTypes.GetLength() != 1 ||
  3721. func->parameterTypes[0].GetTokenType() != ttQuestion ||
  3722. func->inOutFlags[0] != asTM_OUTREF )
  3723. continue;
  3724. ops.PushLast(funcId);
  3725. }
  3726. }
  3727. // It shouldn't be possible to have more than one
  3728. asASSERT( ops.GetLength() <= 1 );
  3729. if( ops.GetLength() == 1 )
  3730. {
  3731. if( generateCode )
  3732. {
  3733. asASSERT(to.IsObjectHandle());
  3734. // Allocate a temporary variable of the requested handle type
  3735. int stackOffset = AllocateVariableNotIn(to, true, false, ctx);
  3736. // Pass the reference of that variable to the function as output parameter
  3737. asCDataType toRef(to);
  3738. toRef.MakeReference(true);
  3739. asCArray<asSExprContext *> args;
  3740. asSExprContext arg(engine);
  3741. arg.bc.InstrSHORT(asBC_PSF, (short)stackOffset);
  3742. // Don't mark the variable as temporary, so it won't be freed too early
  3743. arg.type.SetVariable(toRef, stackOffset, false);
  3744. arg.type.isLValue = true;
  3745. arg.type.isExplicitHandle = true;
  3746. args.PushLast(&arg);
  3747. asCTypeInfo prev = ctx->type;
  3748. // Call the behaviour method
  3749. MakeFunctionCall(ctx, ops[0], ctx->type.dataType.GetObjectType(), args, node);
  3750. // Release previous temporary variable
  3751. ReleaseTemporaryVariable(prev, &ctx->bc);
  3752. // Use the reference to the variable as the result of the expression
  3753. // Now we can mark the variable as temporary
  3754. ctx->type.SetVariable(toRef, stackOffset, true);
  3755. ctx->bc.InstrSHORT(asBC_PSF, (short)stackOffset);
  3756. }
  3757. else
  3758. {
  3759. // All casts are legal
  3760. ctx->type.Set(to);
  3761. }
  3762. }
  3763. }
  3764. }
  3765. return conversionDone;
  3766. }
  3767. asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const asCDataType &toOrig, asCScriptNode *node, EImplicitConv convType, bool generateCode)
  3768. {
  3769. asCDataType to = toOrig;
  3770. to.MakeReference(false);
  3771. asASSERT( !ctx->type.dataType.IsReference() );
  3772. // Maybe no conversion is needed
  3773. if( to.IsEqualExceptConst(ctx->type.dataType) )
  3774. {
  3775. // A primitive is const or not
  3776. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  3777. return asCC_NO_CONV;
  3778. }
  3779. // Determine the cost of this conversion
  3780. asUINT cost = asCC_NO_CONV;
  3781. if( (to.IsIntegerType() || to.IsUnsignedType()) && (ctx->type.dataType.IsFloatType() || ctx->type.dataType.IsDoubleType()) )
  3782. cost = asCC_INT_FLOAT_CONV;
  3783. else if( (to.IsFloatType() || to.IsDoubleType()) && (ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType()) )
  3784. cost = asCC_INT_FLOAT_CONV;
  3785. else if( to.IsUnsignedType() && ctx->type.dataType.IsIntegerType() )
  3786. cost = asCC_SIGNED_CONV;
  3787. else if( to.IsIntegerType() && ctx->type.dataType.IsUnsignedType() )
  3788. cost = asCC_SIGNED_CONV;
  3789. else if( to.GetSizeInMemoryBytes() || ctx->type.dataType.GetSizeInMemoryBytes() )
  3790. cost = asCC_PRIMITIVE_SIZE_CONV;
  3791. // Start by implicitly converting constant values
  3792. if( ctx->type.isConstant )
  3793. {
  3794. ImplicitConversionConstant(ctx, to, node, convType);
  3795. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  3796. return cost;
  3797. }
  3798. // Allow implicit conversion between numbers
  3799. if( generateCode )
  3800. {
  3801. // When generating the code the decision has already been made, so we don't bother determining the cost
  3802. // Convert smaller types to 32bit first
  3803. int s = ctx->type.dataType.GetSizeInMemoryBytes();
  3804. if( s < 4 )
  3805. {
  3806. ConvertToTempVariable(ctx);
  3807. if( ctx->type.dataType.IsIntegerType() )
  3808. {
  3809. if( s == 1 )
  3810. ctx->bc.InstrSHORT(asBC_sbTOi, ctx->type.stackOffset);
  3811. else if( s == 2 )
  3812. ctx->bc.InstrSHORT(asBC_swTOi, ctx->type.stackOffset);
  3813. ctx->type.dataType.SetTokenType(ttInt);
  3814. }
  3815. else if( ctx->type.dataType.IsUnsignedType() )
  3816. {
  3817. if( s == 1 )
  3818. ctx->bc.InstrSHORT(asBC_ubTOi, ctx->type.stackOffset);
  3819. else if( s == 2 )
  3820. ctx->bc.InstrSHORT(asBC_uwTOi, ctx->type.stackOffset);
  3821. ctx->type.dataType.SetTokenType(ttUInt);
  3822. }
  3823. }
  3824. if( (to.IsIntegerType() && to.GetSizeInMemoryDWords() == 1 && !to.IsEnumType()) ||
  3825. (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST) )
  3826. {
  3827. if( ctx->type.dataType.IsIntegerType() ||
  3828. ctx->type.dataType.IsUnsignedType() )
  3829. {
  3830. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  3831. {
  3832. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3833. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3834. }
  3835. else
  3836. {
  3837. ConvertToTempVariable(ctx);
  3838. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3839. int offset = AllocateVariable(to, true);
  3840. ctx->bc.InstrW_W(asBC_i64TOi, offset, ctx->type.stackOffset);
  3841. ctx->type.SetVariable(to, offset, true);
  3842. }
  3843. }
  3844. else if( ctx->type.dataType.IsFloatType() )
  3845. {
  3846. ConvertToTempVariable(ctx);
  3847. ctx->bc.InstrSHORT(asBC_fTOi, ctx->type.stackOffset);
  3848. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3849. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3850. }
  3851. else if( ctx->type.dataType.IsDoubleType() )
  3852. {
  3853. ConvertToTempVariable(ctx);
  3854. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3855. int offset = AllocateVariable(to, true);
  3856. ctx->bc.InstrW_W(asBC_dTOi, offset, ctx->type.stackOffset);
  3857. ctx->type.SetVariable(to, offset, true);
  3858. }
  3859. // Convert to smaller integer if necessary
  3860. int s = to.GetSizeInMemoryBytes();
  3861. if( s < 4 )
  3862. {
  3863. ConvertToTempVariable(ctx);
  3864. if( s == 1 )
  3865. ctx->bc.InstrSHORT(asBC_iTOb, ctx->type.stackOffset);
  3866. else if( s == 2 )
  3867. ctx->bc.InstrSHORT(asBC_iTOw, ctx->type.stackOffset);
  3868. }
  3869. }
  3870. if( to.IsIntegerType() && to.GetSizeInMemoryDWords() == 2 )
  3871. {
  3872. if( ctx->type.dataType.IsIntegerType() ||
  3873. ctx->type.dataType.IsUnsignedType() )
  3874. {
  3875. if( ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  3876. {
  3877. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3878. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3879. }
  3880. else
  3881. {
  3882. ConvertToTempVariable(ctx);
  3883. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3884. int offset = AllocateVariable(to, true);
  3885. if( ctx->type.dataType.IsUnsignedType() )
  3886. ctx->bc.InstrW_W(asBC_uTOi64, offset, ctx->type.stackOffset);
  3887. else
  3888. ctx->bc.InstrW_W(asBC_iTOi64, offset, ctx->type.stackOffset);
  3889. ctx->type.SetVariable(to, offset, true);
  3890. }
  3891. }
  3892. else if( ctx->type.dataType.IsFloatType() )
  3893. {
  3894. ConvertToTempVariable(ctx);
  3895. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3896. int offset = AllocateVariable(to, true);
  3897. ctx->bc.InstrW_W(asBC_fTOi64, offset, ctx->type.stackOffset);
  3898. ctx->type.SetVariable(to, offset, true);
  3899. }
  3900. else if( ctx->type.dataType.IsDoubleType() )
  3901. {
  3902. ConvertToTempVariable(ctx);
  3903. ctx->bc.InstrSHORT(asBC_dTOi64, ctx->type.stackOffset);
  3904. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3905. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3906. }
  3907. }
  3908. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 1 )
  3909. {
  3910. if( ctx->type.dataType.IsIntegerType() ||
  3911. ctx->type.dataType.IsUnsignedType() )
  3912. {
  3913. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  3914. {
  3915. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3916. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3917. }
  3918. else
  3919. {
  3920. ConvertToTempVariable(ctx);
  3921. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3922. int offset = AllocateVariable(to, true);
  3923. ctx->bc.InstrW_W(asBC_i64TOi, offset, ctx->type.stackOffset);
  3924. ctx->type.SetVariable(to, offset, true);
  3925. }
  3926. }
  3927. else if( ctx->type.dataType.IsFloatType() )
  3928. {
  3929. ConvertToTempVariable(ctx);
  3930. ctx->bc.InstrSHORT(asBC_fTOu, ctx->type.stackOffset);
  3931. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3932. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3933. }
  3934. else if( ctx->type.dataType.IsDoubleType() )
  3935. {
  3936. ConvertToTempVariable(ctx);
  3937. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3938. int offset = AllocateVariable(to, true);
  3939. ctx->bc.InstrW_W(asBC_dTOu, offset, ctx->type.stackOffset);
  3940. ctx->type.SetVariable(to, offset, true);
  3941. }
  3942. // Convert to smaller integer if necessary
  3943. int s = to.GetSizeInMemoryBytes();
  3944. if( s < 4 )
  3945. {
  3946. ConvertToTempVariable(ctx);
  3947. if( s == 1 )
  3948. ctx->bc.InstrSHORT(asBC_iTOb, ctx->type.stackOffset);
  3949. else if( s == 2 )
  3950. ctx->bc.InstrSHORT(asBC_iTOw, ctx->type.stackOffset);
  3951. }
  3952. }
  3953. if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 2 )
  3954. {
  3955. if( ctx->type.dataType.IsIntegerType() ||
  3956. ctx->type.dataType.IsUnsignedType() )
  3957. {
  3958. if( ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  3959. {
  3960. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3961. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3962. }
  3963. else
  3964. {
  3965. ConvertToTempVariable(ctx);
  3966. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3967. int offset = AllocateVariable(to, true);
  3968. if( ctx->type.dataType.IsUnsignedType() )
  3969. ctx->bc.InstrW_W(asBC_uTOi64, offset, ctx->type.stackOffset);
  3970. else
  3971. ctx->bc.InstrW_W(asBC_iTOi64, offset, ctx->type.stackOffset);
  3972. ctx->type.SetVariable(to, offset, true);
  3973. }
  3974. }
  3975. else if( ctx->type.dataType.IsFloatType() )
  3976. {
  3977. ConvertToTempVariable(ctx);
  3978. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3979. int offset = AllocateVariable(to, true);
  3980. ctx->bc.InstrW_W(asBC_fTOu64, offset, ctx->type.stackOffset);
  3981. ctx->type.SetVariable(to, offset, true);
  3982. }
  3983. else if( ctx->type.dataType.IsDoubleType() )
  3984. {
  3985. ConvertToTempVariable(ctx);
  3986. ctx->bc.InstrSHORT(asBC_dTOu64, ctx->type.stackOffset);
  3987. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3988. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3989. }
  3990. }
  3991. else if( to.IsFloatType() )
  3992. {
  3993. if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  3994. {
  3995. ConvertToTempVariable(ctx);
  3996. ctx->bc.InstrSHORT(asBC_iTOf, ctx->type.stackOffset);
  3997. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3998. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3999. }
  4000. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  4001. {
  4002. ConvertToTempVariable(ctx);
  4003. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4004. int offset = AllocateVariable(to, true);
  4005. ctx->bc.InstrW_W(asBC_i64TOf, offset, ctx->type.stackOffset);
  4006. ctx->type.SetVariable(to, offset, true);
  4007. }
  4008. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  4009. {
  4010. ConvertToTempVariable(ctx);
  4011. ctx->bc.InstrSHORT(asBC_uTOf, ctx->type.stackOffset);
  4012. ctx->type.dataType.SetTokenType(to.GetTokenType());
  4013. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4014. }
  4015. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  4016. {
  4017. ConvertToTempVariable(ctx);
  4018. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4019. int offset = AllocateVariable(to, true);
  4020. ctx->bc.InstrW_W(asBC_u64TOf, offset, ctx->type.stackOffset);
  4021. ctx->type.SetVariable(to, offset, true);
  4022. }
  4023. else if( ctx->type.dataType.IsDoubleType() )
  4024. {
  4025. ConvertToTempVariable(ctx);
  4026. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4027. int offset = AllocateVariable(to, true);
  4028. ctx->bc.InstrW_W(asBC_dTOf, offset, ctx->type.stackOffset);
  4029. ctx->type.SetVariable(to, offset, true);
  4030. }
  4031. }
  4032. else if( to.IsDoubleType() )
  4033. {
  4034. if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  4035. {
  4036. ConvertToTempVariable(ctx);
  4037. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4038. int offset = AllocateVariable(to, true);
  4039. ctx->bc.InstrW_W(asBC_iTOd, offset, ctx->type.stackOffset);
  4040. ctx->type.SetVariable(to, offset, true);
  4041. }
  4042. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  4043. {
  4044. ConvertToTempVariable(ctx);
  4045. ctx->bc.InstrSHORT(asBC_i64TOd, ctx->type.stackOffset);
  4046. ctx->type.dataType.SetTokenType(to.GetTokenType());
  4047. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4048. }
  4049. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  4050. {
  4051. ConvertToTempVariable(ctx);
  4052. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4053. int offset = AllocateVariable(to, true);
  4054. ctx->bc.InstrW_W(asBC_uTOd, offset, ctx->type.stackOffset);
  4055. ctx->type.SetVariable(to, offset, true);
  4056. }
  4057. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  4058. {
  4059. ConvertToTempVariable(ctx);
  4060. ctx->bc.InstrSHORT(asBC_u64TOd, ctx->type.stackOffset);
  4061. ctx->type.dataType.SetTokenType(to.GetTokenType());
  4062. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4063. }
  4064. else if( ctx->type.dataType.IsFloatType() )
  4065. {
  4066. ConvertToTempVariable(ctx);
  4067. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4068. int offset = AllocateVariable(to, true);
  4069. ctx->bc.InstrW_W(asBC_fTOd, offset, ctx->type.stackOffset);
  4070. ctx->type.SetVariable(to, offset, true);
  4071. }
  4072. }
  4073. }
  4074. else
  4075. {
  4076. if( ((to.IsIntegerType() && !to.IsEnumType()) || to.IsUnsignedType() ||
  4077. to.IsFloatType() || to.IsDoubleType() ||
  4078. (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST)) &&
  4079. (ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType() ||
  4080. ctx->type.dataType.IsFloatType() || ctx->type.dataType.IsDoubleType()) )
  4081. {
  4082. ctx->type.dataType.SetTokenType(to.GetTokenType());
  4083. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4084. }
  4085. }
  4086. // Primitive types on the stack, can be const or non-const
  4087. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  4088. return cost;
  4089. }
  4090. asUINT asCCompiler::ImplicitConversion(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode, bool allowObjectConstruct)
  4091. {
  4092. asASSERT( ctx->type.dataType.GetTokenType() != ttUnrecognizedToken ||
  4093. ctx->type.dataType.IsNullHandle() );
  4094. // No conversion from void to any other type
  4095. if( ctx->type.dataType.GetTokenType() == ttVoid )
  4096. return asCC_NO_CONV;
  4097. // Do we want a var type?
  4098. if( to.GetTokenType() == ttQuestion )
  4099. {
  4100. // Any type can be converted to a var type, but only when not generating code
  4101. asASSERT( !generateCode );
  4102. ctx->type.dataType = to;
  4103. return asCC_VARIABLE_CONV;
  4104. }
  4105. // Do we want a primitive?
  4106. else if( to.IsPrimitive() )
  4107. {
  4108. if( !ctx->type.dataType.IsPrimitive() )
  4109. return ImplicitConvObjectToPrimitive(ctx, to, node, convType, generateCode);
  4110. else
  4111. return ImplicitConvPrimitiveToPrimitive(ctx, to, node, convType, generateCode);
  4112. }
  4113. else // The target is a complex type
  4114. {
  4115. if( ctx->type.dataType.IsPrimitive() )
  4116. return ImplicitConvPrimitiveToObject(ctx, to, node, convType, generateCode, allowObjectConstruct);
  4117. else if( ctx->type.IsNullConstant() || ctx->type.dataType.GetObjectType() )
  4118. return ImplicitConvObjectToObject(ctx, to, node, convType, generateCode, allowObjectConstruct);
  4119. }
  4120. return asCC_NO_CONV;
  4121. }
  4122. asUINT asCCompiler::ImplicitConvObjectToPrimitive(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode)
  4123. {
  4124. if( ctx->type.isExplicitHandle )
  4125. {
  4126. // An explicit handle cannot be converted to a primitive
  4127. if( convType != asIC_IMPLICIT_CONV && node )
  4128. {
  4129. asCString str;
  4130. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  4131. Error(str, node);
  4132. }
  4133. return asCC_NO_CONV;
  4134. }
  4135. // TODO: Must use the const cast behaviour if the object is read-only
  4136. // Find matching value cast behaviours
  4137. // Here we're only interested in those that convert the type to a primitive type
  4138. asCArray<int> funcs;
  4139. asSTypeBehaviour *beh = ctx->type.dataType.GetBehaviour();
  4140. if( beh )
  4141. {
  4142. if( convType == asIC_EXPLICIT_VAL_CAST )
  4143. {
  4144. for( unsigned int n = 0; n < beh->operators.GetLength(); n += 2 )
  4145. {
  4146. // accept both implicit and explicit cast
  4147. if( (beh->operators[n] == asBEHAVE_VALUE_CAST ||
  4148. beh->operators[n] == asBEHAVE_IMPLICIT_VALUE_CAST) &&
  4149. builder->GetFunctionDescription(beh->operators[n+1])->returnType.IsPrimitive() )
  4150. funcs.PushLast(beh->operators[n+1]);
  4151. }
  4152. }
  4153. else
  4154. {
  4155. for( unsigned int n = 0; n < beh->operators.GetLength(); n += 2 )
  4156. {
  4157. // accept only implicit cast
  4158. if( beh->operators[n] == asBEHAVE_IMPLICIT_VALUE_CAST &&
  4159. builder->GetFunctionDescription(beh->operators[n+1])->returnType.IsPrimitive() )
  4160. funcs.PushLast(beh->operators[n+1]);
  4161. }
  4162. }
  4163. }
  4164. // This matrix describes the priorities of the types to search for, for each target type
  4165. // The first column is the target type, the priorities goes from left to right
  4166. eTokenType matchMtx[10][10] =
  4167. {
  4168. {ttDouble, ttFloat, ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8},
  4169. {ttFloat, ttDouble, ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8},
  4170. {ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8, ttDouble, ttFloat},
  4171. {ttUInt64, ttInt64, ttUInt, ttInt, ttUInt16, ttInt16, ttUInt8, ttInt8, ttDouble, ttFloat},
  4172. {ttInt, ttUInt, ttInt64, ttUInt64, ttInt16, ttUInt16, ttInt8, ttUInt8, ttDouble, ttFloat},
  4173. {ttUInt, ttInt, ttUInt64, ttInt64, ttUInt16, ttInt16, ttUInt8, ttInt8, ttDouble, ttFloat},
  4174. {ttInt16, ttUInt16, ttInt, ttUInt, ttInt64, ttUInt64, ttInt8, ttUInt8, ttDouble, ttFloat},
  4175. {ttUInt16, ttInt16, ttUInt, ttInt, ttUInt64, ttInt64, ttUInt8, ttInt8, ttDouble, ttFloat},
  4176. {ttInt8, ttUInt8, ttInt16, ttUInt16, ttInt, ttUInt, ttInt64, ttUInt64, ttDouble, ttFloat},
  4177. {ttUInt8, ttInt8, ttUInt16, ttInt16, ttUInt, ttInt, ttUInt64, ttInt64, ttDouble, ttFloat},
  4178. };
  4179. // Which row to use?
  4180. eTokenType *row = 0;
  4181. for( unsigned int type = 0; type < 10; type++ )
  4182. {
  4183. if( to.GetTokenType() == matchMtx[type][0] )
  4184. {
  4185. row = &matchMtx[type][0];
  4186. break;
  4187. }
  4188. }
  4189. // Find the best matching cast operator
  4190. int funcId = 0;
  4191. if( row )
  4192. {
  4193. asCDataType target(to);
  4194. // Priority goes from left to right in the matrix
  4195. for( unsigned int attempt = 0; attempt < 10 && funcId == 0; attempt++ )
  4196. {
  4197. target.SetTokenType(row[attempt]);
  4198. for( unsigned int n = 0; n < funcs.GetLength(); n++ )
  4199. {
  4200. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[n]);
  4201. if( descr->returnType.IsEqualExceptConst(target) )
  4202. {
  4203. funcId = funcs[n];
  4204. break;
  4205. }
  4206. }
  4207. }
  4208. }
  4209. // Did we find a suitable function?
  4210. if( funcId != 0 )
  4211. {
  4212. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  4213. if( generateCode )
  4214. {
  4215. asCTypeInfo objType = ctx->type;
  4216. Dereference(ctx, true);
  4217. PerformFunctionCall(funcId, ctx);
  4218. ReleaseTemporaryVariable(objType, &ctx->bc);
  4219. }
  4220. else
  4221. ctx->type.Set(descr->returnType);
  4222. // Allow one more implicit conversion to another primitive type
  4223. return asCC_OBJ_TO_PRIMITIVE_CONV + ImplicitConversion(ctx, to, node, convType, generateCode, false);
  4224. }
  4225. else
  4226. {
  4227. if( convType != asIC_IMPLICIT_CONV && node )
  4228. {
  4229. asCString str;
  4230. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  4231. Error(str, node);
  4232. }
  4233. }
  4234. return asCC_NO_CONV;
  4235. }
  4236. asUINT asCCompiler::ImplicitConvObjectRef(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode)
  4237. {
  4238. // Convert null to any object type handle, but not to a non-handle type
  4239. if( ctx->type.IsNullConstant() && ctx->methodName == "" )
  4240. {
  4241. if( to.IsObjectHandle() )
  4242. {
  4243. ctx->type.dataType = to;
  4244. return asCC_REF_CONV;
  4245. }
  4246. return asCC_NO_CONV;
  4247. }
  4248. asASSERT(ctx->type.dataType.GetObjectType() || ctx->methodName != "");
  4249. // First attempt to convert the base type without instanciating another instance
  4250. if( to.GetObjectType() != ctx->type.dataType.GetObjectType() && ctx->methodName == "" )
  4251. {
  4252. // If the to type is an interface and the from type implements it, then we can convert it immediately
  4253. if( ctx->type.dataType.GetObjectType()->Implements(to.GetObjectType()) )
  4254. {
  4255. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4256. return asCC_REF_CONV;
  4257. }
  4258. // If the to type is a class and the from type derives from it, then we can convert it immediately
  4259. else if( ctx->type.dataType.GetObjectType()->DerivesFrom(to.GetObjectType()) )
  4260. {
  4261. ctx->type.dataType.SetObjectType(to.GetObjectType());
  4262. return asCC_REF_CONV;
  4263. }
  4264. // If the types are not equal yet, then we may still be able to find a reference cast
  4265. else if( ctx->type.dataType.GetObjectType() != to.GetObjectType() )
  4266. {
  4267. // A ref cast must not remove the constness
  4268. bool isConst = false;
  4269. if( (ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsHandleToConst()) ||
  4270. (!ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReadOnly()) )
  4271. isConst = true;
  4272. // We may still be able to find an implicit ref cast behaviour
  4273. CompileRefCast(ctx, to, convType == asIC_EXPLICIT_REF_CAST, node, generateCode);
  4274. ctx->type.dataType.MakeHandleToConst(isConst);
  4275. // Was the conversion done?
  4276. if( ctx->type.dataType.GetObjectType() == to.GetObjectType() )
  4277. return asCC_REF_CONV;
  4278. }
  4279. }
  4280. // Convert matching function types
  4281. if( to.GetFuncDef() )
  4282. {
  4283. // If the input expression is already a funcdef, check if it can be converted
  4284. if( ctx->type.dataType.GetFuncDef() &&
  4285. to.GetFuncDef() != ctx->type.dataType.GetFuncDef() )
  4286. {
  4287. asCScriptFunction *toFunc = to.GetFuncDef();
  4288. asCScriptFunction *fromFunc = ctx->type.dataType.GetFuncDef();
  4289. if( toFunc->IsSignatureExceptNameEqual(fromFunc) )
  4290. {
  4291. ctx->type.dataType.SetFuncDef(toFunc);
  4292. return asCC_REF_CONV;
  4293. }
  4294. }
  4295. // If the input expression is a deferred function ref, check if there is a matching func
  4296. if( ctx->methodName != "" )
  4297. {
  4298. // Determine the namespace
  4299. asSNameSpace *ns = 0;
  4300. asCString name = "";
  4301. int pos = ctx->methodName.FindLast("::");
  4302. if( pos >= 0 )
  4303. {
  4304. asCString nsName = ctx->methodName.SubString(0, pos+2);
  4305. ns = DetermineNameSpace(nsName);
  4306. name = ctx->methodName.SubString(pos+2);
  4307. }
  4308. else
  4309. {
  4310. DetermineNameSpace("");
  4311. name = ctx->methodName;
  4312. }
  4313. asCArray<int> funcs;
  4314. if( ns )
  4315. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  4316. // Check if any of the functions have perfect match
  4317. for( asUINT n = 0; n < funcs.GetLength(); n++ )
  4318. {
  4319. asCScriptFunction *func = builder->GetFunctionDescription(funcs[n]);
  4320. if( to.GetFuncDef()->IsSignatureExceptNameEqual(func) )
  4321. {
  4322. if( generateCode )
  4323. {
  4324. ctx->bc.InstrPTR(asBC_FuncPtr, func);
  4325. // Make sure the identified function is shared if we're compiling a shared function
  4326. if( !func->IsShared() && outFunc->IsShared() )
  4327. {
  4328. asCString msg;
  4329. msg.Format(TXT_SHARED_CANNOT_CALL_NON_SHARED_FUNC_s, func->GetDeclaration());
  4330. Error(msg, node);
  4331. }
  4332. }
  4333. ctx->type.dataType = asCDataType::CreateFuncDef(to.GetFuncDef());
  4334. return asCC_REF_CONV;
  4335. }
  4336. }
  4337. }
  4338. }
  4339. return asCC_NO_CONV;
  4340. }
  4341. asUINT asCCompiler::ImplicitConvObjectValue(asSExprContext *ctx, const asCDataType &to, asCScriptNode * /*node*/, EImplicitConv convType, bool generateCode)
  4342. {
  4343. asUINT cost = asCC_NO_CONV;
  4344. // If the base type is still different, and we are allowed to instance
  4345. // another object then we can try an implicit value cast
  4346. if( to.GetObjectType() != ctx->type.dataType.GetObjectType() )
  4347. {
  4348. // TODO: Implement support for implicit constructor/factory
  4349. asCArray<int> funcs;
  4350. asSTypeBehaviour *beh = ctx->type.dataType.GetBehaviour();
  4351. if( beh )
  4352. {
  4353. if( convType == asIC_EXPLICIT_VAL_CAST )
  4354. {
  4355. for( unsigned int n = 0; n < beh->operators.GetLength(); n += 2 )
  4356. {
  4357. // accept both implicit and explicit cast
  4358. if( (beh->operators[n] == asBEHAVE_VALUE_CAST ||
  4359. beh->operators[n] == asBEHAVE_IMPLICIT_VALUE_CAST) &&
  4360. builder->GetFunctionDescription(beh->operators[n+1])->returnType.GetObjectType() == to.GetObjectType() )
  4361. funcs.PushLast(beh->operators[n+1]);
  4362. }
  4363. }
  4364. else
  4365. {
  4366. for( unsigned int n = 0; n < beh->operators.GetLength(); n += 2 )
  4367. {
  4368. // accept only implicit cast
  4369. if( beh->operators[n] == asBEHAVE_IMPLICIT_VALUE_CAST &&
  4370. builder->GetFunctionDescription(beh->operators[n+1])->returnType.GetObjectType() == to.GetObjectType() )
  4371. funcs.PushLast(beh->operators[n+1]);
  4372. }
  4373. }
  4374. }
  4375. // TODO: If there are multiple valid value casts, then we must choose the most appropriate one
  4376. asASSERT( funcs.GetLength() <= 1 );
  4377. if( funcs.GetLength() == 1 )
  4378. {
  4379. asCScriptFunction *f = builder->GetFunctionDescription(funcs[0]);
  4380. if( generateCode )
  4381. {
  4382. asCTypeInfo objType = ctx->type;
  4383. Dereference(ctx, true);
  4384. bool useVariable = false;
  4385. int stackOffset = 0;
  4386. if( f->DoesReturnOnStack() )
  4387. {
  4388. useVariable = true;
  4389. stackOffset = AllocateVariable(f->returnType, true);
  4390. // Push the pointer to the pre-allocated space for the return value
  4391. ctx->bc.InstrSHORT(asBC_PSF, short(stackOffset));
  4392. // The object pointer is already on the stack, but should be the top
  4393. // one, so we need to swap the pointers in order to get the correct
  4394. ctx->bc.Instr(asBC_SwapPtr);
  4395. }
  4396. PerformFunctionCall(funcs[0], ctx, false, 0, 0, useVariable, stackOffset);
  4397. ReleaseTemporaryVariable(objType, &ctx->bc);
  4398. }
  4399. else
  4400. ctx->type.Set(f->returnType);
  4401. cost = asCC_TO_OBJECT_CONV;
  4402. }
  4403. }
  4404. return cost;
  4405. }
  4406. asUINT asCCompiler::ImplicitConvObjectToObject(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode, bool allowObjectConstruct)
  4407. {
  4408. // First try a ref cast
  4409. asUINT cost = ImplicitConvObjectRef(ctx, to, node, convType, generateCode);
  4410. // If the desired type is an asOBJ_ASHANDLE then we'll assume it is allowed to implicitly
  4411. // construct the object through any of the available constructors
  4412. if( to.GetObjectType() && (to.GetObjectType()->flags & asOBJ_ASHANDLE) && to.GetObjectType() != ctx->type.dataType.GetObjectType() && allowObjectConstruct )
  4413. {
  4414. asCArray<int> funcs;
  4415. funcs = to.GetObjectType()->beh.constructors;
  4416. asCArray<asSExprContext *> args;
  4417. args.PushLast(ctx);
  4418. cost = asCC_TO_OBJECT_CONV + MatchFunctions(funcs, args, node, 0, 0, false, true, false);
  4419. // Did we find a matching constructor?
  4420. if( funcs.GetLength() == 1 )
  4421. {
  4422. if( generateCode )
  4423. {
  4424. // TODO: This should really reuse the code from CompileConstructCall
  4425. // Allocate the new object
  4426. asCTypeInfo tempObj;
  4427. tempObj.dataType = to;
  4428. tempObj.dataType.MakeReference(false);
  4429. tempObj.stackOffset = (short)AllocateVariable(tempObj.dataType, true);
  4430. tempObj.dataType.MakeReference(true);
  4431. tempObj.isTemporary = true;
  4432. tempObj.isVariable = true;
  4433. bool onHeap = IsVariableOnHeap(tempObj.stackOffset);
  4434. // Push the address of the object on the stack
  4435. asSExprContext e(engine);
  4436. if( onHeap )
  4437. e.bc.InstrSHORT(asBC_VAR, tempObj.stackOffset);
  4438. PrepareFunctionCall(funcs[0], &e.bc, args);
  4439. MoveArgsToStack(funcs[0], &e.bc, args, false);
  4440. // If the object is allocated on the stack, then call the constructor as a normal function
  4441. if( onHeap )
  4442. {
  4443. int offset = 0;
  4444. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]);
  4445. offset = descr->parameterTypes[0].GetSizeOnStackDWords();
  4446. e.bc.InstrWORD(asBC_GETREF, (asWORD)offset);
  4447. }
  4448. else
  4449. e.bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  4450. PerformFunctionCall(funcs[0], &e, onHeap, &args, tempObj.dataType.GetObjectType());
  4451. // Add tag that the object has been initialized
  4452. e.bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT);
  4453. // The constructor doesn't return anything,
  4454. // so we have to manually inform the type of
  4455. // the return value
  4456. e.type = tempObj;
  4457. if( !onHeap )
  4458. e.type.dataType.MakeReference(false);
  4459. // Push the address of the object on the stack again
  4460. e.bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  4461. MergeExprBytecodeAndType(ctx, &e);
  4462. }
  4463. else
  4464. {
  4465. ctx->type.Set(asCDataType::CreateObject(to.GetObjectType(), false));
  4466. }
  4467. }
  4468. }
  4469. // If the base type is still different, and we are allowed to instance
  4470. // another object then we can try an implicit value cast
  4471. if( to.GetObjectType() != ctx->type.dataType.GetObjectType() && allowObjectConstruct )
  4472. {
  4473. // Attempt implicit value cast
  4474. cost = ImplicitConvObjectValue(ctx, to, node, convType, generateCode);
  4475. }
  4476. // If we still haven't converted the base type to the correct type, then there is
  4477. // no need to continue as it is not possible to do the conversion
  4478. if( to.GetObjectType() != ctx->type.dataType.GetObjectType() )
  4479. return asCC_NO_CONV;
  4480. if( to.IsObjectHandle() )
  4481. {
  4482. // There is no extra cost in converting to a handle
  4483. // reference to handle -> handle
  4484. // reference -> handle
  4485. // object -> handle
  4486. // handle -> reference to handle
  4487. // reference -> reference to handle
  4488. // object -> reference to handle
  4489. // TODO: If the type is handle, then we can't use IsReadOnly to determine the constness of the basetype
  4490. // If the rvalue is a handle to a const object, then
  4491. // the lvalue must also be a handle to a const object
  4492. if( ctx->type.dataType.IsReadOnly() && !to.IsReadOnly() )
  4493. {
  4494. if( convType != asIC_IMPLICIT_CONV )
  4495. {
  4496. asASSERT(node);
  4497. asCString str;
  4498. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  4499. Error(str, node);
  4500. }
  4501. }
  4502. if( !ctx->type.dataType.IsObjectHandle() )
  4503. {
  4504. // An object type can be directly converted to a handle of the
  4505. // same type by doing a ref copy to a new variable
  4506. if( ctx->type.dataType.SupportHandles() )
  4507. {
  4508. asCDataType dt = ctx->type.dataType;
  4509. dt.MakeHandle(true);
  4510. dt.MakeReference(false);
  4511. if( generateCode )
  4512. {
  4513. // If the expression is already a local variable, then it is not
  4514. // necessary to do a ref copy, as the ref objects on the stack are
  4515. // really handles, only the handles cannot be modified.
  4516. if( ctx->type.isVariable )
  4517. {
  4518. bool isHandleToConst = ctx->type.dataType.IsReadOnly();
  4519. ctx->type.dataType.MakeReadOnly(false);
  4520. ctx->type.dataType.MakeHandle(true);
  4521. ctx->type.dataType.MakeReadOnly(true);
  4522. ctx->type.dataType.MakeHandleToConst(isHandleToConst);
  4523. if( to.IsReference() && !ctx->type.dataType.IsReference() )
  4524. {
  4525. ctx->bc.Instr(asBC_PopPtr);
  4526. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  4527. ctx->type.dataType.MakeReference(true);
  4528. }
  4529. else if( ctx->type.dataType.IsReference() )
  4530. {
  4531. ctx->bc.Instr(asBC_RDSPtr);
  4532. ctx->type.dataType.MakeReference(false);
  4533. }
  4534. }
  4535. else
  4536. {
  4537. int offset = AllocateVariable(dt, true);
  4538. if( ctx->type.dataType.IsReference() )
  4539. ctx->bc.Instr(asBC_RDSPtr);
  4540. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  4541. ctx->bc.InstrPTR(asBC_REFCPY, dt.GetObjectType());
  4542. ctx->bc.Instr(asBC_PopPtr);
  4543. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  4544. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4545. if( to.IsReference() )
  4546. dt.MakeReference(true);
  4547. else
  4548. ctx->bc.Instr(asBC_RDSPtr);
  4549. ctx->type.SetVariable(dt, offset, true);
  4550. }
  4551. }
  4552. else
  4553. ctx->type.dataType = dt;
  4554. // When this conversion is done the expression is no longer an lvalue
  4555. ctx->type.isLValue = false;
  4556. }
  4557. }
  4558. if( ctx->type.dataType.IsObjectHandle() )
  4559. {
  4560. // A handle to non-const can be converted to a
  4561. // handle to const, but not the other way
  4562. if( to.IsHandleToConst() )
  4563. ctx->type.dataType.MakeHandleToConst(true);
  4564. // A const handle can be converted to a non-const
  4565. // handle and vice versa as the handle is just a value
  4566. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  4567. }
  4568. if( to.IsReference() && !ctx->type.dataType.IsReference() )
  4569. {
  4570. if( generateCode )
  4571. {
  4572. asASSERT( ctx->type.dataType.IsObjectHandle() );
  4573. // If the input type is a handle, then a simple ref copy is enough
  4574. bool isExplicitHandle = ctx->type.isExplicitHandle;
  4575. ctx->type.isExplicitHandle = ctx->type.dataType.IsObjectHandle();
  4576. // If the input type is read-only we'll need to temporarily
  4577. // remove this constness, otherwise the assignment will fail
  4578. bool typeIsReadOnly = ctx->type.dataType.IsReadOnly();
  4579. ctx->type.dataType.MakeReadOnly(false);
  4580. // If the object already is a temporary variable, then the copy
  4581. // doesn't have to be made as it is already a unique object
  4582. PrepareTemporaryObject(node, ctx);
  4583. ctx->type.dataType.MakeReadOnly(typeIsReadOnly);
  4584. ctx->type.isExplicitHandle = isExplicitHandle;
  4585. }
  4586. // A non-reference can be converted to a reference,
  4587. // by putting the value in a temporary variable
  4588. ctx->type.dataType.MakeReference(true);
  4589. // Since it is a new temporary variable it doesn't have to be const
  4590. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  4591. }
  4592. else if( !to.IsReference() && ctx->type.dataType.IsReference() )
  4593. {
  4594. Dereference(ctx, generateCode);
  4595. }
  4596. }
  4597. else // if( !to.IsObjectHandle() )
  4598. {
  4599. if( !to.IsReference() )
  4600. {
  4601. // reference to handle -> object
  4602. // handle -> object
  4603. // reference -> object
  4604. // An implicit handle can be converted to an object by adding a check for null pointer
  4605. if( ctx->type.dataType.IsObjectHandle() && !ctx->type.isExplicitHandle )
  4606. {
  4607. if( generateCode )
  4608. {
  4609. if( ctx->type.dataType.IsReference() )
  4610. {
  4611. // The pointer on the stack refers to the handle
  4612. ctx->bc.Instr(asBC_ChkRefS);
  4613. }
  4614. else
  4615. {
  4616. // The pointer on the stack refers to the object
  4617. ctx->bc.Instr(asBC_CHKREF);
  4618. }
  4619. }
  4620. ctx->type.dataType.MakeHandle(false);
  4621. }
  4622. // A const object can be converted to a non-const object through a copy
  4623. if( ctx->type.dataType.IsReadOnly() && !to.IsReadOnly() &&
  4624. allowObjectConstruct )
  4625. {
  4626. // Does the object type allow a copy to be made?
  4627. if( ctx->type.dataType.CanBeCopied() )
  4628. {
  4629. if( generateCode )
  4630. {
  4631. // Make a temporary object with the copy
  4632. PrepareTemporaryObject(node, ctx);
  4633. }
  4634. // In case the object was already in a temporary variable, then the function
  4635. // didn't really do anything so we need to remove the constness here
  4636. ctx->type.dataType.MakeReadOnly(false);
  4637. // Add the cost for the copy
  4638. cost += asCC_TO_OBJECT_CONV;
  4639. }
  4640. }
  4641. if( ctx->type.dataType.IsReference() )
  4642. {
  4643. // This may look strange, but a value type allocated on the stack is already
  4644. // correct, so nothing should be done other than remove the mark as reference.
  4645. // For types allocated on the heap, it is necessary to dereference the pointer
  4646. // that is currently on the stack
  4647. if( IsVariableOnHeap(ctx->type.stackOffset) )
  4648. Dereference(ctx, generateCode);
  4649. else
  4650. ctx->type.dataType.MakeReference(false);
  4651. }
  4652. // A non-const object can be converted to a const object directly
  4653. if( !ctx->type.dataType.IsReadOnly() && to.IsReadOnly() )
  4654. {
  4655. ctx->type.dataType.MakeReadOnly(true);
  4656. }
  4657. }
  4658. else // if( to.IsReference() )
  4659. {
  4660. // reference to handle -> reference
  4661. // handle -> reference
  4662. // object -> reference
  4663. if( ctx->type.dataType.IsReference() )
  4664. {
  4665. if( ctx->type.isExplicitHandle && ctx->type.dataType.GetObjectType() && (ctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE) )
  4666. {
  4667. // ASHANDLE objects are really value types, so explicit handle can be removed
  4668. ctx->type.isExplicitHandle = false;
  4669. ctx->type.dataType.MakeHandle(false);
  4670. }
  4671. // A reference to a handle can be converted to a reference to an object
  4672. // by first reading the address, then verifying that it is not null
  4673. if( !to.IsObjectHandle() && ctx->type.dataType.IsObjectHandle() && !ctx->type.isExplicitHandle )
  4674. {
  4675. ctx->type.dataType.MakeHandle(false);
  4676. if( generateCode )
  4677. ctx->bc.Instr(asBC_ChkRefS);
  4678. }
  4679. // A reference to a non-const can be converted to a reference to a const
  4680. if( to.IsReadOnly() )
  4681. ctx->type.dataType.MakeReadOnly(true);
  4682. else if( ctx->type.dataType.IsReadOnly() )
  4683. {
  4684. // A reference to a const can be converted to a reference to a
  4685. // non-const by copying the object to a temporary variable
  4686. ctx->type.dataType.MakeReadOnly(false);
  4687. if( generateCode )
  4688. {
  4689. // If the object already is a temporary variable, then the copy
  4690. // doesn't have to be made as it is already a unique object
  4691. PrepareTemporaryObject(node, ctx);
  4692. }
  4693. // Add the cost for the copy
  4694. cost += asCC_TO_OBJECT_CONV;
  4695. }
  4696. }
  4697. else // if( !ctx->type.dataType.IsReference() )
  4698. {
  4699. // A non-reference handle can be converted to a non-handle reference by checking against null handle
  4700. if( ctx->type.dataType.IsObjectHandle() )
  4701. {
  4702. bool readOnly = false;
  4703. if( ctx->type.dataType.IsHandleToConst() )
  4704. readOnly = true;
  4705. if( generateCode )
  4706. {
  4707. if( ctx->type.isVariable )
  4708. ctx->bc.InstrSHORT(asBC_ChkNullV, ctx->type.stackOffset);
  4709. else
  4710. ctx->bc.Instr(asBC_CHKREF);
  4711. }
  4712. ctx->type.dataType.MakeHandle(false);
  4713. ctx->type.dataType.MakeReference(true);
  4714. // Make sure a handle to const isn't converted to non-const reference
  4715. if( readOnly )
  4716. ctx->type.dataType.MakeReadOnly(true);
  4717. }
  4718. else
  4719. {
  4720. // A value type allocated on the stack is differentiated
  4721. // by it not being a reference. But it can be handled as
  4722. // reference by pushing the pointer on the stack
  4723. if( (ctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_VALUE) &&
  4724. (ctx->type.isVariable || ctx->type.isTemporary) &&
  4725. !IsVariableOnHeap(ctx->type.stackOffset) )
  4726. {
  4727. // Actually the pointer is already pushed on the stack in
  4728. // CompileVariableAccess, so we don't need to do anything else
  4729. }
  4730. else if( generateCode )
  4731. {
  4732. // A non-reference can be converted to a reference,
  4733. // by putting the value in a temporary variable
  4734. // If the input type is read-only we'll need to temporarily
  4735. // remove this constness, otherwise the assignment will fail
  4736. bool typeIsReadOnly = ctx->type.dataType.IsReadOnly();
  4737. ctx->type.dataType.MakeReadOnly(false);
  4738. // If the object already is a temporary variable, then the copy
  4739. // doesn't have to be made as it is already a unique object
  4740. PrepareTemporaryObject(node, ctx);
  4741. ctx->type.dataType.MakeReadOnly(typeIsReadOnly);
  4742. // Add the cost for the copy
  4743. cost += asCC_TO_OBJECT_CONV;
  4744. }
  4745. // This may look strange as the conversion was to make the expression a reference
  4746. // but a value type allocated on the stack is a reference even without the type
  4747. // being marked as such.
  4748. ctx->type.dataType.MakeReference(IsVariableOnHeap(ctx->type.stackOffset));
  4749. }
  4750. // TODO: If the variable is an object allocated on the stack the following is not true as the copy may not have been made
  4751. // Since it is a new temporary variable it doesn't have to be const
  4752. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  4753. }
  4754. }
  4755. }
  4756. return cost;
  4757. }
  4758. asUINT asCCompiler::ImplicitConvPrimitiveToObject(asSExprContext *ctx, const asCDataType &to, asCScriptNode * /*node*/, EImplicitConv /*isExplicit*/, bool generateCode, bool /*allowObjectConstruct*/)
  4759. {
  4760. // Reference types currently don't allow implicit conversion from primitive to object
  4761. // TODO: Allow implicit conversion to scoped reference types as they are supposed to appear like ordinary value types
  4762. asCObjectType *objType = to.GetObjectType();
  4763. asASSERT( objType );
  4764. if( !objType || (objType->flags & asOBJ_REF) )
  4765. return asCC_NO_CONV;
  4766. // For value types the object must have a constructor that takes a single primitive argument either by value or as input reference
  4767. asCArray<int> funcs;
  4768. for( asUINT n = 0; n < objType->beh.constructors.GetLength(); n++ )
  4769. {
  4770. asCScriptFunction *func = engine->scriptFunctions[objType->beh.constructors[n]];
  4771. if( func->parameterTypes.GetLength() == 1 &&
  4772. func->parameterTypes[0].IsPrimitive() &&
  4773. !(func->inOutFlags[0] & asTM_OUTREF) )
  4774. {
  4775. funcs.PushLast(func->id);
  4776. }
  4777. }
  4778. if( funcs.GetLength() == 0 )
  4779. return asCC_NO_CONV;
  4780. // Check if it is possible to choose a best match
  4781. asSExprContext arg(engine);
  4782. arg.type = ctx->type;
  4783. asCArray<asSExprContext*> args;
  4784. args.PushLast(&arg);
  4785. asUINT cost = asCC_TO_OBJECT_CONV + MatchFunctions(funcs, args, 0, 0, objType, false, true, false);
  4786. if( funcs.GetLength() != 1 )
  4787. return asCC_NO_CONV;
  4788. if( !generateCode )
  4789. {
  4790. ctx->type.Set(to);
  4791. return cost;
  4792. }
  4793. // TODO: clean up: This part is similar to CompileCosntructCall(). It should be put in a common function
  4794. bool onHeap = true;
  4795. // Value types and script types are allocated through the constructor
  4796. asCTypeInfo tempObj;
  4797. tempObj.dataType = to;
  4798. tempObj.stackOffset = (short)AllocateVariable(to, true);
  4799. tempObj.dataType.MakeReference(true);
  4800. tempObj.isTemporary = true;
  4801. tempObj.isVariable = true;
  4802. onHeap = IsVariableOnHeap(tempObj.stackOffset);
  4803. // Push the address of the object on the stack
  4804. if( onHeap )
  4805. ctx->bc.InstrSHORT(asBC_VAR, tempObj.stackOffset);
  4806. PrepareFunctionCall(funcs[0], &ctx->bc, args);
  4807. MoveArgsToStack(funcs[0], &ctx->bc, args, false);
  4808. if( !(objType->flags & asOBJ_REF) )
  4809. {
  4810. // If the object is allocated on the stack, then call the constructor as a normal function
  4811. if( onHeap )
  4812. {
  4813. int offset = 0;
  4814. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]);
  4815. for( asUINT n = 0; n < args.GetLength(); n++ )
  4816. offset += descr->parameterTypes[n].GetSizeOnStackDWords();
  4817. ctx->bc.InstrWORD(asBC_GETREF, (asWORD)offset);
  4818. }
  4819. else
  4820. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  4821. PerformFunctionCall(funcs[0], ctx, onHeap, &args, tempObj.dataType.GetObjectType());
  4822. // Add tag that the object has been initialized
  4823. ctx->bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT);
  4824. // The constructor doesn't return anything,
  4825. // so we have to manually inform the type of
  4826. // the return value
  4827. ctx->type = tempObj;
  4828. if( !onHeap )
  4829. ctx->type.dataType.MakeReference(false);
  4830. // Push the address of the object on the stack again
  4831. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  4832. }
  4833. else
  4834. {
  4835. asASSERT( objType->flags & asOBJ_SCOPED );
  4836. // Call the factory to create the reference type
  4837. PerformFunctionCall(funcs[0], ctx, false, &args);
  4838. }
  4839. return cost;
  4840. }
  4841. void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCDataType &to, asCScriptNode *node, EImplicitConv convType)
  4842. {
  4843. asASSERT(from->type.isConstant);
  4844. // TODO: node should be the node of the value that is
  4845. // converted (not the operator that provokes the implicit
  4846. // conversion)
  4847. // If the base type is correct there is no more to do
  4848. if( to.IsEqualExceptRefAndConst(from->type.dataType) ) return;
  4849. // References cannot be constants
  4850. if( from->type.dataType.IsReference() ) return;
  4851. if( (to.IsIntegerType() && to.GetSizeInMemoryDWords() == 1 && !to.IsEnumType()) ||
  4852. (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST) )
  4853. {
  4854. if( from->type.dataType.IsFloatType() ||
  4855. from->type.dataType.IsDoubleType() ||
  4856. from->type.dataType.IsUnsignedType() ||
  4857. from->type.dataType.IsIntegerType() )
  4858. {
  4859. // Transform the value
  4860. // Float constants can be implicitly converted to int
  4861. if( from->type.dataType.IsFloatType() )
  4862. {
  4863. float fc = from->type.floatValue;
  4864. int ic = int(fc);
  4865. if( float(ic) != fc )
  4866. {
  4867. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4868. }
  4869. from->type.intValue = ic;
  4870. }
  4871. // Double constants can be implicitly converted to int
  4872. else if( from->type.dataType.IsDoubleType() )
  4873. {
  4874. double fc = from->type.doubleValue;
  4875. int ic = int(fc);
  4876. if( double(ic) != fc )
  4877. {
  4878. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4879. }
  4880. from->type.intValue = ic;
  4881. }
  4882. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  4883. {
  4884. // Verify that it is possible to convert to signed without getting negative
  4885. if( from->type.intValue < 0 )
  4886. {
  4887. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  4888. }
  4889. // Convert to 32bit
  4890. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4891. from->type.intValue = from->type.byteValue;
  4892. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4893. from->type.intValue = from->type.wordValue;
  4894. }
  4895. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  4896. {
  4897. // Convert to 32bit
  4898. from->type.intValue = int(from->type.qwordValue);
  4899. }
  4900. else if( from->type.dataType.IsIntegerType() &&
  4901. from->type.dataType.GetSizeInMemoryBytes() < 4 )
  4902. {
  4903. // Convert to 32bit
  4904. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4905. from->type.intValue = (signed char)from->type.byteValue;
  4906. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4907. from->type.intValue = (short)from->type.wordValue;
  4908. }
  4909. // Set the resulting type
  4910. if( to.IsEnumType() )
  4911. from->type.dataType = to;
  4912. else
  4913. from->type.dataType = asCDataType::CreatePrimitive(ttInt, true);
  4914. }
  4915. // Check if a downsize is necessary
  4916. if( to.IsIntegerType() &&
  4917. from->type.dataType.IsIntegerType() &&
  4918. from->type.dataType.GetSizeInMemoryBytes() > to.GetSizeInMemoryBytes() )
  4919. {
  4920. // Verify if it is possible
  4921. if( to.GetSizeInMemoryBytes() == 1 )
  4922. {
  4923. if( char(from->type.intValue) != from->type.intValue )
  4924. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  4925. from->type.byteValue = char(from->type.intValue);
  4926. }
  4927. else if( to.GetSizeInMemoryBytes() == 2 )
  4928. {
  4929. if( short(from->type.intValue) != from->type.intValue )
  4930. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  4931. from->type.wordValue = short(from->type.intValue);
  4932. }
  4933. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4934. }
  4935. }
  4936. else if( to.IsIntegerType() && to.GetSizeInMemoryDWords() == 2 )
  4937. {
  4938. // Float constants can be implicitly converted to int
  4939. if( from->type.dataType.IsFloatType() )
  4940. {
  4941. float fc = from->type.floatValue;
  4942. asINT64 ic = asINT64(fc);
  4943. if( float(ic) != fc )
  4944. {
  4945. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4946. }
  4947. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  4948. from->type.qwordValue = ic;
  4949. }
  4950. // Double constants can be implicitly converted to int
  4951. else if( from->type.dataType.IsDoubleType() )
  4952. {
  4953. double fc = from->type.doubleValue;
  4954. asINT64 ic = asINT64(fc);
  4955. if( double(ic) != fc )
  4956. {
  4957. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4958. }
  4959. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  4960. from->type.qwordValue = ic;
  4961. }
  4962. else if( from->type.dataType.IsUnsignedType() )
  4963. {
  4964. // Convert to 64bit
  4965. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4966. from->type.qwordValue = from->type.byteValue;
  4967. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4968. from->type.qwordValue = from->type.wordValue;
  4969. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  4970. from->type.qwordValue = from->type.dwordValue;
  4971. else if( from->type.dataType.GetSizeInMemoryBytes() == 8 )
  4972. {
  4973. if( asINT64(from->type.qwordValue) < 0 )
  4974. {
  4975. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  4976. }
  4977. }
  4978. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  4979. }
  4980. else if( from->type.dataType.IsIntegerType() )
  4981. {
  4982. // Convert to 64bit
  4983. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4984. from->type.qwordValue = (signed char)from->type.byteValue;
  4985. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4986. from->type.qwordValue = (short)from->type.wordValue;
  4987. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  4988. from->type.qwordValue = from->type.intValue;
  4989. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  4990. }
  4991. }
  4992. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 1 )
  4993. {
  4994. if( from->type.dataType.IsFloatType() )
  4995. {
  4996. float fc = from->type.floatValue;
  4997. // Some compilers set the value to 0 when converting a negative float to unsigned int.
  4998. // To maintain a consistent behaviour across compilers we convert to int first.
  4999. asUINT uic = asUINT(int(fc));
  5000. if( float(uic) != fc )
  5001. {
  5002. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5003. }
  5004. from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true);
  5005. from->type.intValue = uic;
  5006. // Try once more, in case of a smaller type
  5007. ImplicitConversionConstant(from, to, node, convType);
  5008. }
  5009. else if( from->type.dataType.IsDoubleType() )
  5010. {
  5011. double fc = from->type.doubleValue;
  5012. // Some compilers set the value to 0 when converting a negative double to unsigned int.
  5013. // To maintain a consistent behaviour across compilers we convert to int first.
  5014. asUINT uic = asUINT(int(fc));
  5015. if( double(uic) != fc )
  5016. {
  5017. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5018. }
  5019. from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true);
  5020. from->type.intValue = uic;
  5021. // Try once more, in case of a smaller type
  5022. ImplicitConversionConstant(from, to, node, convType);
  5023. }
  5024. else if( from->type.dataType.IsIntegerType() )
  5025. {
  5026. // Verify that it is possible to convert to unsigned without loosing negative
  5027. if( from->type.intValue < 0 )
  5028. {
  5029. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  5030. }
  5031. // Convert to 32bit
  5032. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  5033. from->type.intValue = (signed char)from->type.byteValue;
  5034. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  5035. from->type.intValue = (short)from->type.wordValue;
  5036. from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true);
  5037. // Try once more, in case of a smaller type
  5038. ImplicitConversionConstant(from, to, node, convType);
  5039. }
  5040. else if( from->type.dataType.IsUnsignedType() &&
  5041. from->type.dataType.GetSizeInMemoryBytes() < 4 )
  5042. {
  5043. // Convert to 32bit
  5044. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  5045. from->type.dwordValue = from->type.byteValue;
  5046. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  5047. from->type.dwordValue = from->type.wordValue;
  5048. from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true);
  5049. // Try once more, in case of a smaller type
  5050. ImplicitConversionConstant(from, to, node, convType);
  5051. }
  5052. else if( from->type.dataType.IsUnsignedType() &&
  5053. from->type.dataType.GetSizeInMemoryBytes() > to.GetSizeInMemoryBytes() )
  5054. {
  5055. // Verify if it is possible
  5056. if( to.GetSizeInMemoryBytes() == 1 )
  5057. {
  5058. if( asBYTE(from->type.dwordValue) != from->type.dwordValue )
  5059. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  5060. from->type.byteValue = asBYTE(from->type.dwordValue);
  5061. }
  5062. else if( to.GetSizeInMemoryBytes() == 2 )
  5063. {
  5064. if( asWORD(from->type.dwordValue) != from->type.dwordValue )
  5065. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  5066. from->type.wordValue = asWORD(from->type.dwordValue);
  5067. }
  5068. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  5069. }
  5070. }
  5071. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 2 )
  5072. {
  5073. if( from->type.dataType.IsFloatType() )
  5074. {
  5075. float fc = from->type.floatValue;
  5076. // Convert first to int64 then to uint64 to avoid negative float becoming 0 on gnuc base compilers
  5077. asQWORD uic = asQWORD(asINT64(fc));
  5078. #if !defined(_MSC_VER) || _MSC_VER > 1200 // MSVC++ 6
  5079. // MSVC6 doesn't support this conversion
  5080. if( float(uic) != fc )
  5081. {
  5082. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5083. }
  5084. #endif
  5085. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  5086. from->type.qwordValue = uic;
  5087. }
  5088. else if( from->type.dataType.IsDoubleType() )
  5089. {
  5090. double fc = from->type.doubleValue;
  5091. // Convert first to int64 then to uint64 to avoid negative float becoming 0 on gnuc base compilers
  5092. asQWORD uic = asQWORD(asINT64(fc));
  5093. #if !defined(_MSC_VER) || _MSC_VER > 1200 // MSVC++ 6
  5094. // MSVC6 doesn't support this conversion
  5095. if( double(uic) != fc )
  5096. {
  5097. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5098. }
  5099. #endif
  5100. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  5101. from->type.qwordValue = uic;
  5102. }
  5103. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  5104. {
  5105. // Convert to 64bit
  5106. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  5107. from->type.qwordValue = (asINT64)(signed char)from->type.byteValue;
  5108. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  5109. from->type.qwordValue = (asINT64)(short)from->type.wordValue;
  5110. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  5111. from->type.qwordValue = (asINT64)from->type.intValue;
  5112. // Verify that it is possible to convert to unsigned without loosing negative
  5113. if( asINT64(from->type.qwordValue) < 0 )
  5114. {
  5115. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  5116. }
  5117. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  5118. }
  5119. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  5120. {
  5121. // Verify that it is possible to convert to unsigned without loosing negative
  5122. if( asINT64(from->type.qwordValue) < 0 )
  5123. {
  5124. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  5125. }
  5126. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  5127. }
  5128. else if( from->type.dataType.IsUnsignedType() )
  5129. {
  5130. // Convert to 64bit
  5131. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  5132. from->type.qwordValue = from->type.byteValue;
  5133. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  5134. from->type.qwordValue = from->type.wordValue;
  5135. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  5136. from->type.qwordValue = from->type.dwordValue;
  5137. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  5138. }
  5139. }
  5140. else if( to.IsFloatType() )
  5141. {
  5142. if( from->type.dataType.IsDoubleType() )
  5143. {
  5144. double ic = from->type.doubleValue;
  5145. float fc = float(ic);
  5146. // Don't bother warning about this
  5147. // if( double(fc) != ic )
  5148. // {
  5149. // asCString str;
  5150. // str.Format(TXT_POSSIBLE_LOSS_OF_PRECISION);
  5151. // if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(str, node);
  5152. // }
  5153. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  5154. from->type.floatValue = fc;
  5155. }
  5156. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  5157. {
  5158. // Must properly convert value in case the from value is smaller
  5159. int ic;
  5160. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  5161. ic = (signed char)from->type.byteValue;
  5162. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  5163. ic = (short)from->type.wordValue;
  5164. else
  5165. ic = from->type.intValue;
  5166. float fc = float(ic);
  5167. if( int(fc) != ic )
  5168. {
  5169. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5170. }
  5171. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  5172. from->type.floatValue = fc;
  5173. }
  5174. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  5175. {
  5176. float fc = float(asINT64(from->type.qwordValue));
  5177. if( asINT64(fc) != asINT64(from->type.qwordValue) )
  5178. {
  5179. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5180. }
  5181. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  5182. from->type.floatValue = fc;
  5183. }
  5184. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  5185. {
  5186. // Must properly convert value in case the from value is smaller
  5187. unsigned int uic;
  5188. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  5189. uic = from->type.byteValue;
  5190. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  5191. uic = from->type.wordValue;
  5192. else
  5193. uic = from->type.dwordValue;
  5194. float fc = float(uic);
  5195. if( (unsigned int)(fc) != uic )
  5196. {
  5197. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5198. }
  5199. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  5200. from->type.floatValue = fc;
  5201. }
  5202. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  5203. {
  5204. float fc = float((asINT64)from->type.qwordValue);
  5205. if( asQWORD(fc) != from->type.qwordValue )
  5206. {
  5207. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5208. }
  5209. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  5210. from->type.floatValue = fc;
  5211. }
  5212. }
  5213. else if( to.IsDoubleType() )
  5214. {
  5215. if( from->type.dataType.IsFloatType() )
  5216. {
  5217. float ic = from->type.floatValue;
  5218. double fc = double(ic);
  5219. // Don't check for float->double
  5220. // if( float(fc) != ic )
  5221. // {
  5222. // acCString str;
  5223. // str.Format(TXT_NOT_EXACT_g_g_g, ic, fc, float(fc));
  5224. // if( !isExplicit ) Warning(str, node);
  5225. // }
  5226. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  5227. from->type.doubleValue = fc;
  5228. }
  5229. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  5230. {
  5231. // Must properly convert value in case the from value is smaller
  5232. int ic;
  5233. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  5234. ic = (signed char)from->type.byteValue;
  5235. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  5236. ic = (short)from->type.wordValue;
  5237. else
  5238. ic = from->type.intValue;
  5239. double fc = double(ic);
  5240. if( int(fc) != ic )
  5241. {
  5242. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5243. }
  5244. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  5245. from->type.doubleValue = fc;
  5246. }
  5247. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  5248. {
  5249. double fc = double(asINT64(from->type.qwordValue));
  5250. if( asINT64(fc) != asINT64(from->type.qwordValue) )
  5251. {
  5252. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5253. }
  5254. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  5255. from->type.doubleValue = fc;
  5256. }
  5257. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  5258. {
  5259. // Must properly convert value in case the from value is smaller
  5260. unsigned int uic;
  5261. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  5262. uic = from->type.byteValue;
  5263. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  5264. uic = from->type.wordValue;
  5265. else
  5266. uic = from->type.dwordValue;
  5267. double fc = double(uic);
  5268. if( (unsigned int)(fc) != uic )
  5269. {
  5270. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5271. }
  5272. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  5273. from->type.doubleValue = fc;
  5274. }
  5275. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  5276. {
  5277. double fc = double((asINT64)from->type.qwordValue);
  5278. if( asQWORD(fc) != from->type.qwordValue )
  5279. {
  5280. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  5281. }
  5282. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  5283. from->type.doubleValue = fc;
  5284. }
  5285. }
  5286. }
  5287. int asCCompiler::DoAssignment(asSExprContext *ctx, asSExprContext *lctx, asSExprContext *rctx, asCScriptNode *lexpr, asCScriptNode *rexpr, int op, asCScriptNode *opNode)
  5288. {
  5289. // Don't allow any operators on expressions that take address of class method
  5290. // If methodName is set but the type is not an object, then it is a global function
  5291. if( lctx->methodName != "" || (rctx->type.dataType.GetObjectType() && rctx->methodName != "") )
  5292. {
  5293. Error(TXT_INVALID_OP_ON_METHOD, opNode);
  5294. return -1;
  5295. }
  5296. // Implicit handle types should always be treated as handles in assignments
  5297. if (lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE) )
  5298. {
  5299. lctx->type.dataType.MakeHandle(true);
  5300. lctx->type.isExplicitHandle = true;
  5301. }
  5302. // Urho3D: if there is a handle type, and it does not have an overloaded assignment operator, convert to an explicit handle
  5303. // for scripting convenience. (For the Urho3D handle types, value assignment is not supported)
  5304. if (lctx->type.dataType.IsObjectHandle() && !lctx->type.dataType.IsTemplate() && !lctx->type.isExplicitHandle &&
  5305. !lctx->type.dataType.GetBehaviour()->copy)
  5306. lctx->type.isExplicitHandle = true;
  5307. // If the left hand expression is a property accessor, then that should be used
  5308. // to do the assignment instead of the ordinary operator. The exception is when
  5309. // the property accessor is for a handle property, and the operation is a value
  5310. // assignment.
  5311. if( (lctx->property_get || lctx->property_set) &&
  5312. !(lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle) )
  5313. {
  5314. if( op != ttAssignment )
  5315. {
  5316. // TODO: getset: We may actually be able to support this, if we can
  5317. // guarantee that the object reference will stay valid
  5318. // between the calls to the get and set accessors.
  5319. // Process the property to free the memory
  5320. ProcessPropertySetAccessor(lctx, rctx, opNode);
  5321. // Compound assignments are not allowed for properties
  5322. Error(TXT_COMPOUND_ASGN_WITH_PROP, opNode);
  5323. return -1;
  5324. }
  5325. // It is not allowed to do a handle assignment on a property
  5326. // accessor that doesn't take a handle in the set accessor.
  5327. if( lctx->property_set && lctx->type.isExplicitHandle )
  5328. {
  5329. // set_opIndex has 2 arguments, where as normal setters have only 1
  5330. asCArray<asCDataType>& parameterTypes =
  5331. builder->GetFunctionDescription(lctx->property_set)->parameterTypes;
  5332. if( !parameterTypes[parameterTypes.GetLength() - 1].IsObjectHandle() )
  5333. {
  5334. // Process the property to free the memory
  5335. ProcessPropertySetAccessor(lctx, rctx, opNode);
  5336. Error(TXT_HANDLE_ASSIGN_ON_NON_HANDLE_PROP, opNode);
  5337. return -1;
  5338. }
  5339. }
  5340. MergeExprBytecodeAndType(ctx, lctx);
  5341. return ProcessPropertySetAccessor(ctx, rctx, opNode);
  5342. }
  5343. else if( lctx->property_get && lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle )
  5344. {
  5345. // Get the handle to the object that will be used for the value assignment
  5346. ProcessPropertyGetAccessor(lctx, opNode);
  5347. }
  5348. if( lctx->type.dataType.IsPrimitive() )
  5349. {
  5350. if( !lctx->type.isLValue )
  5351. {
  5352. Error(TXT_NOT_LVALUE, lexpr);
  5353. return -1;
  5354. }
  5355. if( op != ttAssignment )
  5356. {
  5357. // Compute the operator before the assignment
  5358. asCTypeInfo lvalue = lctx->type;
  5359. if( lctx->type.isTemporary && !lctx->type.isVariable )
  5360. {
  5361. // The temporary variable must not be freed until the
  5362. // assignment has been performed. lvalue still holds
  5363. // the information about the temporary variable
  5364. lctx->type.isTemporary = false;
  5365. }
  5366. asSExprContext o(engine);
  5367. CompileOperator(opNode, lctx, rctx, &o);
  5368. MergeExprBytecode(rctx, &o);
  5369. rctx->type = o.type;
  5370. // Convert the rvalue to the right type and validate it
  5371. PrepareForAssignment(&lvalue.dataType, rctx, rexpr, false);
  5372. MergeExprBytecode(ctx, rctx);
  5373. lctx->type = lvalue;
  5374. // The lvalue continues the same, either it was a variable, or a reference in the register
  5375. }
  5376. else
  5377. {
  5378. // Convert the rvalue to the right type and validate it
  5379. PrepareForAssignment(&lctx->type.dataType, rctx, rexpr, false, lctx);
  5380. MergeExprBytecode(ctx, rctx);
  5381. MergeExprBytecode(ctx, lctx);
  5382. }
  5383. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  5384. PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode);
  5385. ctx->type = lctx->type;
  5386. }
  5387. else if( lctx->type.isExplicitHandle )
  5388. {
  5389. if( !lctx->type.isLValue )
  5390. {
  5391. Error(TXT_NOT_LVALUE, lexpr);
  5392. return -1;
  5393. }
  5394. // Object handles don't have any compound assignment operators
  5395. if( op != ttAssignment )
  5396. {
  5397. asCString str;
  5398. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format().AddressOf());
  5399. Error(str, lexpr);
  5400. return -1;
  5401. }
  5402. if( lctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE )
  5403. {
  5404. // The object is a value type but that should be treated as a handle
  5405. // Make sure the right hand value is a handle
  5406. if( !rctx->type.isExplicitHandle &&
  5407. !(rctx->type.dataType.GetObjectType() && (rctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE)) )
  5408. {
  5409. // Function names can be considered handles already
  5410. if( rctx->methodName == "" )
  5411. {
  5412. asCDataType dt = rctx->type.dataType;
  5413. dt.MakeHandle(true);
  5414. dt.MakeReference(false);
  5415. PrepareArgument(&dt, rctx, rexpr, true, asTM_INREF);
  5416. if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) )
  5417. {
  5418. asCString str;
  5419. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format().AddressOf(), lctx->type.dataType.Format().AddressOf());
  5420. Error(str, rexpr);
  5421. return -1;
  5422. }
  5423. }
  5424. }
  5425. if( CompileOverloadedDualOperator(opNode, lctx, rctx, ctx) )
  5426. {
  5427. // An overloaded assignment operator was found (or a compilation error occured)
  5428. return 0;
  5429. }
  5430. // The object must implement the opAssign method
  5431. Error(TXT_NO_APPROPRIATE_OPASSIGN, opNode);
  5432. return -1;
  5433. }
  5434. else
  5435. {
  5436. asCDataType dt = lctx->type.dataType;
  5437. dt.MakeReference(false);
  5438. PrepareArgument(&dt, rctx, rexpr, true, asTM_INREF , true);
  5439. if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) )
  5440. {
  5441. asCString str;
  5442. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format().AddressOf(), lctx->type.dataType.Format().AddressOf());
  5443. Error(str, rexpr);
  5444. return -1;
  5445. }
  5446. MergeExprBytecode(ctx, rctx);
  5447. MergeExprBytecode(ctx, lctx);
  5448. ctx->bc.InstrWORD(asBC_GETOBJREF, AS_PTR_SIZE);
  5449. PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode);
  5450. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  5451. ctx->type = lctx->type;
  5452. }
  5453. }
  5454. else // if( lctx->type.dataType.IsObject() )
  5455. {
  5456. // An ASHANDLE type must not allow a value assignment, as
  5457. // the opAssign operator is used for the handle assignment
  5458. if( lctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE )
  5459. {
  5460. asCString str;
  5461. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format().AddressOf());
  5462. Error(str, lexpr);
  5463. return -1;
  5464. }
  5465. // The lvalue reference may be marked as a temporary, if for example
  5466. // it was originated as a handle returned from a function. In such
  5467. // cases it must be possible to assign values to it anyway.
  5468. if( lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle )
  5469. {
  5470. // Convert the handle to a object reference
  5471. asCDataType to;
  5472. to = lctx->type.dataType;
  5473. to.MakeHandle(false);
  5474. ImplicitConversion(lctx, to, lexpr, asIC_IMPLICIT_CONV);
  5475. lctx->type.isLValue = true; // Handle may not have been an lvalue, but the dereferenced object is
  5476. }
  5477. // Check for overloaded assignment operator
  5478. if( CompileOverloadedDualOperator(opNode, lctx, rctx, ctx) )
  5479. {
  5480. // An overloaded assignment operator was found (or a compilation error occured)
  5481. return 0;
  5482. }
  5483. // No registered operator was found. In case the operation is a direct
  5484. // assignment and the rvalue is the same type as the lvalue, then we can
  5485. // still use the byte-for-byte copy to do the assignment
  5486. if( op != ttAssignment )
  5487. {
  5488. asCString str;
  5489. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format().AddressOf());
  5490. Error(str, lexpr);
  5491. return -1;
  5492. }
  5493. // If the left hand expression is simple, i.e. without any
  5494. // function calls or allocations of memory, then we can avoid
  5495. // doing a copy of the right hand expression (done by PrepareArgument).
  5496. // Instead the reference to the value can be placed directly on the
  5497. // stack.
  5498. //
  5499. // This optimization should only be done for value types, where
  5500. // the application developer is responsible for making the
  5501. // implementation safe against unwanted destruction of the input
  5502. // reference before the time.
  5503. bool simpleExpr = (lctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_VALUE) && lctx->bc.IsSimpleExpression();
  5504. // Implicitly convert the rvalue to the type of the lvalue
  5505. bool needConversion = false;
  5506. if( !lctx->type.dataType.IsEqualExceptRefAndConst(rctx->type.dataType) )
  5507. needConversion = true;
  5508. if( !simpleExpr || needConversion )
  5509. {
  5510. asCDataType dt = lctx->type.dataType;
  5511. dt.MakeReference(true);
  5512. dt.MakeReadOnly(true);
  5513. PrepareArgument(&dt, rctx, rexpr, true, 1, !needConversion);
  5514. if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) )
  5515. {
  5516. asCString str;
  5517. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format().AddressOf(), lctx->type.dataType.Format().AddressOf());
  5518. Error(str, rexpr);
  5519. return -1;
  5520. }
  5521. }
  5522. else
  5523. {
  5524. // Process any property accessor first, before placing the final reference on the stack
  5525. ProcessPropertyGetAccessor(rctx, rexpr);
  5526. if( rctx->type.dataType.IsReference() && (!(rctx->type.isVariable || rctx->type.isTemporary) || IsVariableOnHeap(rctx->type.stackOffset)) )
  5527. rctx->bc.Instr(asBC_RDSPtr);
  5528. }
  5529. MergeExprBytecode(ctx, rctx);
  5530. MergeExprBytecode(ctx, lctx);
  5531. if( !simpleExpr || needConversion )
  5532. {
  5533. if( (rctx->type.isVariable || rctx->type.isTemporary) )
  5534. {
  5535. if( !IsVariableOnHeap(rctx->type.stackOffset) )
  5536. // TODO: runtime optimize: Actually the reference can be pushed on the stack directly
  5537. // as the value allocated on the stack is guaranteed to be safe.
  5538. // The bytecode optimizer should be able to determine this and optimize away the VAR + GETREF
  5539. ctx->bc.InstrWORD(asBC_GETREF, AS_PTR_SIZE);
  5540. else
  5541. ctx->bc.InstrWORD(asBC_GETOBJREF, AS_PTR_SIZE);
  5542. }
  5543. }
  5544. PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode);
  5545. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  5546. ctx->type = lctx->type;
  5547. }
  5548. return 0;
  5549. }
  5550. int asCCompiler::CompileAssignment(asCScriptNode *expr, asSExprContext *ctx)
  5551. {
  5552. asCScriptNode *lexpr = expr->firstChild;
  5553. if( lexpr->next )
  5554. {
  5555. // Compile the two expression terms
  5556. asSExprContext lctx(engine), rctx(engine);
  5557. int rr = CompileAssignment(lexpr->next->next, &rctx);
  5558. int lr = CompileCondition(lexpr, &lctx);
  5559. if( lr >= 0 && rr >= 0 )
  5560. return DoAssignment(ctx, &lctx, &rctx, lexpr, lexpr->next->next, lexpr->next->tokenType, lexpr->next);
  5561. // Since the operands failed, the assignment was not computed
  5562. ctx->type.SetDummy();
  5563. return -1;
  5564. }
  5565. return CompileCondition(lexpr, ctx);
  5566. }
  5567. int asCCompiler::CompileCondition(asCScriptNode *expr, asSExprContext *ctx)
  5568. {
  5569. asCTypeInfo ctype;
  5570. // Compile the conditional expression
  5571. asCScriptNode *cexpr = expr->firstChild;
  5572. if( cexpr->next )
  5573. {
  5574. //-------------------------------
  5575. // Compile the condition
  5576. asSExprContext e(engine);
  5577. int r = CompileExpression(cexpr, &e);
  5578. if( r < 0 )
  5579. e.type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  5580. if( r >= 0 && !e.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  5581. {
  5582. Error(TXT_EXPR_MUST_BE_BOOL, cexpr);
  5583. e.type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  5584. }
  5585. ctype = e.type;
  5586. ProcessPropertyGetAccessor(&e, cexpr);
  5587. if( e.type.dataType.IsReference() ) ConvertToVariable(&e);
  5588. ProcessDeferredParams(&e);
  5589. //-------------------------------
  5590. // Compile the left expression
  5591. asSExprContext le(engine);
  5592. int lr = CompileAssignment(cexpr->next, &le);
  5593. //-------------------------------
  5594. // Compile the right expression
  5595. asSExprContext re(engine);
  5596. int rr = CompileAssignment(cexpr->next->next, &re);
  5597. if( lr >= 0 && rr >= 0 )
  5598. {
  5599. // Don't allow any operators on expressions that take address of class method
  5600. if( le.methodName != "" || re.methodName != "" )
  5601. {
  5602. Error(TXT_INVALID_OP_ON_METHOD, expr);
  5603. return -1;
  5604. }
  5605. ProcessPropertyGetAccessor(&le, cexpr->next);
  5606. ProcessPropertyGetAccessor(&re, cexpr->next->next);
  5607. bool isExplicitHandle = le.type.isExplicitHandle || re.type.isExplicitHandle;
  5608. // Allow a 0 or null in the first case to be implicitly converted to the second type
  5609. if( le.type.isConstant && le.type.intValue == 0 && le.type.dataType.IsUnsignedType() )
  5610. {
  5611. asCDataType to = re.type.dataType;
  5612. to.MakeReference(false);
  5613. to.MakeReadOnly(true);
  5614. ImplicitConversionConstant(&le, to, cexpr->next, asIC_IMPLICIT_CONV);
  5615. }
  5616. else if( le.type.IsNullConstant() )
  5617. {
  5618. asCDataType to = re.type.dataType;
  5619. to.MakeHandle(true);
  5620. ImplicitConversion(&le, to, cexpr->next, asIC_IMPLICIT_CONV);
  5621. }
  5622. //---------------------------------
  5623. // Output the byte code
  5624. int afterLabel = nextLabel++;
  5625. int elseLabel = nextLabel++;
  5626. // If left expression is void, then we don't need to store the result
  5627. if( le.type.dataType.IsEqualExceptConst(asCDataType::CreatePrimitive(ttVoid, false)) )
  5628. {
  5629. // Put the code for the condition expression on the output
  5630. MergeExprBytecode(ctx, &e);
  5631. // Added the branch decision
  5632. ctx->type = e.type;
  5633. ConvertToVariable(ctx);
  5634. ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset);
  5635. ctx->bc.Instr(asBC_ClrHi);
  5636. ctx->bc.InstrDWORD(asBC_JZ, elseLabel);
  5637. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5638. // Add the left expression
  5639. MergeExprBytecode(ctx, &le);
  5640. ctx->bc.InstrINT(asBC_JMP, afterLabel);
  5641. // Add the right expression
  5642. ctx->bc.Label((short)elseLabel);
  5643. MergeExprBytecode(ctx, &re);
  5644. ctx->bc.Label((short)afterLabel);
  5645. // Make sure both expressions have the same type
  5646. if( le.type.dataType != re.type.dataType )
  5647. Error(TXT_BOTH_MUST_BE_SAME, expr);
  5648. // Set the type of the result
  5649. ctx->type = le.type;
  5650. }
  5651. else
  5652. {
  5653. // Allocate temporary variable and copy the result to that one
  5654. asCTypeInfo temp;
  5655. temp = le.type;
  5656. temp.dataType.MakeReference(false);
  5657. temp.dataType.MakeReadOnly(false);
  5658. // Make sure the variable isn't used in the initial expression
  5659. int offset = AllocateVariableNotIn(temp.dataType, true, false, &e);
  5660. temp.SetVariable(temp.dataType, offset, true);
  5661. // TODO: copy: Use copy constructor if available. See PrepareTemporaryObject()
  5662. CallDefaultConstructor(temp.dataType, offset, IsVariableOnHeap(offset), &ctx->bc, expr);
  5663. // Put the code for the condition expression on the output
  5664. MergeExprBytecode(ctx, &e);
  5665. // Add the branch decision
  5666. ctx->type = e.type;
  5667. ConvertToVariable(ctx);
  5668. ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset);
  5669. ctx->bc.Instr(asBC_ClrHi);
  5670. ctx->bc.InstrDWORD(asBC_JZ, elseLabel);
  5671. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  5672. // Assign the result of the left expression to the temporary variable
  5673. asCTypeInfo rtemp;
  5674. rtemp = temp;
  5675. if( rtemp.dataType.IsObjectHandle() )
  5676. rtemp.isExplicitHandle = true;
  5677. PrepareForAssignment(&rtemp.dataType, &le, cexpr->next, true);
  5678. MergeExprBytecode(ctx, &le);
  5679. if( !rtemp.dataType.IsPrimitive() )
  5680. {
  5681. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  5682. rtemp.dataType.MakeReference(IsVariableOnHeap(offset));
  5683. }
  5684. PerformAssignment(&rtemp, &le.type, &ctx->bc, cexpr->next);
  5685. if( !rtemp.dataType.IsPrimitive() )
  5686. ctx->bc.Instr(asBC_PopPtr); // Pop the original value (always a pointer)
  5687. // Release the old temporary variable
  5688. ReleaseTemporaryVariable(le.type, &ctx->bc);
  5689. ctx->bc.InstrINT(asBC_JMP, afterLabel);
  5690. // Start of the right expression
  5691. ctx->bc.Label((short)elseLabel);
  5692. // Copy the result to the same temporary variable
  5693. PrepareForAssignment(&rtemp.dataType, &re, cexpr->next, true);
  5694. MergeExprBytecode(ctx, &re);
  5695. if( !rtemp.dataType.IsPrimitive() )
  5696. {
  5697. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  5698. rtemp.dataType.MakeReference(IsVariableOnHeap(offset));
  5699. }
  5700. PerformAssignment(&rtemp, &re.type, &ctx->bc, cexpr->next);
  5701. if( !rtemp.dataType.IsPrimitive() )
  5702. ctx->bc.Instr(asBC_PopPtr); // Pop the original value (always a pointer)
  5703. // Release the old temporary variable
  5704. ReleaseTemporaryVariable(re.type, &ctx->bc);
  5705. ctx->bc.Label((short)afterLabel);
  5706. // Make sure both expressions have the same type
  5707. if( !le.type.dataType.IsEqualExceptConst(re.type.dataType) )
  5708. Error(TXT_BOTH_MUST_BE_SAME, expr);
  5709. // Set the temporary variable as output
  5710. ctx->type = rtemp;
  5711. ctx->type.isExplicitHandle = isExplicitHandle;
  5712. if( !ctx->type.dataType.IsPrimitive() )
  5713. {
  5714. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  5715. ctx->type.dataType.MakeReference(IsVariableOnHeap(offset));
  5716. }
  5717. // Make sure the output isn't marked as being a literal constant
  5718. ctx->type.isConstant = false;
  5719. }
  5720. }
  5721. else
  5722. {
  5723. ctx->type.SetDummy();
  5724. return -1;
  5725. }
  5726. }
  5727. else
  5728. return CompileExpression(cexpr, ctx);
  5729. return 0;
  5730. }
  5731. int asCCompiler::CompileExpression(asCScriptNode *expr, asSExprContext *ctx)
  5732. {
  5733. asASSERT(expr->nodeType == snExpression);
  5734. // Convert to polish post fix, i.e: a+b => ab+
  5735. // The algorithm that I've implemented here is similar to
  5736. // Djikstra's Shunting Yard algorithm, though I didn't know it at the time.
  5737. // ref: http://en.wikipedia.org/wiki/Shunting-yard_algorithm
  5738. // Count the nodes in order to preallocate the buffers
  5739. int count = 0;
  5740. asCScriptNode *node = expr->firstChild;
  5741. while( node )
  5742. {
  5743. count++;
  5744. node = node->next;
  5745. }
  5746. asCArray<asCScriptNode *> stack(count);
  5747. asCArray<asCScriptNode *> stack2(count);
  5748. node = expr->firstChild;
  5749. while( node )
  5750. {
  5751. int precedence = GetPrecedence(node);
  5752. while( stack.GetLength() > 0 &&
  5753. precedence <= GetPrecedence(stack[stack.GetLength()-1]) )
  5754. stack2.PushLast(stack.PopLast());
  5755. stack.PushLast(node);
  5756. node = node->next;
  5757. }
  5758. while( stack.GetLength() > 0 )
  5759. stack2.PushLast(stack.PopLast());
  5760. // Compile the postfix formatted expression
  5761. return CompilePostFixExpression(&stack2, ctx);
  5762. }
  5763. int asCCompiler::CompilePostFixExpression(asCArray<asCScriptNode *> *postfix, asSExprContext *ctx)
  5764. {
  5765. // Shouldn't send any byte code
  5766. asASSERT(ctx->bc.GetLastInstr() == -1);
  5767. // Set the context to a dummy type to avoid further
  5768. // errors in case the expression fails to compile
  5769. ctx->type.SetDummy();
  5770. // Evaluate the operands and operators
  5771. asCArray<asSExprContext*> free;
  5772. asCArray<asSExprContext*> expr;
  5773. int ret = 0;
  5774. for( asUINT n = 0; ret == 0 && n < postfix->GetLength(); n++ )
  5775. {
  5776. asCScriptNode *node = (*postfix)[n];
  5777. if( node->nodeType == snExprTerm )
  5778. {
  5779. asSExprContext *e = free.GetLength() ? free.PopLast() : asNEW(asSExprContext)(engine);
  5780. expr.PushLast(e);
  5781. e->exprNode = node;
  5782. ret = CompileExpressionTerm(node, e);
  5783. }
  5784. else
  5785. {
  5786. asSExprContext *r = expr.PopLast();
  5787. asSExprContext *l = expr.PopLast();
  5788. // Now compile the operator
  5789. asSExprContext *e = free.GetLength() ? free.PopLast() : asNEW(asSExprContext)(engine);
  5790. ret = CompileOperator(node, l, r, e);
  5791. expr.PushLast(e);
  5792. // Free the operands
  5793. l->Clear();
  5794. free.PushLast(l);
  5795. r->Clear();
  5796. free.PushLast(r);
  5797. }
  5798. }
  5799. if( ret == 0 )
  5800. {
  5801. asASSERT(expr.GetLength() == 1);
  5802. // The final result should be moved to the output context
  5803. MergeExprBytecodeAndType(ctx, expr[0]);
  5804. }
  5805. // Clean up
  5806. for( asUINT e = 0; e < expr.GetLength(); e++ )
  5807. asDELETE(expr[e], asSExprContext);
  5808. for( asUINT f = 0; f < free.GetLength(); f++ )
  5809. asDELETE(free[f], asSExprContext);
  5810. return ret;
  5811. }
  5812. int asCCompiler::CompileExpressionTerm(asCScriptNode *node, asSExprContext *ctx)
  5813. {
  5814. // Shouldn't send any byte code
  5815. asASSERT(ctx->bc.GetLastInstr() == -1);
  5816. // Set the type as a dummy by default, in case of any compiler errors
  5817. ctx->type.SetDummy();
  5818. // Compile the value node
  5819. asCScriptNode *vnode = node->firstChild;
  5820. while( vnode->nodeType != snExprValue )
  5821. vnode = vnode->next;
  5822. asSExprContext v(engine);
  5823. int r = CompileExpressionValue(vnode, &v); if( r < 0 ) return r;
  5824. // Compile post fix operators
  5825. asCScriptNode *pnode = vnode->next;
  5826. while( pnode )
  5827. {
  5828. r = CompileExpressionPostOp(pnode, &v); if( r < 0 ) return r;
  5829. pnode = pnode->next;
  5830. }
  5831. // Compile pre fix operators
  5832. pnode = vnode->prev;
  5833. while( pnode )
  5834. {
  5835. r = CompileExpressionPreOp(pnode, &v); if( r < 0 ) return r;
  5836. pnode = pnode->prev;
  5837. }
  5838. // Return the byte code and final type description
  5839. MergeExprBytecodeAndType(ctx, &v);
  5840. return 0;
  5841. }
  5842. int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &scope, asSExprContext *ctx, asCScriptNode *errNode, bool isOptional, bool noFunction, bool noGlobal, asCObjectType *objType)
  5843. {
  5844. bool found = false;
  5845. // It is a local variable or parameter?
  5846. // This is not accessible by default arg expressions
  5847. sVariable *v = 0;
  5848. if( !isCompilingDefaultArg && scope == "" && !objType && variables )
  5849. v = variables->GetVariable(name.AddressOf());
  5850. if( v )
  5851. {
  5852. found = true;
  5853. if( v->isPureConstant )
  5854. ctx->type.SetConstantQW(v->type, v->constantValue);
  5855. else if( v->type.IsPrimitive() )
  5856. {
  5857. if( v->type.IsReference() )
  5858. {
  5859. // Copy the reference into the register
  5860. ctx->bc.InstrSHORT(asBC_PshVPtr, (short)v->stackOffset);
  5861. ctx->bc.Instr(asBC_PopRPtr);
  5862. ctx->type.Set(v->type);
  5863. }
  5864. else
  5865. ctx->type.SetVariable(v->type, v->stackOffset, false);
  5866. ctx->type.isLValue = true;
  5867. }
  5868. else
  5869. {
  5870. ctx->bc.InstrSHORT(asBC_PSF, (short)v->stackOffset);
  5871. ctx->type.SetVariable(v->type, v->stackOffset, false);
  5872. // If the variable is allocated on the heap we have a reference,
  5873. // otherwise the actual object pointer is pushed on the stack.
  5874. if( v->onHeap || v->type.IsObjectHandle() ) ctx->type.dataType.MakeReference(true);
  5875. // Implicitly dereference handle parameters sent by reference
  5876. if( v->type.IsReference() && (!v->type.IsObject() || v->type.IsObjectHandle()) )
  5877. ctx->bc.Instr(asBC_RDSPtr);
  5878. ctx->type.isLValue = true;
  5879. }
  5880. }
  5881. // Is it a class member?
  5882. // This is not accessible by default arg expressions
  5883. if( !isCompilingDefaultArg && !found && ((objType) || (outFunc && outFunc->objectType && scope == "")) )
  5884. {
  5885. if( name == THIS_TOKEN && !objType )
  5886. {
  5887. asCDataType dt = asCDataType::CreateObject(outFunc->objectType, outFunc->isReadOnly);
  5888. // The object pointer is located at stack position 0
  5889. ctx->bc.InstrSHORT(asBC_PSF, 0);
  5890. ctx->type.SetVariable(dt, 0, false);
  5891. ctx->type.dataType.MakeReference(true);
  5892. ctx->type.isLValue = true;
  5893. found = true;
  5894. }
  5895. if( !found )
  5896. {
  5897. // See if there are any matching property accessors
  5898. asSExprContext access(engine);
  5899. if( objType )
  5900. access.type.Set(asCDataType::CreateObject(objType, false));
  5901. else
  5902. access.type.Set(asCDataType::CreateObject(outFunc->objectType, outFunc->isReadOnly));
  5903. access.type.dataType.MakeReference(true);
  5904. int r = 0;
  5905. if( errNode->next && errNode->next->tokenType == ttOpenBracket )
  5906. {
  5907. // This is an index access, check if there is a property accessor that takes an index arg
  5908. asSExprContext dummyArg(engine);
  5909. r = FindPropertyAccessor(name, &access, &dummyArg, errNode, 0, true);
  5910. }
  5911. if( r == 0 )
  5912. {
  5913. // Normal property access
  5914. r = FindPropertyAccessor(name, &access, errNode, 0, true);
  5915. }
  5916. if( r < 0 ) return -1;
  5917. if( access.property_get || access.property_set )
  5918. {
  5919. if( !objType )
  5920. {
  5921. // Prepare the bytecode for the member access
  5922. // This is only done when accessing through the implicit this pointer
  5923. ctx->bc.InstrSHORT(asBC_PSF, 0);
  5924. }
  5925. MergeExprBytecodeAndType(ctx, &access);
  5926. found = true;
  5927. }
  5928. }
  5929. if( !found )
  5930. {
  5931. asCDataType dt;
  5932. if( objType )
  5933. dt = asCDataType::CreateObject(objType, false);
  5934. else
  5935. dt = asCDataType::CreateObject(outFunc->objectType, false);
  5936. asCObjectProperty *prop = builder->GetObjectProperty(dt, name.AddressOf());
  5937. if( prop )
  5938. {
  5939. if( !objType )
  5940. {
  5941. // The object pointer is located at stack position 0
  5942. // This is only done when accessing through the implicit this pointer
  5943. ctx->bc.InstrSHORT(asBC_PSF, 0);
  5944. ctx->type.SetVariable(dt, 0, false);
  5945. ctx->type.dataType.MakeReference(true);
  5946. Dereference(ctx, true);
  5947. }
  5948. // TODO: This is the same as what is in CompileExpressionPostOp
  5949. // Put the offset on the stack
  5950. ctx->bc.InstrSHORT_DW(asBC_ADDSi, (short)prop->byteOffset, engine->GetTypeIdFromDataType(dt));
  5951. if( prop->type.IsReference() )
  5952. ctx->bc.Instr(asBC_RDSPtr);
  5953. // Reference to primitive must be stored in the temp register
  5954. if( prop->type.IsPrimitive() )
  5955. {
  5956. // TODO: runtime optimize: The ADD offset command should store the reference in the register directly
  5957. ctx->bc.Instr(asBC_PopRPtr);
  5958. }
  5959. // Set the new type (keeping info about temp variable)
  5960. ctx->type.dataType = prop->type;
  5961. ctx->type.dataType.MakeReference(true);
  5962. ctx->type.isVariable = false;
  5963. ctx->type.isLValue = true;
  5964. if( ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle() )
  5965. {
  5966. // Objects that are members are not references
  5967. ctx->type.dataType.MakeReference(false);
  5968. }
  5969. // If the object reference is const, the property will also be const
  5970. ctx->type.dataType.MakeReadOnly(outFunc->isReadOnly);
  5971. found = true;
  5972. }
  5973. else if( outFunc->objectType )
  5974. {
  5975. // If it is not a property, it may still be the name of a method which can be used to create delegates
  5976. asCObjectType *ot = outFunc->objectType;
  5977. asCScriptFunction *func = 0;
  5978. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  5979. {
  5980. if( engine->scriptFunctions[ot->methods[n]]->name == name )
  5981. {
  5982. func = engine->scriptFunctions[ot->methods[n]];
  5983. break;
  5984. }
  5985. }
  5986. if( func )
  5987. {
  5988. // An object method was found. Keep the name of the method in the expression, but
  5989. // don't actually modify the bytecode at this point since it is not yet known what
  5990. // the method will be used for, or even what overloaded method should be used.
  5991. ctx->methodName = name;
  5992. // Place the object pointer on the stack, as if the expression was this.func
  5993. if( !objType )
  5994. {
  5995. // The object pointer is located at stack position 0
  5996. // This is only done when accessing through the implicit this pointer
  5997. ctx->bc.InstrSHORT(asBC_PSF, 0);
  5998. ctx->type.SetVariable(asCDataType::CreateObject(outFunc->objectType, false), 0, false);
  5999. ctx->type.dataType.MakeReference(true);
  6000. Dereference(ctx, true);
  6001. }
  6002. found = true;
  6003. }
  6004. }
  6005. }
  6006. }
  6007. // Is it a global property?
  6008. if( !found && !objType && !noGlobal )
  6009. {
  6010. asSNameSpace *ns = DetermineNameSpace(scope);
  6011. if( ns )
  6012. {
  6013. // See if there are any matching global property accessors
  6014. asSExprContext access(engine);
  6015. int r = 0;
  6016. if( errNode->next && errNode->next->tokenType == ttOpenBracket )
  6017. {
  6018. // This is an index access, check if there is a property accessor that takes an index arg
  6019. asSExprContext dummyArg(engine);
  6020. r = FindPropertyAccessor(name, &access, &dummyArg, errNode, ns);
  6021. }
  6022. if( r == 0 )
  6023. {
  6024. // Normal property access
  6025. r = FindPropertyAccessor(name, &access, errNode, ns);
  6026. }
  6027. if( r < 0 ) return -1;
  6028. if( access.property_get || access.property_set )
  6029. {
  6030. // Prepare the bytecode for the function call
  6031. MergeExprBytecodeAndType(ctx, &access);
  6032. found = true;
  6033. }
  6034. // See if there is any matching global property
  6035. if( !found )
  6036. {
  6037. bool isCompiled = true;
  6038. bool isPureConstant = false;
  6039. bool isAppProp = false;
  6040. asQWORD constantValue = 0;
  6041. asCGlobalProperty *prop = builder->GetGlobalProperty(name.AddressOf(), ns, &isCompiled, &isPureConstant, &constantValue, &isAppProp);
  6042. if( prop )
  6043. {
  6044. found = true;
  6045. // Verify that the global property has been compiled already
  6046. if( isCompiled )
  6047. {
  6048. if( ctx->type.dataType.GetObjectType() && (ctx->type.dataType.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE) )
  6049. {
  6050. ctx->type.dataType.MakeHandle(true);
  6051. ctx->type.isExplicitHandle = true;
  6052. }
  6053. // If the global property is a pure constant
  6054. // we can allow the compiler to optimize it. Pure
  6055. // constants are global constant variables that were
  6056. // initialized by literal constants.
  6057. if( isPureConstant )
  6058. ctx->type.SetConstantQW(prop->type, constantValue);
  6059. else
  6060. {
  6061. // A shared type must not access global vars, unless they
  6062. // too are shared, e.g. application registered vars
  6063. if( outFunc->IsShared() )
  6064. {
  6065. if( !isAppProp )
  6066. {
  6067. asCString str;
  6068. str.Format(TXT_SHARED_CANNOT_ACCESS_NON_SHARED_VAR_s, prop->name.AddressOf());
  6069. Error(str, errNode);
  6070. // Allow the compilation to continue to catch other problems
  6071. }
  6072. }
  6073. ctx->type.Set(prop->type);
  6074. ctx->type.isLValue = true;
  6075. if( ctx->type.dataType.IsPrimitive() )
  6076. {
  6077. // Load the address of the variable into the register
  6078. ctx->bc.InstrPTR(asBC_LDG, prop->GetAddressOfValue());
  6079. ctx->type.dataType.MakeReference(true);
  6080. }
  6081. else
  6082. {
  6083. // Push the address of the variable on the stack
  6084. ctx->bc.InstrPTR(asBC_PGA, prop->GetAddressOfValue());
  6085. // If the object is a value type or a non-handle variable to a reference type,
  6086. // then we must validate the existance as it could potentially be accessed
  6087. // before it is initialized.
  6088. if( (ctx->type.dataType.GetObjectType()->flags & asOBJ_VALUE) ||
  6089. !ctx->type.dataType.IsObjectHandle() )
  6090. {
  6091. // TODO: runtime optimize: This is not necessary for application registered properties
  6092. ctx->bc.Instr(asBC_ChkRefS);
  6093. }
  6094. // If the address pushed on the stack is to a value type or an object
  6095. // handle, then mark the expression as a reference. Addresses to a reference
  6096. // type aren't marked as references to get correct behaviour
  6097. if( (ctx->type.dataType.GetObjectType()->flags & asOBJ_VALUE) ||
  6098. ctx->type.dataType.IsObjectHandle() )
  6099. {
  6100. ctx->type.dataType.MakeReference(true);
  6101. }
  6102. else
  6103. {
  6104. asASSERT( (ctx->type.dataType.GetObjectType()->flags & asOBJ_REF) && !ctx->type.dataType.IsObjectHandle() );
  6105. // It's necessary to dereference the pointer so the pointer on the stack will point to the actual object
  6106. ctx->bc.Instr(asBC_RDSPtr);
  6107. }
  6108. }
  6109. }
  6110. }
  6111. else
  6112. {
  6113. asCString str;
  6114. str.Format(TXT_UNINITIALIZED_GLOBAL_VAR_s, prop->name.AddressOf());
  6115. Error(str, errNode);
  6116. return -1;
  6117. }
  6118. }
  6119. }
  6120. }
  6121. }
  6122. // Is it the name of a global function?
  6123. if( !noFunction && !found && !objType && !noGlobal )
  6124. {
  6125. asCArray<int> funcs;
  6126. asSNameSpace *ns = DetermineNameSpace(scope);
  6127. if( ns )
  6128. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  6129. if( funcs.GetLength() > 0 )
  6130. {
  6131. found = true;
  6132. // Defer the evaluation of which function until it is actually used
  6133. // Store the namespace and name of the function for later
  6134. ctx->type.SetNullConstant();
  6135. // Clear the explicit handle so that the script writer is allowed to explicitly set it
  6136. ctx->type.isExplicitHandle = false;
  6137. ctx->methodName = ns ? ns->name + "::" + name : name;
  6138. }
  6139. }
  6140. // Is it an enum value?
  6141. if( !found && !objType && !noGlobal )
  6142. {
  6143. // The enum type may be declared in a namespace too
  6144. asCObjectType *scopeType = 0;
  6145. if( scope != "" && scope != "::" )
  6146. {
  6147. // Use the last scope name as the enum type
  6148. asCString enumType = scope;
  6149. asCString nsScope;
  6150. int p = scope.FindLast("::");
  6151. if( p != -1 )
  6152. {
  6153. enumType = scope.SubString(p+2);
  6154. nsScope = scope.SubString(0, p);
  6155. }
  6156. asSNameSpace *ns = engine->FindNameSpace(nsScope.AddressOf());
  6157. if( ns )
  6158. scopeType = builder->GetObjectType(enumType.AddressOf(), ns);
  6159. }
  6160. asDWORD value = 0;
  6161. asCDataType dt;
  6162. if( scopeType && builder->GetEnumValueFromObjectType(scopeType, name.AddressOf(), dt, value) )
  6163. {
  6164. // scoped enum value found
  6165. found = true;
  6166. }
  6167. else if( !engine->ep.requireEnumScope )
  6168. {
  6169. // Look for the enum value without explicitly informing the enum type
  6170. asSNameSpace *ns = DetermineNameSpace(scope);
  6171. int e = 0;
  6172. if( ns )
  6173. e = builder->GetEnumValue(name.AddressOf(), dt, value, ns);
  6174. if( e )
  6175. {
  6176. found = true;
  6177. if( e == 2 )
  6178. {
  6179. Error(TXT_FOUND_MULTIPLE_ENUM_VALUES, errNode);
  6180. }
  6181. }
  6182. }
  6183. if( found )
  6184. {
  6185. // Even if the enum type is not shared, and we're compiling a shared object,
  6186. // the use of the values are still allowed, since they are treated as constants.
  6187. // an enum value was resolved
  6188. ctx->type.SetConstantDW(dt, value);
  6189. }
  6190. }
  6191. // The name doesn't match any variable
  6192. if( !found )
  6193. {
  6194. // Give dummy value
  6195. ctx->type.SetDummy();
  6196. if( !isOptional )
  6197. {
  6198. // Prepend the scope to the name for the error message
  6199. asCString ename;
  6200. if( scope != "" && scope != "::" )
  6201. ename = scope + "::";
  6202. else
  6203. ename = scope;
  6204. ename += name;
  6205. asCString str;
  6206. str.Format(TXT_s_NOT_DECLARED, ename.AddressOf());
  6207. Error(str, errNode);
  6208. // Declare the variable now so that it will not be reported again
  6209. variables->DeclareVariable(name.AddressOf(), asCDataType::CreatePrimitive(ttInt, false), 0x7FFF, true);
  6210. // Mark the variable as initialized so that the user will not be bother by it again
  6211. sVariable *v = variables->GetVariable(name.AddressOf());
  6212. asASSERT(v);
  6213. if( v ) v->isInitialized = true;
  6214. }
  6215. // Return -1 to signal that the variable wasn't found
  6216. return -1;
  6217. }
  6218. return 0;
  6219. }
  6220. int asCCompiler::CompileExpressionValue(asCScriptNode *node, asSExprContext *ctx)
  6221. {
  6222. // Shouldn't receive any byte code
  6223. asASSERT(ctx->bc.GetLastInstr() == -1);
  6224. asCScriptNode *vnode = node->firstChild;
  6225. ctx->exprNode = vnode;
  6226. if( vnode->nodeType == snVariableAccess )
  6227. {
  6228. // Determine the scope resolution of the variable
  6229. asCString scope = builder->GetScopeFromNode(vnode->firstChild, script, &vnode);
  6230. // Determine the name of the variable
  6231. asASSERT(vnode->nodeType == snIdentifier );
  6232. asCString name(&script->code[vnode->tokenPos], vnode->tokenLength);
  6233. return CompileVariableAccess(name, scope, ctx, node);
  6234. }
  6235. else if( vnode->nodeType == snConstant )
  6236. {
  6237. if( vnode->tokenType == ttIntConstant )
  6238. {
  6239. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  6240. asQWORD val = asStringScanUInt64(value.AddressOf(), 10, 0);
  6241. // Do we need 64 bits?
  6242. if( val>>32 )
  6243. {
  6244. // Only if the value uses the last bit of a 64bit word do we consider the number unsigned
  6245. if( val>>63 )
  6246. ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), val);
  6247. else
  6248. ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), val);
  6249. }
  6250. else
  6251. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), asDWORD(val));
  6252. }
  6253. else if( vnode->tokenType == ttBitsConstant )
  6254. {
  6255. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  6256. // Let the function determine the radix from the prefix 0x = 16, 0d = 10, 0o = 8, or 0b = 2
  6257. // TODO: Check for overflow
  6258. asQWORD val = asStringScanUInt64(value.AddressOf(), 0, 0);
  6259. // Do we need 64 bits?
  6260. if( val>>32 )
  6261. ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), val);
  6262. else
  6263. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), asDWORD(val));
  6264. }
  6265. else if( vnode->tokenType == ttFloatConstant )
  6266. {
  6267. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  6268. // TODO: Check for overflow
  6269. size_t numScanned;
  6270. float v = float(asStringScanDouble(value.AddressOf(), &numScanned));
  6271. ctx->type.SetConstantF(asCDataType::CreatePrimitive(ttFloat, true), v);
  6272. #ifndef AS_USE_DOUBLE_AS_FLOAT
  6273. // Don't check this if we have double as float, because then the whole token would be scanned (i.e. no f suffix)
  6274. asASSERT(numScanned == vnode->tokenLength - 1);
  6275. #endif
  6276. }
  6277. else if( vnode->tokenType == ttDoubleConstant )
  6278. {
  6279. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  6280. // TODO: Check for overflow
  6281. size_t numScanned;
  6282. double v = asStringScanDouble(value.AddressOf(), &numScanned);
  6283. ctx->type.SetConstantD(asCDataType::CreatePrimitive(ttDouble, true), v);
  6284. asASSERT(numScanned == vnode->tokenLength);
  6285. }
  6286. else if( vnode->tokenType == ttTrue ||
  6287. vnode->tokenType == ttFalse )
  6288. {
  6289. #if AS_SIZEOF_BOOL == 1
  6290. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), vnode->tokenType == ttTrue ? VALUE_OF_BOOLEAN_TRUE : 0);
  6291. #else
  6292. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), vnode->tokenType == ttTrue ? VALUE_OF_BOOLEAN_TRUE : 0);
  6293. #endif
  6294. }
  6295. else if( vnode->tokenType == ttStringConstant ||
  6296. vnode->tokenType == ttMultilineStringConstant ||
  6297. vnode->tokenType == ttHeredocStringConstant )
  6298. {
  6299. asCString str;
  6300. asCScriptNode *snode = vnode->firstChild;
  6301. if( script->code[snode->tokenPos] == '\'' && engine->ep.useCharacterLiterals )
  6302. {
  6303. // Treat the single quoted string as a single character literal
  6304. str.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2);
  6305. asDWORD val = 0;
  6306. if( str.GetLength() && (unsigned char)str[0] > 127 && engine->ep.scanner == 1 )
  6307. {
  6308. // This is the start of a UTF8 encoded character. We need to decode it
  6309. val = asStringDecodeUTF8(str.AddressOf(), 0);
  6310. if( val == (asDWORD)-1 )
  6311. Error(TXT_INVALID_CHAR_LITERAL, vnode);
  6312. }
  6313. else
  6314. {
  6315. val = ProcessStringConstant(str, snode);
  6316. if( val == (asDWORD)-1 )
  6317. Error(TXT_INVALID_CHAR_LITERAL, vnode);
  6318. }
  6319. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), val);
  6320. }
  6321. else
  6322. {
  6323. // Process the string constants
  6324. while( snode )
  6325. {
  6326. asCString cat;
  6327. if( snode->tokenType == ttStringConstant )
  6328. {
  6329. cat.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2);
  6330. ProcessStringConstant(cat, snode);
  6331. }
  6332. else if( snode->tokenType == ttMultilineStringConstant )
  6333. {
  6334. if( !engine->ep.allowMultilineStrings )
  6335. Error(TXT_MULTILINE_STRINGS_NOT_ALLOWED, snode);
  6336. cat.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2);
  6337. ProcessStringConstant(cat, snode);
  6338. }
  6339. else if( snode->tokenType == ttHeredocStringConstant )
  6340. {
  6341. cat.Assign(&script->code[snode->tokenPos+3], snode->tokenLength-6);
  6342. ProcessHeredocStringConstant(cat, snode);
  6343. }
  6344. str += cat;
  6345. snode = snode->next;
  6346. }
  6347. // Call the string factory function to create a string object
  6348. asCScriptFunction *descr = engine->stringFactory;
  6349. if( descr == 0 )
  6350. {
  6351. // Error
  6352. Error(TXT_STRINGS_NOT_RECOGNIZED, vnode);
  6353. // Give dummy value
  6354. ctx->type.SetDummy();
  6355. return -1;
  6356. }
  6357. else
  6358. {
  6359. // Register the constant string with the engine
  6360. int id = engine->AddConstantString(str.AddressOf(), str.GetLength());
  6361. ctx->bc.InstrWORD(asBC_STR, (asWORD)id);
  6362. bool useVariable = false;
  6363. int stackOffset = 0;
  6364. if( descr->DoesReturnOnStack() )
  6365. {
  6366. useVariable = true;
  6367. stackOffset = AllocateVariable(descr->returnType, true);
  6368. ctx->bc.InstrSHORT(asBC_PSF, short(stackOffset));
  6369. }
  6370. PerformFunctionCall(descr->id, ctx, false, 0, 0, useVariable, stackOffset);
  6371. }
  6372. }
  6373. }
  6374. else if( vnode->tokenType == ttNull )
  6375. {
  6376. ctx->bc.Instr(asBC_PshNull);
  6377. ctx->type.SetNullConstant();
  6378. }
  6379. else
  6380. asASSERT(false);
  6381. }
  6382. else if( vnode->nodeType == snFunctionCall )
  6383. {
  6384. // Determine the scope resolution
  6385. asCString scope = builder->GetScopeFromNode(vnode->firstChild, script);
  6386. return CompileFunctionCall(vnode, ctx, 0, false, scope);
  6387. }
  6388. else if( vnode->nodeType == snConstructCall )
  6389. {
  6390. CompileConstructCall(vnode, ctx);
  6391. }
  6392. else if( vnode->nodeType == snAssignment )
  6393. {
  6394. asSExprContext e(engine);
  6395. int r = CompileAssignment(vnode, &e);
  6396. if( r < 0 )
  6397. {
  6398. ctx->type.SetDummy();
  6399. return r;
  6400. }
  6401. MergeExprBytecodeAndType(ctx, &e);
  6402. }
  6403. else if( vnode->nodeType == snCast )
  6404. {
  6405. // Implement the cast operator
  6406. CompileConversion(vnode, ctx);
  6407. }
  6408. else
  6409. asASSERT(false);
  6410. return 0;
  6411. }
  6412. asUINT asCCompiler::ProcessStringConstant(asCString &cstr, asCScriptNode *node, bool processEscapeSequences)
  6413. {
  6414. int charLiteral = -1;
  6415. // Process escape sequences
  6416. asCArray<char> str((int)cstr.GetLength());
  6417. for( asUINT n = 0; n < cstr.GetLength(); n++ )
  6418. {
  6419. #ifdef AS_DOUBLEBYTE_CHARSET
  6420. // Double-byte charset is only allowed for ASCII and not UTF16 encoded strings
  6421. if( (cstr[n] & 0x80) && engine->ep.scanner == 0 && engine->ep.stringEncoding != 1 )
  6422. {
  6423. // This is the lead character of a double byte character
  6424. // include the trail character without checking it's value.
  6425. str.PushLast(cstr[n]);
  6426. n++;
  6427. str.PushLast(cstr[n]);
  6428. continue;
  6429. }
  6430. #endif
  6431. asUINT val;
  6432. if( processEscapeSequences && cstr[n] == '\\' )
  6433. {
  6434. ++n;
  6435. if( n == cstr.GetLength() )
  6436. {
  6437. if( charLiteral == -1 ) charLiteral = 0;
  6438. return charLiteral;
  6439. }
  6440. // Hexadecimal escape sequences will allow the construction of
  6441. // invalid unicode sequences, but the string should also work as
  6442. // a bytearray so we must support this. The code for working with
  6443. // unicode text must be prepared to handle invalid unicode sequences
  6444. if( cstr[n] == 'x' || cstr[n] == 'X' )
  6445. {
  6446. ++n;
  6447. if( n == cstr.GetLength() ) break;
  6448. val = 0;
  6449. int c = engine->ep.stringEncoding == 1 ? 4 : 2;
  6450. for( ; c > 0 && n < cstr.GetLength(); c--, n++ )
  6451. {
  6452. if( cstr[n] >= '0' && cstr[n] <= '9' )
  6453. val = val*16 + cstr[n] - '0';
  6454. else if( cstr[n] >= 'a' && cstr[n] <= 'f' )
  6455. val = val*16 + cstr[n] - 'a' + 10;
  6456. else if( cstr[n] >= 'A' && cstr[n] <= 'F' )
  6457. val = val*16 + cstr[n] - 'A' + 10;
  6458. else
  6459. break;
  6460. }
  6461. // Rewind one, since the loop will increment it again
  6462. n--;
  6463. // Hexadecimal escape sequences produce exact value, even if it is not proper unicode chars
  6464. if( engine->ep.stringEncoding == 0 )
  6465. {
  6466. str.PushLast((asBYTE)val);
  6467. }
  6468. else
  6469. {
  6470. #ifndef AS_BIG_ENDIAN
  6471. str.PushLast((asBYTE)val);
  6472. str.PushLast((asBYTE)(val>>8));
  6473. #else
  6474. str.PushLast((asBYTE)(val>>8));
  6475. str.PushLast((asBYTE)val);
  6476. #endif
  6477. }
  6478. if( charLiteral == -1 ) charLiteral = val;
  6479. continue;
  6480. }
  6481. else if( cstr[n] == 'u' || cstr[n] == 'U' )
  6482. {
  6483. // \u expects 4 hex digits
  6484. // \U expects 8 hex digits
  6485. bool expect2 = cstr[n] == 'u';
  6486. int c = expect2 ? 4 : 8;
  6487. val = 0;
  6488. for( ; c > 0; c-- )
  6489. {
  6490. ++n;
  6491. if( n == cstr.GetLength() ) break;
  6492. if( cstr[n] >= '0' && cstr[n] <= '9' )
  6493. val = val*16 + cstr[n] - '0';
  6494. else if( cstr[n] >= 'a' && cstr[n] <= 'f' )
  6495. val = val*16 + cstr[n] - 'a' + 10;
  6496. else if( cstr[n] >= 'A' && cstr[n] <= 'F' )
  6497. val = val*16 + cstr[n] - 'A' + 10;
  6498. else
  6499. break;
  6500. }
  6501. if( c != 0 )
  6502. {
  6503. // Give warning about invalid code point
  6504. // TODO: Need code position for warning
  6505. asCString msg;
  6506. msg.Format(TXT_INVALID_UNICODE_FORMAT_EXPECTED_d, expect2 ? 4 : 8);
  6507. Warning(msg, node);
  6508. continue;
  6509. }
  6510. }
  6511. else
  6512. {
  6513. if( cstr[n] == '"' )
  6514. val = '"';
  6515. else if( cstr[n] == '\'' )
  6516. val = '\'';
  6517. else if( cstr[n] == 'n' )
  6518. val = '\n';
  6519. else if( cstr[n] == 'r' )
  6520. val = '\r';
  6521. else if( cstr[n] == 't' )
  6522. val = '\t';
  6523. else if( cstr[n] == '0' )
  6524. val = '\0';
  6525. else if( cstr[n] == '\\' )
  6526. val = '\\';
  6527. else
  6528. {
  6529. // Invalid escape sequence
  6530. Warning(TXT_INVALID_ESCAPE_SEQUENCE, node);
  6531. continue;
  6532. }
  6533. }
  6534. }
  6535. else
  6536. {
  6537. if( engine->ep.scanner == 1 && (cstr[n] & 0x80) )
  6538. {
  6539. unsigned int len;
  6540. val = asStringDecodeUTF8(&cstr[n], &len);
  6541. if( val == 0xFFFFFFFF )
  6542. {
  6543. // Incorrect UTF8 encoding. Use only the first byte
  6544. // TODO: Need code position for warning
  6545. Warning(TXT_INVALID_UNICODE_SEQUENCE_IN_SRC, node);
  6546. val = (unsigned char)cstr[n];
  6547. }
  6548. else
  6549. n += len-1;
  6550. }
  6551. else
  6552. val = (unsigned char)cstr[n];
  6553. }
  6554. // Add the character to the final string
  6555. char encodedValue[5];
  6556. int len;
  6557. if( engine->ep.scanner == 1 && engine->ep.stringEncoding == 0 )
  6558. {
  6559. // Convert to UTF8 encoded
  6560. len = asStringEncodeUTF8(val, encodedValue);
  6561. }
  6562. else if( engine->ep.stringEncoding == 1 )
  6563. {
  6564. // Convert to 16bit wide character string (even if the script is scanned as ASCII)
  6565. len = asStringEncodeUTF16(val, encodedValue);
  6566. }
  6567. else
  6568. {
  6569. // Do not convert ASCII characters
  6570. encodedValue[0] = (asBYTE)val;
  6571. len = 1;
  6572. }
  6573. if( len < 0 )
  6574. {
  6575. // Give warning about invalid code point
  6576. // TODO: Need code position for warning
  6577. Warning(TXT_INVALID_UNICODE_VALUE, node);
  6578. }
  6579. else
  6580. {
  6581. // Add the encoded value to the final string
  6582. str.Concatenate(encodedValue, len);
  6583. if( charLiteral == -1 ) charLiteral = val;
  6584. }
  6585. }
  6586. cstr.Assign(str.AddressOf(), str.GetLength());
  6587. return charLiteral;
  6588. }
  6589. void asCCompiler::ProcessHeredocStringConstant(asCString &str, asCScriptNode *node)
  6590. {
  6591. // Remove first line if it only contains whitespace
  6592. int start;
  6593. for( start = 0; start < (int)str.GetLength(); start++ )
  6594. {
  6595. if( str[start] == '\n' )
  6596. {
  6597. // Remove the linebreak as well
  6598. start++;
  6599. break;
  6600. }
  6601. if( str[start] != ' ' &&
  6602. str[start] != '\t' &&
  6603. str[start] != '\r' )
  6604. {
  6605. // Don't remove anything
  6606. start = 0;
  6607. break;
  6608. }
  6609. }
  6610. // Remove the line after the last line break if it only contains whitespaces
  6611. int end;
  6612. for( end = (int)str.GetLength() - 1; end >= 0; end-- )
  6613. {
  6614. if( str[end] == '\n' )
  6615. {
  6616. // Don't remove the last line break
  6617. end++;
  6618. break;
  6619. }
  6620. if( str[end] != ' ' &&
  6621. str[end] != '\t' &&
  6622. str[end] != '\r' )
  6623. {
  6624. // Don't remove anything
  6625. end = (int)str.GetLength();
  6626. break;
  6627. }
  6628. }
  6629. if( end < 0 ) end = 0;
  6630. asCString tmp;
  6631. if( end > start )
  6632. tmp.Assign(&str[start], end-start);
  6633. ProcessStringConstant(tmp, node, false);
  6634. str = tmp;
  6635. }
  6636. void asCCompiler::CompileConversion(asCScriptNode *node, asSExprContext *ctx)
  6637. {
  6638. asSExprContext expr(engine);
  6639. asCDataType to;
  6640. bool anyErrors = false;
  6641. EImplicitConv convType;
  6642. if( node->nodeType == snConstructCall )
  6643. {
  6644. convType = asIC_EXPLICIT_VAL_CAST;
  6645. // Verify that there is only one argument
  6646. if( node->lastChild->firstChild == 0 ||
  6647. node->lastChild->firstChild != node->lastChild->lastChild )
  6648. {
  6649. Error(TXT_ONLY_ONE_ARGUMENT_IN_CAST, node->lastChild);
  6650. expr.type.SetDummy();
  6651. anyErrors = true;
  6652. }
  6653. else
  6654. {
  6655. // Compile the expression
  6656. int r = CompileAssignment(node->lastChild->firstChild, &expr);
  6657. if( r < 0 )
  6658. anyErrors = true;
  6659. }
  6660. // Determine the requested type
  6661. to = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace);
  6662. to.MakeReadOnly(true); // Default to const
  6663. asASSERT(to.IsPrimitive());
  6664. }
  6665. else
  6666. {
  6667. convType = asIC_EXPLICIT_REF_CAST;
  6668. // Compile the expression
  6669. int r = CompileAssignment(node->lastChild, &expr);
  6670. if( r < 0 )
  6671. anyErrors = true;
  6672. // Determine the requested type
  6673. to = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace);
  6674. to = builder->ModifyDataTypeFromNode(to, node->firstChild->next, script, 0, 0);
  6675. // If the type support object handles, then use it
  6676. if( to.SupportHandles() )
  6677. {
  6678. to.MakeHandle(true);
  6679. }
  6680. else if( !to.IsObjectHandle() )
  6681. {
  6682. // The cast<type> operator can only be used for reference casts
  6683. Error(TXT_ILLEGAL_TARGET_TYPE_FOR_REF_CAST, node->firstChild);
  6684. anyErrors = true;
  6685. }
  6686. }
  6687. // Do not allow casting to non shared type if we're compiling a shared method
  6688. if( outFunc->IsShared() &&
  6689. to.GetObjectType() && !to.GetObjectType()->IsShared() )
  6690. {
  6691. asCString msg;
  6692. msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, to.GetObjectType()->name.AddressOf());
  6693. Error(msg, node);
  6694. anyErrors = true;
  6695. }
  6696. if( anyErrors )
  6697. {
  6698. // Assume that the error can be fixed and allow the compilation to continue
  6699. ctx->type.SetConstantDW(to, 0);
  6700. return;
  6701. }
  6702. ProcessPropertyGetAccessor(&expr, node);
  6703. // Don't allow any operators on expressions that take address of class method
  6704. if( expr.methodName != "" )
  6705. {
  6706. Error(TXT_INVALID_OP_ON_METHOD, node);
  6707. return;
  6708. }
  6709. // We don't want a reference
  6710. if( expr.type.dataType.IsReference() )
  6711. {
  6712. if( expr.type.dataType.IsObject() )
  6713. Dereference(&expr, true);
  6714. else
  6715. ConvertToVariable(&expr);
  6716. }
  6717. ImplicitConversion(&expr, to, node, convType);
  6718. IsVariableInitialized(&expr.type, node);
  6719. // If no type conversion is really tried ignore it
  6720. if( to == expr.type.dataType )
  6721. {
  6722. // This will keep information about constant type
  6723. MergeExprBytecode(ctx, &expr);
  6724. ctx->type = expr.type;
  6725. return;
  6726. }
  6727. if( to.IsEqualExceptConst(expr.type.dataType) && to.IsPrimitive() )
  6728. {
  6729. MergeExprBytecode(ctx, &expr);
  6730. ctx->type = expr.type;
  6731. ctx->type.dataType.MakeReadOnly(true);
  6732. return;
  6733. }
  6734. // The implicit conversion already does most of the conversions permitted,
  6735. // here we'll only treat those conversions that require an explicit cast.
  6736. bool conversionOK = false;
  6737. if( !expr.type.isConstant )
  6738. {
  6739. if( !expr.type.dataType.IsObject() )
  6740. ConvertToTempVariable(&expr);
  6741. if( to.IsObjectHandle() &&
  6742. expr.type.dataType.IsObjectHandle() &&
  6743. !(!to.IsHandleToConst() && expr.type.dataType.IsHandleToConst()) )
  6744. {
  6745. conversionOK = CompileRefCast(&expr, to, true, node);
  6746. MergeExprBytecode(ctx, &expr);
  6747. ctx->type = expr.type;
  6748. }
  6749. }
  6750. if( conversionOK )
  6751. return;
  6752. // Conversion not available
  6753. ctx->type.SetDummy();
  6754. asCString strTo, strFrom;
  6755. strTo = to.Format();
  6756. strFrom = expr.type.dataType.Format();
  6757. asCString msg;
  6758. msg.Format(TXT_NO_CONVERSION_s_TO_s, strFrom.AddressOf(), strTo.AddressOf());
  6759. Error(msg, node);
  6760. }
  6761. void asCCompiler::AfterFunctionCall(int funcID, asCArray<asSExprContext*> &args, asSExprContext *ctx, bool deferAll)
  6762. {
  6763. asCScriptFunction *descr = builder->GetFunctionDescription(funcID);
  6764. // Parameters that are sent by reference should be assigned
  6765. // to the evaluated expression if it is an lvalue
  6766. // Evaluate the arguments from last to first
  6767. int n = (int)descr->parameterTypes.GetLength() - 1;
  6768. for( ; n >= 0; n-- )
  6769. {
  6770. if( (descr->parameterTypes[n].IsReference() && (descr->inOutFlags[n] & asTM_OUTREF)) ||
  6771. (descr->parameterTypes[n].IsObject() && deferAll) )
  6772. {
  6773. asASSERT( !(descr->parameterTypes[n].IsReference() && (descr->inOutFlags[n] == asTM_OUTREF)) || args[n]->origExpr );
  6774. // For &inout, only store the argument if it is for a temporary variable
  6775. if( engine->ep.allowUnsafeReferences ||
  6776. descr->inOutFlags[n] != asTM_INOUTREF || args[n]->type.isTemporary )
  6777. {
  6778. // Store the argument for later processing
  6779. asSDeferredParam outParam;
  6780. outParam.argNode = args[n]->exprNode;
  6781. outParam.argType = args[n]->type;
  6782. outParam.argInOutFlags = descr->inOutFlags[n];
  6783. outParam.origExpr = args[n]->origExpr;
  6784. ctx->deferredParams.PushLast(outParam);
  6785. }
  6786. }
  6787. else
  6788. {
  6789. // Release the temporary variable now
  6790. ReleaseTemporaryVariable(args[n]->type, &ctx->bc);
  6791. }
  6792. // Move the argument's deferred expressions over to the final expression
  6793. for( asUINT m = 0; m < args[n]->deferredParams.GetLength(); m++ )
  6794. {
  6795. ctx->deferredParams.PushLast(args[n]->deferredParams[m]);
  6796. args[n]->deferredParams[m].origExpr = 0;
  6797. }
  6798. args[n]->deferredParams.SetLength(0);
  6799. }
  6800. }
  6801. void asCCompiler::ProcessDeferredParams(asSExprContext *ctx)
  6802. {
  6803. if( isProcessingDeferredParams ) return;
  6804. isProcessingDeferredParams = true;
  6805. for( asUINT n = 0; n < ctx->deferredParams.GetLength(); n++ )
  6806. {
  6807. asSDeferredParam outParam = ctx->deferredParams[n];
  6808. if( outParam.argInOutFlags < asTM_OUTREF ) // &in, or not reference
  6809. {
  6810. // Just release the variable
  6811. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  6812. }
  6813. else if( outParam.argInOutFlags == asTM_OUTREF )
  6814. {
  6815. asSExprContext *expr = outParam.origExpr;
  6816. outParam.origExpr = 0;
  6817. if( outParam.argType.dataType.IsObjectHandle() )
  6818. {
  6819. // Implicitly convert the value to a handle
  6820. if( expr->type.dataType.IsObjectHandle() )
  6821. expr->type.isExplicitHandle = true;
  6822. }
  6823. // Verify that the expression result in a lvalue, or a property accessor
  6824. if( IsLValue(expr->type) || expr->property_get || expr->property_set )
  6825. {
  6826. asSExprContext rctx(engine);
  6827. rctx.type = outParam.argType;
  6828. if( rctx.type.dataType.IsPrimitive() )
  6829. rctx.type.dataType.MakeReference(false);
  6830. else
  6831. {
  6832. rctx.bc.InstrSHORT(asBC_PSF, outParam.argType.stackOffset);
  6833. rctx.type.dataType.MakeReference(IsVariableOnHeap(outParam.argType.stackOffset));
  6834. if( expr->type.isExplicitHandle )
  6835. rctx.type.isExplicitHandle = true;
  6836. }
  6837. asSExprContext o(engine);
  6838. DoAssignment(&o, expr, &rctx, outParam.argNode, outParam.argNode, ttAssignment, outParam.argNode);
  6839. if( !o.type.dataType.IsPrimitive() ) o.bc.Instr(asBC_PopPtr);
  6840. // The assignment may itself have resulted in a new temporary variable, e.g. if
  6841. // the opAssign returns a non-reference. We must release this temporary variable
  6842. // since it won't be used
  6843. ReleaseTemporaryVariable(o.type, &o.bc);
  6844. MergeExprBytecode(ctx, &o);
  6845. }
  6846. else
  6847. {
  6848. // We must still evaluate the expression
  6849. MergeExprBytecode(ctx, expr);
  6850. if( !expr->type.isConstant || expr->type.IsNullConstant() )
  6851. ctx->bc.Instr(asBC_PopPtr);
  6852. // Give a warning, except if the argument is null or 0 which indicate the argument is really to be ignored
  6853. if( !expr->type.IsNullConstant() && !(expr->type.isConstant && expr->type.qwordValue == 0) )
  6854. Warning(TXT_ARG_NOT_LVALUE, outParam.argNode);
  6855. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  6856. }
  6857. ReleaseTemporaryVariable(expr->type, &ctx->bc);
  6858. // Delete the original expression context
  6859. asDELETE(expr,asSExprContext);
  6860. }
  6861. else // &inout
  6862. {
  6863. if( outParam.argType.isTemporary )
  6864. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  6865. else if( !outParam.argType.isVariable )
  6866. {
  6867. if( outParam.argType.dataType.IsObject() &&
  6868. ((outParam.argType.dataType.GetBehaviour()->addref &&
  6869. outParam.argType.dataType.GetBehaviour()->release) ||
  6870. (outParam.argType.dataType.GetObjectType()->flags & asOBJ_NOCOUNT)) )
  6871. {
  6872. // Release the object handle that was taken to guarantee the reference
  6873. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  6874. }
  6875. }
  6876. }
  6877. }
  6878. ctx->deferredParams.SetLength(0);
  6879. isProcessingDeferredParams = false;
  6880. }
  6881. void asCCompiler::CompileConstructCall(asCScriptNode *node, asSExprContext *ctx)
  6882. {
  6883. // The first node is a datatype node
  6884. asCString name;
  6885. asCTypeInfo tempObj;
  6886. bool onHeap = true;
  6887. asCArray<int> funcs;
  6888. // It is possible that the name is really a constructor
  6889. asCDataType dt;
  6890. dt = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace);
  6891. if( dt.IsPrimitive() )
  6892. {
  6893. // This is a cast to a primitive type
  6894. CompileConversion(node, ctx);
  6895. return;
  6896. }
  6897. // Do not allow constructing non-shared types in shared functions
  6898. if( outFunc->IsShared() &&
  6899. dt.GetObjectType() && !dt.GetObjectType()->IsShared() )
  6900. {
  6901. asCString msg;
  6902. msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, dt.GetObjectType()->name.AddressOf());
  6903. Error(msg, node);
  6904. }
  6905. // Compile the arguments
  6906. asCArray<asSExprContext *> args;
  6907. asCArray<asCTypeInfo> temporaryVariables;
  6908. if( CompileArgumentList(node->lastChild, args) >= 0 )
  6909. {
  6910. // Check for a value cast behaviour
  6911. if( args.GetLength() == 1 && args[0]->type.dataType.GetObjectType() )
  6912. {
  6913. asSExprContext conv(engine);
  6914. conv.type = args[0]->type;
  6915. ImplicitConversion(&conv, dt, node->lastChild, asIC_EXPLICIT_VAL_CAST, false);
  6916. if( conv.type.dataType.IsEqualExceptRef(dt) )
  6917. {
  6918. ImplicitConversion(args[0], dt, node->lastChild, asIC_EXPLICIT_VAL_CAST);
  6919. ctx->bc.AddCode(&args[0]->bc);
  6920. ctx->type = args[0]->type;
  6921. asDELETE(args[0],asSExprContext);
  6922. return;
  6923. }
  6924. }
  6925. // Check for possible constructor/factory
  6926. name = dt.Format();
  6927. asSTypeBehaviour *beh = dt.GetBehaviour();
  6928. if( !(dt.GetObjectType()->flags & asOBJ_REF) )
  6929. {
  6930. funcs = beh->constructors;
  6931. // Value types and script types are allocated through the constructor
  6932. tempObj.dataType = dt;
  6933. tempObj.stackOffset = (short)AllocateVariable(dt, true);
  6934. tempObj.dataType.MakeReference(true);
  6935. tempObj.isTemporary = true;
  6936. tempObj.isVariable = true;
  6937. onHeap = IsVariableOnHeap(tempObj.stackOffset);
  6938. // Push the address of the object on the stack
  6939. if( onHeap )
  6940. ctx->bc.InstrSHORT(asBC_VAR, tempObj.stackOffset);
  6941. }
  6942. else
  6943. {
  6944. funcs = beh->factories;
  6945. }
  6946. // Special case: Allow calling func(void) with a void expression.
  6947. if( args.GetLength() == 1 && args[0]->type.dataType == asCDataType::CreatePrimitive(ttVoid, false) )
  6948. {
  6949. // Evaluate the expression before the function call
  6950. MergeExprBytecode(ctx, args[0]);
  6951. asDELETE(args[0],asSExprContext);
  6952. args.SetLength(0);
  6953. }
  6954. // Special case: If this is an object constructor and there are no arguments use the default constructor.
  6955. // If none has been registered, just allocate the variable and push it on the stack.
  6956. if( args.GetLength() == 0 )
  6957. {
  6958. asSTypeBehaviour *beh = tempObj.dataType.GetBehaviour();
  6959. if( beh && beh->construct == 0 && !(dt.GetObjectType()->flags & asOBJ_REF) )
  6960. {
  6961. // Call the default constructor
  6962. ctx->type = tempObj;
  6963. if( onHeap )
  6964. {
  6965. asASSERT(ctx->bc.GetLastInstr() == asBC_VAR);
  6966. ctx->bc.RemoveLastInstr();
  6967. }
  6968. CallDefaultConstructor(tempObj.dataType, tempObj.stackOffset, IsVariableOnHeap(tempObj.stackOffset), &ctx->bc, node);
  6969. // Push the reference on the stack
  6970. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  6971. return;
  6972. }
  6973. }
  6974. // Special case: If this is a construction of a delegate and the expression names an object method
  6975. if( dt.GetFuncDef() && args.GetLength() == 1 && args[0]->methodName != "" )
  6976. {
  6977. // TODO: delegate: It is possible that the argument returns a function pointer already, in which
  6978. // case no object delegate will be created, but instead a delegate for a function pointer
  6979. // In theory a simple cast would be good in this case, but this is a construct call so it
  6980. // is expected that a new object is created.
  6981. dt.MakeHandle(true);
  6982. ctx->type.Set(dt);
  6983. // The delegate must be able to hold on to a reference to the object
  6984. if( !args[0]->type.dataType.SupportHandles() )
  6985. Error(TXT_CANNOT_CREATE_DELEGATE_FOR_NOREF_TYPES, node);
  6986. else
  6987. {
  6988. // Filter the available object methods to find the one that matches the func def
  6989. asCObjectType *type = args[0]->type.dataType.GetObjectType();
  6990. asCScriptFunction *bestMethod = 0;
  6991. for( asUINT n = 0; n < type->methods.GetLength(); n++ )
  6992. {
  6993. asCScriptFunction *func = engine->scriptFunctions[type->methods[n]];
  6994. if( func->name != args[0]->methodName )
  6995. continue;
  6996. // If the expression is for a const object, then only const methods should be accepted
  6997. if( args[0]->type.dataType.IsReadOnly() && !func->IsReadOnly() )
  6998. continue;
  6999. if( func->IsSignatureExceptNameAndObjectTypeEqual(dt.GetFuncDef()) )
  7000. {
  7001. bestMethod = func;
  7002. // If the expression is non-const the non-const overloaded method has priority
  7003. if( args[0]->type.dataType.IsReadOnly() == func->IsReadOnly() )
  7004. break;
  7005. }
  7006. }
  7007. if( bestMethod )
  7008. {
  7009. // The object pointer is already on the stack
  7010. MergeExprBytecode(ctx, args[0]);
  7011. // Push the function pointer as an additional argument
  7012. ctx->bc.InstrPTR(asBC_FuncPtr, bestMethod);
  7013. // Call the factory function for the delegate
  7014. asCArray<int> funcs;
  7015. builder->GetFunctionDescriptions(DELEGATE_FACTORY, funcs, engine->nameSpaces[0]);
  7016. asASSERT( funcs.GetLength() == 1 );
  7017. ctx->bc.Call(asBC_CALLSYS , funcs[0], 2*AS_PTR_SIZE);
  7018. // Store the returned delegate in a temporary variable
  7019. int returnOffset = AllocateVariable(dt, true, false);
  7020. dt.MakeReference(true);
  7021. ctx->type.SetVariable(dt, returnOffset, true);
  7022. ctx->bc.InstrSHORT(asBC_STOREOBJ, (short)returnOffset);
  7023. // Push a reference to the temporary variable on the stack
  7024. ctx->bc.InstrSHORT(asBC_PSF, (short)returnOffset);
  7025. }
  7026. else
  7027. {
  7028. asCString msg;
  7029. msg.Format(TXT_NO_MATCHING_SIGNATURES_TO_s, dt.GetFuncDef()->GetDeclaration());
  7030. Error(msg.AddressOf(), node);
  7031. }
  7032. }
  7033. // Clean-up arg
  7034. asDELETE(args[0],asSExprContext);
  7035. return;
  7036. }
  7037. MatchFunctions(funcs, args, node, name.AddressOf(), NULL, false);
  7038. if( funcs.GetLength() != 1 )
  7039. {
  7040. // The error was reported by MatchFunctions()
  7041. // Dummy value
  7042. ctx->type.SetDummy();
  7043. }
  7044. else
  7045. {
  7046. int r = asSUCCESS;
  7047. // Add the default values for arguments not explicitly supplied
  7048. asCScriptFunction *func = (funcs[0] & FUNC_IMPORTED) == 0 ? engine->scriptFunctions[funcs[0]] : 0;
  7049. if( func && args.GetLength() < (asUINT)func->GetParamCount() )
  7050. r = CompileDefaultArgs(node, args, func);
  7051. if( r == asSUCCESS )
  7052. {
  7053. asCByteCode objBC(engine);
  7054. PrepareFunctionCall(funcs[0], &ctx->bc, args);
  7055. MoveArgsToStack(funcs[0], &ctx->bc, args, false);
  7056. if( !(dt.GetObjectType()->flags & asOBJ_REF) )
  7057. {
  7058. // If the object is allocated on the stack, then call the constructor as a normal function
  7059. if( onHeap )
  7060. {
  7061. int offset = 0;
  7062. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]);
  7063. for( asUINT n = 0; n < args.GetLength(); n++ )
  7064. offset += descr->parameterTypes[n].GetSizeOnStackDWords();
  7065. ctx->bc.InstrWORD(asBC_GETREF, (asWORD)offset);
  7066. }
  7067. else
  7068. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  7069. PerformFunctionCall(funcs[0], ctx, onHeap, &args, tempObj.dataType.GetObjectType());
  7070. // Add tag that the object has been initialized
  7071. ctx->bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT);
  7072. // The constructor doesn't return anything,
  7073. // so we have to manually inform the type of
  7074. // the return value
  7075. ctx->type = tempObj;
  7076. if( !onHeap )
  7077. ctx->type.dataType.MakeReference(false);
  7078. // Push the address of the object on the stack again
  7079. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  7080. }
  7081. else
  7082. {
  7083. // Call the factory to create the reference type
  7084. PerformFunctionCall(funcs[0], ctx, false, &args);
  7085. }
  7086. }
  7087. }
  7088. }
  7089. else
  7090. {
  7091. // Failed to compile the argument list, set the result to the dummy type
  7092. ctx->type.SetDummy();
  7093. }
  7094. // Cleanup
  7095. for( asUINT n = 0; n < args.GetLength(); n++ )
  7096. if( args[n] )
  7097. {
  7098. asDELETE(args[n],asSExprContext);
  7099. }
  7100. }
  7101. int asCCompiler::CompileFunctionCall(asCScriptNode *node, asSExprContext *ctx, asCObjectType *objectType, bool objIsConst, const asCString &scope)
  7102. {
  7103. asCString name;
  7104. asCTypeInfo tempObj;
  7105. asCArray<int> funcs;
  7106. int localVar = -1;
  7107. bool initializeMembers = false;
  7108. asCScriptNode *nm = node->lastChild->prev;
  7109. name.Assign(&script->code[nm->tokenPos], nm->tokenLength);
  7110. // First check for a local variable of a function type as it would take precedence
  7111. // Must not allow function names, nor global variables to be returned in this instance
  7112. // If objectType is set then this is a post op expression and we shouldn't look for local variables
  7113. asSExprContext funcPtr(engine);
  7114. if( objectType == 0 )
  7115. {
  7116. localVar = CompileVariableAccess(name, scope, &funcPtr, node, true, true, true);
  7117. if( localVar >= 0 && !funcPtr.type.dataType.GetFuncDef() && funcPtr.methodName == "" )
  7118. {
  7119. // The variable is not a function
  7120. asCString msg;
  7121. msg.Format(TXT_NOT_A_FUNC_s_IS_VAR, name.AddressOf());
  7122. Error(msg, node);
  7123. return -1;
  7124. }
  7125. // If the name matches a method name, then reset the indicator that nothing was found
  7126. if( funcPtr.methodName != "" )
  7127. localVar = -1;
  7128. }
  7129. if( localVar < 0 )
  7130. {
  7131. // If this is an expression post op, or if a class method is
  7132. // being compiled, then we should look for matching class methods
  7133. if( objectType || (outFunc && outFunc->objectType && scope != "::") )
  7134. {
  7135. // If we're compiling a constructor and the name of the function is super then
  7136. // the constructor of the base class is being called.
  7137. // super cannot be prefixed with a scope operator
  7138. if( scope == "" && m_isConstructor && name == SUPER_TOKEN )
  7139. {
  7140. // If the class is not derived from anyone else, calling super should give an error
  7141. if( outFunc && outFunc->objectType->derivedFrom )
  7142. funcs = outFunc->objectType->derivedFrom->beh.constructors;
  7143. // Must not allow calling base class' constructor multiple times
  7144. if( continueLabels.GetLength() > 0 )
  7145. {
  7146. // If a continue label is set we are in a loop
  7147. Error(TXT_CANNOT_CALL_CONSTRUCTOR_IN_LOOPS, node);
  7148. }
  7149. else if( breakLabels.GetLength() > 0 )
  7150. {
  7151. // TODO: inheritance: Should eventually allow constructors in switch statements
  7152. // If a break label is set we are either in a loop or a switch statements
  7153. Error(TXT_CANNOT_CALL_CONSTRUCTOR_IN_SWITCH, node);
  7154. }
  7155. else if( m_isConstructorCalled )
  7156. {
  7157. Error(TXT_CANNOT_CALL_CONSTRUCTOR_TWICE, node);
  7158. }
  7159. m_isConstructorCalled = true;
  7160. // We need to initialize the class members, but only after all the deferred arguments have been completed
  7161. initializeMembers = true;
  7162. }
  7163. else
  7164. {
  7165. // The scope is can be used to specify the base class
  7166. builder->GetObjectMethodDescriptions(name.AddressOf(), objectType ? objectType : outFunc->objectType, funcs, objIsConst, scope);
  7167. }
  7168. // It is still possible that there is a class member of a function type
  7169. if( funcs.GetLength() == 0 )
  7170. {
  7171. int r = CompileVariableAccess(name, scope, &funcPtr, node, true, true, true, objectType);
  7172. if( r >= 0 && !funcPtr.type.dataType.GetFuncDef() && funcPtr.methodName == "" )
  7173. {
  7174. // The variable is not a function
  7175. asCString msg;
  7176. msg.Format(TXT_NOT_A_FUNC_s_IS_VAR, name.AddressOf());
  7177. Error(msg, node);
  7178. return -1;
  7179. }
  7180. }
  7181. // If a class method is being called implicitly, then add the this pointer for the call
  7182. if( funcs.GetLength() && !objectType )
  7183. {
  7184. objectType = outFunc->objectType;
  7185. asCDataType dt = asCDataType::CreateObject(objectType, false);
  7186. // The object pointer is located at stack position 0
  7187. ctx->bc.InstrSHORT(asBC_PSF, 0);
  7188. ctx->type.SetVariable(dt, 0, false);
  7189. ctx->type.dataType.MakeReference(true);
  7190. Dereference(ctx, true);
  7191. }
  7192. }
  7193. // If it is not a class method or member function pointer,
  7194. // then look for global functions or global function pointers,
  7195. // unless this is an expression post op, incase only member
  7196. // functions are expected
  7197. if( objectType == 0 && funcs.GetLength() == 0 && funcPtr.type.dataType.GetFuncDef() == 0 )
  7198. {
  7199. // The scope is used to define the namespace
  7200. asSNameSpace *ns = DetermineNameSpace(scope);
  7201. if( ns )
  7202. {
  7203. builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns);
  7204. if( funcs.GetLength() == 0 )
  7205. {
  7206. int r = CompileVariableAccess(name, scope, &funcPtr, node, true, true);
  7207. if( r >= 0 && !funcPtr.type.dataType.GetFuncDef() )
  7208. {
  7209. // The variable is not a function
  7210. asCString msg;
  7211. msg.Format(TXT_NOT_A_FUNC_s_IS_VAR, name.AddressOf());
  7212. Error(msg, node);
  7213. return -1;
  7214. }
  7215. }
  7216. }
  7217. else
  7218. {
  7219. asCString msg;
  7220. msg.Format(TXT_NAMESPACE_s_DOESNT_EXIST, scope.AddressOf());
  7221. Error(msg, node);
  7222. return -1;
  7223. }
  7224. }
  7225. }
  7226. if( funcs.GetLength() == 0 && funcPtr.type.dataType.GetFuncDef() )
  7227. {
  7228. funcs.PushLast(funcPtr.type.dataType.GetFuncDef()->id);
  7229. }
  7230. // Compile the arguments
  7231. asCArray<asSExprContext *> args;
  7232. asCArray<asCTypeInfo> temporaryVariables;
  7233. if( CompileArgumentList(node->lastChild, args) >= 0 )
  7234. {
  7235. // Special case: Allow calling func(void) with a void expression.
  7236. if( args.GetLength() == 1 && args[0]->type.dataType == asCDataType::CreatePrimitive(ttVoid, false) )
  7237. {
  7238. // Evaluate the expression before the function call
  7239. MergeExprBytecode(ctx, args[0]);
  7240. asDELETE(args[0],asSExprContext);
  7241. args.SetLength(0);
  7242. }
  7243. MatchFunctions(funcs, args, node, name.AddressOf(), objectType, objIsConst, false, true, scope);
  7244. if( funcs.GetLength() != 1 )
  7245. {
  7246. // The error was reported by MatchFunctions()
  7247. // Dummy value
  7248. ctx->type.SetDummy();
  7249. }
  7250. else
  7251. {
  7252. int r = asSUCCESS;
  7253. // Add the default values for arguments not explicitly supplied
  7254. asCScriptFunction *func = builder->GetFunctionDescription(funcs[0]);
  7255. if( func && args.GetLength() < (asUINT)func->GetParamCount() )
  7256. r = CompileDefaultArgs(node, args, func);
  7257. // TODO: funcdef: Do we have to make sure the handle is stored in a temporary variable, or
  7258. // is it enough to make sure it is in a local variable?
  7259. // For function pointer we must guarantee that the function is safe, i.e.
  7260. // by first storing the function pointer in a local variable (if it isn't already in one)
  7261. if( r == asSUCCESS )
  7262. {
  7263. if( func->funcType == asFUNC_FUNCDEF )
  7264. {
  7265. if( objectType && funcPtr.property_get <= 0 )
  7266. {
  7267. Dereference(ctx, true); // Dereference the object pointer to access the member
  7268. // The actual function should be called as if a global function
  7269. objectType = 0;
  7270. }
  7271. if( funcPtr.property_get > 0 )
  7272. {
  7273. ProcessPropertyGetAccessor(&funcPtr, node);
  7274. Dereference(&funcPtr, true);
  7275. // The function call will be made directly from the local variable so the function pointer shouldn't be on the stack
  7276. funcPtr.bc.Instr(asBC_PopPtr);
  7277. }
  7278. else
  7279. {
  7280. Dereference(&funcPtr, true);
  7281. ConvertToVariable(&funcPtr);
  7282. // The function call will be made directly from the local variable so the function pointer shouldn't be on the stack
  7283. if( !funcPtr.type.isTemporary )
  7284. funcPtr.bc.Instr(asBC_PopPtr);
  7285. }
  7286. MergeExprBytecodeAndType(ctx, &funcPtr);
  7287. }
  7288. MakeFunctionCall(ctx, funcs[0], objectType, args, node, false, 0, funcPtr.type.stackOffset);
  7289. // If the function pointer was copied to a local variable for the call, then
  7290. // release it again (temporary local variable)
  7291. if( (funcs[0] & FUNC_IMPORTED) == 0 && engine->scriptFunctions[funcs[0]]->funcType == asFUNC_FUNCDEF )
  7292. {
  7293. ReleaseTemporaryVariable(funcPtr.type, &ctx->bc);
  7294. }
  7295. }
  7296. }
  7297. }
  7298. else
  7299. {
  7300. // Failed to compile the argument list, set the dummy type and continue compilation
  7301. ctx->type.SetDummy();
  7302. }
  7303. // Cleanup
  7304. for( asUINT n = 0; n < args.GetLength(); n++ )
  7305. if( args[n] )
  7306. {
  7307. asDELETE(args[n],asSExprContext);
  7308. }
  7309. if( initializeMembers )
  7310. {
  7311. asASSERT( m_isConstructor );
  7312. // Need to initialize members here, as they may use the properties of the base class
  7313. // If there are multiple paths that call super(), then there will also be multiple
  7314. // locations with initializations of the members. It is not possible to consolidate
  7315. // these in one place, as the expressions for the initialization are evaluated where
  7316. // they are compiled, which means that they may access different variables depending
  7317. // on the scope where super() is called.
  7318. // Members that don't have an explicit initialization expression will be initialized
  7319. // beginning of the constructor as they are guaranteed not to use at the any
  7320. // members of the base class.
  7321. CompileMemberInitialization(&ctx->bc, false);
  7322. }
  7323. return 0;
  7324. }
  7325. asSNameSpace *asCCompiler::DetermineNameSpace(const asCString &scope)
  7326. {
  7327. asSNameSpace *ns;
  7328. if( scope == "" )
  7329. {
  7330. if( outFunc->nameSpace->name != "" )
  7331. ns = outFunc->nameSpace;
  7332. else if( outFunc->objectType && outFunc->objectType->nameSpace->name != "" )
  7333. ns = outFunc->objectType->nameSpace;
  7334. else
  7335. ns = engine->nameSpaces[0];
  7336. }
  7337. else if( scope == "::" )
  7338. ns = engine->nameSpaces[0];
  7339. else
  7340. ns = engine->FindNameSpace(scope.AddressOf());
  7341. return ns;
  7342. }
  7343. int asCCompiler::CompileExpressionPreOp(asCScriptNode *node, asSExprContext *ctx)
  7344. {
  7345. int op = node->tokenType;
  7346. // Don't allow any prefix operators except handle on expressions that take address of class method
  7347. if( ctx->methodName != "" && op != ttHandle )
  7348. {
  7349. Error(TXT_INVALID_OP_ON_METHOD, node);
  7350. return -1;
  7351. }
  7352. IsVariableInitialized(&ctx->type, node);
  7353. if( op == ttHandle )
  7354. {
  7355. if( ctx->methodName != "" )
  7356. {
  7357. // Don't allow taking the handle of a handle
  7358. if( ctx->type.isExplicitHandle )
  7359. {
  7360. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node);
  7361. return -1;
  7362. }
  7363. }
  7364. else
  7365. {
  7366. // Verify that the type allow its handle to be taken
  7367. if( ctx->type.isExplicitHandle ||
  7368. !ctx->type.dataType.IsObject() ||
  7369. !(((ctx->type.dataType.GetObjectType()->beh.addref && ctx->type.dataType.GetObjectType()->beh.release) || (ctx->type.dataType.GetObjectType()->flags & asOBJ_NOCOUNT)) ||
  7370. (ctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE)) )
  7371. {
  7372. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node);
  7373. return -1;
  7374. }
  7375. // Objects that are not local variables are not references
  7376. // Objects allocated on the stack are also not marked as references
  7377. if( !ctx->type.dataType.IsReference() &&
  7378. !(ctx->type.dataType.IsObject() && !ctx->type.isVariable) &&
  7379. !(ctx->type.isVariable && !IsVariableOnHeap(ctx->type.stackOffset)) )
  7380. {
  7381. Error(TXT_NOT_VALID_REFERENCE, node);
  7382. return -1;
  7383. }
  7384. // Convert the expression to a handle
  7385. if( !ctx->type.dataType.IsObjectHandle() && !(ctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE) )
  7386. {
  7387. asCDataType to = ctx->type.dataType;
  7388. to.MakeHandle(true);
  7389. to.MakeReference(true);
  7390. to.MakeHandleToConst(ctx->type.dataType.IsReadOnly());
  7391. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV, true, false);
  7392. asASSERT( ctx->type.dataType.IsObjectHandle() );
  7393. }
  7394. else if( ctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE )
  7395. {
  7396. // For the ASHANDLE type we'll simply set the expression as a handle
  7397. ctx->type.dataType.MakeHandle(true);
  7398. }
  7399. }
  7400. // Mark the expression as an explicit handle to avoid implicit conversions to non-handle expressions
  7401. ctx->type.isExplicitHandle = true;
  7402. }
  7403. else if( (op == ttMinus || op == ttPlus || op == ttBitNot || op == ttInc || op == ttDec) && ctx->type.dataType.IsObject() )
  7404. {
  7405. // Look for the appropriate method
  7406. // There is no overloadable operator for unary plus
  7407. const char *opName = 0;
  7408. switch( op )
  7409. {
  7410. case ttMinus: opName = "opNeg"; break;
  7411. case ttBitNot: opName = "opCom"; break;
  7412. case ttInc: opName = "opPreInc"; break;
  7413. case ttDec: opName = "opPreDec"; break;
  7414. }
  7415. if( opName )
  7416. {
  7417. // TODO: Should convert this to something similar to CompileOverloadedDualOperator2
  7418. ProcessPropertyGetAccessor(ctx, node);
  7419. // Is it a const value?
  7420. bool isConst = false;
  7421. if( ctx->type.dataType.IsObjectHandle() )
  7422. isConst = ctx->type.dataType.IsHandleToConst();
  7423. else
  7424. isConst = ctx->type.dataType.IsReadOnly();
  7425. // 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
  7426. // Find the correct method
  7427. asCArray<int> funcs;
  7428. asCObjectType *ot = ctx->type.dataType.GetObjectType();
  7429. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  7430. {
  7431. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  7432. if( func->name == opName &&
  7433. func->parameterTypes.GetLength() == 0 &&
  7434. (!isConst || func->isReadOnly) )
  7435. {
  7436. funcs.PushLast(func->id);
  7437. }
  7438. }
  7439. // Did we find the method?
  7440. if( funcs.GetLength() == 1 )
  7441. {
  7442. asCTypeInfo objType = ctx->type;
  7443. asCArray<asSExprContext *> args;
  7444. MakeFunctionCall(ctx, funcs[0], objType.dataType.GetObjectType(), args, node);
  7445. ReleaseTemporaryVariable(objType, &ctx->bc);
  7446. return 0;
  7447. }
  7448. else if( funcs.GetLength() == 0 )
  7449. {
  7450. asCString str;
  7451. str = asCString(opName) + "()";
  7452. if( isConst )
  7453. str += " const";
  7454. str.Format(TXT_FUNCTION_s_NOT_FOUND, str.AddressOf());
  7455. Error(str, node);
  7456. ctx->type.SetDummy();
  7457. return -1;
  7458. }
  7459. else if( funcs.GetLength() > 1 )
  7460. {
  7461. Error(TXT_MORE_THAN_ONE_MATCHING_OP, node);
  7462. PrintMatchingFuncs(funcs, node);
  7463. ctx->type.SetDummy();
  7464. return -1;
  7465. }
  7466. }
  7467. else if( op == ttPlus )
  7468. {
  7469. Error(TXT_ILLEGAL_OPERATION, node);
  7470. ctx->type.SetDummy();
  7471. return -1;
  7472. }
  7473. }
  7474. else if( op == ttPlus || op == ttMinus )
  7475. {
  7476. // This is only for primitives. Objects are treated in the above block
  7477. // Make sure the type is a math type
  7478. if( !(ctx->type.dataType.IsIntegerType() ||
  7479. ctx->type.dataType.IsUnsignedType() ||
  7480. ctx->type.dataType.IsFloatType() ||
  7481. ctx->type.dataType.IsDoubleType() ) )
  7482. {
  7483. Error(TXT_ILLEGAL_OPERATION, node);
  7484. return -1;
  7485. }
  7486. ProcessPropertyGetAccessor(ctx, node);
  7487. asCDataType to = ctx->type.dataType;
  7488. // TODO: The case -2147483648 gives an unecessary warning of changed sign for implicit conversion
  7489. if( ctx->type.dataType.IsUnsignedType() )
  7490. {
  7491. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  7492. to = asCDataType::CreatePrimitive(ttInt8, false);
  7493. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  7494. to = asCDataType::CreatePrimitive(ttInt16, false);
  7495. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 )
  7496. to = asCDataType::CreatePrimitive(ttInt, false);
  7497. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 8 )
  7498. to = asCDataType::CreatePrimitive(ttInt64, false);
  7499. else
  7500. {
  7501. Error(TXT_INVALID_TYPE, node);
  7502. return -1;
  7503. }
  7504. }
  7505. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  7506. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV);
  7507. if( !ctx->type.isConstant )
  7508. {
  7509. ConvertToTempVariable(ctx);
  7510. asASSERT(!ctx->type.isLValue);
  7511. if( op == ttMinus )
  7512. {
  7513. if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  7514. ctx->bc.InstrSHORT(asBC_NEGi, ctx->type.stackOffset);
  7515. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  7516. ctx->bc.InstrSHORT(asBC_NEGi64, ctx->type.stackOffset);
  7517. else if( ctx->type.dataType.IsFloatType() )
  7518. ctx->bc.InstrSHORT(asBC_NEGf, ctx->type.stackOffset);
  7519. else if( ctx->type.dataType.IsDoubleType() )
  7520. ctx->bc.InstrSHORT(asBC_NEGd, ctx->type.stackOffset);
  7521. else
  7522. {
  7523. Error(TXT_ILLEGAL_OPERATION, node);
  7524. return -1;
  7525. }
  7526. return 0;
  7527. }
  7528. }
  7529. else
  7530. {
  7531. if( op == ttMinus )
  7532. {
  7533. if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  7534. ctx->type.intValue = -ctx->type.intValue;
  7535. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  7536. ctx->type.qwordValue = -(asINT64)ctx->type.qwordValue;
  7537. else if( ctx->type.dataType.IsFloatType() )
  7538. ctx->type.floatValue = -ctx->type.floatValue;
  7539. else if( ctx->type.dataType.IsDoubleType() )
  7540. ctx->type.doubleValue = -ctx->type.doubleValue;
  7541. else
  7542. {
  7543. Error(TXT_ILLEGAL_OPERATION, node);
  7544. return -1;
  7545. }
  7546. return 0;
  7547. }
  7548. }
  7549. }
  7550. else if( op == ttNot )
  7551. {
  7552. if( ctx->type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  7553. {
  7554. if( ctx->type.isConstant )
  7555. {
  7556. ctx->type.dwordValue = (ctx->type.dwordValue == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  7557. return 0;
  7558. }
  7559. ProcessPropertyGetAccessor(ctx, node);
  7560. ConvertToTempVariable(ctx);
  7561. asASSERT(!ctx->type.isLValue);
  7562. ctx->bc.InstrSHORT(asBC_NOT, ctx->type.stackOffset);
  7563. }
  7564. else
  7565. {
  7566. Error(TXT_ILLEGAL_OPERATION, node);
  7567. return -1;
  7568. }
  7569. }
  7570. else if( op == ttBitNot )
  7571. {
  7572. ProcessPropertyGetAccessor(ctx, node);
  7573. asCDataType to = ctx->type.dataType;
  7574. if( ctx->type.dataType.IsIntegerType() )
  7575. {
  7576. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  7577. to = asCDataType::CreatePrimitive(ttUInt8, false);
  7578. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  7579. to = asCDataType::CreatePrimitive(ttUInt16, false);
  7580. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 )
  7581. to = asCDataType::CreatePrimitive(ttUInt, false);
  7582. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 8 )
  7583. to = asCDataType::CreatePrimitive(ttUInt64, false);
  7584. else
  7585. {
  7586. Error(TXT_INVALID_TYPE, node);
  7587. return -1;
  7588. }
  7589. }
  7590. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  7591. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV);
  7592. if( ctx->type.dataType.IsUnsignedType() )
  7593. {
  7594. if( ctx->type.isConstant )
  7595. {
  7596. ctx->type.qwordValue = ~ctx->type.qwordValue;
  7597. return 0;
  7598. }
  7599. ConvertToTempVariable(ctx);
  7600. asASSERT(!ctx->type.isLValue);
  7601. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  7602. ctx->bc.InstrSHORT(asBC_BNOT, ctx->type.stackOffset);
  7603. else
  7604. ctx->bc.InstrSHORT(asBC_BNOT64, ctx->type.stackOffset);
  7605. }
  7606. else
  7607. {
  7608. Error(TXT_ILLEGAL_OPERATION, node);
  7609. return -1;
  7610. }
  7611. }
  7612. else if( op == ttInc || op == ttDec )
  7613. {
  7614. // Need a reference to the primitive that will be updated
  7615. // The result of this expression is the same reference as before
  7616. // Make sure the reference isn't a temporary variable
  7617. if( ctx->type.isTemporary )
  7618. {
  7619. Error(TXT_REF_IS_TEMP, node);
  7620. return -1;
  7621. }
  7622. if( ctx->type.dataType.IsReadOnly() )
  7623. {
  7624. Error(TXT_REF_IS_READ_ONLY, node);
  7625. return -1;
  7626. }
  7627. if( ctx->property_get || ctx->property_set )
  7628. {
  7629. Error(TXT_INVALID_REF_PROP_ACCESS, node);
  7630. return -1;
  7631. }
  7632. if( !ctx->type.isLValue )
  7633. {
  7634. Error(TXT_NOT_LVALUE, node);
  7635. return -1;
  7636. }
  7637. if( ctx->type.isVariable && !ctx->type.dataType.IsReference() )
  7638. ConvertToReference(ctx);
  7639. else if( !ctx->type.dataType.IsReference() )
  7640. {
  7641. Error(TXT_NOT_VALID_REFERENCE, node);
  7642. return -1;
  7643. }
  7644. if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt64, false)) ||
  7645. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt64, false)) )
  7646. {
  7647. if( op == ttInc )
  7648. ctx->bc.Instr(asBC_INCi64);
  7649. else
  7650. ctx->bc.Instr(asBC_DECi64);
  7651. }
  7652. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt, false)) ||
  7653. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt, false)) )
  7654. {
  7655. if( op == ttInc )
  7656. ctx->bc.Instr(asBC_INCi);
  7657. else
  7658. ctx->bc.Instr(asBC_DECi);
  7659. }
  7660. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt16, false)) ||
  7661. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt16, false)) )
  7662. {
  7663. if( op == ttInc )
  7664. ctx->bc.Instr(asBC_INCi16);
  7665. else
  7666. ctx->bc.Instr(asBC_DECi16);
  7667. }
  7668. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt8, false)) ||
  7669. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt8, false)) )
  7670. {
  7671. if( op == ttInc )
  7672. ctx->bc.Instr(asBC_INCi8);
  7673. else
  7674. ctx->bc.Instr(asBC_DECi8);
  7675. }
  7676. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttFloat, false)) )
  7677. {
  7678. if( op == ttInc )
  7679. ctx->bc.Instr(asBC_INCf);
  7680. else
  7681. ctx->bc.Instr(asBC_DECf);
  7682. }
  7683. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttDouble, false)) )
  7684. {
  7685. if( op == ttInc )
  7686. ctx->bc.Instr(asBC_INCd);
  7687. else
  7688. ctx->bc.Instr(asBC_DECd);
  7689. }
  7690. else
  7691. {
  7692. Error(TXT_ILLEGAL_OPERATION, node);
  7693. return -1;
  7694. }
  7695. }
  7696. else
  7697. {
  7698. // Unknown operator
  7699. asASSERT(false);
  7700. return -1;
  7701. }
  7702. return 0;
  7703. }
  7704. void asCCompiler::ConvertToReference(asSExprContext *ctx)
  7705. {
  7706. if( ctx->type.isVariable && !ctx->type.dataType.IsReference() )
  7707. {
  7708. ctx->bc.InstrSHORT(asBC_LDV, ctx->type.stackOffset);
  7709. ctx->type.dataType.MakeReference(true);
  7710. ctx->type.SetVariable(ctx->type.dataType, ctx->type.stackOffset, ctx->type.isTemporary);
  7711. }
  7712. }
  7713. int asCCompiler::FindPropertyAccessor(const asCString &name, asSExprContext *ctx, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess)
  7714. {
  7715. return FindPropertyAccessor(name, ctx, 0, node, ns, isThisAccess);
  7716. }
  7717. int asCCompiler::FindPropertyAccessor(const asCString &name, asSExprContext *ctx, asSExprContext *arg, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess)
  7718. {
  7719. if( engine->ep.propertyAccessorMode == 0 )
  7720. {
  7721. // Property accessors have been disabled by the application
  7722. return 0;
  7723. }
  7724. int getId = 0, setId = 0;
  7725. asCString getName = "get_" + name;
  7726. asCString setName = "set_" + name;
  7727. asCArray<int> multipleGetFuncs, multipleSetFuncs;
  7728. if( ctx->type.dataType.IsObject() )
  7729. {
  7730. asASSERT( ns == 0 );
  7731. // Don't look for property accessors in script classes if the script
  7732. // property accessors have been disabled by the application
  7733. if( !(ctx->type.dataType.GetObjectType()->flags & asOBJ_SCRIPT_OBJECT) ||
  7734. engine->ep.propertyAccessorMode == 2 )
  7735. {
  7736. // Check if the object has any methods with the corresponding accessor name(s)
  7737. asCObjectType *ot = ctx->type.dataType.GetObjectType();
  7738. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  7739. {
  7740. asCScriptFunction *f = engine->scriptFunctions[ot->methods[n]];
  7741. // TODO: The type of the parameter should match the argument (unless the arg is a dummy)
  7742. if( f->name == getName && (int)f->parameterTypes.GetLength() == (arg?1:0) )
  7743. {
  7744. if( getId == 0 )
  7745. getId = ot->methods[n];
  7746. else
  7747. {
  7748. if( multipleGetFuncs.GetLength() == 0 )
  7749. multipleGetFuncs.PushLast(getId);
  7750. multipleGetFuncs.PushLast(ot->methods[n]);
  7751. }
  7752. }
  7753. // TODO: getset: If the parameter is a reference, it must not be an out reference. Should we allow inout ref?
  7754. if( f->name == setName && (int)f->parameterTypes.GetLength() == (arg?2:1) )
  7755. {
  7756. if( setId == 0 )
  7757. setId = ot->methods[n];
  7758. else
  7759. {
  7760. if( multipleSetFuncs.GetLength() == 0 )
  7761. multipleSetFuncs.PushLast(setId);
  7762. multipleSetFuncs.PushLast(ot->methods[n]);
  7763. }
  7764. }
  7765. }
  7766. }
  7767. }
  7768. else
  7769. {
  7770. asASSERT( ns != 0 );
  7771. // Look for appropriate global functions.
  7772. asCArray<int> funcs;
  7773. asUINT n;
  7774. builder->GetFunctionDescriptions(getName.AddressOf(), funcs, ns);
  7775. for( n = 0; n < funcs.GetLength(); n++ )
  7776. {
  7777. asCScriptFunction *f = builder->GetFunctionDescription(funcs[n]);
  7778. // TODO: The type of the parameter should match the argument (unless the arg is a dummy)
  7779. if( (int)f->parameterTypes.GetLength() == (arg?1:0) )
  7780. {
  7781. if( getId == 0 )
  7782. getId = funcs[n];
  7783. else
  7784. {
  7785. if( multipleGetFuncs.GetLength() == 0 )
  7786. multipleGetFuncs.PushLast(getId);
  7787. multipleGetFuncs.PushLast(funcs[n]);
  7788. }
  7789. }
  7790. }
  7791. funcs.SetLength(0);
  7792. builder->GetFunctionDescriptions(setName.AddressOf(), funcs, ns);
  7793. for( n = 0; n < funcs.GetLength(); n++ )
  7794. {
  7795. asCScriptFunction *f = builder->GetFunctionDescription(funcs[n]);
  7796. // TODO: getset: If the parameter is a reference, it must not be an out reference. Should we allow inout ref?
  7797. if( (int)f->parameterTypes.GetLength() == (arg?2:1) )
  7798. {
  7799. if( setId == 0 )
  7800. setId = funcs[n];
  7801. else
  7802. {
  7803. if( multipleSetFuncs.GetLength() == 0 )
  7804. multipleSetFuncs.PushLast(getId);
  7805. multipleSetFuncs.PushLast(funcs[n]);
  7806. }
  7807. }
  7808. }
  7809. }
  7810. bool isConst = false;
  7811. if( ctx->type.dataType.IsObjectHandle() )
  7812. isConst = ctx->type.dataType.IsHandleToConst();
  7813. else
  7814. isConst = ctx->type.dataType.IsReadOnly();
  7815. // Check for multiple matches
  7816. if( multipleGetFuncs.GetLength() > 0 )
  7817. {
  7818. // Filter the list by constness
  7819. FilterConst(multipleGetFuncs, !isConst);
  7820. if( multipleGetFuncs.GetLength() > 1 )
  7821. {
  7822. asCString str;
  7823. str.Format(TXT_MULTIPLE_PROP_GET_ACCESSOR_FOR_s, name.AddressOf());
  7824. Error(str, node);
  7825. PrintMatchingFuncs(multipleGetFuncs, node);
  7826. return -1;
  7827. }
  7828. else
  7829. {
  7830. // The id may have changed
  7831. getId = multipleGetFuncs[0];
  7832. }
  7833. }
  7834. if( multipleSetFuncs.GetLength() > 0 )
  7835. {
  7836. // Filter the list by constness
  7837. FilterConst(multipleSetFuncs, !isConst);
  7838. if( multipleSetFuncs.GetLength() > 1 )
  7839. {
  7840. asCString str;
  7841. str.Format(TXT_MULTIPLE_PROP_SET_ACCESSOR_FOR_s, name.AddressOf());
  7842. Error(str, node);
  7843. PrintMatchingFuncs(multipleSetFuncs, node);
  7844. return -1;
  7845. }
  7846. else
  7847. {
  7848. // The id may have changed
  7849. setId = multipleSetFuncs[0];
  7850. }
  7851. }
  7852. // Check for type compatibility between get and set accessor
  7853. if( getId && setId )
  7854. {
  7855. asCScriptFunction *getFunc = builder->GetFunctionDescription(getId);
  7856. asCScriptFunction *setFunc = builder->GetFunctionDescription(setId);
  7857. // It is permitted for a getter to return a handle and the setter to take a reference
  7858. int idx = (arg?1:0);
  7859. if( !getFunc->returnType.IsEqualExceptRefAndConst(setFunc->parameterTypes[idx]) &&
  7860. !((getFunc->returnType.IsObjectHandle() && !setFunc->parameterTypes[idx].IsObjectHandle()) &&
  7861. (getFunc->returnType.GetObjectType() == setFunc->parameterTypes[idx].GetObjectType())) )
  7862. {
  7863. asCString str;
  7864. str.Format(TXT_GET_SET_ACCESSOR_TYPE_MISMATCH_FOR_s, name.AddressOf());
  7865. Error(str, node);
  7866. asCArray<int> funcs;
  7867. funcs.PushLast(getId);
  7868. funcs.PushLast(setId);
  7869. PrintMatchingFuncs(funcs, node);
  7870. return -1;
  7871. }
  7872. }
  7873. // Check if we are within one of the accessors
  7874. int realGetId = getId;
  7875. int realSetId = setId;
  7876. if( outFunc->objectType && isThisAccess )
  7877. {
  7878. // The property accessors would be virtual functions, so we need to find the real implementation
  7879. asCScriptFunction *getFunc = getId ? builder->GetFunctionDescription(getId) : 0;
  7880. if( getFunc &&
  7881. getFunc->funcType == asFUNC_VIRTUAL &&
  7882. outFunc->objectType->DerivesFrom(getFunc->objectType) )
  7883. realGetId = outFunc->objectType->virtualFunctionTable[getFunc->vfTableIdx]->id;
  7884. asCScriptFunction *setFunc = setId ? builder->GetFunctionDescription(setId) : 0;
  7885. if( setFunc &&
  7886. setFunc->funcType == asFUNC_VIRTUAL &&
  7887. outFunc->objectType->DerivesFrom(setFunc->objectType) )
  7888. realSetId = outFunc->objectType->virtualFunctionTable[setFunc->vfTableIdx]->id;
  7889. }
  7890. // Avoid recursive call, by not treating this as a property accessor call.
  7891. // This will also allow having the real property with the same name as the accessors.
  7892. if( (isThisAccess || outFunc->objectType == 0) &&
  7893. ((realGetId && realGetId == outFunc->id) ||
  7894. (realSetId && realSetId == outFunc->id)) )
  7895. {
  7896. getId = 0;
  7897. setId = 0;
  7898. }
  7899. // Check if the application has disabled script written property accessors
  7900. if( engine->ep.propertyAccessorMode == 1 )
  7901. {
  7902. if( getId && builder->GetFunctionDescription(getId)->funcType != asFUNC_SYSTEM )
  7903. getId = 0;
  7904. if( setId && builder->GetFunctionDescription(setId)->funcType != asFUNC_SYSTEM )
  7905. setId = 0;
  7906. }
  7907. if( getId || setId )
  7908. {
  7909. // Property accessors were found, but we don't know which is to be used yet, so
  7910. // we just prepare the bytecode for the method call, and then store the function ids
  7911. // so that the right one can be used when we get there.
  7912. ctx->property_get = getId;
  7913. ctx->property_set = setId;
  7914. if( ctx->type.dataType.IsObject() )
  7915. {
  7916. // If the object is read-only then we need to remember that
  7917. if( (!ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReadOnly()) ||
  7918. (ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsHandleToConst()) )
  7919. ctx->property_const = true;
  7920. else
  7921. ctx->property_const = false;
  7922. // If the object is a handle then we need to remember that
  7923. ctx->property_handle = ctx->type.dataType.IsObjectHandle();
  7924. ctx->property_ref = ctx->type.dataType.IsReference();
  7925. }
  7926. // The setter's parameter type is used as the property type,
  7927. // unless only the getter is available
  7928. asCDataType dt;
  7929. if( setId )
  7930. dt = builder->GetFunctionDescription(setId)->parameterTypes[(arg?1:0)];
  7931. else
  7932. dt = builder->GetFunctionDescription(getId)->returnType;
  7933. // Just change the type, the context must still maintain information
  7934. // about previous variable offset and the indicator of temporary variable.
  7935. int offset = ctx->type.stackOffset;
  7936. bool isTemp = ctx->type.isTemporary;
  7937. ctx->type.Set(dt);
  7938. ctx->type.stackOffset = (short)offset;
  7939. ctx->type.isTemporary = isTemp;
  7940. ctx->exprNode = node;
  7941. // Store the argument for later use
  7942. if( arg )
  7943. {
  7944. ctx->property_arg = asNEW(asSExprContext)(engine);
  7945. if( ctx->property_arg == 0 )
  7946. {
  7947. // Out of memory
  7948. return -1;
  7949. }
  7950. MergeExprBytecodeAndType(ctx->property_arg, arg);
  7951. }
  7952. return 1;
  7953. }
  7954. // No accessor was found
  7955. return 0;
  7956. }
  7957. int asCCompiler::ProcessPropertySetAccessor(asSExprContext *ctx, asSExprContext *arg, asCScriptNode *node)
  7958. {
  7959. // TODO: A lot of this code is similar to ProcessPropertyGetAccessor. Can we unify them?
  7960. if( !ctx->property_set )
  7961. {
  7962. Error(TXT_PROPERTY_HAS_NO_SET_ACCESSOR, node);
  7963. return -1;
  7964. }
  7965. asCTypeInfo objType = ctx->type;
  7966. asCScriptFunction *func = builder->GetFunctionDescription(ctx->property_set);
  7967. // Make sure the arg match the property
  7968. asCArray<int> funcs;
  7969. funcs.PushLast(ctx->property_set);
  7970. asCArray<asSExprContext *> args;
  7971. if( ctx->property_arg )
  7972. args.PushLast(ctx->property_arg);
  7973. args.PushLast(arg);
  7974. MatchFunctions(funcs, args, node, func->GetName(), func->objectType, ctx->property_const);
  7975. if( funcs.GetLength() == 0 )
  7976. {
  7977. // MatchFunctions already reported the error
  7978. if( ctx->property_arg )
  7979. {
  7980. asDELETE(ctx->property_arg, asSExprContext);
  7981. ctx->property_arg = 0;
  7982. }
  7983. return -1;
  7984. }
  7985. if( func->objectType )
  7986. {
  7987. // Setup the context with the original type so the method call gets built correctly
  7988. ctx->type.dataType = asCDataType::CreateObject(func->objectType, ctx->property_const);
  7989. if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
  7990. if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
  7991. // Don't allow the call if the object is read-only and the property accessor is not const
  7992. if( ctx->property_const && !func->isReadOnly )
  7993. {
  7994. Error(TXT_NON_CONST_METHOD_ON_CONST_OBJ, node);
  7995. asCArray<int> funcs;
  7996. funcs.PushLast(ctx->property_set);
  7997. PrintMatchingFuncs(funcs, node);
  7998. }
  7999. }
  8000. // Call the accessor
  8001. MakeFunctionCall(ctx, ctx->property_set, func->objectType, args, node);
  8002. if( func->objectType )
  8003. {
  8004. // TODO: This is from CompileExpressionPostOp, can we unify the code?
  8005. if( !objType.isTemporary ||
  8006. !ctx->type.dataType.IsReference() ||
  8007. ctx->type.isVariable ) // If the resulting type is a variable, then the reference is not a member
  8008. {
  8009. // As the method didn't return a reference to a member
  8010. // we can safely release the original object now
  8011. ReleaseTemporaryVariable(objType, &ctx->bc);
  8012. }
  8013. }
  8014. ctx->property_get = 0;
  8015. ctx->property_set = 0;
  8016. if( ctx->property_arg )
  8017. {
  8018. asDELETE(ctx->property_arg, asSExprContext);
  8019. ctx->property_arg = 0;
  8020. }
  8021. return 0;
  8022. }
  8023. void asCCompiler::ProcessPropertyGetAccessor(asSExprContext *ctx, asCScriptNode *node)
  8024. {
  8025. // If no property accessor has been prepared then don't do anything
  8026. if( !ctx->property_get && !ctx->property_set )
  8027. return;
  8028. if( !ctx->property_get )
  8029. {
  8030. // Raise error on missing accessor
  8031. Error(TXT_PROPERTY_HAS_NO_GET_ACCESSOR, node);
  8032. ctx->type.SetDummy();
  8033. return;
  8034. }
  8035. asCTypeInfo objType = ctx->type;
  8036. asCScriptFunction *func = builder->GetFunctionDescription(ctx->property_get);
  8037. // Make sure the arg match the property
  8038. asCArray<int> funcs;
  8039. funcs.PushLast(ctx->property_get);
  8040. asCArray<asSExprContext *> args;
  8041. if( ctx->property_arg )
  8042. args.PushLast(ctx->property_arg);
  8043. MatchFunctions(funcs, args, node, func->GetName(), func->objectType, ctx->property_const);
  8044. if( funcs.GetLength() == 0 )
  8045. {
  8046. // MatchFunctions already reported the error
  8047. if( ctx->property_arg )
  8048. {
  8049. asDELETE(ctx->property_arg, asSExprContext);
  8050. ctx->property_arg = 0;
  8051. }
  8052. ctx->type.SetDummy();
  8053. return;
  8054. }
  8055. if( func->objectType )
  8056. {
  8057. // Setup the context with the original type so the method call gets built correctly
  8058. ctx->type.dataType = asCDataType::CreateObject(func->objectType, ctx->property_const);
  8059. if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
  8060. if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
  8061. // Don't allow the call if the object is read-only and the property accessor is not const
  8062. if( ctx->property_const && !func->isReadOnly )
  8063. {
  8064. Error(TXT_NON_CONST_METHOD_ON_CONST_OBJ, node);
  8065. asCArray<int> funcs;
  8066. funcs.PushLast(ctx->property_get);
  8067. PrintMatchingFuncs(funcs, node);
  8068. }
  8069. }
  8070. // Call the accessor
  8071. MakeFunctionCall(ctx, ctx->property_get, func->objectType, args, node);
  8072. if( func->objectType )
  8073. {
  8074. // TODO: This is from CompileExpressionPostOp, can we unify the code?
  8075. // If the method returned a reference, then we can't release the original
  8076. // object yet, because the reference may be to a member of it
  8077. if( !objType.isTemporary ||
  8078. !(ctx->type.dataType.IsReference() || (ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle())) ||
  8079. ctx->type.isVariable ) // If the resulting type is a variable, then the reference is not a member
  8080. {
  8081. // As the method didn't return a reference to a member
  8082. // we can safely release the original object now
  8083. ReleaseTemporaryVariable(objType, &ctx->bc);
  8084. }
  8085. }
  8086. ctx->property_get = 0;
  8087. ctx->property_set = 0;
  8088. if( ctx->property_arg )
  8089. {
  8090. asDELETE(ctx->property_arg, asSExprContext);
  8091. ctx->property_arg = 0;
  8092. }
  8093. }
  8094. int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ctx)
  8095. {
  8096. // Don't allow any postfix operators on expressions that take address of class method
  8097. if( ctx->methodName != "" )
  8098. {
  8099. Error(TXT_INVALID_OP_ON_METHOD, node);
  8100. return -1;
  8101. }
  8102. // Check if the variable is initialized (if it indeed is a variable)
  8103. IsVariableInitialized(&ctx->type, node);
  8104. int op = node->tokenType;
  8105. if( (op == ttInc || op == ttDec) && ctx->type.dataType.IsObject() )
  8106. {
  8107. const char *opName = 0;
  8108. switch( op )
  8109. {
  8110. case ttInc: opName = "opPostInc"; break;
  8111. case ttDec: opName = "opPostDec"; break;
  8112. }
  8113. if( opName )
  8114. {
  8115. // TODO: Should convert this to something similar to CompileOverloadedDualOperator2
  8116. ProcessPropertyGetAccessor(ctx, node);
  8117. // Is it a const value?
  8118. bool isConst = false;
  8119. if( ctx->type.dataType.IsObjectHandle() )
  8120. isConst = ctx->type.dataType.IsHandleToConst();
  8121. else
  8122. isConst = ctx->type.dataType.IsReadOnly();
  8123. // 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
  8124. // Find the correct method
  8125. asCArray<int> funcs;
  8126. asCObjectType *ot = ctx->type.dataType.GetObjectType();
  8127. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  8128. {
  8129. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  8130. if( func->name == opName &&
  8131. func->parameterTypes.GetLength() == 0 &&
  8132. (!isConst || func->isReadOnly) )
  8133. {
  8134. funcs.PushLast(func->id);
  8135. }
  8136. }
  8137. // Did we find the method?
  8138. if( funcs.GetLength() == 1 )
  8139. {
  8140. asCTypeInfo objType = ctx->type;
  8141. asCArray<asSExprContext *> args;
  8142. MakeFunctionCall(ctx, funcs[0], objType.dataType.GetObjectType(), args, node);
  8143. ReleaseTemporaryVariable(objType, &ctx->bc);
  8144. return 0;
  8145. }
  8146. else if( funcs.GetLength() == 0 )
  8147. {
  8148. asCString str;
  8149. str = asCString(opName) + "()";
  8150. if( isConst )
  8151. str += " const";
  8152. str.Format(TXT_FUNCTION_s_NOT_FOUND, str.AddressOf());
  8153. Error(str, node);
  8154. ctx->type.SetDummy();
  8155. return -1;
  8156. }
  8157. else if( funcs.GetLength() > 1 )
  8158. {
  8159. Error(TXT_MORE_THAN_ONE_MATCHING_OP, node);
  8160. PrintMatchingFuncs(funcs, node);
  8161. ctx->type.SetDummy();
  8162. return -1;
  8163. }
  8164. }
  8165. }
  8166. else if( op == ttInc || op == ttDec )
  8167. {
  8168. // Make sure the reference isn't a temporary variable
  8169. if( ctx->type.isTemporary )
  8170. {
  8171. Error(TXT_REF_IS_TEMP, node);
  8172. return -1;
  8173. }
  8174. if( ctx->type.dataType.IsReadOnly() )
  8175. {
  8176. Error(TXT_REF_IS_READ_ONLY, node);
  8177. return -1;
  8178. }
  8179. if( ctx->property_get || ctx->property_set )
  8180. {
  8181. Error(TXT_INVALID_REF_PROP_ACCESS, node);
  8182. return -1;
  8183. }
  8184. if( !ctx->type.isLValue )
  8185. {
  8186. Error(TXT_NOT_LVALUE, node);
  8187. return -1;
  8188. }
  8189. if( ctx->type.isVariable && !ctx->type.dataType.IsReference() )
  8190. ConvertToReference(ctx);
  8191. else if( !ctx->type.dataType.IsReference() )
  8192. {
  8193. Error(TXT_NOT_VALID_REFERENCE, node);
  8194. return -1;
  8195. }
  8196. // Copy the value to a temp before changing it
  8197. ConvertToTempVariable(ctx);
  8198. asASSERT(!ctx->type.isLValue);
  8199. // Increment the value pointed to by the reference still in the register
  8200. asEBCInstr iInc = asBC_INCi, iDec = asBC_DECi;
  8201. if( ctx->type.dataType.IsDoubleType() )
  8202. {
  8203. iInc = asBC_INCd;
  8204. iDec = asBC_DECd;
  8205. }
  8206. else if( ctx->type.dataType.IsFloatType() )
  8207. {
  8208. iInc = asBC_INCf;
  8209. iDec = asBC_DECf;
  8210. }
  8211. else if( ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType() )
  8212. {
  8213. if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt16, false)) ||
  8214. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt16, false)) )
  8215. {
  8216. iInc = asBC_INCi16;
  8217. iDec = asBC_DECi16;
  8218. }
  8219. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt8, false)) ||
  8220. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt8, false)) )
  8221. {
  8222. iInc = asBC_INCi8;
  8223. iDec = asBC_DECi8;
  8224. }
  8225. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt64, false)) ||
  8226. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt64, false)) )
  8227. {
  8228. iInc = asBC_INCi64;
  8229. iDec = asBC_DECi64;
  8230. }
  8231. }
  8232. else
  8233. {
  8234. Error(TXT_ILLEGAL_OPERATION, node);
  8235. return -1;
  8236. }
  8237. if( op == ttInc ) ctx->bc.Instr(iInc); else ctx->bc.Instr(iDec);
  8238. }
  8239. else if( op == ttDot )
  8240. {
  8241. if( node->firstChild->nodeType == snIdentifier )
  8242. {
  8243. ProcessPropertyGetAccessor(ctx, node);
  8244. // Get the property name
  8245. asCString name(&script->code[node->firstChild->tokenPos], node->firstChild->tokenLength);
  8246. if( ctx->type.dataType.IsObject() )
  8247. {
  8248. // We need to look for get/set property accessors.
  8249. // If found, the context stores information on the get/set accessors
  8250. // until it is known which is to be used.
  8251. int r = 0;
  8252. if( node->next && node->next->tokenType == ttOpenBracket )
  8253. {
  8254. // The property accessor should take an index arg
  8255. asSExprContext dummyArg(engine);
  8256. r = FindPropertyAccessor(name, ctx, &dummyArg, node, 0);
  8257. }
  8258. if( r == 0 )
  8259. r = FindPropertyAccessor(name, ctx, node, 0);
  8260. if( r != 0 )
  8261. return r;
  8262. if( !ctx->type.dataType.IsPrimitive() )
  8263. Dereference(ctx, true);
  8264. if( ctx->type.dataType.IsObjectHandle() )
  8265. {
  8266. // Convert the handle to a normal object
  8267. asCDataType dt = ctx->type.dataType;
  8268. dt.MakeHandle(false);
  8269. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV);
  8270. // The handle may not have been an lvalue, but the dereferenced object is
  8271. ctx->type.isLValue = true;
  8272. }
  8273. bool isConst = ctx->type.dataType.IsReadOnly();
  8274. asCObjectProperty *prop = builder->GetObjectProperty(ctx->type.dataType, name.AddressOf());
  8275. if( prop )
  8276. {
  8277. // Is the property access allowed?
  8278. if( prop->isPrivate && (!outFunc || outFunc->objectType != ctx->type.dataType.GetObjectType()) )
  8279. {
  8280. asCString msg;
  8281. msg.Format(TXT_PRIVATE_PROP_ACCESS_s, name.AddressOf());
  8282. Error(msg, node);
  8283. }
  8284. // Put the offset on the stack
  8285. ctx->bc.InstrSHORT_DW(asBC_ADDSi, (short)prop->byteOffset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(ctx->type.dataType.GetObjectType(), false)));
  8286. if( prop->type.IsReference() )
  8287. ctx->bc.Instr(asBC_RDSPtr);
  8288. // Reference to primitive must be stored in the temp register
  8289. if( prop->type.IsPrimitive() )
  8290. {
  8291. ctx->bc.Instr(asBC_PopRPtr);
  8292. }
  8293. // Keep information about temporary variables as deferred expression
  8294. if( ctx->type.isTemporary )
  8295. {
  8296. // Add the release of this reference, as a deferred expression
  8297. asSDeferredParam deferred;
  8298. deferred.origExpr = 0;
  8299. deferred.argInOutFlags = asTM_INREF;
  8300. deferred.argNode = 0;
  8301. deferred.argType.SetVariable(ctx->type.dataType, ctx->type.stackOffset, true);
  8302. ctx->deferredParams.PushLast(deferred);
  8303. }
  8304. // Set the new type and make sure it is not treated as a variable anymore
  8305. ctx->type.dataType = prop->type;
  8306. ctx->type.dataType.MakeReference(true);
  8307. ctx->type.isVariable = false;
  8308. ctx->type.isTemporary = false;
  8309. if( ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle() )
  8310. {
  8311. // Objects that are members are not references
  8312. ctx->type.dataType.MakeReference(false);
  8313. }
  8314. ctx->type.dataType.MakeReadOnly(isConst ? true : prop->type.IsReadOnly());
  8315. }
  8316. else
  8317. {
  8318. // If the name is not a property, the compiler must check if the name matches
  8319. // a method, which can be used for constructing delegates
  8320. asIScriptFunction *func = 0;
  8321. asCObjectType *ot = ctx->type.dataType.GetObjectType();
  8322. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  8323. {
  8324. if( engine->scriptFunctions[ot->methods[n]]->name == name )
  8325. {
  8326. func = engine->scriptFunctions[ot->methods[n]];
  8327. break;
  8328. }
  8329. }
  8330. if( func )
  8331. {
  8332. // An object method was found. Keep the name of the method in the expression, but
  8333. // don't actually modify the bytecode at this point since it is not yet known what
  8334. // the method will be used for, or even what overloaded method should be used.
  8335. ctx->methodName = name;
  8336. }
  8337. else
  8338. {
  8339. asCString str;
  8340. str.Format(TXT_s_NOT_MEMBER_OF_s, name.AddressOf(), ctx->type.dataType.Format().AddressOf());
  8341. Error(str, node);
  8342. return -1;
  8343. }
  8344. }
  8345. }
  8346. else
  8347. {
  8348. asCString str;
  8349. str.Format(TXT_s_NOT_MEMBER_OF_s, name.AddressOf(), ctx->type.dataType.Format().AddressOf());
  8350. Error(str, node);
  8351. return -1;
  8352. }
  8353. }
  8354. else
  8355. {
  8356. // Make sure it is an object we are accessing
  8357. if( !ctx->type.dataType.IsObject() )
  8358. {
  8359. asCString str;
  8360. str.Format(TXT_ILLEGAL_OPERATION_ON_s, ctx->type.dataType.Format().AddressOf());
  8361. Error(str, node);
  8362. return -1;
  8363. }
  8364. // Process the get property accessor
  8365. ProcessPropertyGetAccessor(ctx, node);
  8366. bool isConst = false;
  8367. if( ctx->type.dataType.IsObjectHandle() )
  8368. isConst = ctx->type.dataType.IsHandleToConst();
  8369. else
  8370. isConst = ctx->type.dataType.IsReadOnly();
  8371. asCObjectType *trueObj = ctx->type.dataType.GetObjectType();
  8372. asCTypeInfo objType = ctx->type;
  8373. // Compile function call
  8374. int r = CompileFunctionCall(node->firstChild, ctx, trueObj, isConst);
  8375. if( r < 0 ) return r;
  8376. // If the method returned a reference, then we can't release the original
  8377. // object yet, because the reference may be to a member of it
  8378. if( !objType.isTemporary ||
  8379. !(ctx->type.dataType.IsReference() || (ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle())) ||
  8380. ctx->type.isVariable ) // If the resulting type is a variable, then the reference is not a member
  8381. {
  8382. // As the method didn't return a reference to a member
  8383. // we can safely release the original object now
  8384. ReleaseTemporaryVariable(objType, &ctx->bc);
  8385. }
  8386. }
  8387. }
  8388. else if( op == ttOpenBracket )
  8389. {
  8390. // If the property access takes an index arg and the argument hasn't been evaluated yet,
  8391. // then we should use that instead of processing it now. If the argument has already been
  8392. // evaluated, then we should process the property accessor as a get access now as the new
  8393. // index operator is on the result of that accessor.
  8394. asCString propertyName;
  8395. asSNameSpace *ns = 0;
  8396. if( ((ctx->property_get && builder->GetFunctionDescription(ctx->property_get)->GetParamCount() == 1) ||
  8397. (ctx->property_set && builder->GetFunctionDescription(ctx->property_set)->GetParamCount() == 2)) &&
  8398. (ctx->property_arg && ctx->property_arg->type.dataType.GetTokenType() == ttUnrecognizedToken) )
  8399. {
  8400. // Determine the name of the property accessor
  8401. asCScriptFunction *func = 0;
  8402. if( ctx->property_get )
  8403. func = builder->GetFunctionDescription(ctx->property_get);
  8404. else
  8405. func = builder->GetFunctionDescription(ctx->property_set);
  8406. propertyName = func->GetName();
  8407. propertyName = propertyName.SubString(4);
  8408. // Set the original type of the expression so we can re-evaluate the property accessor
  8409. if( func->objectType )
  8410. {
  8411. ctx->type.dataType = asCDataType::CreateObject(func->objectType, ctx->property_const);
  8412. if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
  8413. if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
  8414. }
  8415. else
  8416. {
  8417. // Store the namespace where the function is declared
  8418. // so the same function can be found later
  8419. ctx->type.SetDummy();
  8420. ns = func->nameSpace;
  8421. }
  8422. ctx->property_get = ctx->property_set = 0;
  8423. if( ctx->property_arg )
  8424. {
  8425. asDELETE(ctx->property_arg, asSExprContext);
  8426. ctx->property_arg = 0;
  8427. }
  8428. }
  8429. else
  8430. {
  8431. if( !ctx->type.dataType.IsObject() )
  8432. {
  8433. asCString str;
  8434. str.Format(TXT_OBJECT_DOESNT_SUPPORT_INDEX_OP, ctx->type.dataType.Format().AddressOf());
  8435. Error(str, node);
  8436. return -1;
  8437. }
  8438. ProcessPropertyGetAccessor(ctx, node);
  8439. }
  8440. Dereference(ctx, true);
  8441. // Compile the expression
  8442. asSExprContext expr(engine);
  8443. CompileAssignment(node->firstChild, &expr);
  8444. // Check for the existence of the opIndex method
  8445. asSExprContext lctx(engine);
  8446. MergeExprBytecodeAndType(&lctx, ctx);
  8447. int r = 0;
  8448. if( propertyName == "" )
  8449. r = CompileOverloadedDualOperator2(node, "opIndex", &lctx, &expr, ctx);
  8450. if( r == 0 )
  8451. {
  8452. // Check for accessors methods for the opIndex
  8453. r = FindPropertyAccessor(propertyName == "" ? "opIndex" : propertyName.AddressOf(), &lctx, &expr, node, ns);
  8454. if( r == 0 )
  8455. {
  8456. asCString str;
  8457. str.Format(TXT_OBJECT_DOESNT_SUPPORT_INDEX_OP, ctx->type.dataType.Format().AddressOf());
  8458. Error(str, node);
  8459. return -1;
  8460. }
  8461. else if( r < 0 )
  8462. return -1;
  8463. MergeExprBytecodeAndType(ctx, &lctx);
  8464. }
  8465. }
  8466. else if( op == ttOpenParanthesis )
  8467. {
  8468. // TODO: Most of this is already done by CompileFunctionCall(). Can we share the code?
  8469. // Make sure the expression is a funcdef
  8470. if( !ctx->type.dataType.GetFuncDef() )
  8471. {
  8472. Error(TXT_EXPR_DOESNT_EVAL_TO_FUNC, node);
  8473. return -1;
  8474. }
  8475. // Compile arguments
  8476. asCArray<asSExprContext *> args;
  8477. if( CompileArgumentList(node->lastChild, args) >= 0 )
  8478. {
  8479. // Match arguments with the funcdef
  8480. asCArray<int> funcs;
  8481. funcs.PushLast(ctx->type.dataType.GetFuncDef()->id);
  8482. MatchFunctions(funcs, args, node, ctx->type.dataType.GetFuncDef()->name.AddressOf());
  8483. if( funcs.GetLength() != 1 )
  8484. {
  8485. // The error was reported by MatchFunctions()
  8486. // Dummy value
  8487. ctx->type.SetDummy();
  8488. }
  8489. else
  8490. {
  8491. int r = asSUCCESS;
  8492. // Add the default values for arguments not explicitly supplied
  8493. asCScriptFunction *func = (funcs[0] & FUNC_IMPORTED) == 0 ? engine->scriptFunctions[funcs[0]] : 0;
  8494. if( func && args.GetLength() < (asUINT)func->GetParamCount() )
  8495. r = CompileDefaultArgs(node, args, func);
  8496. // TODO: funcdef: Do we have to make sure the handle is stored in a temporary variable, or
  8497. // is it enough to make sure it is in a local variable?
  8498. // For function pointer we must guarantee that the function is safe, i.e.
  8499. // by first storing the function pointer in a local variable (if it isn't already in one)
  8500. if( r == asSUCCESS )
  8501. {
  8502. Dereference(ctx, true);
  8503. if( !ctx->type.isVariable )
  8504. ConvertToVariable(ctx);
  8505. else
  8506. {
  8507. // Remove the reference from the stack as the asBC_CALLPTR instruction takes the variable as argument
  8508. ctx->bc.Instr(asBC_PopPtr);
  8509. }
  8510. asCTypeInfo t = ctx->type;
  8511. MakeFunctionCall(ctx, funcs[0], 0, args, node, false, 0, ctx->type.stackOffset);
  8512. ReleaseTemporaryVariable(t, &ctx->bc);
  8513. }
  8514. }
  8515. }
  8516. else
  8517. ctx->type.SetDummy();
  8518. // Cleanup
  8519. for( asUINT n = 0; n < args.GetLength(); n++ )
  8520. if( args[n] )
  8521. {
  8522. asDELETE(args[n],asSExprContext);
  8523. }
  8524. }
  8525. return 0;
  8526. }
  8527. int asCCompiler::GetPrecedence(asCScriptNode *op)
  8528. {
  8529. // x * y, x / y, x % y
  8530. // x + y, x - y
  8531. // x <= y, x < y, x >= y, x > y
  8532. // x = =y, x != y, x xor y, x is y, x !is y
  8533. // x and y
  8534. // x or y
  8535. // The following are not used in this function,
  8536. // but should have lower precedence than the above
  8537. // x ? y : z
  8538. // x = y
  8539. // The expression term have the highest precedence
  8540. if( op->nodeType == snExprTerm )
  8541. return 1;
  8542. // Evaluate operators by token
  8543. int tokenType = op->tokenType;
  8544. if( tokenType == ttStar || tokenType == ttSlash || tokenType == ttPercent )
  8545. return 0;
  8546. if( tokenType == ttPlus || tokenType == ttMinus )
  8547. return -1;
  8548. if( tokenType == ttBitShiftLeft ||
  8549. tokenType == ttBitShiftRight ||
  8550. tokenType == ttBitShiftRightArith )
  8551. return -2;
  8552. if( tokenType == ttAmp )
  8553. return -3;
  8554. if( tokenType == ttBitXor )
  8555. return -4;
  8556. if( tokenType == ttBitOr )
  8557. return -5;
  8558. if( tokenType == ttLessThanOrEqual ||
  8559. tokenType == ttLessThan ||
  8560. tokenType == ttGreaterThanOrEqual ||
  8561. tokenType == ttGreaterThan )
  8562. return -6;
  8563. if( tokenType == ttEqual || tokenType == ttNotEqual || tokenType == ttXor || tokenType == ttIs || tokenType == ttNotIs )
  8564. return -7;
  8565. if( tokenType == ttAnd )
  8566. return -8;
  8567. if( tokenType == ttOr )
  8568. return -9;
  8569. // Unknown operator
  8570. asASSERT(false);
  8571. return 0;
  8572. }
  8573. asUINT asCCompiler::MatchArgument(asCArray<int> &funcs, asCArray<asSOverloadCandidate> &matches, const asSExprContext *argExpr, int paramNum, bool allowObjectConstruct)
  8574. {
  8575. matches.SetLength(0);
  8576. for( asUINT n = 0; n < funcs.GetLength(); n++ )
  8577. {
  8578. asCScriptFunction *desc = builder->GetFunctionDescription(funcs[n]);
  8579. // Does the function have arguments enough?
  8580. if( (int)desc->parameterTypes.GetLength() <= paramNum )
  8581. continue;
  8582. // Can we make the match by implicit conversion?
  8583. asSExprContext ti(engine);
  8584. ti.type = argExpr->type;
  8585. ti.methodName = argExpr->methodName;
  8586. if( argExpr->type.dataType.IsPrimitive() ) ti.type.dataType.MakeReference(false);
  8587. asUINT cost = ImplicitConversion(&ti, desc->parameterTypes[paramNum], 0, asIC_IMPLICIT_CONV, false, allowObjectConstruct);
  8588. // If the function parameter is an inout-reference then it must not be possible to call the
  8589. // function with an incorrect argument type, even though the type can normally be converted.
  8590. if( desc->parameterTypes[paramNum].IsReference() &&
  8591. desc->inOutFlags[paramNum] == asTM_INOUTREF &&
  8592. desc->parameterTypes[paramNum].GetTokenType() != ttQuestion )
  8593. {
  8594. // Observe, that the below checks are only necessary for when unsafe references have been
  8595. // enabled by the application. Without this the &inout reference form wouldn't be allowed
  8596. // for these value types.
  8597. // Don't allow a primitive to be converted to a reference of another primitive type
  8598. if( desc->parameterTypes[paramNum].IsPrimitive() &&
  8599. desc->parameterTypes[paramNum].GetTokenType() != argExpr->type.dataType.GetTokenType() )
  8600. {
  8601. asASSERT( engine->ep.allowUnsafeReferences );
  8602. continue;
  8603. }
  8604. // Don't allow an enum to be converted to a reference of another enum type
  8605. if( desc->parameterTypes[paramNum].IsEnumType() &&
  8606. desc->parameterTypes[paramNum].GetObjectType() != argExpr->type.dataType.GetObjectType() )
  8607. {
  8608. asASSERT( engine->ep.allowUnsafeReferences );
  8609. continue;
  8610. }
  8611. // Don't allow a non-handle expression to be converted to a reference to a handle
  8612. if( desc->parameterTypes[paramNum].IsObjectHandle() &&
  8613. !argExpr->type.dataType.IsObjectHandle() )
  8614. {
  8615. asASSERT( engine->ep.allowUnsafeReferences );
  8616. continue;
  8617. }
  8618. // Don't allow a value type to be converted
  8619. if( (desc->parameterTypes[paramNum].GetObjectType() && (desc->parameterTypes[paramNum].GetObjectType()->GetFlags() & asOBJ_VALUE)) &&
  8620. (desc->parameterTypes[paramNum].GetObjectType() != argExpr->type.dataType.GetObjectType()) )
  8621. {
  8622. asASSERT( engine->ep.allowUnsafeReferences );
  8623. continue;
  8624. }
  8625. }
  8626. // How well does the argument match the function parameter?
  8627. if( desc->parameterTypes[paramNum].IsEqualExceptRef(ti.type.dataType) )
  8628. matches.PushLast(asSOverloadCandidate(funcs[n], cost));
  8629. }
  8630. return (asUINT)matches.GetLength();
  8631. }
  8632. void asCCompiler::PrepareArgument2(asSExprContext *ctx, asSExprContext *arg, asCDataType *paramType, bool isFunction, int refType, bool isMakingCopy)
  8633. {
  8634. // Reference parameters whose value won't be used don't evaluate the expression
  8635. if( paramType->IsReference() && !(refType & asTM_INREF) )
  8636. {
  8637. // Store the original bytecode so that it can be reused when processing the deferred output parameter
  8638. asSExprContext *orig = asNEW(asSExprContext)(engine);
  8639. if( orig == 0 )
  8640. {
  8641. // Out of memory
  8642. return;
  8643. }
  8644. MergeExprBytecodeAndType(orig, arg);
  8645. arg->origExpr = orig;
  8646. }
  8647. PrepareArgument(paramType, arg, arg->exprNode, isFunction, refType, isMakingCopy);
  8648. // arg still holds the original expression for output parameters
  8649. ctx->bc.AddCode(&arg->bc);
  8650. }
  8651. bool asCCompiler::CompileOverloadedDualOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  8652. {
  8653. DetermineSingleFunc(lctx, node);
  8654. DetermineSingleFunc(rctx, node);
  8655. ctx->exprNode = node;
  8656. // What type of operator is it?
  8657. int token = node->tokenType;
  8658. if( token == ttUnrecognizedToken )
  8659. {
  8660. // This happens when the compiler is inferring an assignment
  8661. // operation from another action, for example in preparing a value
  8662. // as a function argument
  8663. token = ttAssignment;
  8664. }
  8665. // boolean operators are not overloadable
  8666. if( token == ttAnd ||
  8667. token == ttOr ||
  8668. token == ttXor )
  8669. return false;
  8670. // Dual operators can also be implemented as class methods
  8671. if( token == ttEqual ||
  8672. token == ttNotEqual )
  8673. {
  8674. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  8675. // Find the matching opEquals method
  8676. int r = CompileOverloadedDualOperator2(node, "opEquals", lctx, rctx, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  8677. if( r == 0 )
  8678. {
  8679. // Try again by switching the order of the operands
  8680. r = CompileOverloadedDualOperator2(node, "opEquals", rctx, lctx, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  8681. }
  8682. if( r == 1 )
  8683. {
  8684. if( token == ttNotEqual )
  8685. ctx->bc.InstrSHORT(asBC_NOT, ctx->type.stackOffset);
  8686. // Success, don't continue
  8687. return true;
  8688. }
  8689. else if( r < 0 )
  8690. {
  8691. // Compiler error, don't continue
  8692. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  8693. return true;
  8694. }
  8695. }
  8696. if( token == ttEqual ||
  8697. token == ttNotEqual ||
  8698. token == ttLessThan ||
  8699. token == ttLessThanOrEqual ||
  8700. token == ttGreaterThan ||
  8701. token == ttGreaterThanOrEqual )
  8702. {
  8703. bool swappedOrder = false;
  8704. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  8705. // Find the matching opCmp method
  8706. int r = CompileOverloadedDualOperator2(node, "opCmp", lctx, rctx, ctx, true, asCDataType::CreatePrimitive(ttInt, false));
  8707. if( r == 0 )
  8708. {
  8709. // Try again by switching the order of the operands
  8710. swappedOrder = true;
  8711. r = CompileOverloadedDualOperator2(node, "opCmp", rctx, lctx, ctx, true, asCDataType::CreatePrimitive(ttInt, false));
  8712. }
  8713. if( r == 1 )
  8714. {
  8715. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  8716. int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, false), true);
  8717. ctx->bc.InstrW_DW(asBC_CMPIi, ctx->type.stackOffset, 0);
  8718. if( token == ttEqual )
  8719. ctx->bc.Instr(asBC_TZ);
  8720. else if( token == ttNotEqual )
  8721. ctx->bc.Instr(asBC_TNZ);
  8722. else if( (token == ttLessThan && !swappedOrder) ||
  8723. (token == ttGreaterThan && swappedOrder) )
  8724. ctx->bc.Instr(asBC_TS);
  8725. else if( (token == ttLessThanOrEqual && !swappedOrder) ||
  8726. (token == ttGreaterThanOrEqual && swappedOrder) )
  8727. ctx->bc.Instr(asBC_TNP);
  8728. else if( (token == ttGreaterThan && !swappedOrder) ||
  8729. (token == ttLessThan && swappedOrder) )
  8730. ctx->bc.Instr(asBC_TP);
  8731. else if( (token == ttGreaterThanOrEqual && !swappedOrder) ||
  8732. (token == ttLessThanOrEqual && swappedOrder) )
  8733. ctx->bc.Instr(asBC_TNS);
  8734. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  8735. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, false), a, true);
  8736. // Success, don't continue
  8737. return true;
  8738. }
  8739. else if( r < 0 )
  8740. {
  8741. // Compiler error, don't continue
  8742. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  8743. return true;
  8744. }
  8745. }
  8746. // The rest of the operators are not commutative, and doesn't require specific return type
  8747. const char *op = 0, *op_r = 0;
  8748. switch( token )
  8749. {
  8750. case ttPlus: op = "opAdd"; op_r = "opAdd_r"; break;
  8751. case ttMinus: op = "opSub"; op_r = "opSub_r"; break;
  8752. case ttStar: op = "opMul"; op_r = "opMul_r"; break;
  8753. case ttSlash: op = "opDiv"; op_r = "opDiv_r"; break;
  8754. case ttPercent: op = "opMod"; op_r = "opMod_r"; break;
  8755. case ttBitOr: op = "opOr"; op_r = "opOr_r"; break;
  8756. case ttAmp: op = "opAnd"; op_r = "opAnd_r"; break;
  8757. case ttBitXor: op = "opXor"; op_r = "opXor_r"; break;
  8758. case ttBitShiftLeft: op = "opShl"; op_r = "opShl_r"; break;
  8759. case ttBitShiftRight: op = "opShr"; op_r = "opShr_r"; break;
  8760. case ttBitShiftRightArith: op = "opUShr"; op_r = "opUShr_r"; break;
  8761. }
  8762. // TODO: Might be interesting to support a concatenation operator, e.g. ~
  8763. if( op && op_r )
  8764. {
  8765. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  8766. // Find the matching operator method
  8767. int r = CompileOverloadedDualOperator2(node, op, lctx, rctx, ctx);
  8768. if( r == 0 )
  8769. {
  8770. // Try again by switching the order of the operands, and using the reversed operator
  8771. r = CompileOverloadedDualOperator2(node, op_r, rctx, lctx, ctx);
  8772. }
  8773. if( r == 1 )
  8774. {
  8775. // Success, don't continue
  8776. return true;
  8777. }
  8778. else if( r < 0 )
  8779. {
  8780. // Compiler error, don't continue
  8781. ctx->type.SetDummy();
  8782. return true;
  8783. }
  8784. }
  8785. // Assignment operators
  8786. op = 0;
  8787. switch( token )
  8788. {
  8789. case ttAssignment: op = "opAssign"; break;
  8790. case ttAddAssign: op = "opAddAssign"; break;
  8791. case ttSubAssign: op = "opSubAssign"; break;
  8792. case ttMulAssign: op = "opMulAssign"; break;
  8793. case ttDivAssign: op = "opDivAssign"; break;
  8794. case ttModAssign: op = "opModAssign"; break;
  8795. case ttOrAssign: op = "opOrAssign"; break;
  8796. case ttAndAssign: op = "opAndAssign"; break;
  8797. case ttXorAssign: op = "opXorAssign"; break;
  8798. case ttShiftLeftAssign: op = "opShlAssign"; break;
  8799. case ttShiftRightLAssign: op = "opShrAssign"; break;
  8800. case ttShiftRightAAssign: op = "opUShrAssign"; break;
  8801. }
  8802. if( op )
  8803. {
  8804. if( builder->engine->ep.disallowValueAssignForRefType &&
  8805. lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->flags & asOBJ_REF) && !(lctx->type.dataType.GetObjectType()->flags & asOBJ_SCOPED) )
  8806. {
  8807. if( token == ttAssignment )
  8808. Error(TXT_DISALLOW_ASSIGN_ON_REF_TYPE, node);
  8809. else
  8810. Error(TXT_DISALLOW_COMPOUND_ASSIGN_ON_REF_TYPE, node);
  8811. // Set a dummy output
  8812. ctx->type.Set(lctx->type.dataType);
  8813. return true;
  8814. }
  8815. // TODO: Shouldn't accept const lvalue with the assignment operators
  8816. // Find the matching operator method
  8817. int r = CompileOverloadedDualOperator2(node, op, lctx, rctx, ctx);
  8818. if( r == 1 )
  8819. {
  8820. // Success, don't continue
  8821. return true;
  8822. }
  8823. else if( r < 0 )
  8824. {
  8825. // Compiler error, don't continue
  8826. ctx->type.SetDummy();
  8827. return true;
  8828. }
  8829. }
  8830. // No suitable operator was found
  8831. return false;
  8832. }
  8833. // Returns negative on compile error
  8834. // zero on no matching operator
  8835. // one on matching operator
  8836. int asCCompiler::CompileOverloadedDualOperator2(asCScriptNode *node, const char *methodName, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx, bool specificReturn, const asCDataType &returnType)
  8837. {
  8838. // Find the matching method
  8839. if( lctx->type.dataType.IsObject() &&
  8840. (!lctx->type.isExplicitHandle ||
  8841. lctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE) )
  8842. {
  8843. asUINT n;
  8844. // Is the left value a const?
  8845. bool isConst = false;
  8846. if( lctx->type.dataType.IsObjectHandle() )
  8847. isConst = lctx->type.dataType.IsHandleToConst();
  8848. else
  8849. isConst = lctx->type.dataType.IsReadOnly();
  8850. asCArray<int> funcs;
  8851. asCObjectType *ot = lctx->type.dataType.GetObjectType();
  8852. for( n = 0; n < ot->methods.GetLength(); n++ )
  8853. {
  8854. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  8855. if( func->name == methodName &&
  8856. (!specificReturn || func->returnType == returnType) &&
  8857. func->parameterTypes.GetLength() == 1 &&
  8858. (!isConst || func->isReadOnly) )
  8859. {
  8860. // Make sure the method is accessible by the module
  8861. if( builder->module->accessMask & func->accessMask )
  8862. {
  8863. funcs.PushLast(func->id);
  8864. }
  8865. }
  8866. }
  8867. // Which is the best matching function?
  8868. asCArray<asSOverloadCandidate> tempFuncs;
  8869. MatchArgument(funcs, tempFuncs, rctx, 0);
  8870. // Find the lowest cost operator(s)
  8871. asCArray<int> ops;
  8872. asUINT bestCost = asUINT(-1);
  8873. for( n = 0; n < tempFuncs.GetLength(); ++n )
  8874. {
  8875. asUINT cost = tempFuncs[n].cost;
  8876. if( cost < bestCost )
  8877. {
  8878. ops.SetLength(0);
  8879. bestCost = cost;
  8880. }
  8881. if( cost == bestCost )
  8882. ops.PushLast(tempFuncs[n].funcId);
  8883. }
  8884. // If the object is not const, then we need to prioritize non-const methods
  8885. if( !isConst )
  8886. FilterConst(ops);
  8887. // Did we find an operator?
  8888. if( ops.GetLength() == 1 )
  8889. {
  8890. // Process the lctx expression as get accessor
  8891. ProcessPropertyGetAccessor(lctx, node);
  8892. // Merge the bytecode so that it forms lvalue.methodName(rvalue)
  8893. asCTypeInfo objType = lctx->type;
  8894. asCArray<asSExprContext *> args;
  8895. args.PushLast(rctx);
  8896. MergeExprBytecode(ctx, lctx);
  8897. ctx->type = lctx->type;
  8898. MakeFunctionCall(ctx, ops[0], objType.dataType.GetObjectType(), args, node);
  8899. // If the method returned a reference, then we can't release the original
  8900. // object yet, because the reference may be to a member of it
  8901. if( !objType.isTemporary ||
  8902. !(ctx->type.dataType.IsReference() || (ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle())) ||
  8903. ctx->type.isVariable ) // If the resulting type is a variable, then the reference is not to a member
  8904. {
  8905. // As the index operator didn't return a reference to a
  8906. // member we can release the original object now
  8907. ReleaseTemporaryVariable(objType, &ctx->bc);
  8908. }
  8909. // Found matching operator
  8910. return 1;
  8911. }
  8912. else if( ops.GetLength() > 1 )
  8913. {
  8914. Error(TXT_MORE_THAN_ONE_MATCHING_OP, node);
  8915. PrintMatchingFuncs(ops, node);
  8916. ctx->type.SetDummy();
  8917. // Compiler error
  8918. return -1;
  8919. }
  8920. }
  8921. // No matching operator
  8922. return 0;
  8923. }
  8924. void asCCompiler::MakeFunctionCall(asSExprContext *ctx, int funcId, asCObjectType *objectType, asCArray<asSExprContext*> &args, asCScriptNode * /*node*/, bool useVariable, int stackOffset, int funcPtrVar)
  8925. {
  8926. if( objectType )
  8927. {
  8928. Dereference(ctx, true);
  8929. // This following warning was removed as there may be valid reasons
  8930. // for calling non-const methods on temporary objects, and we shouldn't
  8931. // warn when there is no way of removing the warning.
  8932. /*
  8933. // Warn if the method is non-const and the object is temporary
  8934. // since the changes will be lost when the object is destroyed.
  8935. // If the object is accessed through a handle, then it is assumed
  8936. // the object is not temporary, even though the handle is.
  8937. if( ctx->type.isTemporary &&
  8938. !ctx->type.dataType.IsObjectHandle() &&
  8939. !engine->scriptFunctions[funcId]->isReadOnly )
  8940. {
  8941. Warning("A non-const method is called on temporary object. Changes to the object may be lost.", node);
  8942. Information(engine->scriptFunctions[funcId]->GetDeclaration(), node);
  8943. }
  8944. */ }
  8945. asCByteCode objBC(engine);
  8946. objBC.AddCode(&ctx->bc);
  8947. PrepareFunctionCall(funcId, &ctx->bc, args);
  8948. // Verify if any of the args variable offsets are used in the other code.
  8949. // If they are exchange the offset for a new one
  8950. asUINT n;
  8951. for( n = 0; n < args.GetLength(); n++ )
  8952. {
  8953. if( args[n]->type.isTemporary && objBC.IsVarUsed(args[n]->type.stackOffset) )
  8954. {
  8955. // Release the current temporary variable
  8956. ReleaseTemporaryVariable(args[n]->type, 0);
  8957. asCDataType dt = args[n]->type.dataType;
  8958. dt.MakeReference(false);
  8959. int l = int(reservedVariables.GetLength());
  8960. objBC.GetVarsUsed(reservedVariables);
  8961. ctx->bc.GetVarsUsed(reservedVariables);
  8962. int newOffset = AllocateVariable(dt, true, IsVariableOnHeap(args[n]->type.stackOffset));
  8963. reservedVariables.SetLength(l);
  8964. asASSERT( IsVariableOnHeap(args[n]->type.stackOffset) == IsVariableOnHeap(newOffset) );
  8965. ctx->bc.ExchangeVar(args[n]->type.stackOffset, newOffset);
  8966. args[n]->type.stackOffset = (short)newOffset;
  8967. args[n]->type.isTemporary = true;
  8968. args[n]->type.isVariable = true;
  8969. }
  8970. }
  8971. // If the function will return a value type on the stack, then we must allocate space
  8972. // for that here and push the address on the stack as a hidden argument to the function
  8973. asCScriptFunction *func = builder->GetFunctionDescription(funcId);
  8974. if( func->DoesReturnOnStack() )
  8975. {
  8976. asASSERT(!useVariable);
  8977. useVariable = true;
  8978. stackOffset = AllocateVariable(func->returnType, true);
  8979. ctx->bc.InstrSHORT(asBC_PSF, short(stackOffset));
  8980. }
  8981. ctx->bc.AddCode(&objBC);
  8982. MoveArgsToStack(funcId, &ctx->bc, args, objectType ? true : false);
  8983. PerformFunctionCall(funcId, ctx, false, &args, 0, useVariable, stackOffset, funcPtrVar);
  8984. }
  8985. int asCCompiler::CompileOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  8986. {
  8987. // Don't allow any operators on expressions that take address of class method, but allow it on global functions
  8988. if( (lctx->methodName != "" && lctx->type.dataType.GetObjectType()) || (rctx->methodName != "" && rctx->type.dataType.GetObjectType()) )
  8989. {
  8990. Error(TXT_INVALID_OP_ON_METHOD, node);
  8991. return -1;
  8992. }
  8993. IsVariableInitialized(&lctx->type, node);
  8994. IsVariableInitialized(&rctx->type, node);
  8995. if( lctx->type.isExplicitHandle || rctx->type.isExplicitHandle ||
  8996. node->tokenType == ttIs || node->tokenType == ttNotIs )
  8997. {
  8998. CompileOperatorOnHandles(node, lctx, rctx, ctx);
  8999. return 0;
  9000. }
  9001. else
  9002. {
  9003. // Compile an overloaded operator for the two operands
  9004. if( CompileOverloadedDualOperator(node, lctx, rctx, ctx) )
  9005. return 0;
  9006. // If both operands are objects, then we shouldn't continue
  9007. if( lctx->type.dataType.IsObject() && rctx->type.dataType.IsObject() )
  9008. {
  9009. asCString str;
  9010. str.Format(TXT_NO_MATCHING_OP_FOUND_FOR_TYPES_s_AND_s, lctx->type.dataType.Format().AddressOf(), rctx->type.dataType.Format().AddressOf());
  9011. Error(str, node);
  9012. ctx->type.SetDummy();
  9013. return -1;
  9014. }
  9015. // Process the property get accessors (if any)
  9016. ProcessPropertyGetAccessor(lctx, node);
  9017. ProcessPropertyGetAccessor(rctx, node);
  9018. // Make sure we have two variables or constants
  9019. if( lctx->type.dataType.IsReference() ) ConvertToVariableNotIn(lctx, rctx);
  9020. if( rctx->type.dataType.IsReference() ) ConvertToVariableNotIn(rctx, lctx);
  9021. // Make sure lctx doesn't end up with a variable used in rctx
  9022. if( lctx->type.isTemporary && rctx->bc.IsVarUsed(lctx->type.stackOffset) )
  9023. {
  9024. int offset = AllocateVariableNotIn(lctx->type.dataType, true, false, rctx);
  9025. rctx->bc.ExchangeVar(lctx->type.stackOffset, offset);
  9026. ReleaseTemporaryVariable(offset, 0);
  9027. }
  9028. // Math operators
  9029. // + - * / % += -= *= /= %=
  9030. int op = node->tokenType;
  9031. if( op == ttPlus || op == ttAddAssign ||
  9032. op == ttMinus || op == ttSubAssign ||
  9033. op == ttStar || op == ttMulAssign ||
  9034. op == ttSlash || op == ttDivAssign ||
  9035. op == ttPercent || op == ttModAssign )
  9036. {
  9037. CompileMathOperator(node, lctx, rctx, ctx);
  9038. return 0;
  9039. }
  9040. // Bitwise operators
  9041. // << >> >>> & | ^ <<= >>= >>>= &= |= ^=
  9042. if( op == ttAmp || op == ttAndAssign ||
  9043. op == ttBitOr || op == ttOrAssign ||
  9044. op == ttBitXor || op == ttXorAssign ||
  9045. op == ttBitShiftLeft || op == ttShiftLeftAssign ||
  9046. op == ttBitShiftRight || op == ttShiftRightLAssign ||
  9047. op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  9048. {
  9049. CompileBitwiseOperator(node, lctx, rctx, ctx);
  9050. return 0;
  9051. }
  9052. // Comparison operators
  9053. // == != < > <= >=
  9054. if( op == ttEqual || op == ttNotEqual ||
  9055. op == ttLessThan || op == ttLessThanOrEqual ||
  9056. op == ttGreaterThan || op == ttGreaterThanOrEqual )
  9057. {
  9058. CompileComparisonOperator(node, lctx, rctx, ctx);
  9059. return 0;
  9060. }
  9061. // Boolean operators
  9062. // && || ^^
  9063. if( op == ttAnd || op == ttOr || op == ttXor )
  9064. {
  9065. CompileBooleanOperator(node, lctx, rctx, ctx);
  9066. return 0;
  9067. }
  9068. }
  9069. asASSERT(false);
  9070. return -1;
  9071. }
  9072. void asCCompiler::ConvertToTempVariableNotIn(asSExprContext *ctx, asSExprContext *exclude)
  9073. {
  9074. int l = int(reservedVariables.GetLength());
  9075. if( exclude ) exclude->bc.GetVarsUsed(reservedVariables);
  9076. ConvertToTempVariable(ctx);
  9077. reservedVariables.SetLength(l);
  9078. }
  9079. void asCCompiler::ConvertToTempVariable(asSExprContext *ctx)
  9080. {
  9081. // This is only used for primitive types and null handles
  9082. asASSERT( ctx->type.dataType.IsPrimitive() || ctx->type.dataType.IsNullHandle() );
  9083. ConvertToVariable(ctx);
  9084. if( !ctx->type.isTemporary )
  9085. {
  9086. if( ctx->type.dataType.IsPrimitive() )
  9087. {
  9088. // Copy the variable to a temporary variable
  9089. int offset = AllocateVariable(ctx->type.dataType, true);
  9090. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  9091. ctx->bc.InstrW_W(asBC_CpyVtoV4, offset, ctx->type.stackOffset);
  9092. else
  9093. ctx->bc.InstrW_W(asBC_CpyVtoV8, offset, ctx->type.stackOffset);
  9094. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  9095. }
  9096. else
  9097. {
  9098. // We should never get here
  9099. asASSERT(false);
  9100. }
  9101. }
  9102. }
  9103. void asCCompiler::ConvertToVariable(asSExprContext *ctx)
  9104. {
  9105. // We should never get here while the context is still an unprocessed property accessor
  9106. asASSERT(ctx->property_get == 0 && ctx->property_set == 0);
  9107. int offset;
  9108. if( !ctx->type.isVariable &&
  9109. (ctx->type.dataType.IsObjectHandle() ||
  9110. (ctx->type.dataType.IsObject() && ctx->type.dataType.SupportHandles())) )
  9111. {
  9112. offset = AllocateVariable(ctx->type.dataType, true);
  9113. if( ctx->type.IsNullConstant() )
  9114. {
  9115. if( ctx->bc.GetLastInstr() == asBC_PshNull )
  9116. ctx->bc.Instr(asBC_PopPtr); // Pop the null constant pushed onto the stack
  9117. ctx->bc.InstrSHORT(asBC_ClrVPtr, (short)offset);
  9118. }
  9119. else
  9120. {
  9121. // Copy the object handle to a variable
  9122. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  9123. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetObjectType());
  9124. ctx->bc.Instr(asBC_PopPtr);
  9125. }
  9126. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  9127. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  9128. ctx->type.dataType.MakeHandle(true);
  9129. }
  9130. else if( (!ctx->type.isVariable || ctx->type.dataType.IsReference()) &&
  9131. ctx->type.dataType.IsPrimitive() )
  9132. {
  9133. if( ctx->type.isConstant )
  9134. {
  9135. offset = AllocateVariable(ctx->type.dataType, true);
  9136. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  9137. ctx->bc.InstrSHORT_B(asBC_SetV1, (short)offset, ctx->type.byteValue);
  9138. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  9139. ctx->bc.InstrSHORT_W(asBC_SetV2, (short)offset, ctx->type.wordValue);
  9140. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 )
  9141. ctx->bc.InstrSHORT_DW(asBC_SetV4, (short)offset, ctx->type.dwordValue);
  9142. else
  9143. ctx->bc.InstrSHORT_QW(asBC_SetV8, (short)offset, ctx->type.qwordValue);
  9144. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  9145. return;
  9146. }
  9147. else
  9148. {
  9149. asASSERT(ctx->type.dataType.IsPrimitive());
  9150. asASSERT(ctx->type.dataType.IsReference());
  9151. ctx->type.dataType.MakeReference(false);
  9152. offset = AllocateVariable(ctx->type.dataType, true);
  9153. // Read the value from the address in the register directly into the variable
  9154. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  9155. ctx->bc.InstrSHORT(asBC_RDR1, (short)offset);
  9156. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  9157. ctx->bc.InstrSHORT(asBC_RDR2, (short)offset);
  9158. else if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  9159. ctx->bc.InstrSHORT(asBC_RDR4, (short)offset);
  9160. else
  9161. ctx->bc.InstrSHORT(asBC_RDR8, (short)offset);
  9162. }
  9163. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  9164. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  9165. }
  9166. }
  9167. void asCCompiler::ConvertToVariableNotIn(asSExprContext *ctx, asSExprContext *exclude)
  9168. {
  9169. int l = int(reservedVariables.GetLength());
  9170. if( exclude ) exclude->bc.GetVarsUsed(reservedVariables);
  9171. ConvertToVariable(ctx);
  9172. reservedVariables.SetLength(l);
  9173. }
  9174. void asCCompiler::CompileMathOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  9175. {
  9176. // TODO: If a constant is only using 32bits, then a 32bit operation is preferred
  9177. // TODO: clean up: This initial part is identical to CompileComparisonOperator. Make a common function out of it
  9178. // Implicitly convert the operands to a number type
  9179. asCDataType to;
  9180. // If either operand is a non-primitive then use the primitive type
  9181. if( !lctx->type.dataType.IsPrimitive() )
  9182. to.SetTokenType(rctx->type.dataType.GetTokenType());
  9183. else if( !rctx->type.dataType.IsPrimitive() )
  9184. to.SetTokenType(lctx->type.dataType.GetTokenType());
  9185. else if( lctx->type.dataType.IsDoubleType() || rctx->type.dataType.IsDoubleType() )
  9186. to.SetTokenType(ttDouble);
  9187. else if( lctx->type.dataType.IsFloatType() || rctx->type.dataType.IsFloatType() )
  9188. to.SetTokenType(ttFloat);
  9189. else if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 || rctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  9190. {
  9191. // Convert to int64 if both are signed or if one is non-constant and signed
  9192. if( (lctx->type.dataType.IsIntegerType() && rctx->type.dataType.IsIntegerType()) ||
  9193. (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) ||
  9194. (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) )
  9195. to.SetTokenType(ttInt64);
  9196. else
  9197. to.SetTokenType(ttUInt64);
  9198. }
  9199. else
  9200. {
  9201. // Convert to int32 if both are signed or if one is non-constant and signed
  9202. if( (lctx->type.dataType.IsIntegerType() && rctx->type.dataType.IsIntegerType()) ||
  9203. (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) ||
  9204. (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) )
  9205. to.SetTokenType(ttInt);
  9206. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  9207. to.SetTokenType(ttUInt);
  9208. else if( lctx->type.dataType.IsBooleanType() || rctx->type.dataType.IsBooleanType() )
  9209. to.SetTokenType(ttBool);
  9210. }
  9211. // If doing an operation with double constant and float variable, the constant should be converted to float
  9212. if( (lctx->type.isConstant && lctx->type.dataType.IsDoubleType() && !rctx->type.isConstant && rctx->type.dataType.IsFloatType()) ||
  9213. (rctx->type.isConstant && rctx->type.dataType.IsDoubleType() && !lctx->type.isConstant && lctx->type.dataType.IsFloatType()) )
  9214. to.SetTokenType(ttFloat);
  9215. // Do the actual conversion
  9216. int l = int(reservedVariables.GetLength());
  9217. rctx->bc.GetVarsUsed(reservedVariables);
  9218. lctx->bc.GetVarsUsed(reservedVariables);
  9219. if( lctx->type.dataType.IsReference() )
  9220. ConvertToVariable(lctx);
  9221. if( rctx->type.dataType.IsReference() )
  9222. ConvertToVariable(rctx);
  9223. if( to.IsPrimitive() )
  9224. {
  9225. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true);
  9226. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true);
  9227. }
  9228. reservedVariables.SetLength(l);
  9229. // Verify that the conversion was successful
  9230. if( !lctx->type.dataType.IsIntegerType() &&
  9231. !lctx->type.dataType.IsUnsignedType() &&
  9232. !lctx->type.dataType.IsFloatType() &&
  9233. !lctx->type.dataType.IsDoubleType() )
  9234. {
  9235. asCString str;
  9236. str.Format(TXT_NO_CONVERSION_s_TO_MATH_TYPE, lctx->type.dataType.Format().AddressOf());
  9237. Error(str, node);
  9238. ctx->type.SetDummy();
  9239. return;
  9240. }
  9241. if( !rctx->type.dataType.IsIntegerType() &&
  9242. !rctx->type.dataType.IsUnsignedType() &&
  9243. !rctx->type.dataType.IsFloatType() &&
  9244. !rctx->type.dataType.IsDoubleType() )
  9245. {
  9246. asCString str;
  9247. str.Format(TXT_NO_CONVERSION_s_TO_MATH_TYPE, rctx->type.dataType.Format().AddressOf());
  9248. Error(str, node);
  9249. ctx->type.SetDummy();
  9250. return;
  9251. }
  9252. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  9253. // Verify if we are dividing with a constant zero
  9254. int op = node->tokenType;
  9255. if( rctx->type.isConstant && rctx->type.qwordValue == 0 &&
  9256. (op == ttSlash || op == ttDivAssign ||
  9257. op == ttPercent || op == ttModAssign) )
  9258. {
  9259. Error(TXT_DIVIDE_BY_ZERO, node);
  9260. }
  9261. if( !isConstant )
  9262. {
  9263. ConvertToVariableNotIn(lctx, rctx);
  9264. ConvertToVariableNotIn(rctx, lctx);
  9265. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  9266. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  9267. if( op == ttAddAssign || op == ttSubAssign ||
  9268. op == ttMulAssign || op == ttDivAssign ||
  9269. op == ttModAssign )
  9270. {
  9271. // Merge the operands in the different order so that they are evaluated correctly
  9272. MergeExprBytecode(ctx, rctx);
  9273. MergeExprBytecode(ctx, lctx);
  9274. }
  9275. else
  9276. {
  9277. MergeExprBytecode(ctx, lctx);
  9278. MergeExprBytecode(ctx, rctx);
  9279. }
  9280. ProcessDeferredParams(ctx);
  9281. asEBCInstr instruction = asBC_ADDi;
  9282. if( lctx->type.dataType.IsIntegerType() ||
  9283. lctx->type.dataType.IsUnsignedType() )
  9284. {
  9285. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  9286. {
  9287. if( op == ttPlus || op == ttAddAssign )
  9288. instruction = asBC_ADDi;
  9289. else if( op == ttMinus || op == ttSubAssign )
  9290. instruction = asBC_SUBi;
  9291. else if( op == ttStar || op == ttMulAssign )
  9292. instruction = asBC_MULi;
  9293. else if( op == ttSlash || op == ttDivAssign )
  9294. {
  9295. if( lctx->type.dataType.IsIntegerType() )
  9296. instruction = asBC_DIVi;
  9297. else
  9298. instruction = asBC_DIVu;
  9299. }
  9300. else if( op == ttPercent || op == ttModAssign )
  9301. {
  9302. if( lctx->type.dataType.IsIntegerType() )
  9303. instruction = asBC_MODi;
  9304. else
  9305. instruction = asBC_MODu;
  9306. }
  9307. }
  9308. else
  9309. {
  9310. if( op == ttPlus || op == ttAddAssign )
  9311. instruction = asBC_ADDi64;
  9312. else if( op == ttMinus || op == ttSubAssign )
  9313. instruction = asBC_SUBi64;
  9314. else if( op == ttStar || op == ttMulAssign )
  9315. instruction = asBC_MULi64;
  9316. else if( op == ttSlash || op == ttDivAssign )
  9317. {
  9318. if( lctx->type.dataType.IsIntegerType() )
  9319. instruction = asBC_DIVi64;
  9320. else
  9321. instruction = asBC_DIVu64;
  9322. }
  9323. else if( op == ttPercent || op == ttModAssign )
  9324. {
  9325. if( lctx->type.dataType.IsIntegerType() )
  9326. instruction = asBC_MODi64;
  9327. else
  9328. instruction = asBC_MODu64;
  9329. }
  9330. }
  9331. }
  9332. else if( lctx->type.dataType.IsFloatType() )
  9333. {
  9334. if( op == ttPlus || op == ttAddAssign )
  9335. instruction = asBC_ADDf;
  9336. else if( op == ttMinus || op == ttSubAssign )
  9337. instruction = asBC_SUBf;
  9338. else if( op == ttStar || op == ttMulAssign )
  9339. instruction = asBC_MULf;
  9340. else if( op == ttSlash || op == ttDivAssign )
  9341. instruction = asBC_DIVf;
  9342. else if( op == ttPercent || op == ttModAssign )
  9343. instruction = asBC_MODf;
  9344. }
  9345. else if( lctx->type.dataType.IsDoubleType() )
  9346. {
  9347. if( op == ttPlus || op == ttAddAssign )
  9348. instruction = asBC_ADDd;
  9349. else if( op == ttMinus || op == ttSubAssign )
  9350. instruction = asBC_SUBd;
  9351. else if( op == ttStar || op == ttMulAssign )
  9352. instruction = asBC_MULd;
  9353. else if( op == ttSlash || op == ttDivAssign )
  9354. instruction = asBC_DIVd;
  9355. else if( op == ttPercent || op == ttModAssign )
  9356. instruction = asBC_MODd;
  9357. }
  9358. else
  9359. {
  9360. // Shouldn't be possible
  9361. asASSERT(false);
  9362. }
  9363. // Do the operation
  9364. int a = AllocateVariable(lctx->type.dataType, true);
  9365. int b = lctx->type.stackOffset;
  9366. int c = rctx->type.stackOffset;
  9367. ctx->bc.InstrW_W_W(instruction, a, b, c);
  9368. ctx->type.SetVariable(lctx->type.dataType, a, true);
  9369. }
  9370. else
  9371. {
  9372. // Both values are constants
  9373. if( lctx->type.dataType.IsIntegerType() ||
  9374. lctx->type.dataType.IsUnsignedType() )
  9375. {
  9376. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  9377. {
  9378. int v = 0;
  9379. if( op == ttPlus )
  9380. v = lctx->type.intValue + rctx->type.intValue;
  9381. else if( op == ttMinus )
  9382. v = lctx->type.intValue - rctx->type.intValue;
  9383. else if( op == ttStar )
  9384. v = lctx->type.intValue * rctx->type.intValue;
  9385. else if( op == ttSlash )
  9386. {
  9387. // TODO: Should probably report an error, rather than silently convert the value to 0
  9388. if( rctx->type.intValue == 0 || (rctx->type.intValue == -1 && lctx->type.dwordValue == 0x80000000) )
  9389. v = 0;
  9390. else
  9391. if( lctx->type.dataType.IsIntegerType() )
  9392. v = lctx->type.intValue / rctx->type.intValue;
  9393. else
  9394. v = lctx->type.dwordValue / rctx->type.dwordValue;
  9395. }
  9396. else if( op == ttPercent )
  9397. {
  9398. // TODO: Should probably report an error, rather than silently convert the value to 0
  9399. if( rctx->type.intValue == 0 || (rctx->type.intValue == -1 && lctx->type.dwordValue == 0x80000000) )
  9400. v = 0;
  9401. else
  9402. if( lctx->type.dataType.IsIntegerType() )
  9403. v = lctx->type.intValue % rctx->type.intValue;
  9404. else
  9405. v = lctx->type.dwordValue % rctx->type.dwordValue;
  9406. }
  9407. ctx->type.SetConstantDW(lctx->type.dataType, v);
  9408. // If the right value is greater than the left value in a minus operation, then we need to convert the type to int
  9409. if( lctx->type.dataType.GetTokenType() == ttUInt && op == ttMinus && lctx->type.intValue < rctx->type.intValue )
  9410. ctx->type.dataType.SetTokenType(ttInt);
  9411. }
  9412. else
  9413. {
  9414. asQWORD v = 0;
  9415. if( op == ttPlus )
  9416. v = lctx->type.qwordValue + rctx->type.qwordValue;
  9417. else if( op == ttMinus )
  9418. v = lctx->type.qwordValue - rctx->type.qwordValue;
  9419. else if( op == ttStar )
  9420. v = lctx->type.qwordValue * rctx->type.qwordValue;
  9421. else if( op == ttSlash )
  9422. {
  9423. // TODO: Should probably report an error, rather than silently convert the value to 0
  9424. if( rctx->type.qwordValue == 0 || (rctx->type.qwordValue == asQWORD(-1) && lctx->type.qwordValue == (asQWORD(1)<<63)) )
  9425. v = 0;
  9426. else
  9427. if( lctx->type.dataType.IsIntegerType() )
  9428. v = asINT64(lctx->type.qwordValue) / asINT64(rctx->type.qwordValue);
  9429. else
  9430. v = lctx->type.qwordValue / rctx->type.qwordValue;
  9431. }
  9432. else if( op == ttPercent )
  9433. {
  9434. // TODO: Should probably report an error, rather than silently convert the value to 0
  9435. if( rctx->type.qwordValue == 0 || (rctx->type.qwordValue == asQWORD(-1) && lctx->type.qwordValue == (asQWORD(1)<<63)) )
  9436. v = 0;
  9437. else
  9438. if( lctx->type.dataType.IsIntegerType() )
  9439. v = asINT64(lctx->type.qwordValue) % asINT64(rctx->type.qwordValue);
  9440. else
  9441. v = lctx->type.qwordValue % rctx->type.qwordValue;
  9442. }
  9443. ctx->type.SetConstantQW(lctx->type.dataType, v);
  9444. // If the right value is greater than the left value in a minus operation, then we need to convert the type to int
  9445. if( lctx->type.dataType.GetTokenType() == ttUInt64 && op == ttMinus && lctx->type.qwordValue < rctx->type.qwordValue )
  9446. ctx->type.dataType.SetTokenType(ttInt64);
  9447. }
  9448. }
  9449. else if( lctx->type.dataType.IsFloatType() )
  9450. {
  9451. float v = 0.0f;
  9452. if( op == ttPlus )
  9453. v = lctx->type.floatValue + rctx->type.floatValue;
  9454. else if( op == ttMinus )
  9455. v = lctx->type.floatValue - rctx->type.floatValue;
  9456. else if( op == ttStar )
  9457. v = lctx->type.floatValue * rctx->type.floatValue;
  9458. else if( op == ttSlash )
  9459. {
  9460. if( rctx->type.floatValue == 0 )
  9461. v = 0;
  9462. else
  9463. v = lctx->type.floatValue / rctx->type.floatValue;
  9464. }
  9465. else if( op == ttPercent )
  9466. {
  9467. if( rctx->type.floatValue == 0 )
  9468. v = 0;
  9469. else
  9470. v = fmodf(lctx->type.floatValue, rctx->type.floatValue);
  9471. }
  9472. ctx->type.SetConstantF(lctx->type.dataType, v);
  9473. }
  9474. else if( lctx->type.dataType.IsDoubleType() )
  9475. {
  9476. double v = 0.0;
  9477. if( op == ttPlus )
  9478. v = lctx->type.doubleValue + rctx->type.doubleValue;
  9479. else if( op == ttMinus )
  9480. v = lctx->type.doubleValue - rctx->type.doubleValue;
  9481. else if( op == ttStar )
  9482. v = lctx->type.doubleValue * rctx->type.doubleValue;
  9483. else if( op == ttSlash )
  9484. {
  9485. if( rctx->type.doubleValue == 0 )
  9486. v = 0;
  9487. else
  9488. v = lctx->type.doubleValue / rctx->type.doubleValue;
  9489. }
  9490. else if( op == ttPercent )
  9491. {
  9492. if( rctx->type.doubleValue == 0 )
  9493. v = 0;
  9494. else
  9495. v = fmod(lctx->type.doubleValue, rctx->type.doubleValue);
  9496. }
  9497. ctx->type.SetConstantD(lctx->type.dataType, v);
  9498. }
  9499. else
  9500. {
  9501. // Shouldn't be possible
  9502. asASSERT(false);
  9503. }
  9504. }
  9505. }
  9506. void asCCompiler::CompileBitwiseOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  9507. {
  9508. // TODO: If a constant is only using 32bits, then a 32bit operation is preferred
  9509. int op = node->tokenType;
  9510. if( op == ttAmp || op == ttAndAssign ||
  9511. op == ttBitOr || op == ttOrAssign ||
  9512. op == ttBitXor || op == ttXorAssign )
  9513. {
  9514. // Convert left hand operand to integer if it's not already one
  9515. asCDataType to;
  9516. if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 ||
  9517. rctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  9518. to.SetTokenType(ttUInt64);
  9519. else
  9520. to.SetTokenType(ttUInt);
  9521. // Do the actual conversion
  9522. int l = int(reservedVariables.GetLength());
  9523. rctx->bc.GetVarsUsed(reservedVariables);
  9524. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true);
  9525. reservedVariables.SetLength(l);
  9526. // Verify that the conversion was successful
  9527. if( !lctx->type.dataType.IsUnsignedType() )
  9528. {
  9529. asCString str;
  9530. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  9531. Error(str, node);
  9532. }
  9533. // Convert right hand operand to same type as left hand operand
  9534. l = int(reservedVariables.GetLength());
  9535. lctx->bc.GetVarsUsed(reservedVariables);
  9536. ImplicitConversion(rctx, lctx->type.dataType, node, asIC_IMPLICIT_CONV, true);
  9537. reservedVariables.SetLength(l);
  9538. if( !rctx->type.dataType.IsEqualExceptRef(lctx->type.dataType) )
  9539. {
  9540. asCString str;
  9541. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format().AddressOf(), lctx->type.dataType.Format().AddressOf());
  9542. Error(str, node);
  9543. }
  9544. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  9545. if( !isConstant )
  9546. {
  9547. ConvertToVariableNotIn(lctx, rctx);
  9548. ConvertToVariableNotIn(rctx, lctx);
  9549. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  9550. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  9551. if( op == ttAndAssign || op == ttOrAssign || op == ttXorAssign )
  9552. {
  9553. // Compound assignments execute the right hand value first
  9554. MergeExprBytecode(ctx, rctx);
  9555. MergeExprBytecode(ctx, lctx);
  9556. }
  9557. else
  9558. {
  9559. MergeExprBytecode(ctx, lctx);
  9560. MergeExprBytecode(ctx, rctx);
  9561. }
  9562. ProcessDeferredParams(ctx);
  9563. asEBCInstr instruction = asBC_BAND;
  9564. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  9565. {
  9566. if( op == ttAmp || op == ttAndAssign )
  9567. instruction = asBC_BAND;
  9568. else if( op == ttBitOr || op == ttOrAssign )
  9569. instruction = asBC_BOR;
  9570. else if( op == ttBitXor || op == ttXorAssign )
  9571. instruction = asBC_BXOR;
  9572. }
  9573. else
  9574. {
  9575. if( op == ttAmp || op == ttAndAssign )
  9576. instruction = asBC_BAND64;
  9577. else if( op == ttBitOr || op == ttOrAssign )
  9578. instruction = asBC_BOR64;
  9579. else if( op == ttBitXor || op == ttXorAssign )
  9580. instruction = asBC_BXOR64;
  9581. }
  9582. // Do the operation
  9583. int a = AllocateVariable(lctx->type.dataType, true);
  9584. int b = lctx->type.stackOffset;
  9585. int c = rctx->type.stackOffset;
  9586. ctx->bc.InstrW_W_W(instruction, a, b, c);
  9587. ctx->type.SetVariable(lctx->type.dataType, a, true);
  9588. }
  9589. else
  9590. {
  9591. if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  9592. {
  9593. asQWORD v = 0;
  9594. if( op == ttAmp )
  9595. v = lctx->type.qwordValue & rctx->type.qwordValue;
  9596. else if( op == ttBitOr )
  9597. v = lctx->type.qwordValue | rctx->type.qwordValue;
  9598. else if( op == ttBitXor )
  9599. v = lctx->type.qwordValue ^ rctx->type.qwordValue;
  9600. // Remember the result
  9601. ctx->type.SetConstantQW(lctx->type.dataType, v);
  9602. }
  9603. else
  9604. {
  9605. asDWORD v = 0;
  9606. if( op == ttAmp )
  9607. v = lctx->type.dwordValue & rctx->type.dwordValue;
  9608. else if( op == ttBitOr )
  9609. v = lctx->type.dwordValue | rctx->type.dwordValue;
  9610. else if( op == ttBitXor )
  9611. v = lctx->type.dwordValue ^ rctx->type.dwordValue;
  9612. // Remember the result
  9613. ctx->type.SetConstantDW(lctx->type.dataType, v);
  9614. }
  9615. }
  9616. }
  9617. else if( op == ttBitShiftLeft || op == ttShiftLeftAssign ||
  9618. op == ttBitShiftRight || op == ttShiftRightLAssign ||
  9619. op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  9620. {
  9621. // Don't permit object to primitive conversion, since we don't know which integer type is the correct one
  9622. if( lctx->type.dataType.IsObject() )
  9623. {
  9624. asCString str;
  9625. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format().AddressOf());
  9626. Error(str, node);
  9627. // Set an integer value and allow the compiler to continue
  9628. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), 0);
  9629. return;
  9630. }
  9631. // Convert left hand operand to integer if it's not already one
  9632. asCDataType to = lctx->type.dataType;
  9633. if( lctx->type.dataType.IsUnsignedType() &&
  9634. lctx->type.dataType.GetSizeInMemoryBytes() < 4 )
  9635. {
  9636. to = asCDataType::CreatePrimitive(ttUInt, false);
  9637. }
  9638. else if( !lctx->type.dataType.IsUnsignedType() )
  9639. {
  9640. asCDataType to;
  9641. if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  9642. to.SetTokenType(ttInt64);
  9643. else
  9644. to.SetTokenType(ttInt);
  9645. }
  9646. // Do the actual conversion
  9647. int l = int(reservedVariables.GetLength());
  9648. rctx->bc.GetVarsUsed(reservedVariables);
  9649. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true);
  9650. reservedVariables.SetLength(l);
  9651. // Verify that the conversion was successful
  9652. if( lctx->type.dataType != to )
  9653. {
  9654. asCString str;
  9655. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  9656. Error(str, node);
  9657. }
  9658. // Right operand must be 32bit uint
  9659. l = int(reservedVariables.GetLength());
  9660. lctx->bc.GetVarsUsed(reservedVariables);
  9661. ImplicitConversion(rctx, asCDataType::CreatePrimitive(ttUInt, true), node, asIC_IMPLICIT_CONV, true);
  9662. reservedVariables.SetLength(l);
  9663. if( !rctx->type.dataType.IsUnsignedType() )
  9664. {
  9665. asCString str;
  9666. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format().AddressOf(), "uint");
  9667. Error(str, node);
  9668. }
  9669. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  9670. if( !isConstant )
  9671. {
  9672. ConvertToVariableNotIn(lctx, rctx);
  9673. ConvertToVariableNotIn(rctx, lctx);
  9674. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  9675. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  9676. if( op == ttShiftLeftAssign || op == ttShiftRightLAssign || op == ttShiftRightAAssign )
  9677. {
  9678. // Compound assignments execute the right hand value first
  9679. MergeExprBytecode(ctx, rctx);
  9680. MergeExprBytecode(ctx, lctx);
  9681. }
  9682. else
  9683. {
  9684. MergeExprBytecode(ctx, lctx);
  9685. MergeExprBytecode(ctx, rctx);
  9686. }
  9687. ProcessDeferredParams(ctx);
  9688. asEBCInstr instruction = asBC_BSLL;
  9689. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  9690. {
  9691. if( op == ttBitShiftLeft || op == ttShiftLeftAssign )
  9692. instruction = asBC_BSLL;
  9693. else if( op == ttBitShiftRight || op == ttShiftRightLAssign )
  9694. instruction = asBC_BSRL;
  9695. else if( op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  9696. instruction = asBC_BSRA;
  9697. }
  9698. else
  9699. {
  9700. if( op == ttBitShiftLeft || op == ttShiftLeftAssign )
  9701. instruction = asBC_BSLL64;
  9702. else if( op == ttBitShiftRight || op == ttShiftRightLAssign )
  9703. instruction = asBC_BSRL64;
  9704. else if( op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  9705. instruction = asBC_BSRA64;
  9706. }
  9707. // Do the operation
  9708. int a = AllocateVariable(lctx->type.dataType, true);
  9709. int b = lctx->type.stackOffset;
  9710. int c = rctx->type.stackOffset;
  9711. ctx->bc.InstrW_W_W(instruction, a, b, c);
  9712. ctx->type.SetVariable(lctx->type.dataType, a, true);
  9713. }
  9714. else
  9715. {
  9716. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  9717. {
  9718. asDWORD v = 0;
  9719. if( op == ttBitShiftLeft )
  9720. v = lctx->type.dwordValue << rctx->type.dwordValue;
  9721. else if( op == ttBitShiftRight )
  9722. v = lctx->type.dwordValue >> rctx->type.dwordValue;
  9723. else if( op == ttBitShiftRightArith )
  9724. v = lctx->type.intValue >> rctx->type.dwordValue;
  9725. ctx->type.SetConstantDW(lctx->type.dataType, v);
  9726. }
  9727. else
  9728. {
  9729. asQWORD v = 0;
  9730. if( op == ttBitShiftLeft )
  9731. v = lctx->type.qwordValue << rctx->type.dwordValue;
  9732. else if( op == ttBitShiftRight )
  9733. v = lctx->type.qwordValue >> rctx->type.dwordValue;
  9734. else if( op == ttBitShiftRightArith )
  9735. v = asINT64(lctx->type.qwordValue) >> rctx->type.dwordValue;
  9736. ctx->type.SetConstantQW(lctx->type.dataType, v);
  9737. }
  9738. }
  9739. }
  9740. }
  9741. void asCCompiler::CompileComparisonOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  9742. {
  9743. // Both operands must be of the same type
  9744. // Implicitly convert the operands to a number type
  9745. asCDataType to;
  9746. // If either operand is a non-primitive then use the primitive type
  9747. if( !lctx->type.dataType.IsPrimitive() )
  9748. to.SetTokenType(rctx->type.dataType.GetTokenType());
  9749. else if( !rctx->type.dataType.IsPrimitive() )
  9750. to.SetTokenType(lctx->type.dataType.GetTokenType());
  9751. else if( lctx->type.dataType.IsDoubleType() || rctx->type.dataType.IsDoubleType() )
  9752. to.SetTokenType(ttDouble);
  9753. else if( lctx->type.dataType.IsFloatType() || rctx->type.dataType.IsFloatType() )
  9754. to.SetTokenType(ttFloat);
  9755. else if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 || rctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  9756. {
  9757. // Convert to int64 if both are signed or if one is non-constant and signed
  9758. if( (lctx->type.dataType.IsIntegerType() && rctx->type.dataType.IsIntegerType()) ||
  9759. (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) ||
  9760. (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) )
  9761. to.SetTokenType(ttInt64);
  9762. else
  9763. to.SetTokenType(ttUInt64);
  9764. }
  9765. else
  9766. {
  9767. // Convert to int32 if both are signed or if one is non-constant and signed
  9768. if( (lctx->type.dataType.IsIntegerType() && rctx->type.dataType.IsIntegerType()) ||
  9769. (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) ||
  9770. (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) )
  9771. to.SetTokenType(ttInt);
  9772. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  9773. to.SetTokenType(ttUInt);
  9774. else if( lctx->type.dataType.IsBooleanType() || rctx->type.dataType.IsBooleanType() )
  9775. to.SetTokenType(ttBool);
  9776. }
  9777. // If doing an operation with double constant and float variable, the constant should be converted to float
  9778. if( (lctx->type.isConstant && lctx->type.dataType.IsDoubleType() && !rctx->type.isConstant && rctx->type.dataType.IsFloatType()) ||
  9779. (rctx->type.isConstant && rctx->type.dataType.IsDoubleType() && !lctx->type.isConstant && lctx->type.dataType.IsFloatType()) )
  9780. to.SetTokenType(ttFloat);
  9781. asASSERT( to.GetTokenType() != ttUnrecognizedToken );
  9782. // Do we have a mismatch between the sign of the operand?
  9783. bool signMismatch = false;
  9784. for( int n = 0; !signMismatch && n < 2; n++ )
  9785. {
  9786. asSExprContext *op = n ? rctx : lctx;
  9787. if( op->type.dataType.IsUnsignedType() != to.IsUnsignedType() )
  9788. {
  9789. // We have a mismatch, unless the value is a literal constant and the conversion won't affect its value
  9790. signMismatch = true;
  9791. if( op->type.isConstant )
  9792. {
  9793. if( op->type.dataType.GetTokenType() == ttUInt64 || op->type.dataType.GetTokenType() == ttInt64 )
  9794. {
  9795. if( !(op->type.qwordValue & (asQWORD(1)<<63)) )
  9796. signMismatch = false;
  9797. }
  9798. else
  9799. {
  9800. if( !(op->type.dwordValue & (1<<31)) )
  9801. signMismatch = false;
  9802. }
  9803. // It's not necessary to check for floats or double, because if
  9804. // it was then the types for the conversion will never be unsigned
  9805. }
  9806. }
  9807. }
  9808. // Check for signed/unsigned mismatch
  9809. if( signMismatch )
  9810. Warning(TXT_SIGNED_UNSIGNED_MISMATCH, node);
  9811. // Do the actual conversion
  9812. int l = int(reservedVariables.GetLength());
  9813. rctx->bc.GetVarsUsed(reservedVariables);
  9814. if( lctx->type.dataType.IsReference() )
  9815. ConvertToVariable(lctx);
  9816. if( rctx->type.dataType.IsReference() )
  9817. ConvertToVariable(rctx);
  9818. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV);
  9819. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV);
  9820. reservedVariables.SetLength(l);
  9821. // Verify that the conversion was successful
  9822. bool ok = true;
  9823. if( !lctx->type.dataType.IsEqualExceptConst(to) )
  9824. {
  9825. asCString str;
  9826. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  9827. Error(str, node);
  9828. ok = false;
  9829. }
  9830. if( !rctx->type.dataType.IsEqualExceptConst(to) )
  9831. {
  9832. asCString str;
  9833. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  9834. Error(str, node);
  9835. ok = false;
  9836. }
  9837. if( !ok )
  9838. {
  9839. // It wasn't possible to get two valid operands, so we just return
  9840. // a boolean result and let the compiler continue.
  9841. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  9842. return;
  9843. }
  9844. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  9845. int op = node->tokenType;
  9846. if( !isConstant )
  9847. {
  9848. if( to.IsBooleanType() )
  9849. {
  9850. int op = node->tokenType;
  9851. if( op == ttEqual || op == ttNotEqual )
  9852. {
  9853. // Must convert to temporary variable, because we are changing the value before comparison
  9854. ConvertToTempVariableNotIn(lctx, rctx);
  9855. ConvertToTempVariableNotIn(rctx, lctx);
  9856. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  9857. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  9858. // Make sure they are equal if not false
  9859. lctx->bc.InstrWORD(asBC_NOT, lctx->type.stackOffset);
  9860. rctx->bc.InstrWORD(asBC_NOT, rctx->type.stackOffset);
  9861. MergeExprBytecode(ctx, lctx);
  9862. MergeExprBytecode(ctx, rctx);
  9863. ProcessDeferredParams(ctx);
  9864. int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, true), true);
  9865. int b = lctx->type.stackOffset;
  9866. int c = rctx->type.stackOffset;
  9867. if( op == ttEqual )
  9868. {
  9869. ctx->bc.InstrW_W(asBC_CMPi,b,c);
  9870. ctx->bc.Instr(asBC_TZ);
  9871. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  9872. }
  9873. else if( op == ttNotEqual )
  9874. {
  9875. ctx->bc.InstrW_W(asBC_CMPi,b,c);
  9876. ctx->bc.Instr(asBC_TNZ);
  9877. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  9878. }
  9879. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  9880. }
  9881. else
  9882. {
  9883. // TODO: Use TXT_ILLEGAL_OPERATION_ON
  9884. Error(TXT_ILLEGAL_OPERATION, node);
  9885. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), 0);
  9886. }
  9887. }
  9888. else
  9889. {
  9890. ConvertToVariableNotIn(lctx, rctx);
  9891. ConvertToVariableNotIn(rctx, lctx);
  9892. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  9893. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  9894. MergeExprBytecode(ctx, lctx);
  9895. MergeExprBytecode(ctx, rctx);
  9896. ProcessDeferredParams(ctx);
  9897. asEBCInstr iCmp = asBC_CMPi, iT = asBC_TZ;
  9898. if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  9899. iCmp = asBC_CMPi;
  9900. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  9901. iCmp = asBC_CMPu;
  9902. else if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  9903. iCmp = asBC_CMPi64;
  9904. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  9905. iCmp = asBC_CMPu64;
  9906. else if( lctx->type.dataType.IsFloatType() )
  9907. iCmp = asBC_CMPf;
  9908. else if( lctx->type.dataType.IsDoubleType() )
  9909. iCmp = asBC_CMPd;
  9910. else
  9911. asASSERT(false);
  9912. if( op == ttEqual )
  9913. iT = asBC_TZ;
  9914. else if( op == ttNotEqual )
  9915. iT = asBC_TNZ;
  9916. else if( op == ttLessThan )
  9917. iT = asBC_TS;
  9918. else if( op == ttLessThanOrEqual )
  9919. iT = asBC_TNP;
  9920. else if( op == ttGreaterThan )
  9921. iT = asBC_TP;
  9922. else if( op == ttGreaterThanOrEqual )
  9923. iT = asBC_TNS;
  9924. int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, true), true);
  9925. int b = lctx->type.stackOffset;
  9926. int c = rctx->type.stackOffset;
  9927. ctx->bc.InstrW_W(iCmp, b, c);
  9928. ctx->bc.Instr(iT);
  9929. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  9930. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  9931. }
  9932. }
  9933. else
  9934. {
  9935. if( to.IsBooleanType() )
  9936. {
  9937. int op = node->tokenType;
  9938. if( op == ttEqual || op == ttNotEqual )
  9939. {
  9940. // Make sure they are equal if not false
  9941. if( lctx->type.dwordValue != 0 ) lctx->type.dwordValue = VALUE_OF_BOOLEAN_TRUE;
  9942. if( rctx->type.dwordValue != 0 ) rctx->type.dwordValue = VALUE_OF_BOOLEAN_TRUE;
  9943. asDWORD v = 0;
  9944. if( op == ttEqual )
  9945. {
  9946. v = lctx->type.intValue - rctx->type.intValue;
  9947. if( v == 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  9948. }
  9949. else if( op == ttNotEqual )
  9950. {
  9951. v = lctx->type.intValue - rctx->type.intValue;
  9952. if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  9953. }
  9954. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), v);
  9955. }
  9956. else
  9957. {
  9958. // TODO: Use TXT_ILLEGAL_OPERATION_ON
  9959. Error(TXT_ILLEGAL_OPERATION, node);
  9960. }
  9961. }
  9962. else
  9963. {
  9964. int i = 0;
  9965. if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  9966. {
  9967. int v = lctx->type.intValue - rctx->type.intValue;
  9968. if( v < 0 ) i = -1;
  9969. if( v > 0 ) i = 1;
  9970. }
  9971. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  9972. {
  9973. asDWORD v1 = lctx->type.dwordValue;
  9974. asDWORD v2 = rctx->type.dwordValue;
  9975. if( v1 < v2 ) i = -1;
  9976. if( v1 > v2 ) i = 1;
  9977. }
  9978. else if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  9979. {
  9980. asINT64 v = asINT64(lctx->type.qwordValue) - asINT64(rctx->type.qwordValue);
  9981. if( v < 0 ) i = -1;
  9982. if( v > 0 ) i = 1;
  9983. }
  9984. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  9985. {
  9986. asQWORD v1 = lctx->type.qwordValue;
  9987. asQWORD v2 = rctx->type.qwordValue;
  9988. if( v1 < v2 ) i = -1;
  9989. if( v1 > v2 ) i = 1;
  9990. }
  9991. else if( lctx->type.dataType.IsFloatType() )
  9992. {
  9993. float v = lctx->type.floatValue - rctx->type.floatValue;
  9994. if( v < 0 ) i = -1;
  9995. if( v > 0 ) i = 1;
  9996. }
  9997. else if( lctx->type.dataType.IsDoubleType() )
  9998. {
  9999. double v = lctx->type.doubleValue - rctx->type.doubleValue;
  10000. if( v < 0 ) i = -1;
  10001. if( v > 0 ) i = 1;
  10002. }
  10003. if( op == ttEqual )
  10004. i = (i == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  10005. else if( op == ttNotEqual )
  10006. i = (i != 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  10007. else if( op == ttLessThan )
  10008. i = (i < 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  10009. else if( op == ttLessThanOrEqual )
  10010. i = (i <= 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  10011. else if( op == ttGreaterThan )
  10012. i = (i > 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  10013. else if( op == ttGreaterThanOrEqual )
  10014. i = (i >= 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  10015. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), i);
  10016. }
  10017. }
  10018. }
  10019. void asCCompiler::PushVariableOnStack(asSExprContext *ctx, bool asReference)
  10020. {
  10021. // Put the result on the stack
  10022. if( asReference )
  10023. {
  10024. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  10025. ctx->type.dataType.MakeReference(true);
  10026. }
  10027. else
  10028. {
  10029. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  10030. ctx->bc.InstrSHORT(asBC_PshV4, ctx->type.stackOffset);
  10031. else
  10032. ctx->bc.InstrSHORT(asBC_PshV8, ctx->type.stackOffset);
  10033. }
  10034. }
  10035. void asCCompiler::CompileBooleanOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  10036. {
  10037. // Both operands must be booleans
  10038. asCDataType to;
  10039. to.SetTokenType(ttBool);
  10040. // Do the actual conversion
  10041. int l = int(reservedVariables.GetLength());
  10042. rctx->bc.GetVarsUsed(reservedVariables);
  10043. lctx->bc.GetVarsUsed(reservedVariables);
  10044. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV);
  10045. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV);
  10046. reservedVariables.SetLength(l);
  10047. // Verify that the conversion was successful
  10048. if( !lctx->type.dataType.IsBooleanType() )
  10049. {
  10050. asCString str;
  10051. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format().AddressOf(), "bool");
  10052. Error(str, node);
  10053. // Force the conversion to allow compilation to proceed
  10054. lctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  10055. }
  10056. if( !rctx->type.dataType.IsBooleanType() )
  10057. {
  10058. asCString str;
  10059. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format().AddressOf(), "bool");
  10060. Error(str, node);
  10061. // Force the conversion to allow compilation to proceed
  10062. rctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  10063. }
  10064. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  10065. ctx->type.Set(asCDataType::CreatePrimitive(ttBool, true));
  10066. // What kind of operator is it?
  10067. int op = node->tokenType;
  10068. if( op == ttXor )
  10069. {
  10070. if( !isConstant )
  10071. {
  10072. // Must convert to temporary variable, because we are changing the value before comparison
  10073. ConvertToTempVariableNotIn(lctx, rctx);
  10074. ConvertToTempVariableNotIn(rctx, lctx);
  10075. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  10076. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  10077. // Make sure they are equal if not false
  10078. lctx->bc.InstrWORD(asBC_NOT, lctx->type.stackOffset);
  10079. rctx->bc.InstrWORD(asBC_NOT, rctx->type.stackOffset);
  10080. MergeExprBytecode(ctx, lctx);
  10081. MergeExprBytecode(ctx, rctx);
  10082. ProcessDeferredParams(ctx);
  10083. int a = AllocateVariable(ctx->type.dataType, true);
  10084. int b = lctx->type.stackOffset;
  10085. int c = rctx->type.stackOffset;
  10086. ctx->bc.InstrW_W_W(asBC_BXOR,a,b,c);
  10087. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  10088. }
  10089. else
  10090. {
  10091. // Make sure they are equal if not false
  10092. #if AS_SIZEOF_BOOL == 1
  10093. if( lctx->type.byteValue != 0 ) lctx->type.byteValue = VALUE_OF_BOOLEAN_TRUE;
  10094. if( rctx->type.byteValue != 0 ) rctx->type.byteValue = VALUE_OF_BOOLEAN_TRUE;
  10095. asBYTE v = 0;
  10096. v = lctx->type.byteValue - rctx->type.byteValue;
  10097. if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  10098. ctx->type.isConstant = true;
  10099. ctx->type.byteValue = v;
  10100. #else
  10101. if( lctx->type.dwordValue != 0 ) lctx->type.dwordValue = VALUE_OF_BOOLEAN_TRUE;
  10102. if( rctx->type.dwordValue != 0 ) rctx->type.dwordValue = VALUE_OF_BOOLEAN_TRUE;
  10103. asDWORD v = 0;
  10104. v = lctx->type.intValue - rctx->type.intValue;
  10105. if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  10106. ctx->type.isConstant = true;
  10107. ctx->type.dwordValue = v;
  10108. #endif
  10109. }
  10110. }
  10111. else if( op == ttAnd ||
  10112. op == ttOr )
  10113. {
  10114. if( !isConstant )
  10115. {
  10116. // If or-operator and first value is 1 the second value shouldn't be calculated
  10117. // if and-operator and first value is 0 the second value shouldn't be calculated
  10118. ConvertToVariable(lctx);
  10119. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  10120. MergeExprBytecode(ctx, lctx);
  10121. int offset = AllocateVariable(asCDataType::CreatePrimitive(ttBool, false), true);
  10122. int label1 = nextLabel++;
  10123. int label2 = nextLabel++;
  10124. ctx->bc.InstrSHORT(asBC_CpyVtoR4, lctx->type.stackOffset);
  10125. ctx->bc.Instr(asBC_ClrHi);
  10126. if( op == ttAnd )
  10127. {
  10128. ctx->bc.InstrDWORD(asBC_JNZ, label1);
  10129. ctx->bc.InstrW_DW(asBC_SetV4, (asWORD)offset, 0);
  10130. ctx->bc.InstrINT(asBC_JMP, label2);
  10131. }
  10132. else if( op == ttOr )
  10133. {
  10134. ctx->bc.InstrDWORD(asBC_JZ, label1);
  10135. #if AS_SIZEOF_BOOL == 1
  10136. ctx->bc.InstrSHORT_B(asBC_SetV1, (short)offset, VALUE_OF_BOOLEAN_TRUE);
  10137. #else
  10138. ctx->bc.InstrSHORT_DW(asBC_SetV4, (short)offset, VALUE_OF_BOOLEAN_TRUE);
  10139. #endif
  10140. ctx->bc.InstrINT(asBC_JMP, label2);
  10141. }
  10142. ctx->bc.Label((short)label1);
  10143. ConvertToVariable(rctx);
  10144. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  10145. rctx->bc.InstrW_W(asBC_CpyVtoV4, offset, rctx->type.stackOffset);
  10146. MergeExprBytecode(ctx, rctx);
  10147. ctx->bc.Label((short)label2);
  10148. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, false), offset, true);
  10149. }
  10150. else
  10151. {
  10152. #if AS_SIZEOF_BOOL == 1
  10153. asBYTE v = 0;
  10154. if( op == ttAnd )
  10155. v = lctx->type.byteValue && rctx->type.byteValue;
  10156. else if( op == ttOr )
  10157. v = lctx->type.byteValue || rctx->type.byteValue;
  10158. // Remember the result
  10159. ctx->type.isConstant = true;
  10160. ctx->type.byteValue = v;
  10161. #else
  10162. asDWORD v = 0;
  10163. if( op == ttAnd )
  10164. v = lctx->type.dwordValue && rctx->type.dwordValue;
  10165. else if( op == ttOr )
  10166. v = lctx->type.dwordValue || rctx->type.dwordValue;
  10167. // Remember the result
  10168. ctx->type.isConstant = true;
  10169. ctx->type.dwordValue = v;
  10170. #endif
  10171. }
  10172. }
  10173. }
  10174. void asCCompiler::CompileOperatorOnHandles(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  10175. {
  10176. // Process the property accessor as get
  10177. ProcessPropertyGetAccessor(lctx, node);
  10178. ProcessPropertyGetAccessor(rctx, node);
  10179. DetermineSingleFunc(lctx, node);
  10180. DetermineSingleFunc(rctx, node);
  10181. // Make sure lctx doesn't end up with a variable used in rctx
  10182. if( lctx->type.isTemporary && rctx->bc.IsVarUsed(lctx->type.stackOffset) )
  10183. {
  10184. asCArray<int> vars;
  10185. rctx->bc.GetVarsUsed(vars);
  10186. int offset = AllocateVariable(lctx->type.dataType, true);
  10187. rctx->bc.ExchangeVar(lctx->type.stackOffset, offset);
  10188. ReleaseTemporaryVariable(offset, 0);
  10189. }
  10190. // Warn if not both operands are explicit handles
  10191. if( (node->tokenType == ttEqual || node->tokenType == ttNotEqual) &&
  10192. ((!lctx->type.isExplicitHandle && !(lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE))) ||
  10193. (!rctx->type.isExplicitHandle && !(rctx->type.dataType.GetObjectType() && (rctx->type.dataType.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE)))) )
  10194. {
  10195. Warning(TXT_HANDLE_COMPARISON, node);
  10196. }
  10197. // If one of the operands is a value type used as handle, we should look for the opEquals method
  10198. if( ((lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE)) ||
  10199. (rctx->type.dataType.GetObjectType() && (rctx->type.dataType.GetObjectType()->flags & asOBJ_ASHANDLE))) &&
  10200. (node->tokenType == ttEqual || node->tokenType == ttIs ||
  10201. node->tokenType == ttNotEqual || node->tokenType == ttNotIs) )
  10202. {
  10203. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  10204. // Find the matching opEquals method
  10205. int r = CompileOverloadedDualOperator2(node, "opEquals", lctx, rctx, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  10206. if( r == 0 )
  10207. {
  10208. // Try again by switching the order of the operands
  10209. r = CompileOverloadedDualOperator2(node, "opEquals", rctx, lctx, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  10210. }
  10211. if( r == 1 )
  10212. {
  10213. if( node->tokenType == ttNotEqual || node->tokenType == ttNotIs )
  10214. ctx->bc.InstrSHORT(asBC_NOT, ctx->type.stackOffset);
  10215. // Success, don't continue
  10216. return;
  10217. }
  10218. else if( r == 0 )
  10219. {
  10220. // Couldn't find opEquals method
  10221. Error(TXT_NO_APPROPRIATE_OPEQUALS, node);
  10222. }
  10223. // Compiler error, don't continue
  10224. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  10225. return;
  10226. }
  10227. // Implicitly convert null to the other type
  10228. asCDataType to;
  10229. if( lctx->type.IsNullConstant() )
  10230. to = rctx->type.dataType;
  10231. else if( rctx->type.IsNullConstant() )
  10232. to = lctx->type.dataType;
  10233. else
  10234. {
  10235. // TODO: Use the common base type
  10236. to = lctx->type.dataType;
  10237. }
  10238. // Need to pop the value if it is a null constant
  10239. if( lctx->type.IsNullConstant() )
  10240. lctx->bc.Instr(asBC_PopPtr);
  10241. if( rctx->type.IsNullConstant() )
  10242. rctx->bc.Instr(asBC_PopPtr);
  10243. // Convert both sides to explicit handles
  10244. to.MakeHandle(true);
  10245. to.MakeReference(false);
  10246. if( !to.IsObjectHandle() )
  10247. {
  10248. // Compiler error, don't continue
  10249. Error(TXT_OPERANDS_MUST_BE_HANDLES, node);
  10250. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  10251. return;
  10252. }
  10253. // Do the conversion
  10254. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV);
  10255. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV);
  10256. // Both operands must be of the same type
  10257. // Verify that the conversion was successful
  10258. if( !lctx->type.dataType.IsEqualExceptConst(to) )
  10259. {
  10260. asCString str;
  10261. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  10262. Error(str, node);
  10263. }
  10264. if( !rctx->type.dataType.IsEqualExceptConst(to) )
  10265. {
  10266. asCString str;
  10267. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  10268. Error(str, node);
  10269. }
  10270. // Make sure it really is handles that are being compared
  10271. if( !lctx->type.dataType.IsObjectHandle() )
  10272. {
  10273. Error(TXT_OPERANDS_MUST_BE_HANDLES, node);
  10274. }
  10275. ctx->type.Set(asCDataType::CreatePrimitive(ttBool, true));
  10276. int op = node->tokenType;
  10277. if( op == ttEqual || op == ttNotEqual || op == ttIs || op == ttNotIs )
  10278. {
  10279. // If the object handle already is in a variable we must manually pop it from the stack
  10280. if( lctx->type.isVariable )
  10281. lctx->bc.Instr(asBC_PopPtr);
  10282. if( rctx->type.isVariable )
  10283. rctx->bc.Instr(asBC_PopPtr);
  10284. // TODO: runtime optimize: don't do REFCPY
  10285. ConvertToVariableNotIn(lctx, rctx);
  10286. ConvertToVariable(rctx);
  10287. MergeExprBytecode(ctx, lctx);
  10288. MergeExprBytecode(ctx, rctx);
  10289. int a = AllocateVariable(ctx->type.dataType, true);
  10290. int b = lctx->type.stackOffset;
  10291. int c = rctx->type.stackOffset;
  10292. ctx->bc.InstrW_W(asBC_CmpPtr, b, c);
  10293. if( op == ttEqual || op == ttIs )
  10294. ctx->bc.Instr(asBC_TZ);
  10295. else if( op == ttNotEqual || op == ttNotIs )
  10296. ctx->bc.Instr(asBC_TNZ);
  10297. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  10298. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  10299. ReleaseTemporaryVariable(lctx->type, &ctx->bc);
  10300. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  10301. ProcessDeferredParams(ctx);
  10302. }
  10303. else
  10304. {
  10305. // TODO: Use TXT_ILLEGAL_OPERATION_ON
  10306. Error(TXT_ILLEGAL_OPERATION, node);
  10307. }
  10308. }
  10309. void asCCompiler::PerformFunctionCall(int funcId, asSExprContext *ctx, bool isConstructor, asCArray<asSExprContext*> *args, asCObjectType *objType, bool useVariable, int varOffset, int funcPtrVar)
  10310. {
  10311. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  10312. // A shared object may not call non-shared functions
  10313. if( outFunc->IsShared() && !descr->IsShared() )
  10314. {
  10315. asCString msg;
  10316. msg.Format(TXT_SHARED_CANNOT_CALL_NON_SHARED_FUNC_s, descr->GetDeclarationStr().AddressOf());
  10317. Error(msg, ctx->exprNode);
  10318. }
  10319. // Check if the function is private
  10320. if( descr->isPrivate && descr->GetObjectType() != outFunc->GetObjectType() )
  10321. {
  10322. asCString msg;
  10323. msg.Format(TXT_PRIVATE_METHOD_CALL_s, descr->GetDeclarationStr().AddressOf());
  10324. Error(msg, ctx->exprNode);
  10325. }
  10326. int argSize = descr->GetSpaceNeededForArguments();
  10327. if( descr->objectType && descr->returnType.IsReference() &&
  10328. !(ctx->type.isVariable || ctx->type.isTemporary) &&
  10329. (ctx->type.dataType.IsObjectHandle() || ctx->type.dataType.SupportHandles()) &&
  10330. !(ctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_SCOPED) &&
  10331. !(ctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_ASHANDLE) )
  10332. {
  10333. // The class method we're calling is returning a reference, which may be to a member of the object.
  10334. // In order to guarantee the lifetime of the reference, we must hold a local reference to the object.
  10335. // TODO: runtime optimize: This can be avoided for local variables (non-handles) as they have a well defined life time
  10336. int tempRef = AllocateVariable(ctx->type.dataType, true);
  10337. ctx->bc.InstrSHORT(asBC_PSF, (short)tempRef);
  10338. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetObjectType());
  10339. // Add the release of this reference, as a deferred expression
  10340. asSDeferredParam deferred;
  10341. deferred.origExpr = 0;
  10342. deferred.argInOutFlags = asTM_INREF;
  10343. deferred.argNode = 0;
  10344. deferred.argType.SetVariable(ctx->type.dataType, tempRef, true);
  10345. ctx->deferredParams.PushLast(deferred);
  10346. // Forget the current type
  10347. ctx->type.SetDummy();
  10348. }
  10349. if( isConstructor )
  10350. {
  10351. // Sometimes the value types are allocated on the heap,
  10352. // which is when this way of constructing them is used.
  10353. asASSERT(useVariable == false);
  10354. ctx->bc.Alloc(asBC_ALLOC, objType, descr->id, argSize+AS_PTR_SIZE);
  10355. // The instruction has already moved the returned object to the variable
  10356. ctx->type.Set(asCDataType::CreatePrimitive(ttVoid, false));
  10357. ctx->type.isLValue = false;
  10358. // Clean up arguments
  10359. if( args )
  10360. AfterFunctionCall(funcId, *args, ctx, false);
  10361. ProcessDeferredParams(ctx);
  10362. return;
  10363. }
  10364. else
  10365. {
  10366. if( descr->objectType )
  10367. argSize += AS_PTR_SIZE;
  10368. // If the function returns an object by value the address of the location
  10369. // where the value should be stored is passed as an argument too
  10370. if( descr->DoesReturnOnStack() )
  10371. {
  10372. argSize += AS_PTR_SIZE;
  10373. }
  10374. // TODO: runtime optimize: If it is known that a class method cannot be overridden the call
  10375. // should be made with asBC_CALL as it is faster. Examples where this
  10376. // is known is for example finalled methods where the class doesn't derive
  10377. // from any other, or even non-finalled methods but where it is known
  10378. // at compile time the true type of the object. The first should be
  10379. // quite easy to determine, but the latter will be quite complex and possibly
  10380. // not worth it.
  10381. if( descr->funcType == asFUNC_IMPORTED )
  10382. ctx->bc.Call(asBC_CALLBND , descr->id, argSize);
  10383. // TODO: Maybe we need two different byte codes
  10384. else if( descr->funcType == asFUNC_INTERFACE || descr->funcType == asFUNC_VIRTUAL )
  10385. ctx->bc.Call(asBC_CALLINTF, descr->id, argSize);
  10386. else if( descr->funcType == asFUNC_SCRIPT )
  10387. ctx->bc.Call(asBC_CALL , descr->id, argSize);
  10388. else if( descr->funcType == asFUNC_SYSTEM )
  10389. ctx->bc.Call(asBC_CALLSYS , descr->id, argSize);
  10390. else if( descr->funcType == asFUNC_FUNCDEF )
  10391. ctx->bc.CallPtr(asBC_CallPtr, funcPtrVar, argSize);
  10392. }
  10393. if( descr->returnType.IsObject() && !descr->returnType.IsReference() )
  10394. {
  10395. int returnOffset = 0;
  10396. if( descr->DoesReturnOnStack() )
  10397. {
  10398. asASSERT( useVariable );
  10399. // The variable was allocated before the function was called
  10400. returnOffset = varOffset;
  10401. ctx->type.SetVariable(descr->returnType, returnOffset, true);
  10402. // The variable was initialized by the function, so we need to mark it as initialized here
  10403. ctx->bc.ObjInfo(varOffset, asOBJ_INIT);
  10404. }
  10405. else
  10406. {
  10407. if( useVariable )
  10408. {
  10409. // Use the given variable
  10410. returnOffset = varOffset;
  10411. ctx->type.SetVariable(descr->returnType, returnOffset, false);
  10412. }
  10413. else
  10414. {
  10415. // Allocate a temporary variable for the returned object
  10416. // The returned object will actually be allocated on the heap, so
  10417. // we must force the allocation of the variable to do the same
  10418. returnOffset = AllocateVariable(descr->returnType, true, !descr->returnType.IsObjectHandle());
  10419. ctx->type.SetVariable(descr->returnType, returnOffset, true);
  10420. }
  10421. // Move the pointer from the object register to the temporary variable
  10422. ctx->bc.InstrSHORT(asBC_STOREOBJ, (short)returnOffset);
  10423. }
  10424. ctx->type.dataType.MakeReference(IsVariableOnHeap(returnOffset));
  10425. ctx->type.isLValue = false; // It is a reference, but not an lvalue
  10426. // Clean up arguments
  10427. if( args )
  10428. AfterFunctionCall(funcId, *args, ctx, false);
  10429. ProcessDeferredParams(ctx);
  10430. ctx->bc.InstrSHORT(asBC_PSF, (short)returnOffset);
  10431. }
  10432. else if( descr->returnType.IsReference() )
  10433. {
  10434. asASSERT(useVariable == false);
  10435. // We cannot clean up the arguments yet, because the
  10436. // reference might be pointing to one of them.
  10437. if( args )
  10438. AfterFunctionCall(funcId, *args, ctx, true);
  10439. // Do not process the output parameters yet, because it
  10440. // might invalidate the returned reference
  10441. // If the context holds a variable that needs cleanup
  10442. // store it as a deferred parameter so it will be cleaned up
  10443. // afterwards.
  10444. if( ctx->type.isTemporary )
  10445. {
  10446. asSDeferredParam defer;
  10447. defer.argNode = 0;
  10448. defer.argType = ctx->type;
  10449. defer.argInOutFlags = asTM_INOUTREF;
  10450. defer.origExpr = 0;
  10451. ctx->deferredParams.PushLast(defer);
  10452. }
  10453. ctx->type.Set(descr->returnType);
  10454. if( !descr->returnType.IsPrimitive() )
  10455. {
  10456. ctx->bc.Instr(asBC_PshRPtr);
  10457. if( descr->returnType.IsObject() &&
  10458. !descr->returnType.IsObjectHandle() )
  10459. {
  10460. // We are getting the pointer to the object
  10461. // not a pointer to a object variable
  10462. ctx->type.dataType.MakeReference(false);
  10463. }
  10464. }
  10465. // A returned reference can be used as lvalue
  10466. ctx->type.isLValue = true;
  10467. }
  10468. else
  10469. {
  10470. asASSERT(useVariable == false);
  10471. if( descr->returnType.GetSizeInMemoryBytes() )
  10472. {
  10473. // Allocate a temporary variable to hold the value, but make sure
  10474. // the temporary variable isn't used in any of the deferred arguments
  10475. int l = int(reservedVariables.GetLength());
  10476. for( asUINT n = 0; args && n < args->GetLength(); n++ )
  10477. {
  10478. asSExprContext *expr = (*args)[n]->origExpr;
  10479. if( expr )
  10480. expr->bc.GetVarsUsed(reservedVariables);
  10481. }
  10482. int offset = AllocateVariable(descr->returnType, true);
  10483. reservedVariables.SetLength(l);
  10484. ctx->type.SetVariable(descr->returnType, offset, true);
  10485. // Move the value from the return register to the variable
  10486. if( descr->returnType.GetSizeOnStackDWords() == 1 )
  10487. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)offset);
  10488. else if( descr->returnType.GetSizeOnStackDWords() == 2 )
  10489. ctx->bc.InstrSHORT(asBC_CpyRtoV8, (short)offset);
  10490. }
  10491. else
  10492. ctx->type.Set(descr->returnType);
  10493. ctx->type.isLValue = false;
  10494. // Clean up arguments
  10495. if( args )
  10496. AfterFunctionCall(funcId, *args, ctx, false);
  10497. ProcessDeferredParams(ctx);
  10498. }
  10499. }
  10500. // This only merges the bytecode, but doesn't modify the type of the final context
  10501. void asCCompiler::MergeExprBytecode(asSExprContext *before, asSExprContext *after)
  10502. {
  10503. before->bc.AddCode(&after->bc);
  10504. for( asUINT n = 0; n < after->deferredParams.GetLength(); n++ )
  10505. {
  10506. before->deferredParams.PushLast(after->deferredParams[n]);
  10507. after->deferredParams[n].origExpr = 0;
  10508. }
  10509. after->deferredParams.SetLength(0);
  10510. }
  10511. // This merges both bytecode and the type of the final context
  10512. void asCCompiler::MergeExprBytecodeAndType(asSExprContext *before, asSExprContext *after)
  10513. {
  10514. MergeExprBytecode(before, after);
  10515. before->type = after->type;
  10516. before->property_get = after->property_get;
  10517. before->property_set = after->property_set;
  10518. before->property_const = after->property_const;
  10519. before->property_handle = after->property_handle;
  10520. before->property_ref = after->property_ref;
  10521. before->property_arg = after->property_arg;
  10522. before->exprNode = after->exprNode;
  10523. before->methodName = after->methodName;
  10524. after->property_arg = 0;
  10525. // Do not copy the origExpr member
  10526. }
  10527. void asCCompiler::FilterConst(asCArray<int> &funcs, bool removeConst)
  10528. {
  10529. if( funcs.GetLength() == 0 ) return;
  10530. // This is only done for object methods
  10531. asCScriptFunction *desc = builder->GetFunctionDescription(funcs[0]);
  10532. if( desc->objectType == 0 ) return;
  10533. // Check if there are any non-const matches
  10534. asUINT n;
  10535. bool foundNonConst = false;
  10536. for( n = 0; n < funcs.GetLength(); n++ )
  10537. {
  10538. desc = builder->GetFunctionDescription(funcs[n]);
  10539. if( desc->isReadOnly != removeConst )
  10540. {
  10541. foundNonConst = true;
  10542. break;
  10543. }
  10544. }
  10545. if( foundNonConst )
  10546. {
  10547. // Remove all const methods
  10548. for( n = 0; n < funcs.GetLength(); n++ )
  10549. {
  10550. desc = builder->GetFunctionDescription(funcs[n]);
  10551. if( desc->isReadOnly == removeConst )
  10552. {
  10553. if( n == funcs.GetLength() - 1 )
  10554. funcs.PopLast();
  10555. else
  10556. funcs[n] = funcs.PopLast();
  10557. n--;
  10558. }
  10559. }
  10560. }
  10561. }
  10562. END_AS_NAMESPACE
  10563. #endif // AS_NO_COMPILER