as_compiler.cpp 326 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871987298739874987598769877987898799880988198829883988498859886988798889889989098919892989398949895989698979898989999009901990299039904990599069907990899099910991199129913991499159916991799189919992099219922992399249925992699279928992999309931993299339934993599369937993899399940994199429943994499459946994799489949995099519952995399549955995699579958995999609961996299639964996599669967996899699970997199729973997499759976997799789979998099819982998399849985998699879988998999909991999299939994999599969997999899991000010001100021000310004100051000610007100081000910010100111001210013100141001510016100171001810019100201002110022100231002410025100261002710028100291003010031100321003310034100351003610037100381003910040100411004210043100441004510046100471004810049100501005110052100531005410055100561005710058100591006010061100621006310064100651006610067100681006910070100711007210073100741007510076100771007810079100801008110082100831008410085100861008710088100891009010091100921009310094100951009610097100981009910100101011010210103101041010510106101071010810109101101011110112101131011410115101161011710118101191012010121101221012310124101251012610127101281012910130101311013210133101341013510136101371013810139101401014110142101431014410145101461014710148101491015010151101521015310154101551015610157101581015910160101611016210163101641016510166101671016810169101701017110172101731017410175101761017710178101791018010181101821018310184101851018610187101881018910190101911019210193101941019510196101971019810199102001020110202102031020410205102061020710208102091021010211102121021310214102151021610217102181021910220102211022210223102241022510226102271022810229102301023110232102331023410235102361023710238102391024010241102421024310244102451024610247102481024910250102511025210253102541025510256102571025810259102601026110262102631026410265102661026710268102691027010271102721027310274102751027610277102781027910280102811028210283102841028510286102871028810289102901029110292102931029410295102961029710298102991030010301103021030310304103051030610307103081030910310103111031210313103141031510316103171031810319103201032110322103231032410325103261032710328103291033010331103321033310334103351033610337103381033910340103411034210343103441034510346103471034810349103501035110352103531035410355103561035710358103591036010361103621036310364103651036610367103681036910370103711037210373103741037510376103771037810379103801038110382103831038410385103861038710388103891039010391103921039310394103951039610397103981039910400104011040210403104041040510406104071040810409104101041110412104131041410415104161041710418104191042010421104221042310424104251042610427104281042910430104311043210433104341043510436104371043810439104401044110442104431044410445104461044710448104491045010451104521045310454104551045610457104581045910460104611046210463104641046510466104671046810469104701047110472104731047410475104761047710478104791048010481104821048310484104851048610487104881048910490104911049210493104941049510496104971049810499105001050110502105031050410505105061050710508105091051010511105121051310514105151051610517105181051910520105211052210523105241052510526105271052810529105301053110532105331053410535105361053710538105391054010541105421054310544105451054610547105481054910550105511055210553105541055510556105571055810559105601056110562105631056410565105661056710568105691057010571105721057310574105751057610577105781057910580105811058210583105841058510586105871058810589105901059110592
  1. /*
  2. AngelCode Scripting Library
  3. Copyright (c) 2003-2011 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 Öörni 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. #include "as_compiler.h"
  32. #include "as_tokendef.h"
  33. #include "as_tokenizer.h"
  34. #include "as_string_util.h"
  35. #include "as_texts.h"
  36. #include "as_parser.h"
  37. BEGIN_AS_NAMESPACE
  38. // TODO: I must correct the interpretation of a references to objects in the compiler.
  39. // A reference should mean that a pointer to the object is on the stack.
  40. // No expression should end up as non-references to objects, as the actual object is
  41. // never put on the stack.
  42. // Local variables are declared as non-references, but the expression should be a reference to the variable.
  43. // Function parameters of called functions can also be non-references, but in that case it means the
  44. // object will be passed by value (currently on the heap, which will be moved to the application stack).
  45. asCCompiler::asCCompiler(asCScriptEngine *engine) : byteCode(engine)
  46. {
  47. builder = 0;
  48. script = 0;
  49. variables = 0;
  50. isProcessingDeferredParams = false;
  51. isCompilingDefaultArg = false;
  52. noCodeOutput = 0;
  53. }
  54. asCCompiler::~asCCompiler()
  55. {
  56. while( variables )
  57. {
  58. asCVariableScope *var = variables;
  59. variables = variables->parent;
  60. asDELETE(var,asCVariableScope);
  61. }
  62. }
  63. void asCCompiler::Reset(asCBuilder *builder, asCScriptCode *script, asCScriptFunction *outFunc)
  64. {
  65. this->builder = builder;
  66. this->engine = builder->engine;
  67. this->script = script;
  68. this->outFunc = outFunc;
  69. hasCompileErrors = false;
  70. m_isConstructor = false;
  71. m_isConstructorCalled = false;
  72. nextLabel = 0;
  73. breakLabels.SetLength(0);
  74. continueLabels.SetLength(0);
  75. byteCode.ClearAll();
  76. globalExpression = false;
  77. }
  78. int asCCompiler::CompileDefaultConstructor(asCBuilder *builder, asCScriptCode *script, asCScriptFunction *outFunc)
  79. {
  80. Reset(builder, script, outFunc);
  81. // If the class is derived from another, then the base class' default constructor must be called
  82. if( outFunc->objectType->derivedFrom )
  83. {
  84. // Call the base class' default constructor
  85. byteCode.InstrSHORT(asBC_PSF, 0);
  86. byteCode.Instr(asBC_RDSPTR);
  87. byteCode.Call(asBC_CALL, outFunc->objectType->derivedFrom->beh.construct, AS_PTR_SIZE);
  88. }
  89. // Pop the object pointer from the stack
  90. byteCode.Ret(AS_PTR_SIZE);
  91. FinalizeFunction();
  92. #ifdef AS_DEBUG
  93. // DEBUG: output byte code
  94. byteCode.DebugOutput(("__" + outFunc->objectType->name + "_" + outFunc->name + "__dc.txt").AddressOf(), engine, outFunc);
  95. #endif
  96. return 0;
  97. }
  98. int asCCompiler::CompileFactory(asCBuilder *builder, asCScriptCode *script, asCScriptFunction *outFunc)
  99. {
  100. Reset(builder, script, outFunc);
  101. unsigned int n;
  102. // Find the corresponding constructor
  103. asCDataType dt = asCDataType::CreateObject(outFunc->returnType.GetObjectType(), false);
  104. int constructor = 0;
  105. for( n = 0; n < dt.GetBehaviour()->factories.GetLength(); n++ )
  106. {
  107. if( dt.GetBehaviour()->factories[n] == outFunc->id )
  108. {
  109. constructor = dt.GetBehaviour()->constructors[n];
  110. break;
  111. }
  112. }
  113. // Allocate the class and instanciate it with the constructor
  114. int varOffset = AllocateVariable(dt, true);
  115. byteCode.Push(AS_PTR_SIZE);
  116. byteCode.InstrSHORT(asBC_PSF, (short)varOffset);
  117. // Copy all arguments to the top of the stack
  118. int argDwords = (int)outFunc->GetSpaceNeededForArguments();
  119. for( int a = argDwords-1; a >= 0; a-- )
  120. byteCode.InstrSHORT(asBC_PshV4, short(-a));
  121. byteCode.Alloc(asBC_ALLOC, dt.GetObjectType(), constructor, argDwords + AS_PTR_SIZE);
  122. // Return a handle to the newly created object
  123. byteCode.InstrSHORT(asBC_LOADOBJ, (short)varOffset);
  124. byteCode.Ret(argDwords);
  125. FinalizeFunction();
  126. // Tell the virtual machine not to clean up parameters on exception
  127. outFunc->dontCleanUpOnException = true;
  128. /*
  129. #ifdef AS_DEBUG
  130. // DEBUG: output byte code
  131. asCString args;
  132. args.Format("%d", outFunc->parameterTypes.GetLength());
  133. byteCode.DebugOutput(("__" + outFunc->name + "__factory" + args + ".txt").AddressOf(), engine);
  134. #endif
  135. */
  136. return 0;
  137. }
  138. // Entry
  139. int asCCompiler::CompileTemplateFactoryStub(asCBuilder *builder, int trueFactoryId, asCObjectType *objType, asCScriptFunction *outFunc)
  140. {
  141. Reset(builder, 0, outFunc);
  142. asCScriptFunction *descr = builder->GetFunctionDescription(trueFactoryId);
  143. byteCode.InstrPTR(asBC_OBJTYPE, objType);
  144. byteCode.Call(asBC_CALLSYS, trueFactoryId, descr->GetSpaceNeededForArguments());
  145. byteCode.Ret(outFunc->GetSpaceNeededForArguments());
  146. FinalizeFunction();
  147. // Tell the virtual machine not to clean up the object on exception
  148. outFunc->dontCleanUpOnException = true;
  149. return 0;
  150. }
  151. // Entry
  152. int asCCompiler::CompileFunction(asCBuilder *builder, asCScriptCode *script, asCScriptNode *func, asCScriptFunction *outFunc)
  153. {
  154. Reset(builder, script, outFunc);
  155. int buildErrors = builder->numErrors;
  156. int stackPos = 0;
  157. if( outFunc->objectType )
  158. stackPos = -AS_PTR_SIZE; // The first parameter is the pointer to the object
  159. // Reserve a label for the cleanup code
  160. nextLabel++;
  161. // Add the first variable scope, which the parameters and
  162. // variables declared in the outermost statement block is
  163. // part of.
  164. AddVariableScope();
  165. // Skip the private keyword if it is there
  166. asCScriptNode *node = func->firstChild;
  167. if( node->nodeType == snUndefined && node->tokenType == ttPrivate )
  168. node = node->next;
  169. //----------------------------------------------
  170. // Examine return type
  171. bool isDestructor = false;
  172. asCDataType returnType;
  173. if( node->nodeType == snDataType )
  174. {
  175. returnType = builder->CreateDataTypeFromNode(node, script);
  176. returnType = builder->ModifyDataTypeFromNode(returnType, node->next, script, 0, 0);
  177. // Make sure the return type is instanciable or is void
  178. if( !returnType.CanBeInstanciated() &&
  179. returnType != asCDataType::CreatePrimitive(ttVoid, false) )
  180. {
  181. asCString str;
  182. str.Format(TXT_DATA_TYPE_CANT_BE_s, returnType.Format().AddressOf());
  183. Error(str.AddressOf(), func->firstChild);
  184. }
  185. }
  186. else
  187. {
  188. returnType = asCDataType::CreatePrimitive(ttVoid, false);
  189. if( node->tokenType == ttBitNot )
  190. isDestructor = true;
  191. else
  192. m_isConstructor = true;
  193. }
  194. //----------------------------------------------
  195. // Declare parameters
  196. // Find first parameter
  197. while( node && node->nodeType != snParameterList )
  198. node = node->next;
  199. // Register parameters from last to first, otherwise they will be destroyed in the wrong order
  200. asCVariableScope vs(0);
  201. if( node ) node = node->firstChild;
  202. while( node )
  203. {
  204. // Get the parameter type
  205. asCDataType type = builder->CreateDataTypeFromNode(node, script);
  206. asETypeModifiers inoutFlag = asTM_NONE;
  207. type = builder->ModifyDataTypeFromNode(type, node->next, script, &inoutFlag, 0);
  208. // Is the data type allowed?
  209. if( (type.IsReference() && inoutFlag != asTM_INOUTREF && !type.CanBeInstanciated()) ||
  210. (!type.IsReference() && !type.CanBeInstanciated()) )
  211. {
  212. asCString str;
  213. str.Format(TXT_PARAMETER_CANT_BE_s, type.Format().AddressOf());
  214. Error(str.AddressOf(), node);
  215. }
  216. // If the parameter has a name then declare it as variable
  217. node = node->next->next;
  218. if( node && node->nodeType == snIdentifier )
  219. {
  220. asCString name(&script->code[node->tokenPos], node->tokenLength);
  221. if( vs.DeclareVariable(name.AddressOf(), type, stackPos, true) < 0 )
  222. Error(TXT_PARAMETER_ALREADY_DECLARED, node);
  223. outFunc->AddVariable(name, type, stackPos);
  224. node = node->next;
  225. // Skip the default arg
  226. if( node && node->nodeType == snExpression )
  227. node = node->next;
  228. }
  229. else
  230. vs.DeclareVariable("", type, stackPos, true);
  231. // Move to next parameter
  232. stackPos -= type.GetSizeOnStackDWords();
  233. }
  234. int n;
  235. for( n = (int)vs.variables.GetLength() - 1; n >= 0; n-- )
  236. {
  237. variables->DeclareVariable(vs.variables[n]->name.AddressOf(), vs.variables[n]->type, vs.variables[n]->stackOffset, vs.variables[n]->onHeap);
  238. }
  239. // Is the return type allowed?
  240. if( (returnType.GetSizeOnStackDWords() == 0 && returnType != asCDataType::CreatePrimitive(ttVoid, false)) ||
  241. (returnType.IsReference() && !returnType.CanBeInstanciated()) )
  242. {
  243. asCString str;
  244. str.Format(TXT_RETURN_CANT_BE_s, returnType.Format().AddressOf());
  245. Error(str.AddressOf(), node);
  246. }
  247. variables->DeclareVariable("return", returnType, stackPos, true);
  248. //--------------------------------------------
  249. // Compile the statement block
  250. // We need to parse the statement block now
  251. // TODO: memory: We can parse the statement block one statement at a time, thus save even more memory
  252. asCParser parser(builder);
  253. int r = parser.ParseStatementBlock(script, func->lastChild);
  254. if( r < 0 ) return -1;
  255. asCScriptNode *block = parser.GetScriptNode();
  256. bool hasReturn;
  257. asCByteCode bc(engine);
  258. LineInstr(&bc, func->lastChild->tokenPos);
  259. CompileStatementBlock(block, false, &hasReturn, &bc);
  260. LineInstr(&bc, func->lastChild->tokenPos + func->lastChild->tokenLength);
  261. // Make sure there is a return in all paths (if not return type is void)
  262. if( returnType != asCDataType::CreatePrimitive(ttVoid, false) )
  263. {
  264. if( hasReturn == false )
  265. Error(TXT_NOT_ALL_PATHS_RETURN, func->lastChild);
  266. }
  267. //------------------------------------------------
  268. // Concatenate the bytecode
  269. // Insert a JitEntry at the start of the function for JIT compilers
  270. byteCode.InstrWORD(asBC_JitEntry, 0);
  271. // Count total variable size
  272. int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1;
  273. byteCode.Push(varSize);
  274. if( outFunc->objectType )
  275. {
  276. // Call the base class' default constructor unless called manually in the code
  277. if( m_isConstructor && !m_isConstructorCalled && outFunc->objectType->derivedFrom )
  278. {
  279. byteCode.InstrSHORT(asBC_PSF, 0);
  280. byteCode.Instr(asBC_RDSPTR);
  281. byteCode.Call(asBC_CALL, outFunc->objectType->derivedFrom->beh.construct, AS_PTR_SIZE);
  282. }
  283. // Increase the reference for the object pointer, so that it is guaranteed to live during the entire call
  284. // TODO: optimize: This is probably not necessary for constructors as no outside reference to the object is created yet
  285. byteCode.InstrSHORT(asBC_PSF, 0);
  286. byteCode.Instr(asBC_RDSPTR);
  287. byteCode.Call(asBC_CALLSYS, outFunc->objectType->beh.addref, AS_PTR_SIZE);
  288. }
  289. // Add the code for the statement block
  290. byteCode.AddCode(&bc);
  291. // Deallocate all local variables
  292. for( n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  293. {
  294. sVariable *v = variables->variables[n];
  295. if( v->stackOffset > 0 )
  296. {
  297. // Call variables destructors
  298. if( v->name != "return" && v->name != "return address" )
  299. CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode);
  300. DeallocateVariable(v->stackOffset);
  301. }
  302. }
  303. // This is the label that return statements jump to
  304. // in order to exit the function
  305. byteCode.Label(0);
  306. // Call destructors for function parameters
  307. for( n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  308. {
  309. sVariable *v = variables->variables[n];
  310. if( v->stackOffset <= 0 )
  311. {
  312. // Call variable destructors here, for variables not yet destroyed
  313. if( v->name != "return" && v->name != "return address" )
  314. CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode);
  315. }
  316. // Do not deallocate parameters
  317. }
  318. // Release the object pointer again
  319. if( outFunc->objectType )
  320. {
  321. byteCode.InstrW_PTR(asBC_FREE, 0, outFunc->objectType);
  322. }
  323. // If there are compile errors, there is no reason to build the final code
  324. if( hasCompileErrors || builder->numErrors != buildErrors )
  325. return -1;
  326. // At this point there should be no variables allocated
  327. asASSERT(variableAllocations.GetLength() == freeVariables.GetLength());
  328. // Remove the variable scope
  329. RemoveVariableScope();
  330. // This POP is not necessary as the return will clean up the stack frame anyway.
  331. // The bytecode optimizer would remove this POP, however by not including it here
  332. // it is guaranteed it doesn't have to be adjusted by the asCRestore class when
  333. // a types are of a different size than originally compiled for.
  334. // byteCode.Pop(varSize);
  335. byteCode.Ret(-stackPos);
  336. FinalizeFunction();
  337. #ifdef AS_DEBUG
  338. // DEBUG: output byte code
  339. if( outFunc->objectType )
  340. byteCode.DebugOutput(("__" + outFunc->objectType->name + "_" + outFunc->name + ".txt").AddressOf(), engine, outFunc);
  341. else
  342. byteCode.DebugOutput(("__" + outFunc->name + ".txt").AddressOf(), engine, outFunc);
  343. #endif
  344. return 0;
  345. }
  346. int asCCompiler::CallCopyConstructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asSExprContext *arg, asCScriptNode *node, bool isGlobalVar)
  347. {
  348. if( !type.IsObject() )
  349. return 0;
  350. // CallCopyConstructor should not be called for object handles.
  351. asASSERT(!type.IsObjectHandle());
  352. asCArray<asSExprContext*> args;
  353. args.PushLast(arg);
  354. // The reference parameter must be pushed on the stack
  355. asASSERT( arg->type.dataType.GetObjectType() == type.GetObjectType() );
  356. // Since we're calling the copy constructor, we have to trust the function to not do
  357. // anything stupid otherwise we will just enter a loop, as we try to make temporary
  358. // copies of the argument in order to guarantee safety.
  359. if( type.GetObjectType()->flags & asOBJ_REF )
  360. {
  361. asSExprContext ctx(engine);
  362. int func = 0;
  363. asSTypeBehaviour *beh = type.GetBehaviour();
  364. if( beh ) func = beh->copyfactory;
  365. if( func > 0 )
  366. {
  367. if( !isGlobalVar )
  368. {
  369. // Call factory and store the handle in the given variable
  370. PerformFunctionCall(func, &ctx, false, &args, type.GetObjectType(), true, offset);
  371. // Pop the reference left by the function call
  372. ctx.bc.Pop(AS_PTR_SIZE);
  373. }
  374. else
  375. {
  376. // Call factory
  377. PerformFunctionCall(func, &ctx, false, &args, type.GetObjectType());
  378. // Store the returned handle in the global variable
  379. ctx.bc.Instr(asBC_RDSPTR);
  380. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  381. ctx.bc.InstrPTR(asBC_REFCPY, type.GetObjectType());
  382. ctx.bc.Pop(AS_PTR_SIZE);
  383. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  384. }
  385. bc->AddCode(&ctx.bc);
  386. return 0;
  387. }
  388. }
  389. else
  390. {
  391. asSTypeBehaviour *beh = type.GetBehaviour();
  392. int func = beh ? beh->copyconstruct : 0;
  393. if( func > 0 )
  394. {
  395. // Push the address where the object will be stored on the stack, before the argument
  396. // TODO: When the context is serializable this probably has to be changed, since this
  397. // pointer can remain on the stack while the context is suspended. There is no
  398. // risk the pointer becomes invalid though, there is just no easy way to serialize it.
  399. asCByteCode tmp(engine);
  400. if( isGlobalVar )
  401. tmp.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  402. else if( isObjectOnHeap )
  403. tmp.InstrSHORT(asBC_PSF, (short)offset);
  404. tmp.AddCode(bc);
  405. bc->AddCode(&tmp);
  406. // When the object is allocated on the stack the object pointer
  407. // must be pushed on the stack after the arguments
  408. if( !isObjectOnHeap )
  409. {
  410. asASSERT( !isGlobalVar );
  411. bc->InstrSHORT(asBC_PSF, (short)offset);
  412. }
  413. asSExprContext ctx(engine);
  414. PerformFunctionCall(func, &ctx, isObjectOnHeap, &args, type.GetObjectType());
  415. bc->AddCode(&ctx.bc);
  416. // TODO: value on stack: This probably needs to be done in PerformFunctionCall
  417. // Mark the object as initialized
  418. if( !isObjectOnHeap )
  419. bc->ObjInfo(offset, asOBJ_INIT);
  420. return 0;
  421. }
  422. }
  423. // Class has no copy constructor/factory.
  424. asCString str;
  425. str.Format(TXT_NO_COPY_CONSTRUCTOR_FOR_s, type.GetObjectType()->GetName());
  426. Error(str.AddressOf(), node);
  427. return -1;
  428. }
  429. int asCCompiler::CallDefaultConstructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asCScriptNode *node, bool isGlobalVar)
  430. {
  431. if( !type.IsObject() || type.IsObjectHandle() )
  432. return 0;
  433. if( type.GetObjectType()->flags & asOBJ_REF )
  434. {
  435. asSExprContext ctx(engine);
  436. int func = 0;
  437. asSTypeBehaviour *beh = type.GetBehaviour();
  438. if( beh ) func = beh->factory;
  439. if( func > 0 )
  440. {
  441. if( !isGlobalVar )
  442. {
  443. // Call factory and store the handle in the given variable
  444. PerformFunctionCall(func, &ctx, false, 0, type.GetObjectType(), true, offset);
  445. // Pop the reference left by the function call
  446. ctx.bc.Pop(AS_PTR_SIZE);
  447. }
  448. else
  449. {
  450. // Call factory
  451. PerformFunctionCall(func, &ctx, false, 0, type.GetObjectType());
  452. // Store the returned handle in the global variable
  453. ctx.bc.Instr(asBC_RDSPTR);
  454. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  455. ctx.bc.InstrPTR(asBC_REFCPY, type.GetObjectType());
  456. ctx.bc.Pop(AS_PTR_SIZE);
  457. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  458. }
  459. bc->AddCode(&ctx.bc);
  460. return 0;
  461. }
  462. }
  463. else
  464. {
  465. asSTypeBehaviour *beh = type.GetBehaviour();
  466. int func = 0;
  467. if( beh ) func = beh->construct;
  468. // Allocate and initialize with the default constructor
  469. if( func != 0 || (type.GetObjectType()->flags & asOBJ_POD) )
  470. {
  471. if( !isObjectOnHeap )
  472. {
  473. asASSERT( !isGlobalVar );
  474. // There is nothing to do if there is no function,
  475. // as the memory is already allocated on the stack
  476. if( func )
  477. {
  478. // Call the constructor as a normal function
  479. bc->InstrSHORT(asBC_PSF, (short)offset);
  480. asSExprContext ctx(engine);
  481. PerformFunctionCall(func, &ctx, false, 0, type.GetObjectType());
  482. bc->AddCode(&ctx.bc);
  483. // TODO: value on stack: This probably needs to be done in PerformFunctionCall
  484. // Mark the object as initialized
  485. bc->ObjInfo(offset, asOBJ_INIT);
  486. }
  487. }
  488. else
  489. {
  490. if( isGlobalVar )
  491. bc->InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
  492. else
  493. bc->InstrSHORT(asBC_PSF, (short)offset);
  494. bc->Alloc(asBC_ALLOC, type.GetObjectType(), func, AS_PTR_SIZE);
  495. }
  496. return 0;
  497. }
  498. }
  499. // Class has no default factory/constructor.
  500. asCString str;
  501. // TODO: funcdef: asCDataType should have a GetTypeName()
  502. if( type.GetFuncDef() )
  503. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, type.GetFuncDef()->GetName());
  504. else
  505. str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, type.GetObjectType()->GetName());
  506. Error(str.AddressOf(), node);
  507. return -1;
  508. }
  509. void asCCompiler::CallDestructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc)
  510. {
  511. if( !type.IsReference() )
  512. {
  513. // Call destructor for the data type
  514. if( type.IsObject() )
  515. {
  516. if( isObjectOnHeap || type.IsObjectHandle() )
  517. {
  518. // Free the memory
  519. bc->InstrW_PTR(asBC_FREE, (short)offset, type.GetObjectType());
  520. }
  521. else
  522. {
  523. asASSERT( type.GetObjectType()->GetFlags() & asOBJ_VALUE );
  524. if( type.GetBehaviour()->destruct )
  525. {
  526. // Call the destructor as a regular function
  527. bc->InstrSHORT(asBC_PSF, (short)offset);
  528. asSExprContext ctx(engine);
  529. PerformFunctionCall(type.GetBehaviour()->destruct, &ctx);
  530. bc->AddCode(&ctx.bc);
  531. }
  532. // TODO: Value on stack: This probably needs to be done in PerformFunctionCall
  533. // Mark the object as destroyed
  534. bc->ObjInfo(offset, asOBJ_UNINIT);
  535. }
  536. }
  537. }
  538. }
  539. void asCCompiler::LineInstr(asCByteCode *bc, size_t pos)
  540. {
  541. int r, c;
  542. script->ConvertPosToRowCol(pos, &r, &c);
  543. bc->Line(r, c);
  544. }
  545. void asCCompiler::CompileStatementBlock(asCScriptNode *block, bool ownVariableScope, bool *hasReturn, asCByteCode *bc)
  546. {
  547. *hasReturn = false;
  548. bool isFinished = false;
  549. bool hasWarned = false;
  550. if( ownVariableScope )
  551. {
  552. bc->Block(true);
  553. AddVariableScope();
  554. }
  555. asCScriptNode *node = block->firstChild;
  556. while( node )
  557. {
  558. if( !hasWarned && (*hasReturn || isFinished) )
  559. {
  560. hasWarned = true;
  561. Warning(TXT_UNREACHABLE_CODE, node);
  562. }
  563. if( node->nodeType == snBreak || node->nodeType == snContinue )
  564. isFinished = true;
  565. asCByteCode statement(engine);
  566. if( node->nodeType == snDeclaration )
  567. CompileDeclaration(node, &statement);
  568. else
  569. CompileStatement(node, hasReturn, &statement);
  570. LineInstr(bc, node->tokenPos);
  571. bc->AddCode(&statement);
  572. if( !hasCompileErrors )
  573. asASSERT( tempVariables.GetLength() == 0 );
  574. node = node->next;
  575. }
  576. if( ownVariableScope )
  577. {
  578. // Deallocate variables in this block, in reverse order
  579. for( int n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  580. {
  581. sVariable *v = variables->variables[n];
  582. // Call variable destructors here, for variables not yet destroyed
  583. // If the block is terminated with a break, continue, or
  584. // return the variables are already destroyed
  585. if( !isFinished && !*hasReturn )
  586. CallDestructor(v->type, v->stackOffset, v->onHeap, bc);
  587. // Don't deallocate function parameters
  588. if( v->stackOffset > 0 )
  589. DeallocateVariable(v->stackOffset);
  590. }
  591. RemoveVariableScope();
  592. bc->Block(false);
  593. }
  594. }
  595. // Entry
  596. int asCCompiler::CompileGlobalVariable(asCBuilder *builder, asCScriptCode *script, asCScriptNode *node, sGlobalVariableDescription *gvar, asCScriptFunction *outFunc)
  597. {
  598. Reset(builder, script, outFunc);
  599. globalExpression = true;
  600. // Add a variable scope (even though variables can't be declared)
  601. AddVariableScope();
  602. asSExprContext ctx(engine);
  603. gvar->isPureConstant = false;
  604. // Parse the initialization nodes
  605. asCParser parser(builder);
  606. if( node )
  607. {
  608. int r = parser.ParseGlobalVarInit(script, node);
  609. if( r < 0 )
  610. return r;
  611. node = parser.GetScriptNode();
  612. }
  613. // Compile the expression
  614. if( node && node->nodeType == snArgList )
  615. {
  616. // Make sure that it is a registered type, and that it isn't a pointer
  617. if( gvar->datatype.GetObjectType() == 0 || gvar->datatype.IsObjectHandle() )
  618. {
  619. Error(TXT_MUST_BE_OBJECT, node);
  620. }
  621. else
  622. {
  623. // Compile the arguments
  624. asCArray<asSExprContext *> args;
  625. if( CompileArgumentList(node, args) >= 0 )
  626. {
  627. // Find all constructors
  628. asCArray<int> funcs;
  629. asSTypeBehaviour *beh = gvar->datatype.GetBehaviour();
  630. if( beh )
  631. {
  632. if( gvar->datatype.GetObjectType()->flags & asOBJ_REF )
  633. funcs = beh->factories;
  634. else
  635. funcs = beh->constructors;
  636. }
  637. asCString str = gvar->datatype.Format();
  638. MatchFunctions(funcs, args, node, str.AddressOf());
  639. if( funcs.GetLength() == 1 )
  640. {
  641. int r = asSUCCESS;
  642. // Add the default values for arguments not explicitly supplied
  643. asCScriptFunction *func = (funcs[0] & 0xFFFF0000) == 0 ? engine->scriptFunctions[funcs[0]] : 0;
  644. if( func && args.GetLength() < (asUINT)func->GetParamCount() )
  645. r = CompileDefaultArgs(node, args, func);
  646. if( r == asSUCCESS )
  647. {
  648. if( gvar->datatype.GetObjectType()->flags & asOBJ_REF )
  649. {
  650. MakeFunctionCall(&ctx, funcs[0], 0, args, node);
  651. // Store the returned handle in the global variable
  652. ctx.bc.Instr(asBC_RDSPTR);
  653. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[gvar->index]->GetAddressOfValue());
  654. ctx.bc.InstrPTR(asBC_REFCPY, gvar->datatype.GetObjectType());
  655. ctx.bc.Pop(AS_PTR_SIZE);
  656. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  657. }
  658. else
  659. {
  660. // Push the address of the location where the variable will be stored on the stack.
  661. // This reference is safe, because the addresses of the global variables cannot change.
  662. // TODO: When serialization of the context is implemented this will probably have to change,
  663. // because this pointer may be on the stack while the context is suspended, and may
  664. // be difficult to serialize as the context doesn't know that the value represents a
  665. // pointer.
  666. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[gvar->index]->GetAddressOfValue());
  667. PrepareFunctionCall(funcs[0], &ctx.bc, args);
  668. MoveArgsToStack(funcs[0], &ctx.bc, args, false);
  669. PerformFunctionCall(funcs[0], &ctx, true, &args, gvar->datatype.GetObjectType());
  670. }
  671. }
  672. }
  673. }
  674. // Cleanup
  675. for( asUINT n = 0; n < args.GetLength(); n++ )
  676. if( args[n] )
  677. {
  678. asDELETE(args[n],asSExprContext);
  679. }
  680. }
  681. }
  682. else if( node && node->nodeType == snInitList )
  683. {
  684. asCTypeInfo ti;
  685. ti.Set(gvar->datatype);
  686. ti.isVariable = false;
  687. ti.isTemporary = false;
  688. ti.stackOffset = (short)gvar->index;
  689. CompileInitList(&ti, node, &ctx.bc);
  690. node = node->next;
  691. }
  692. else if( node )
  693. {
  694. // Compile the right hand expression
  695. asSExprContext expr(engine);
  696. int r = CompileAssignment(node, &expr); if( r < 0 ) return r;
  697. // Assign the value to the variable
  698. if( gvar->datatype.IsPrimitive() )
  699. {
  700. if( gvar->datatype.IsReadOnly() && expr.type.isConstant )
  701. {
  702. ImplicitConversion(&expr, gvar->datatype, node, asIC_IMPLICIT_CONV);
  703. gvar->isPureConstant = true;
  704. gvar->constantValue = expr.type.qwordValue;
  705. }
  706. asSExprContext lctx(engine);
  707. lctx.type.Set(gvar->datatype);
  708. lctx.type.dataType.MakeReference(true);
  709. lctx.type.dataType.MakeReadOnly(false);
  710. // If it is an enum value that is being compiled, then
  711. // we skip this, as the bytecode won't be used anyway
  712. if( !gvar->isEnumValue )
  713. lctx.bc.InstrPTR(asBC_LDG, engine->globalProperties[gvar->index]->GetAddressOfValue());
  714. DoAssignment(&ctx, &lctx, &expr, node, node, ttAssignment, node);
  715. }
  716. else
  717. {
  718. // TODO: copy: Here we should look for the best matching constructor, instead of
  719. // just the copy constructor. Only if no appropriate constructor is
  720. // available should the assignment operator be used.
  721. if( !gvar->datatype.IsObjectHandle() )
  722. {
  723. // Call the default constructor to have a valid object for the assignment
  724. CallDefaultConstructor(gvar->datatype, gvar->index, true, &ctx.bc, gvar->idNode, true);
  725. }
  726. asSExprContext lexpr(engine);
  727. lexpr.type.Set(gvar->datatype);
  728. lexpr.type.dataType.MakeReference(true);
  729. lexpr.type.dataType.MakeReadOnly(false);
  730. lexpr.type.stackOffset = -1;
  731. if( gvar->datatype.IsObjectHandle() )
  732. lexpr.type.isExplicitHandle = true;
  733. lexpr.bc.InstrPTR(asBC_PGA, engine->globalProperties[gvar->index]->GetAddressOfValue());
  734. // If left expression resolves into a registered type
  735. // check if the assignment operator is overloaded, and check
  736. // the type of the right hand expression. If none is found
  737. // the default action is a direct copy if it is the same type
  738. // and a simple assignment.
  739. bool assigned = false;
  740. if( lexpr.type.dataType.IsObject() && !lexpr.type.isExplicitHandle )
  741. {
  742. assigned = CompileOverloadedDualOperator(node, &lexpr, &expr, &ctx);
  743. if( assigned )
  744. {
  745. // Pop the resulting value
  746. ctx.bc.Pop(ctx.type.dataType.GetSizeOnStackDWords());
  747. // Release the argument
  748. ProcessDeferredParams(&ctx);
  749. }
  750. }
  751. if( !assigned )
  752. {
  753. PrepareForAssignment(&lexpr.type.dataType, &expr, node);
  754. // If the expression is constant and the variable also is constant
  755. // then mark the variable as pure constant. This will allow the compiler
  756. // to optimize expressions with this variable.
  757. if( gvar->datatype.IsReadOnly() && expr.type.isConstant )
  758. {
  759. gvar->isPureConstant = true;
  760. gvar->constantValue = expr.type.qwordValue;
  761. }
  762. // Add expression code to bytecode
  763. MergeExprBytecode(&ctx, &expr);
  764. // Add byte code for storing value of expression in variable
  765. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[gvar->index]->GetAddressOfValue());
  766. PerformAssignment(&lexpr.type, &expr.type, &ctx.bc, node);
  767. // Release temporary variables used by expression
  768. ReleaseTemporaryVariable(expr.type, &ctx.bc);
  769. ctx.bc.Pop(expr.type.dataType.GetSizeOnStackDWords());
  770. }
  771. }
  772. }
  773. else if( gvar->datatype.IsObject() && !gvar->datatype.IsObjectHandle() )
  774. {
  775. // Call the default constructor in case no explicit initialization is given
  776. CallDefaultConstructor(gvar->datatype, gvar->index, true, &ctx.bc, gvar->idNode, true);
  777. }
  778. // Concatenate the bytecode
  779. int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1;
  780. // Add information on the line number for the global variable
  781. size_t pos = 0;
  782. if( gvar->idNode )
  783. pos = gvar->idNode->tokenPos;
  784. else if( gvar->nextNode )
  785. pos = gvar->nextNode->tokenPos;
  786. LineInstr(&byteCode, pos);
  787. // We need to push zeroes on the stack to guarantee
  788. // that temporary object handles are clear
  789. int n;
  790. for( n = 0; n < varSize; n++ )
  791. byteCode.InstrINT(asBC_PshC4, 0);
  792. byteCode.AddCode(&ctx.bc);
  793. // Deallocate variables in this block, in reverse order
  794. for( n = (int)variables->variables.GetLength() - 1; n >= 0; --n )
  795. {
  796. sVariable *v = variables->variables[n];
  797. // Call variable destructors here, for variables not yet destroyed
  798. CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode);
  799. DeallocateVariable(v->stackOffset);
  800. }
  801. if( hasCompileErrors ) return -1;
  802. // At this point there should be no variables allocated
  803. asASSERT(variableAllocations.GetLength() == freeVariables.GetLength());
  804. // Remove the variable scope again
  805. RemoveVariableScope();
  806. byteCode.Ret(0);
  807. FinalizeFunction();
  808. #ifdef AS_DEBUG
  809. // DEBUG: output byte code
  810. byteCode.DebugOutput(("___init_" + gvar->name + ".txt").AddressOf(), engine, outFunc);
  811. #endif
  812. return 0;
  813. }
  814. void asCCompiler::FinalizeFunction()
  815. {
  816. asUINT n;
  817. // Tell the bytecode which variables are temporary
  818. for( n = 0; n < variableIsTemporary.GetLength(); n++ )
  819. {
  820. if( variableIsTemporary[n] )
  821. byteCode.DefineTemporaryVariable(GetVariableOffset(n));
  822. }
  823. // Finalize the bytecode
  824. byteCode.Finalize();
  825. byteCode.ExtractObjectVariableInfo(outFunc);
  826. // Compile the list of object variables for the exception handler
  827. for( n = 0; n < variableAllocations.GetLength(); n++ )
  828. {
  829. if( variableAllocations[n].IsObject() && !variableAllocations[n].IsReference() )
  830. {
  831. outFunc->objVariableTypes.PushLast(variableAllocations[n].GetObjectType());
  832. outFunc->objVariablePos.PushLast(GetVariableOffset(n));
  833. outFunc->objVariableIsOnHeap.PushLast(variableIsOnHeap[n]);
  834. }
  835. }
  836. // Copy byte code to the function
  837. outFunc->byteCode.SetLength(byteCode.GetSize());
  838. byteCode.Output(outFunc->byteCode.AddressOf());
  839. outFunc->AddReferences();
  840. outFunc->stackNeeded = byteCode.largestStackUsed;
  841. outFunc->lineNumbers = byteCode.lineNumbers;
  842. }
  843. void asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, asCScriptNode *node, bool isFunction, int refType, asCArray<int> *reservedVars, bool /* forceOnHeap */)
  844. {
  845. asCDataType param = *paramType;
  846. if( paramType->GetTokenType() == ttQuestion )
  847. {
  848. // Since the function is expecting a var type ?, then we don't want to convert the argument to anything else
  849. param = ctx->type.dataType;
  850. param.MakeHandle(ctx->type.isExplicitHandle);
  851. param.MakeReference(paramType->IsReference());
  852. param.MakeReadOnly(paramType->IsReadOnly());
  853. }
  854. else
  855. param = *paramType;
  856. asCDataType dt = param;
  857. // Need to protect arguments by reference
  858. if( isFunction && dt.IsReference() )
  859. {
  860. if( paramType->GetTokenType() == ttQuestion )
  861. {
  862. asCByteCode tmpBC(engine);
  863. // Place the type id on the stack as a hidden parameter
  864. tmpBC.InstrDWORD(asBC_TYPEID, engine->GetTypeIdFromDataType(param));
  865. // Insert the code before the expression code
  866. tmpBC.AddCode(&ctx->bc);
  867. ctx->bc.AddCode(&tmpBC);
  868. }
  869. // Allocate a temporary variable of the same type as the argument
  870. dt.MakeReference(false);
  871. dt.MakeReadOnly(false);
  872. int offset;
  873. if( refType == 1 ) // &in
  874. {
  875. ProcessPropertyGetAccessor(ctx, node);
  876. // If the reference is const, then it is not necessary to make a copy if the value already is a variable
  877. // Even if the same variable is passed in another argument as non-const then there is no problem
  878. if( dt.IsPrimitive() || dt.IsNullHandle() )
  879. {
  880. IsVariableInitialized(&ctx->type, node);
  881. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  882. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true, reservedVars);
  883. if( !(param.IsReadOnly() && ctx->type.isVariable) )
  884. ConvertToTempVariable(ctx);
  885. PushVariableOnStack(ctx, true);
  886. ctx->type.dataType.MakeReadOnly(param.IsReadOnly());
  887. }
  888. else
  889. {
  890. IsVariableInitialized(&ctx->type, node);
  891. ImplicitConversion(ctx, param, node, asIC_IMPLICIT_CONV, true, reservedVars);
  892. if( !ctx->type.dataType.IsEqualExceptRef(param) )
  893. {
  894. asCString str;
  895. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), param.Format().AddressOf());
  896. Error(str.AddressOf(), node);
  897. ctx->type.Set(param);
  898. }
  899. // If the argument already is a temporary
  900. // variable we don't need to allocate another
  901. // If the parameter is read-only and the object already is a local
  902. // variable then it is not necessary to make a copy either
  903. if( !ctx->type.isTemporary && !(param.IsReadOnly() && ctx->type.isVariable) )
  904. {
  905. // Make sure the variable is not used in the expression
  906. asCArray<int> vars;
  907. ctx->bc.GetVarsUsed(vars);
  908. if( reservedVars ) vars.Concatenate(*reservedVars);
  909. offset = AllocateVariableNotIn(dt, true, &vars);
  910. // TODO: copy: Use copy constructor if available. See PrepareTemporaryObject()
  911. // Allocate and construct the temporary object
  912. asCByteCode tmpBC(engine);
  913. CallDefaultConstructor(dt, offset, IsVariableOnHeap(offset), &tmpBC, node);
  914. // Insert the code before the expression code
  915. tmpBC.AddCode(&ctx->bc);
  916. ctx->bc.AddCode(&tmpBC);
  917. // Assign the evaluated expression to the temporary variable
  918. PrepareForAssignment(&dt, ctx, node);
  919. dt.MakeReference(IsVariableOnHeap(offset));
  920. asCTypeInfo type;
  921. type.Set(dt);
  922. type.isTemporary = true;
  923. type.stackOffset = (short)offset;
  924. if( dt.IsObjectHandle() )
  925. type.isExplicitHandle = true;
  926. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  927. PerformAssignment(&type, &ctx->type, &ctx->bc, node);
  928. ctx->bc.Pop(ctx->type.dataType.GetSizeOnStackDWords());
  929. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  930. ctx->type = type;
  931. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  932. if( dt.IsObject() && !dt.IsObjectHandle() )
  933. ctx->bc.Instr(asBC_RDSPTR);
  934. if( paramType->IsReadOnly() )
  935. ctx->type.dataType.MakeReadOnly(true);
  936. }
  937. }
  938. }
  939. else if( refType == 2 ) // &out
  940. {
  941. // Make sure the variable is not used in the expression
  942. asCArray<int> vars;
  943. ctx->bc.GetVarsUsed(vars);
  944. if( reservedVars ) vars.Concatenate(*reservedVars);
  945. offset = AllocateVariableNotIn(dt, true, &vars);
  946. if( dt.IsPrimitive() )
  947. {
  948. ctx->type.SetVariable(dt, offset, true);
  949. PushVariableOnStack(ctx, true);
  950. }
  951. else
  952. {
  953. // Allocate and construct the temporary object
  954. asCByteCode tmpBC(engine);
  955. CallDefaultConstructor(dt, offset, IsVariableOnHeap(offset), &tmpBC, node);
  956. // Insert the code before the expression code
  957. tmpBC.AddCode(&ctx->bc);
  958. ctx->bc.AddCode(&tmpBC);
  959. dt.MakeReference((!dt.IsObject() || dt.IsObjectHandle()));
  960. asCTypeInfo type;
  961. type.Set(dt);
  962. type.isTemporary = true;
  963. type.stackOffset = (short)offset;
  964. ctx->type = type;
  965. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  966. if( dt.IsObject() && !dt.IsObjectHandle() )
  967. ctx->bc.Instr(asBC_RDSPTR);
  968. }
  969. // After the function returns the temporary variable will
  970. // be assigned to the expression, if it is a valid lvalue
  971. }
  972. else if( refType == asTM_INOUTREF )
  973. {
  974. // Literal constants cannot be passed to inout ref arguments
  975. if( !ctx->type.isVariable && ctx->type.isConstant )
  976. {
  977. Error(TXT_NOT_VALID_REFERENCE, node);
  978. }
  979. // Only objects that support object handles
  980. // can be guaranteed to be safe. Local variables are
  981. // already safe, so there is no need to add an extra
  982. // references
  983. if( !engine->ep.allowUnsafeReferences &&
  984. !ctx->type.isVariable &&
  985. ctx->type.dataType.IsObject() &&
  986. !ctx->type.dataType.IsObjectHandle() &&
  987. ctx->type.dataType.GetBehaviour()->addref &&
  988. ctx->type.dataType.GetBehaviour()->release )
  989. {
  990. // Store a handle to the object as local variable
  991. asSExprContext tmp(engine);
  992. asCDataType dt = ctx->type.dataType;
  993. dt.MakeHandle(true);
  994. dt.MakeReference(false);
  995. asCArray<int> vars;
  996. ctx->bc.GetVarsUsed(vars);
  997. if( reservedVars ) vars.Concatenate(*reservedVars);
  998. offset = AllocateVariableNotIn(dt, true, &vars);
  999. // Copy the handle
  1000. if( !ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReference() )
  1001. ctx->bc.Instr(asBC_RDSPTR);
  1002. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1003. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetObjectType());
  1004. ctx->bc.Pop(AS_PTR_SIZE);
  1005. ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset);
  1006. dt.MakeHandle(false);
  1007. dt.MakeReference(true);
  1008. // Release previous temporary variable stored in the context (if any)
  1009. if( ctx->type.isTemporary )
  1010. {
  1011. ReleaseTemporaryVariable(ctx->type.stackOffset, &ctx->bc);
  1012. }
  1013. ctx->type.SetVariable(dt, offset, true);
  1014. }
  1015. // Make sure the reference to the value is on the stack
  1016. if( ctx->type.dataType.IsObject() && ctx->type.dataType.IsReference() )
  1017. Dereference(ctx, true);
  1018. else if( ctx->type.isVariable && !ctx->type.dataType.IsObject() )
  1019. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  1020. else if( ctx->type.dataType.IsPrimitive() )
  1021. ctx->bc.Instr(asBC_PshRPtr);
  1022. }
  1023. }
  1024. else
  1025. {
  1026. ProcessPropertyGetAccessor(ctx, node);
  1027. if( dt.IsPrimitive() )
  1028. {
  1029. IsVariableInitialized(&ctx->type, node);
  1030. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  1031. // Implicitly convert primitives to the parameter type
  1032. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true, reservedVars);
  1033. if( ctx->type.isVariable )
  1034. {
  1035. PushVariableOnStack(ctx, dt.IsReference());
  1036. }
  1037. else if( ctx->type.isConstant )
  1038. {
  1039. ConvertToVariable(ctx);
  1040. PushVariableOnStack(ctx, dt.IsReference());
  1041. }
  1042. }
  1043. else
  1044. {
  1045. IsVariableInitialized(&ctx->type, node);
  1046. // Implicitly convert primitives to the parameter type
  1047. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true, reservedVars);
  1048. // Was the conversion successful?
  1049. if( !ctx->type.dataType.IsEqualExceptRef(dt) )
  1050. {
  1051. asCString str;
  1052. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), dt.Format().AddressOf());
  1053. Error(str.AddressOf(), node);
  1054. ctx->type.Set(dt);
  1055. }
  1056. if( dt.IsObjectHandle() )
  1057. ctx->type.isExplicitHandle = true;
  1058. if( dt.IsObject() )
  1059. {
  1060. if( !dt.IsReference() )
  1061. {
  1062. // Objects passed by value must be placed in temporary variables
  1063. // so that they are guaranteed to not be referenced anywhere else.
  1064. // The object must also be allocated on the heap, as the memory will
  1065. // be deleted by in as_callfunc_xxx.
  1066. // TODO: value on stack: How can we avoid this unnecessary allocation?
  1067. PrepareTemporaryObject(node, ctx, reservedVars, true);
  1068. // The implicit conversion shouldn't convert the object to
  1069. // non-reference yet. It will be dereferenced just before the call.
  1070. // Otherwise the object might be missed by the exception handler.
  1071. dt.MakeReference(true);
  1072. }
  1073. else
  1074. {
  1075. // An object passed by reference should place the pointer to
  1076. // the object on the stack.
  1077. dt.MakeReference(false);
  1078. }
  1079. }
  1080. }
  1081. }
  1082. // Don't put any pointer on the stack yet
  1083. if( param.IsReference() || param.IsObject() )
  1084. {
  1085. // &inout parameter may leave the reference on the stack already
  1086. if( refType != 3 )
  1087. {
  1088. ctx->bc.Pop(AS_PTR_SIZE);
  1089. ctx->bc.InstrSHORT(asBC_VAR, ctx->type.stackOffset);
  1090. }
  1091. ProcessDeferredParams(ctx);
  1092. }
  1093. }
  1094. void asCCompiler::PrepareFunctionCall(int funcID, asCByteCode *bc, asCArray<asSExprContext *> &args)
  1095. {
  1096. // When a match has been found, compile the final byte code using correct parameter types
  1097. asCScriptFunction *descr = builder->GetFunctionDescription(funcID);
  1098. // Add code for arguments
  1099. asSExprContext e(engine);
  1100. int n;
  1101. for( n = (int)args.GetLength()-1; n >= 0; n-- )
  1102. {
  1103. // Make sure PrepareArgument doesn't use any variable that is already
  1104. // being used by any of the following argument expressions
  1105. asCArray<int> reservedVars;
  1106. for( int m = n-1; m >= 0; m-- )
  1107. args[m]->bc.GetVarsUsed(reservedVars);
  1108. PrepareArgument2(&e, args[n], &descr->parameterTypes[n], true, descr->inOutFlags[n], &reservedVars);
  1109. }
  1110. bc->AddCode(&e.bc);
  1111. }
  1112. void asCCompiler::MoveArgsToStack(int funcID, asCByteCode *bc, asCArray<asSExprContext *> &args, bool addOneToOffset)
  1113. {
  1114. asCScriptFunction *descr = builder->GetFunctionDescription(funcID);
  1115. int offset = 0;
  1116. if( addOneToOffset )
  1117. offset += AS_PTR_SIZE;
  1118. // Move the objects that are sent by value to the stack just before the call
  1119. for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ )
  1120. {
  1121. if( descr->parameterTypes[n].IsReference() )
  1122. {
  1123. if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() )
  1124. {
  1125. if( descr->inOutFlags[n] != asTM_INOUTREF )
  1126. {
  1127. if( (args[n]->type.isVariable || args[n]->type.isTemporary) &&
  1128. !IsVariableOnHeap(args[n]->type.stackOffset) )
  1129. // TODO: optimize: Actually the reference can be pushed on the stack directly
  1130. // as the value allocated on the stack is guaranteed to be safe
  1131. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1132. else
  1133. bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset);
  1134. }
  1135. if( args[n]->type.dataType.IsObjectHandle() )
  1136. bc->InstrWORD(asBC_ChkNullS, (asWORD)offset);
  1137. }
  1138. else if( descr->inOutFlags[n] != asTM_INOUTREF )
  1139. {
  1140. if( descr->parameterTypes[n].GetTokenType() == ttQuestion &&
  1141. args[n]->type.dataType.IsObject() && !args[n]->type.dataType.IsObjectHandle() )
  1142. {
  1143. // Send the object as a reference to the object,
  1144. // and not to the variable holding the object
  1145. bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset);
  1146. }
  1147. else
  1148. bc->InstrWORD(asBC_GETREF, (asWORD)offset);
  1149. }
  1150. }
  1151. else if( descr->parameterTypes[n].IsObject() )
  1152. {
  1153. // TODO: value on stack: What can we do to avoid this unnecessary allocation?
  1154. // The object must be allocated on the heap, because this memory will be deleted in as_callfunc_xxx
  1155. asASSERT(IsVariableOnHeap(args[n]->type.stackOffset));
  1156. bc->InstrWORD(asBC_GETOBJ, (asWORD)offset);
  1157. // The temporary variable must not be freed as it will no longer hold an object
  1158. DeallocateVariable(args[n]->type.stackOffset);
  1159. args[n]->type.isTemporary = false;
  1160. }
  1161. offset += descr->parameterTypes[n].GetSizeOnStackDWords();
  1162. }
  1163. }
  1164. int asCCompiler::CompileArgumentList(asCScriptNode *node, asCArray<asSExprContext*> &args)
  1165. {
  1166. asASSERT(node->nodeType == snArgList);
  1167. // Count arguments
  1168. asCScriptNode *arg = node->firstChild;
  1169. int argCount = 0;
  1170. while( arg )
  1171. {
  1172. argCount++;
  1173. arg = arg->next;
  1174. }
  1175. // Prepare the arrays
  1176. args.SetLength(argCount);
  1177. int n;
  1178. for( n = 0; n < argCount; n++ )
  1179. args[n] = 0;
  1180. n = argCount-1;
  1181. // Compile the arguments in reverse order (as they will be pushed on the stack)
  1182. bool anyErrors = false;
  1183. arg = node->lastChild;
  1184. while( arg )
  1185. {
  1186. asSExprContext expr(engine);
  1187. int r = CompileAssignment(arg, &expr);
  1188. if( r < 0 ) anyErrors = true;
  1189. args[n] = asNEW(asSExprContext)(engine);
  1190. MergeExprBytecodeAndType(args[n], &expr);
  1191. n--;
  1192. arg = arg->prev;
  1193. }
  1194. return anyErrors ? -1 : 0;
  1195. }
  1196. int asCCompiler::CompileDefaultArgs(asCScriptNode *node, asCArray<asSExprContext*> &args, asCScriptFunction *func)
  1197. {
  1198. bool anyErrors = false;
  1199. asCArray<int> varsUsed;
  1200. int explicitArgs = (int)args.GetLength();
  1201. for( int p = 0; p < explicitArgs; p++ )
  1202. args[p]->bc.GetVarsUsed(varsUsed);
  1203. // Compile the arguments in reverse order (as they will be pushed on the stack)
  1204. args.SetLength(func->parameterTypes.GetLength());
  1205. for( asUINT c = explicitArgs; c < args.GetLength(); c++ )
  1206. args[c] = 0;
  1207. for( int n = (int)func->parameterTypes.GetLength() - 1; n >= explicitArgs; n-- )
  1208. {
  1209. if( func->defaultArgs[n] == 0 ) { anyErrors = true; continue; }
  1210. // Parse the default arg string
  1211. asCParser parser(builder);
  1212. asCScriptCode code;
  1213. code.SetCode("default arg", func->defaultArgs[n]->AddressOf(), false);
  1214. int r = parser.ParseExpression(&code);
  1215. if( r < 0 ) { anyErrors = true; continue; }
  1216. asCScriptNode *arg = parser.GetScriptNode();
  1217. // Temporarily set the script code to the default arg expression
  1218. asCScriptCode *origScript = script;
  1219. script = &code;
  1220. // Don't allow the expression to access local variables
  1221. // TODO: namespace: The default arg should see the symbols declared in the same scope as the function
  1222. isCompilingDefaultArg = true;
  1223. asSExprContext expr(engine);
  1224. r = CompileExpression(arg, &expr);
  1225. isCompilingDefaultArg = false;
  1226. script = origScript;
  1227. if( r < 0 )
  1228. {
  1229. asCString msg;
  1230. msg.Format(TXT_FAILED_TO_COMPILE_DEF_ARG_d_IN_FUNC_s, n, func->GetDeclaration());
  1231. Error(msg.AddressOf(), node);
  1232. anyErrors = true;
  1233. continue;
  1234. }
  1235. args[n] = asNEW(asSExprContext)(engine);
  1236. MergeExprBytecodeAndType(args[n], &expr);
  1237. // Make sure the default arg expression doesn't end up
  1238. // with a variable that is used in a previous expression
  1239. if( args[n]->type.isVariable )
  1240. {
  1241. int offset = args[n]->type.stackOffset;
  1242. if( varsUsed.Exists(offset) )
  1243. {
  1244. // Release the current temporary variable
  1245. ReleaseTemporaryVariable(args[n]->type, 0);
  1246. asCDataType dt = args[n]->type.dataType;
  1247. dt.MakeReference(false);
  1248. int newOffset = AllocateVariableNotIn(dt, true, &varsUsed, IsVariableOnHeap(offset));
  1249. asASSERT( IsVariableOnHeap(offset) == IsVariableOnHeap(newOffset) );
  1250. args[n]->bc.ExchangeVar(offset, newOffset);
  1251. args[n]->type.stackOffset = (short)newOffset;
  1252. args[n]->type.isTemporary = true;
  1253. args[n]->type.isVariable = true;
  1254. }
  1255. }
  1256. }
  1257. return anyErrors ? -1 : 0;
  1258. }
  1259. void asCCompiler::MatchFunctions(asCArray<int> &funcs, asCArray<asSExprContext*> &args, asCScriptNode *node, const char *name, asCObjectType *objectType, bool isConstMethod, bool silent, bool allowObjectConstruct, const asCString &scope)
  1260. {
  1261. asCArray<int> origFuncs = funcs; // Keep the original list for error message
  1262. asUINT n;
  1263. if( funcs.GetLength() > 0 )
  1264. {
  1265. // Check the number of parameters in the found functions
  1266. for( n = 0; n < funcs.GetLength(); ++n )
  1267. {
  1268. asCScriptFunction *desc = builder->GetFunctionDescription(funcs[n]);
  1269. if( desc->parameterTypes.GetLength() != args.GetLength() )
  1270. {
  1271. // Count the number of default args
  1272. asUINT defaultArgs = 0;
  1273. for( asUINT d = 0; d < desc->defaultArgs.GetLength(); d++ )
  1274. if( desc->defaultArgs[d] )
  1275. defaultArgs++;
  1276. if( args.GetLength() < desc->parameterTypes.GetLength() - defaultArgs )
  1277. {
  1278. // remove it from the list
  1279. if( n == funcs.GetLength()-1 )
  1280. funcs.PopLast();
  1281. else
  1282. funcs[n] = funcs.PopLast();
  1283. n--;
  1284. }
  1285. }
  1286. }
  1287. // Match functions with the parameters, and discard those that do not match
  1288. asCArray<int> matchingFuncs = funcs;
  1289. for( n = 0; n < args.GetLength(); ++n )
  1290. {
  1291. asCArray<int> tempFuncs;
  1292. MatchArgument(funcs, tempFuncs, &args[n]->type, n, allowObjectConstruct);
  1293. // Intersect the found functions with the list of matching functions
  1294. for( asUINT f = 0; f < matchingFuncs.GetLength(); f++ )
  1295. {
  1296. asUINT c;
  1297. for( c = 0; c < tempFuncs.GetLength(); c++ )
  1298. {
  1299. if( matchingFuncs[f] == tempFuncs[c] )
  1300. break;
  1301. }
  1302. // Was the function a match?
  1303. if( c == tempFuncs.GetLength() )
  1304. {
  1305. // No, remove it from the list
  1306. if( f == matchingFuncs.GetLength()-1 )
  1307. matchingFuncs.PopLast();
  1308. else
  1309. matchingFuncs[f] = matchingFuncs.PopLast();
  1310. f--;
  1311. }
  1312. }
  1313. }
  1314. funcs = matchingFuncs;
  1315. }
  1316. if( !isConstMethod )
  1317. FilterConst(funcs);
  1318. if( funcs.GetLength() != 1 && !silent )
  1319. {
  1320. // Build a readable string of the function with parameter types
  1321. asCString str;
  1322. if( scope != "" )
  1323. {
  1324. if( scope == "::" )
  1325. str = scope;
  1326. else
  1327. str = scope + "::";
  1328. }
  1329. str += name;
  1330. str += "(";
  1331. if( args.GetLength() )
  1332. str += args[0]->type.dataType.Format();
  1333. for( n = 1; n < args.GetLength(); n++ )
  1334. str += ", " + args[n]->type.dataType.Format();
  1335. str += ")";
  1336. if( isConstMethod )
  1337. str += " const";
  1338. if( objectType && scope == "" )
  1339. str = objectType->name + "::" + str;
  1340. if( funcs.GetLength() == 0 )
  1341. {
  1342. str.Format(TXT_NO_MATCHING_SIGNATURES_TO_s, str.AddressOf());
  1343. Error(str.AddressOf(), node);
  1344. // Print the list of candidates
  1345. if( origFuncs.GetLength() > 0 )
  1346. {
  1347. int r = 0, c = 0;
  1348. asASSERT( node );
  1349. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  1350. builder->WriteInfo(script->name.AddressOf(), TXT_CANDIDATES_ARE, r, c, false);
  1351. PrintMatchingFuncs(origFuncs, node);
  1352. }
  1353. }
  1354. else
  1355. {
  1356. str.Format(TXT_MULTIPLE_MATCHING_SIGNATURES_TO_s, str.AddressOf());
  1357. Error(str.AddressOf(), node);
  1358. PrintMatchingFuncs(funcs, node);
  1359. }
  1360. }
  1361. }
  1362. void asCCompiler::CompileDeclaration(asCScriptNode *decl, asCByteCode *bc)
  1363. {
  1364. // Get the data type
  1365. asCDataType type = builder->CreateDataTypeFromNode(decl->firstChild, script);
  1366. // Declare all variables in this declaration
  1367. asCScriptNode *node = decl->firstChild->next;
  1368. while( node )
  1369. {
  1370. // Is the type allowed?
  1371. if( !type.CanBeInstanciated() )
  1372. {
  1373. asCString str;
  1374. // TODO: Change to "'type' cannot be declared as variable"
  1375. str.Format(TXT_DATA_TYPE_CANT_BE_s, type.Format().AddressOf());
  1376. Error(str.AddressOf(), node);
  1377. // Use int instead to avoid further problems
  1378. type = asCDataType::CreatePrimitive(ttInt, false);
  1379. }
  1380. // Get the name of the identifier
  1381. asCString name(&script->code[node->tokenPos], node->tokenLength);
  1382. // Verify that the name isn't used by a dynamic data type
  1383. if( engine->GetObjectType(name.AddressOf()) != 0 )
  1384. {
  1385. asCString str;
  1386. str.Format(TXT_ILLEGAL_VARIABLE_NAME_s, name.AddressOf());
  1387. Error(str.AddressOf(), node);
  1388. }
  1389. int offset = AllocateVariable(type, false);
  1390. if( variables->DeclareVariable(name.AddressOf(), type, offset, IsVariableOnHeap(offset)) < 0 )
  1391. {
  1392. asCString str;
  1393. str.Format(TXT_s_ALREADY_DECLARED, name.AddressOf());
  1394. Error(str.AddressOf(), node);
  1395. // Don't continue after this error, as it will just
  1396. // lead to more errors that are likely false
  1397. return;
  1398. }
  1399. outFunc->AddVariable(name, type, offset);
  1400. // Keep the node for the variable decl
  1401. asCScriptNode *varNode = node;
  1402. node = node->next;
  1403. if( node && node->nodeType == snArgList )
  1404. {
  1405. // Make sure that it is a registered type, and that is isn't a pointer
  1406. if( type.GetObjectType() == 0 || type.IsObjectHandle() )
  1407. {
  1408. Error(TXT_MUST_BE_OBJECT, node);
  1409. }
  1410. else
  1411. {
  1412. // Compile the arguments
  1413. asCArray<asSExprContext *> args;
  1414. if( CompileArgumentList(node, args) >= 0 )
  1415. {
  1416. // Find all constructors
  1417. asCArray<int> funcs;
  1418. asSTypeBehaviour *beh = type.GetBehaviour();
  1419. if( beh )
  1420. {
  1421. if( type.GetObjectType()->flags & asOBJ_REF )
  1422. funcs = beh->factories;
  1423. else
  1424. funcs = beh->constructors;
  1425. }
  1426. asCString str = type.Format();
  1427. MatchFunctions(funcs, args, node, str.AddressOf());
  1428. if( funcs.GetLength() == 1 )
  1429. {
  1430. int r = asSUCCESS;
  1431. // Add the default values for arguments not explicitly supplied
  1432. asCScriptFunction *func = (funcs[0] & 0xFFFF0000) == 0 ? engine->scriptFunctions[funcs[0]] : 0;
  1433. if( func && args.GetLength() < (asUINT)func->GetParamCount() )
  1434. r = CompileDefaultArgs(node, args, func);
  1435. if( r == asSUCCESS )
  1436. {
  1437. sVariable *v = variables->GetVariable(name.AddressOf());
  1438. asSExprContext ctx(engine);
  1439. if( v->type.GetObjectType() && (v->type.GetObjectType()->flags & asOBJ_REF) )
  1440. {
  1441. MakeFunctionCall(&ctx, funcs[0], 0, args, node, true, v->stackOffset);
  1442. // Pop the reference left by the function call
  1443. ctx.bc.Pop(AS_PTR_SIZE);
  1444. }
  1445. else
  1446. {
  1447. // When the object is allocated on the heap, the address where the
  1448. // reference will be stored must be pushed on the stack before the
  1449. // arguments. This reference on the stack is safe, even if the script
  1450. // is suspended during the evaluation of the arguments.
  1451. if( v->onHeap )
  1452. ctx.bc.InstrSHORT(asBC_PSF, (short)v->stackOffset);
  1453. PrepareFunctionCall(funcs[0], &ctx.bc, args);
  1454. MoveArgsToStack(funcs[0], &ctx.bc, args, false);
  1455. // When the object is allocated on the stack, the address to the
  1456. // object is pushed on the stack after the arguments as the object pointer
  1457. if( !v->onHeap )
  1458. ctx.bc.InstrSHORT(asBC_PSF, (short)v->stackOffset);
  1459. PerformFunctionCall(funcs[0], &ctx, v->onHeap, &args, type.GetObjectType());
  1460. // TODO: value on stack: This probably has to be done in PerformFunctionCall
  1461. // Mark the object as initialized
  1462. ctx.bc.ObjInfo(v->stackOffset, asOBJ_INIT);
  1463. }
  1464. bc->AddCode(&ctx.bc);
  1465. }
  1466. }
  1467. }
  1468. // Cleanup
  1469. for( asUINT n = 0; n < args.GetLength(); n++ )
  1470. if( args[n] )
  1471. {
  1472. asDELETE(args[n],asSExprContext);
  1473. }
  1474. }
  1475. node = node->next;
  1476. }
  1477. else if( node && node->nodeType == snInitList )
  1478. {
  1479. sVariable *v = variables->GetVariable(name.AddressOf());
  1480. asCTypeInfo ti;
  1481. ti.Set(type);
  1482. ti.isVariable = true;
  1483. ti.isTemporary = false;
  1484. ti.stackOffset = (short)v->stackOffset;
  1485. CompileInitList(&ti, node, bc);
  1486. node = node->next;
  1487. }
  1488. else if( node && node->nodeType == snAssignment )
  1489. {
  1490. asSExprContext ctx(engine);
  1491. // TODO: copy: Here we should look for the best matching constructor, instead of
  1492. // just the copy constructor. Only if no appropriate constructor is
  1493. // available should the assignment operator be used.
  1494. // Call the default constructor here
  1495. CallDefaultConstructor(type, offset, IsVariableOnHeap(offset), &ctx.bc, varNode);
  1496. // Compile the expression
  1497. asSExprContext expr(engine);
  1498. int r = CompileAssignment(node, &expr);
  1499. if( r >= 0 )
  1500. {
  1501. if( type.IsPrimitive() )
  1502. {
  1503. if( type.IsReadOnly() && expr.type.isConstant )
  1504. {
  1505. ImplicitConversion(&expr, type, node, asIC_IMPLICIT_CONV);
  1506. sVariable *v = variables->GetVariable(name.AddressOf());
  1507. v->isPureConstant = true;
  1508. v->constantValue = expr.type.qwordValue;
  1509. }
  1510. asSExprContext lctx(engine);
  1511. lctx.type.SetVariable(type, offset, false);
  1512. lctx.type.dataType.MakeReadOnly(false);
  1513. DoAssignment(&ctx, &lctx, &expr, node, node, ttAssignment, node);
  1514. ProcessDeferredParams(&ctx);
  1515. }
  1516. else
  1517. {
  1518. // TODO: We can use a copy constructor here
  1519. sVariable *v = variables->GetVariable(name.AddressOf());
  1520. asSExprContext lexpr(engine);
  1521. lexpr.type.Set(type);
  1522. lexpr.type.dataType.MakeReference(v->onHeap);
  1523. // Allow initialization of constant variables
  1524. lexpr.type.dataType.MakeReadOnly(false);
  1525. if( type.IsObjectHandle() )
  1526. lexpr.type.isExplicitHandle = true;
  1527. lexpr.bc.InstrSHORT(asBC_PSF, (short)v->stackOffset);
  1528. lexpr.type.stackOffset = (short)v->stackOffset;
  1529. lexpr.type.isVariable = true;
  1530. // If left expression resolves into a registered type
  1531. // check if the assignment operator is overloaded, and check
  1532. // the type of the right hand expression. If none is found
  1533. // the default action is a direct copy if it is the same type
  1534. // and a simple assignment.
  1535. bool assigned = false;
  1536. if( lexpr.type.dataType.IsObject() && !lexpr.type.isExplicitHandle )
  1537. {
  1538. assigned = CompileOverloadedDualOperator(node, &lexpr, &expr, &ctx);
  1539. if( assigned )
  1540. {
  1541. // Pop the resulting value
  1542. ctx.bc.Pop(ctx.type.dataType.GetSizeOnStackDWords());
  1543. // Release the argument
  1544. ProcessDeferredParams(&ctx);
  1545. // Release temporary variable that may be allocated by the overloaded operator
  1546. ReleaseTemporaryVariable(ctx.type, &ctx.bc);
  1547. }
  1548. }
  1549. if( !assigned )
  1550. {
  1551. PrepareForAssignment(&lexpr.type.dataType, &expr, node);
  1552. // If the expression is constant and the variable also is constant
  1553. // then mark the variable as pure constant. This will allow the compiler
  1554. // to optimize expressions with this variable.
  1555. if( v->type.IsReadOnly() && expr.type.isConstant )
  1556. {
  1557. v->isPureConstant = true;
  1558. v->constantValue = expr.type.qwordValue;
  1559. }
  1560. // Add expression code to bytecode
  1561. MergeExprBytecode(&ctx, &expr);
  1562. // Add byte code for storing value of expression in variable
  1563. ctx.bc.AddCode(&lexpr.bc);
  1564. lexpr.type.stackOffset = (short)v->stackOffset;
  1565. PerformAssignment(&lexpr.type, &expr.type, &ctx.bc, node->prev);
  1566. // Release temporary variables used by expression
  1567. ReleaseTemporaryVariable(expr.type, &ctx.bc);
  1568. ctx.bc.Pop(expr.type.dataType.GetSizeOnStackDWords());
  1569. ProcessDeferredParams(&ctx);
  1570. }
  1571. }
  1572. }
  1573. node = node->next;
  1574. bc->AddCode(&ctx.bc);
  1575. // TODO: Can't this leave deferred output params without being compiled?
  1576. }
  1577. else
  1578. {
  1579. // Call the default constructor here if no explicit initialization is done
  1580. CallDefaultConstructor(type, offset, IsVariableOnHeap(offset), bc, varNode);
  1581. }
  1582. }
  1583. }
  1584. void asCCompiler::CompileInitList(asCTypeInfo *var, asCScriptNode *node, asCByteCode *bc)
  1585. {
  1586. // Check if the type supports initialization lists
  1587. if( var->dataType.GetObjectType() == 0 ||
  1588. var->dataType.GetBehaviour()->listFactory == 0 ||
  1589. var->dataType.IsObjectHandle() )
  1590. {
  1591. asCString str;
  1592. str.Format(TXT_INIT_LIST_CANNOT_BE_USED_WITH_s, var->dataType.Format().AddressOf());
  1593. Error(str.AddressOf(), node);
  1594. return;
  1595. }
  1596. // Count the number of elements and initialize the array with the correct size
  1597. int countElements = 0;
  1598. asCScriptNode *el = node->firstChild;
  1599. while( el )
  1600. {
  1601. countElements++;
  1602. el = el->next;
  1603. }
  1604. // Construct the array with the size elements
  1605. // TODO: value on stack: This needs to support value types on the stack as well
  1606. // Find the list factory
  1607. // TODO: initlist: Add support for value types as well
  1608. int funcId = var->dataType.GetBehaviour()->listFactory;
  1609. asCArray<asSExprContext *> args;
  1610. asSExprContext arg1(engine);
  1611. arg1.bc.InstrDWORD(asBC_PshC4, countElements);
  1612. arg1.type.Set(asCDataType::CreatePrimitive(ttUInt, false));
  1613. args.PushLast(&arg1);
  1614. asSExprContext ctx(engine);
  1615. PrepareFunctionCall(funcId, &ctx.bc, args);
  1616. MoveArgsToStack(funcId, &ctx.bc, args, false);
  1617. if( var->isVariable )
  1618. {
  1619. // Call factory and store the handle in the given variable
  1620. PerformFunctionCall(funcId, &ctx, false, &args, 0, true, var->stackOffset);
  1621. ctx.bc.Pop(AS_PTR_SIZE);
  1622. }
  1623. else
  1624. {
  1625. PerformFunctionCall(funcId, &ctx, false, &args);
  1626. // Store the returned handle in the global variable
  1627. ctx.bc.Instr(asBC_RDSPTR);
  1628. ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[var->stackOffset]->GetAddressOfValue());
  1629. ctx.bc.InstrPTR(asBC_REFCPY, var->dataType.GetObjectType());
  1630. ctx.bc.Pop(AS_PTR_SIZE);
  1631. ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc);
  1632. }
  1633. bc->AddCode(&ctx.bc);
  1634. // TODO: initlist: Should we have a special indexing operator for this? How can we support
  1635. // initialization lists with different types for different elements? Maybe
  1636. // by using the variable arguments the initialization can be done with one
  1637. // call, passing all the elements as arguments. The registered function can
  1638. // then traverse them however it wants.
  1639. // Find the indexing operator that is not read-only that will be used for all elements
  1640. asCDataType retType;
  1641. retType = var->dataType.GetSubType();
  1642. retType.MakeReference(true);
  1643. retType.MakeReadOnly(false);
  1644. funcId = 0;
  1645. for( asUINT n = 0; n < var->dataType.GetObjectType()->methods.GetLength(); n++ )
  1646. {
  1647. asCScriptFunction *desc = builder->GetFunctionDescription(var->dataType.GetObjectType()->methods[n]);
  1648. if( !desc->isReadOnly &&
  1649. desc->parameterTypes.GetLength() == 1 &&
  1650. (desc->parameterTypes[0] == asCDataType::CreatePrimitive(ttUInt, false) ||
  1651. desc->parameterTypes[0] == asCDataType::CreatePrimitive(ttInt, false)) &&
  1652. desc->returnType == retType &&
  1653. desc->name == "opIndex" )
  1654. {
  1655. funcId = var->dataType.GetObjectType()->methods[n];
  1656. break;
  1657. }
  1658. }
  1659. if( funcId == 0 )
  1660. {
  1661. Error(TXT_NO_APPROPRIATE_INDEX_OPERATOR, node);
  1662. return;
  1663. }
  1664. asUINT index = 0;
  1665. el = node->firstChild;
  1666. while( el )
  1667. {
  1668. if( el->nodeType == snAssignment || el->nodeType == snInitList )
  1669. {
  1670. asSExprContext lctx(engine);
  1671. asSExprContext rctx(engine);
  1672. if( el->nodeType == snAssignment )
  1673. {
  1674. // Compile the assignment expression
  1675. CompileAssignment(el, &rctx);
  1676. }
  1677. else if( el->nodeType == snInitList )
  1678. {
  1679. int offset = AllocateVariable(var->dataType.GetSubType(), true);
  1680. rctx.type.Set(var->dataType.GetSubType());
  1681. rctx.type.isVariable = true;
  1682. rctx.type.isTemporary = true;
  1683. rctx.type.stackOffset = (short)offset;
  1684. CompileInitList(&rctx.type, el, &rctx.bc);
  1685. // Put the object on the stack
  1686. rctx.bc.InstrSHORT(asBC_PSF, rctx.type.stackOffset);
  1687. // It is a reference that we place on the stack
  1688. rctx.type.dataType.MakeReference(true);
  1689. }
  1690. // Compile the lvalue
  1691. lctx.bc.InstrDWORD(asBC_PshC4, index);
  1692. if( var->isVariable )
  1693. lctx.bc.InstrSHORT(asBC_PSF, var->stackOffset);
  1694. else
  1695. lctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[var->stackOffset]->GetAddressOfValue());
  1696. lctx.bc.Instr(asBC_RDSPTR);
  1697. lctx.bc.Call(asBC_CALLSYS, funcId, 1+AS_PTR_SIZE);
  1698. if( !var->dataType.GetSubType().IsPrimitive() )
  1699. lctx.bc.Instr(asBC_PshRPtr);
  1700. lctx.type.Set(var->dataType.GetSubType());
  1701. if( !lctx.type.dataType.IsObject() || lctx.type.dataType.IsObjectHandle() )
  1702. lctx.type.dataType.MakeReference(true);
  1703. // If the element type is handles, then we're expected to do handle assignments
  1704. if( lctx.type.dataType.IsObjectHandle() )
  1705. lctx.type.isExplicitHandle = true;
  1706. asSExprContext ctx(engine);
  1707. DoAssignment(&ctx, &lctx, &rctx, el, el, ttAssignment, el);
  1708. if( !lctx.type.dataType.IsPrimitive() )
  1709. ctx.bc.Pop(AS_PTR_SIZE);
  1710. // Release temporary variables used by expression
  1711. ReleaseTemporaryVariable(ctx.type, &ctx.bc);
  1712. ProcessDeferredParams(&ctx);
  1713. bc->AddCode(&ctx.bc);
  1714. }
  1715. el = el->next;
  1716. index++;
  1717. }
  1718. }
  1719. void asCCompiler::CompileStatement(asCScriptNode *statement, bool *hasReturn, asCByteCode *bc)
  1720. {
  1721. *hasReturn = false;
  1722. if( statement->nodeType == snStatementBlock )
  1723. CompileStatementBlock(statement, true, hasReturn, bc);
  1724. else if( statement->nodeType == snIf )
  1725. CompileIfStatement(statement, hasReturn, bc);
  1726. else if( statement->nodeType == snFor )
  1727. CompileForStatement(statement, bc);
  1728. else if( statement->nodeType == snWhile )
  1729. CompileWhileStatement(statement, bc);
  1730. else if( statement->nodeType == snDoWhile )
  1731. CompileDoWhileStatement(statement, bc);
  1732. else if( statement->nodeType == snExpressionStatement )
  1733. CompileExpressionStatement(statement, bc);
  1734. else if( statement->nodeType == snBreak )
  1735. CompileBreakStatement(statement, bc);
  1736. else if( statement->nodeType == snContinue )
  1737. CompileContinueStatement(statement, bc);
  1738. else if( statement->nodeType == snSwitch )
  1739. CompileSwitchStatement(statement, hasReturn, bc);
  1740. else if( statement->nodeType == snReturn )
  1741. {
  1742. CompileReturnStatement(statement, bc);
  1743. *hasReturn = true;
  1744. }
  1745. }
  1746. void asCCompiler::CompileSwitchStatement(asCScriptNode *snode, bool *, asCByteCode *bc)
  1747. {
  1748. // TODO: inheritance: Must guarantee that all options in the switch case call a constructor, or that none call it.
  1749. // Reserve label for break statements
  1750. int breakLabel = nextLabel++;
  1751. breakLabels.PushLast(breakLabel);
  1752. // Add a variable scope that will be used by CompileBreak
  1753. // to know where to stop deallocating variables
  1754. AddVariableScope(true, false);
  1755. //---------------------------
  1756. // Compile the switch expression
  1757. //-------------------------------
  1758. // Compile the switch expression
  1759. asSExprContext expr(engine);
  1760. CompileAssignment(snode->firstChild, &expr);
  1761. // Verify that the expression is a primitive type
  1762. if( !expr.type.dataType.IsIntegerType() && !expr.type.dataType.IsUnsignedType() && !expr.type.dataType.IsEnumType() )
  1763. {
  1764. Error(TXT_SWITCH_MUST_BE_INTEGRAL, snode->firstChild);
  1765. return;
  1766. }
  1767. ProcessPropertyGetAccessor(&expr, snode);
  1768. // TODO: Need to support 64bit integers
  1769. // Convert the expression to a 32bit variable
  1770. asCDataType to;
  1771. if( expr.type.dataType.IsIntegerType() || expr.type.dataType.IsEnumType() )
  1772. to.SetTokenType(ttInt);
  1773. else if( expr.type.dataType.IsUnsignedType() )
  1774. to.SetTokenType(ttUInt);
  1775. // Make sure the value is in a variable
  1776. if( expr.type.dataType.IsReference() )
  1777. ConvertToVariable(&expr);
  1778. ImplicitConversion(&expr, to, snode->firstChild, asIC_IMPLICIT_CONV, true);
  1779. ConvertToVariable(&expr);
  1780. int offset = expr.type.stackOffset;
  1781. ProcessDeferredParams(&expr);
  1782. //-------------------------------
  1783. // Determine case values and labels
  1784. //--------------------------------
  1785. // Remember the first label so that we can later pass the
  1786. // correct label to each CompileCase()
  1787. int firstCaseLabel = nextLabel;
  1788. int defaultLabel = 0;
  1789. asCArray<int> caseValues;
  1790. asCArray<int> caseLabels;
  1791. // Compile all case comparisons and make them jump to the right label
  1792. asCScriptNode *cnode = snode->firstChild->next;
  1793. while( cnode )
  1794. {
  1795. // Each case should have a constant expression
  1796. if( cnode->firstChild && cnode->firstChild->nodeType == snExpression )
  1797. {
  1798. // Compile expression
  1799. asSExprContext c(engine);
  1800. CompileExpression(cnode->firstChild, &c);
  1801. // Verify that the result is a constant
  1802. if( !c.type.isConstant )
  1803. Error(TXT_SWITCH_CASE_MUST_BE_CONSTANT, cnode->firstChild);
  1804. // Verify that the result is an integral number
  1805. if( !c.type.dataType.IsIntegerType() && !c.type.dataType.IsUnsignedType() && !c.type.dataType.IsEnumType() )
  1806. Error(TXT_SWITCH_MUST_BE_INTEGRAL, cnode->firstChild);
  1807. ImplicitConversion(&c, to, cnode->firstChild, asIC_IMPLICIT_CONV, true);
  1808. // Has this case been declared already?
  1809. if( caseValues.IndexOf(c.type.intValue) >= 0 )
  1810. {
  1811. Error(TXT_DUPLICATE_SWITCH_CASE, cnode->firstChild);
  1812. }
  1813. // TODO: Optimize: We can insert the numbers sorted already
  1814. // Store constant for later use
  1815. caseValues.PushLast(c.type.intValue);
  1816. // Reserve label for this case
  1817. caseLabels.PushLast(nextLabel++);
  1818. }
  1819. else
  1820. {
  1821. // Is default the last case?
  1822. if( cnode->next )
  1823. {
  1824. Error(TXT_DEFAULT_MUST_BE_LAST, cnode);
  1825. break;
  1826. }
  1827. // Reserve label for this case
  1828. defaultLabel = nextLabel++;
  1829. }
  1830. cnode = cnode->next;
  1831. }
  1832. // check for empty switch
  1833. if (caseValues.GetLength() == 0)
  1834. {
  1835. Error(TXT_EMPTY_SWITCH, snode);
  1836. return;
  1837. }
  1838. if( defaultLabel == 0 )
  1839. defaultLabel = breakLabel;
  1840. //---------------------------------
  1841. // Output the optimized case comparisons
  1842. // with jumps to the case code
  1843. //------------------------------------
  1844. // Sort the case values by increasing value. Do the sort together with the labels
  1845. // A simple bubble sort is sufficient since we don't expect a huge number of values
  1846. for( asUINT fwd = 1; fwd < caseValues.GetLength(); fwd++ )
  1847. {
  1848. for( int bck = fwd - 1; bck >= 0; bck-- )
  1849. {
  1850. int bckp = bck + 1;
  1851. if( caseValues[bck] > caseValues[bckp] )
  1852. {
  1853. // Swap the values in both arrays
  1854. int swap = caseValues[bckp];
  1855. caseValues[bckp] = caseValues[bck];
  1856. caseValues[bck] = swap;
  1857. swap = caseLabels[bckp];
  1858. caseLabels[bckp] = caseLabels[bck];
  1859. caseLabels[bck] = swap;
  1860. }
  1861. else
  1862. break;
  1863. }
  1864. }
  1865. // Find ranges of consecutive numbers
  1866. asCArray<int> ranges;
  1867. ranges.PushLast(0);
  1868. asUINT n;
  1869. for( n = 1; n < caseValues.GetLength(); ++n )
  1870. {
  1871. // We can join numbers that are less than 5 numbers
  1872. // apart since the output code will still be smaller
  1873. if( caseValues[n] > caseValues[n-1] + 5 )
  1874. ranges.PushLast(n);
  1875. }
  1876. // If the value is larger than the largest case value, jump to default
  1877. int tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  1878. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[caseValues.GetLength()-1]);
  1879. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  1880. expr.bc.InstrDWORD(asBC_JP, defaultLabel);
  1881. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  1882. // TODO: optimize: We could possibly optimize this even more by doing a
  1883. // binary search instead of a linear search through the ranges
  1884. // For each range
  1885. int range;
  1886. for( range = 0; range < (int)ranges.GetLength(); range++ )
  1887. {
  1888. // Find the largest value in this range
  1889. int maxRange = caseValues[ranges[range]];
  1890. int index = ranges[range];
  1891. for( ; (index < (int)caseValues.GetLength()) && (caseValues[index] <= maxRange + 5); index++ )
  1892. maxRange = caseValues[index];
  1893. // If there are only 2 numbers then it is better to compare them directly
  1894. if( index - ranges[range] > 2 )
  1895. {
  1896. // If the value is smaller than the smallest case value in the range, jump to default
  1897. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  1898. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[ranges[range]]);
  1899. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  1900. expr.bc.InstrDWORD(asBC_JS, defaultLabel);
  1901. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  1902. int nextRangeLabel = nextLabel++;
  1903. // If this is the last range we don't have to make this test
  1904. if( range < (int)ranges.GetLength() - 1 )
  1905. {
  1906. // If the value is larger than the largest case value in the range, jump to the next range
  1907. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  1908. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, maxRange);
  1909. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  1910. expr.bc.InstrDWORD(asBC_JP, nextRangeLabel);
  1911. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  1912. }
  1913. // Jump forward according to the value
  1914. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  1915. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[ranges[range]]);
  1916. expr.bc.InstrW_W_W(asBC_SUBi, tmpOffset, offset, tmpOffset);
  1917. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  1918. expr.bc.JmpP(tmpOffset, maxRange - caseValues[ranges[range]]);
  1919. // Add the list of jumps to the correct labels (any holes, jump to default)
  1920. index = ranges[range];
  1921. for( int n = caseValues[index]; n <= maxRange; n++ )
  1922. {
  1923. if( caseValues[index] == n )
  1924. expr.bc.InstrINT(asBC_JMP, caseLabels[index++]);
  1925. else
  1926. expr.bc.InstrINT(asBC_JMP, defaultLabel);
  1927. }
  1928. expr.bc.Label((short)nextRangeLabel);
  1929. }
  1930. else
  1931. {
  1932. // Simply make a comparison with each value
  1933. int n;
  1934. for( n = ranges[range]; n < index; ++n )
  1935. {
  1936. tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true);
  1937. expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[n]);
  1938. expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset);
  1939. expr.bc.InstrDWORD(asBC_JZ, caseLabels[n]);
  1940. ReleaseTemporaryVariable(tmpOffset, &expr.bc);
  1941. }
  1942. }
  1943. }
  1944. // Catch any value that falls trough
  1945. expr.bc.InstrINT(asBC_JMP, defaultLabel);
  1946. // Release the temporary variable previously stored
  1947. ReleaseTemporaryVariable(expr.type, &expr.bc);
  1948. //----------------------------------
  1949. // Output case implementations
  1950. //----------------------------------
  1951. // Compile case implementations, each one with the label before it
  1952. cnode = snode->firstChild->next;
  1953. while( cnode )
  1954. {
  1955. // Each case should have a constant expression
  1956. if( cnode->firstChild && cnode->firstChild->nodeType == snExpression )
  1957. {
  1958. expr.bc.Label((short)firstCaseLabel++);
  1959. CompileCase(cnode->firstChild->next, &expr.bc);
  1960. }
  1961. else
  1962. {
  1963. expr.bc.Label((short)defaultLabel);
  1964. // Is default the last case?
  1965. if( cnode->next )
  1966. {
  1967. // We've already reported this error
  1968. break;
  1969. }
  1970. CompileCase(cnode->firstChild, &expr.bc);
  1971. }
  1972. cnode = cnode->next;
  1973. }
  1974. //--------------------------------
  1975. bc->AddCode(&expr.bc);
  1976. // Add break label
  1977. bc->Label((short)breakLabel);
  1978. breakLabels.PopLast();
  1979. RemoveVariableScope();
  1980. }
  1981. void asCCompiler::CompileCase(asCScriptNode *node, asCByteCode *bc)
  1982. {
  1983. bool isFinished = false;
  1984. bool hasReturn = false;
  1985. while( node )
  1986. {
  1987. if( hasReturn || isFinished )
  1988. {
  1989. Warning(TXT_UNREACHABLE_CODE, node);
  1990. break;
  1991. }
  1992. if( node->nodeType == snBreak || node->nodeType == snContinue )
  1993. isFinished = true;
  1994. asCByteCode statement(engine);
  1995. if( node->nodeType == snDeclaration )
  1996. {
  1997. Error(TXT_DECL_IN_SWITCH, node);
  1998. // Compile it anyway to avoid further compiler errors
  1999. CompileDeclaration(node, &statement);
  2000. }
  2001. else
  2002. CompileStatement(node, &hasReturn, &statement);
  2003. LineInstr(bc, node->tokenPos);
  2004. bc->AddCode(&statement);
  2005. if( !hasCompileErrors )
  2006. asASSERT( tempVariables.GetLength() == 0 );
  2007. node = node->next;
  2008. }
  2009. }
  2010. void asCCompiler::CompileIfStatement(asCScriptNode *inode, bool *hasReturn, asCByteCode *bc)
  2011. {
  2012. // We will use one label for the if statement
  2013. // and possibly another for the else statement
  2014. int afterLabel = nextLabel++;
  2015. // Compile the expression
  2016. asSExprContext expr(engine);
  2017. CompileAssignment(inode->firstChild, &expr);
  2018. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  2019. {
  2020. Error(TXT_EXPR_MUST_BE_BOOL, inode->firstChild);
  2021. expr.type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), 1);
  2022. }
  2023. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  2024. ProcessDeferredParams(&expr);
  2025. if( !expr.type.isConstant )
  2026. {
  2027. ProcessPropertyGetAccessor(&expr, inode);
  2028. ConvertToVariable(&expr);
  2029. // Add byte code from the expression
  2030. bc->AddCode(&expr.bc);
  2031. // Add a test
  2032. bc->InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  2033. bc->Instr(asBC_ClrHi);
  2034. bc->InstrDWORD(asBC_JZ, afterLabel);
  2035. ReleaseTemporaryVariable(expr.type, bc);
  2036. }
  2037. else if( expr.type.dwordValue == 0 )
  2038. {
  2039. // Jump to the else case
  2040. bc->InstrINT(asBC_JMP, afterLabel);
  2041. // TODO: Should we warn that the expression will always go to the else?
  2042. }
  2043. // Compile the if statement
  2044. bool origIsConstructorCalled = m_isConstructorCalled;
  2045. bool hasReturn1;
  2046. asCByteCode ifBC(engine);
  2047. CompileStatement(inode->firstChild->next, &hasReturn1, &ifBC);
  2048. // Add the byte code
  2049. LineInstr(bc, inode->firstChild->next->tokenPos);
  2050. bc->AddCode(&ifBC);
  2051. if( inode->firstChild->next->nodeType == snExpressionStatement && inode->firstChild->next->firstChild == 0 )
  2052. {
  2053. // Don't allow if( expr );
  2054. Error(TXT_IF_WITH_EMPTY_STATEMENT, inode->firstChild->next);
  2055. }
  2056. // If one of the statements call the constructor, the other must as well
  2057. // otherwise it is possible the constructor is never called
  2058. bool constructorCall1 = false;
  2059. bool constructorCall2 = false;
  2060. if( !origIsConstructorCalled && m_isConstructorCalled )
  2061. constructorCall1 = true;
  2062. // Do we have an else statement?
  2063. if( inode->firstChild->next != inode->lastChild )
  2064. {
  2065. // Reset the constructor called flag so the else statement can call the constructor too
  2066. m_isConstructorCalled = origIsConstructorCalled;
  2067. int afterElse = 0;
  2068. if( !hasReturn1 )
  2069. {
  2070. afterElse = nextLabel++;
  2071. // Add jump to after the else statement
  2072. bc->InstrINT(asBC_JMP, afterElse);
  2073. }
  2074. // Add label for the else statement
  2075. bc->Label((short)afterLabel);
  2076. bool hasReturn2;
  2077. asCByteCode elseBC(engine);
  2078. CompileStatement(inode->lastChild, &hasReturn2, &elseBC);
  2079. // Add byte code for the else statement
  2080. LineInstr(bc, inode->lastChild->tokenPos);
  2081. bc->AddCode(&elseBC);
  2082. if( inode->lastChild->nodeType == snExpressionStatement && inode->lastChild->firstChild == 0 )
  2083. {
  2084. // Don't allow if( expr ) {} else;
  2085. Error(TXT_ELSE_WITH_EMPTY_STATEMENT, inode->lastChild);
  2086. }
  2087. if( !hasReturn1 )
  2088. {
  2089. // Add label for the end of else statement
  2090. bc->Label((short)afterElse);
  2091. }
  2092. // The if statement only has return if both alternatives have
  2093. *hasReturn = hasReturn1 && hasReturn2;
  2094. if( !origIsConstructorCalled && m_isConstructorCalled )
  2095. constructorCall2 = true;
  2096. }
  2097. else
  2098. {
  2099. // Add label for the end of if statement
  2100. bc->Label((short)afterLabel);
  2101. *hasReturn = false;
  2102. }
  2103. // Make sure both or neither conditions call a constructor
  2104. if( (constructorCall1 && !constructorCall2) ||
  2105. (constructorCall2 && !constructorCall1) )
  2106. {
  2107. Error(TXT_BOTH_CONDITIONS_MUST_CALL_CONSTRUCTOR, inode);
  2108. }
  2109. m_isConstructorCalled = origIsConstructorCalled || constructorCall1 || constructorCall2;
  2110. }
  2111. void asCCompiler::CompileForStatement(asCScriptNode *fnode, asCByteCode *bc)
  2112. {
  2113. // TODO: optimize: We should be able to remove the static JMP to the beginning of the loop by rearranging the
  2114. // byte code a bit.
  2115. //
  2116. // init
  2117. // jump to before
  2118. // begin:
  2119. // statements
  2120. // continue:
  2121. // next
  2122. // before:
  2123. // condition
  2124. // if loop jump to begin
  2125. // break:
  2126. // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables
  2127. AddVariableScope(true, true);
  2128. // We will use three labels for the for loop
  2129. int beforeLabel = nextLabel++;
  2130. int afterLabel = nextLabel++;
  2131. int continueLabel = nextLabel++;
  2132. continueLabels.PushLast(continueLabel);
  2133. breakLabels.PushLast(afterLabel);
  2134. //---------------------------------------
  2135. // Compile the initialization statement
  2136. asCByteCode initBC(engine);
  2137. if( fnode->firstChild->nodeType == snDeclaration )
  2138. CompileDeclaration(fnode->firstChild, &initBC);
  2139. else
  2140. CompileExpressionStatement(fnode->firstChild, &initBC);
  2141. //-----------------------------------
  2142. // Compile the condition statement
  2143. asSExprContext expr(engine);
  2144. asCScriptNode *second = fnode->firstChild->next;
  2145. if( second->firstChild )
  2146. {
  2147. int r = CompileAssignment(second->firstChild, &expr);
  2148. if( r >= 0 )
  2149. {
  2150. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  2151. Error(TXT_EXPR_MUST_BE_BOOL, second);
  2152. else
  2153. {
  2154. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  2155. ProcessDeferredParams(&expr);
  2156. ProcessPropertyGetAccessor(&expr, second);
  2157. // If expression is false exit the loop
  2158. ConvertToVariable(&expr);
  2159. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  2160. expr.bc.Instr(asBC_ClrHi);
  2161. expr.bc.InstrDWORD(asBC_JZ, afterLabel);
  2162. ReleaseTemporaryVariable(expr.type, &expr.bc);
  2163. }
  2164. }
  2165. }
  2166. //---------------------------
  2167. // Compile the increment statement
  2168. asCByteCode nextBC(engine);
  2169. asCScriptNode *third = second->next;
  2170. if( third->nodeType == snExpressionStatement )
  2171. CompileExpressionStatement(third, &nextBC);
  2172. //------------------------------
  2173. // Compile loop statement
  2174. bool hasReturn;
  2175. asCByteCode forBC(engine);
  2176. CompileStatement(fnode->lastChild, &hasReturn, &forBC);
  2177. //-------------------------------
  2178. // Join the code pieces
  2179. bc->AddCode(&initBC);
  2180. bc->Label((short)beforeLabel);
  2181. // Add a suspend bytecode inside the loop to guarantee
  2182. // that the application can suspend the execution
  2183. bc->Instr(asBC_SUSPEND);
  2184. bc->InstrWORD(asBC_JitEntry, 0);
  2185. bc->AddCode(&expr.bc);
  2186. LineInstr(bc, fnode->lastChild->tokenPos);
  2187. bc->AddCode(&forBC);
  2188. bc->Label((short)continueLabel);
  2189. bc->AddCode(&nextBC);
  2190. bc->InstrINT(asBC_JMP, beforeLabel);
  2191. bc->Label((short)afterLabel);
  2192. continueLabels.PopLast();
  2193. breakLabels.PopLast();
  2194. // Deallocate variables in this block, in reverse order
  2195. for( int n = (int)variables->variables.GetLength() - 1; n >= 0; n-- )
  2196. {
  2197. sVariable *v = variables->variables[n];
  2198. // Call variable destructors here, for variables not yet destroyed
  2199. CallDestructor(v->type, v->stackOffset, v->onHeap, bc);
  2200. // Don't deallocate function parameters
  2201. if( v->stackOffset > 0 )
  2202. DeallocateVariable(v->stackOffset);
  2203. }
  2204. RemoveVariableScope();
  2205. }
  2206. void asCCompiler::CompileWhileStatement(asCScriptNode *wnode, asCByteCode *bc)
  2207. {
  2208. // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables
  2209. AddVariableScope(true, true);
  2210. // We will use two labels for the while loop
  2211. int beforeLabel = nextLabel++;
  2212. int afterLabel = nextLabel++;
  2213. continueLabels.PushLast(beforeLabel);
  2214. breakLabels.PushLast(afterLabel);
  2215. // Add label before the expression
  2216. bc->Label((short)beforeLabel);
  2217. // Compile expression
  2218. asSExprContext expr(engine);
  2219. CompileAssignment(wnode->firstChild, &expr);
  2220. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  2221. Error(TXT_EXPR_MUST_BE_BOOL, wnode->firstChild);
  2222. else
  2223. {
  2224. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  2225. ProcessDeferredParams(&expr);
  2226. ProcessPropertyGetAccessor(&expr, wnode);
  2227. // Add byte code for the expression
  2228. ConvertToVariable(&expr);
  2229. bc->AddCode(&expr.bc);
  2230. // Jump to end of statement if expression is false
  2231. bc->InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  2232. bc->Instr(asBC_ClrHi);
  2233. bc->InstrDWORD(asBC_JZ, afterLabel);
  2234. ReleaseTemporaryVariable(expr.type, bc);
  2235. }
  2236. // Add a suspend bytecode inside the loop to guarantee
  2237. // that the application can suspend the execution
  2238. bc->Instr(asBC_SUSPEND);
  2239. bc->InstrWORD(asBC_JitEntry, 0);
  2240. // Compile statement
  2241. bool hasReturn;
  2242. asCByteCode whileBC(engine);
  2243. CompileStatement(wnode->lastChild, &hasReturn, &whileBC);
  2244. // Add byte code for the statement
  2245. LineInstr(bc, wnode->lastChild->tokenPos);
  2246. bc->AddCode(&whileBC);
  2247. // Jump to the expression
  2248. bc->InstrINT(asBC_JMP, beforeLabel);
  2249. // Add label after the statement
  2250. bc->Label((short)afterLabel);
  2251. continueLabels.PopLast();
  2252. breakLabels.PopLast();
  2253. RemoveVariableScope();
  2254. }
  2255. void asCCompiler::CompileDoWhileStatement(asCScriptNode *wnode, asCByteCode *bc)
  2256. {
  2257. // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables
  2258. AddVariableScope(true, true);
  2259. // We will use two labels for the while loop
  2260. int beforeLabel = nextLabel++;
  2261. int beforeTest = nextLabel++;
  2262. int afterLabel = nextLabel++;
  2263. continueLabels.PushLast(beforeTest);
  2264. breakLabels.PushLast(afterLabel);
  2265. // Add label before the statement
  2266. bc->Label((short)beforeLabel);
  2267. // Compile statement
  2268. bool hasReturn;
  2269. asCByteCode whileBC(engine);
  2270. CompileStatement(wnode->firstChild, &hasReturn, &whileBC);
  2271. // Add byte code for the statement
  2272. LineInstr(bc, wnode->firstChild->tokenPos);
  2273. bc->AddCode(&whileBC);
  2274. // Add label before the expression
  2275. bc->Label((short)beforeTest);
  2276. // Add a suspend bytecode inside the loop to guarantee
  2277. // that the application can suspend the execution
  2278. bc->Instr(asBC_SUSPEND);
  2279. bc->InstrWORD(asBC_JitEntry, 0);
  2280. // Add a line instruction
  2281. LineInstr(bc, wnode->lastChild->tokenPos);
  2282. // Compile expression
  2283. asSExprContext expr(engine);
  2284. CompileAssignment(wnode->lastChild, &expr);
  2285. if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  2286. Error(TXT_EXPR_MUST_BE_BOOL, wnode->firstChild);
  2287. else
  2288. {
  2289. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  2290. ProcessDeferredParams(&expr);
  2291. ProcessPropertyGetAccessor(&expr, wnode);
  2292. // Add byte code for the expression
  2293. ConvertToVariable(&expr);
  2294. bc->AddCode(&expr.bc);
  2295. // Jump to next iteration if expression is true
  2296. bc->InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  2297. bc->Instr(asBC_ClrHi);
  2298. bc->InstrDWORD(asBC_JNZ, beforeLabel);
  2299. ReleaseTemporaryVariable(expr.type, bc);
  2300. }
  2301. // Add label after the statement
  2302. bc->Label((short)afterLabel);
  2303. continueLabels.PopLast();
  2304. breakLabels.PopLast();
  2305. RemoveVariableScope();
  2306. }
  2307. void asCCompiler::CompileBreakStatement(asCScriptNode *node, asCByteCode *bc)
  2308. {
  2309. if( breakLabels.GetLength() == 0 )
  2310. {
  2311. Error(TXT_INVALID_BREAK, node);
  2312. return;
  2313. }
  2314. // Add destructor calls for all variables that will go out of scope
  2315. // Put this clean up in a block to allow exception handler to understand them
  2316. bc->Block(true);
  2317. asCVariableScope *vs = variables;
  2318. while( !vs->isBreakScope )
  2319. {
  2320. for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- )
  2321. CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc);
  2322. vs = vs->parent;
  2323. }
  2324. bc->Block(false);
  2325. bc->InstrINT(asBC_JMP, breakLabels[breakLabels.GetLength()-1]);
  2326. }
  2327. void asCCompiler::CompileContinueStatement(asCScriptNode *node, asCByteCode *bc)
  2328. {
  2329. if( continueLabels.GetLength() == 0 )
  2330. {
  2331. Error(TXT_INVALID_CONTINUE, node);
  2332. return;
  2333. }
  2334. // Add destructor calls for all variables that will go out of scope
  2335. // Put this clean up in a block to allow exception handler to understand them
  2336. bc->Block(true);
  2337. asCVariableScope *vs = variables;
  2338. while( !vs->isContinueScope )
  2339. {
  2340. for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- )
  2341. CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc);
  2342. vs = vs->parent;
  2343. }
  2344. bc->Block(false);
  2345. bc->InstrINT(asBC_JMP, continueLabels[continueLabels.GetLength()-1]);
  2346. }
  2347. void asCCompiler::CompileExpressionStatement(asCScriptNode *enode, asCByteCode *bc)
  2348. {
  2349. if( enode->firstChild )
  2350. {
  2351. // Compile the expression
  2352. asSExprContext expr(engine);
  2353. CompileAssignment(enode->firstChild, &expr);
  2354. // Pop the value from the stack
  2355. if( !expr.type.dataType.IsPrimitive() )
  2356. expr.bc.Pop(expr.type.dataType.GetSizeOnStackDWords());
  2357. // Release temporary variables used by expression
  2358. ReleaseTemporaryVariable(expr.type, &expr.bc);
  2359. ProcessDeferredParams(&expr);
  2360. bc->AddCode(&expr.bc);
  2361. }
  2362. }
  2363. void asCCompiler::PrepareTemporaryObject(asCScriptNode *node, asSExprContext *ctx, asCArray<int> *reservedVars, bool forceOnHeap)
  2364. {
  2365. // If the object already is stored in temporary variable then nothing needs to be done
  2366. // Note, a type can be temporary without being a variable, in which case it is holding off
  2367. // on releasing a previously used object.
  2368. if( ctx->type.isTemporary && ctx->type.isVariable &&
  2369. !(forceOnHeap && !IsVariableOnHeap(ctx->type.stackOffset)) )
  2370. {
  2371. // If the temporary object is currently not a reference
  2372. // the expression needs to be reevaluated to a reference
  2373. if( !ctx->type.dataType.IsReference() )
  2374. {
  2375. ctx->bc.Pop(AS_PTR_SIZE);
  2376. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  2377. ctx->type.dataType.MakeReference(true);
  2378. }
  2379. return;
  2380. }
  2381. // Allocate temporary variable
  2382. asCDataType dt = ctx->type.dataType;
  2383. dt.MakeReference(false);
  2384. dt.MakeReadOnly(false);
  2385. int offset = AllocateVariableNotIn(dt, true, reservedVars, forceOnHeap);
  2386. // Objects stored on the stack are not considered references
  2387. dt.MakeReference(IsVariableOnHeap(offset));
  2388. asCTypeInfo lvalue;
  2389. lvalue.Set(dt);
  2390. lvalue.isTemporary = true;
  2391. lvalue.stackOffset = (short)offset;
  2392. lvalue.isVariable = true;
  2393. lvalue.isExplicitHandle = ctx->type.isExplicitHandle;
  2394. if( !dt.IsObjectHandle() && dt.GetObjectType() && (dt.GetBehaviour()->copyconstruct || dt.GetBehaviour()->copyfactory) )
  2395. {
  2396. PrepareForAssignment(&lvalue.dataType, ctx, node);
  2397. // Use the copy constructor/factory when available
  2398. CallCopyConstructor(dt, offset, IsVariableOnHeap(offset), &ctx->bc, ctx, node);
  2399. }
  2400. else
  2401. {
  2402. // Allocate and construct the temporary object
  2403. CallDefaultConstructor(dt, offset, IsVariableOnHeap(offset), &ctx->bc, node);
  2404. // Assign the object to the temporary variable
  2405. PrepareForAssignment(&lvalue.dataType, ctx, node);
  2406. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  2407. PerformAssignment(&lvalue, &ctx->type, &ctx->bc, node);
  2408. // Pop the original reference
  2409. ctx->bc.Pop(AS_PTR_SIZE);
  2410. }
  2411. // If the expression was holding off on releasing a
  2412. // previously used object, we need to release it now
  2413. if( ctx->type.isTemporary )
  2414. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  2415. // Push the reference to the temporary variable on the stack
  2416. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  2417. lvalue.dataType.MakeReference(IsVariableOnHeap(offset));
  2418. ctx->type = lvalue;
  2419. }
  2420. void asCCompiler::CompileReturnStatement(asCScriptNode *rnode, asCByteCode *bc)
  2421. {
  2422. // Get return type and location
  2423. sVariable *v = variables->GetVariable("return");
  2424. // Basic validations
  2425. if( v->type.GetSizeOnStackDWords() > 0 && !rnode->firstChild )
  2426. {
  2427. Error(TXT_MUST_RETURN_VALUE, rnode);
  2428. return;
  2429. }
  2430. else if( v->type.GetSizeOnStackDWords() == 0 && rnode->firstChild )
  2431. {
  2432. Error(TXT_CANT_RETURN_VALUE, rnode);
  2433. return;
  2434. }
  2435. // Compile the expression
  2436. if( rnode->firstChild )
  2437. {
  2438. // Compile the expression
  2439. asSExprContext expr(engine);
  2440. int r = CompileAssignment(rnode->firstChild, &expr);
  2441. if( r < 0 ) return;
  2442. if( v->type.IsReference() )
  2443. {
  2444. // The expression that gives the reference must not use any of the
  2445. // variables that must be destroyed upon exit, because then it means
  2446. // reference will stay alive while the clean-up is done, which could
  2447. // potentially mean that the reference is invalidated by the clean-up.
  2448. //
  2449. // When the function is returning a reference, the clean-up of the
  2450. // variables must be done before the evaluation of the expression.
  2451. //
  2452. // A reference to a global variable, or a class member for class methods
  2453. // should be allowed to be returned.
  2454. if( !(expr.type.dataType.IsReference() ||
  2455. (expr.type.dataType.IsObject() && !expr.type.dataType.IsObjectHandle())) )
  2456. {
  2457. // Clean up the potential deferred parameters
  2458. ProcessDeferredParams(&expr);
  2459. Error(TXT_NOT_VALID_REFERENCE, rnode);
  2460. return;
  2461. }
  2462. // No references to local variables, temporary variables, or parameters
  2463. // are allowed to be returned, since they go out of scope when the function
  2464. // returns. Even reference parameters are disallowed, since it is not possible
  2465. // to know the scope of them. The exception is the 'this' pointer, which
  2466. // is treated by the compiler as a local variable, but isn't really so.
  2467. if( (expr.type.isVariable && !(expr.type.stackOffset == 0 && outFunc->objectType)) || expr.type.isTemporary )
  2468. {
  2469. // Clean up the potential deferred parameters
  2470. ProcessDeferredParams(&expr);
  2471. Error(TXT_CANNOT_RETURN_REF_TO_LOCAL, rnode);
  2472. return;
  2473. }
  2474. // The type must match exactly as we cannot convert
  2475. // the reference without loosing the original value
  2476. if( !(v->type == expr.type.dataType ||
  2477. (expr.type.dataType.IsObject() && !expr.type.dataType.IsObjectHandle() && v->type.IsEqualExceptRef(expr.type.dataType))) )
  2478. {
  2479. // Clean up the potential deferred parameters
  2480. ProcessDeferredParams(&expr);
  2481. asCString str;
  2482. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, expr.type.dataType.Format().AddressOf(), v->type.Format().AddressOf());
  2483. Error(str.AddressOf(), rnode);
  2484. return;
  2485. }
  2486. // The expression must not have any deferred expressions, because the evaluation
  2487. // of these cannot be done without keeping the reference which is not safe
  2488. if( expr.deferredParams.GetLength() )
  2489. {
  2490. // Clean up the potential deferred parameters
  2491. ProcessDeferredParams(&expr);
  2492. Error(TXT_REF_CANT_BE_RETURNED_DEFERRED_PARAM, rnode);
  2493. return;
  2494. }
  2495. // Make sure the expression isn't using any local variables that
  2496. // will need to be cleaned up before the function completes
  2497. asCArray<int> usedVars;
  2498. expr.bc.GetVarsUsed(usedVars);
  2499. for( asUINT n = 0; n < usedVars.GetLength(); n++ )
  2500. {
  2501. int var = GetVariableSlot(usedVars[n]);
  2502. if( var != -1 )
  2503. {
  2504. asCDataType dt = variableAllocations[var];
  2505. if( dt.IsObject() )
  2506. {
  2507. ProcessDeferredParams(&expr);
  2508. Error(TXT_REF_CANT_BE_RETURNED_LOCAL_VARS, rnode);
  2509. return;
  2510. }
  2511. }
  2512. }
  2513. // All objects in the function must be cleaned up before the expression
  2514. // is evaluated, otherwise there is a possibility that the cleanup will
  2515. // invalidate the reference.
  2516. // Destroy the local variables before loading
  2517. // the reference into the register. This will
  2518. // be done before the expression is evaluated.
  2519. DestroyVariables(bc);
  2520. // For primitives the reference is already in the register,
  2521. // but for non-primitives the reference is on the stack so we
  2522. // need to load it into the register
  2523. if( !expr.type.dataType.IsPrimitive() )
  2524. {
  2525. if( !expr.type.dataType.IsObjectHandle() && expr.type.dataType.IsReference() )
  2526. expr.bc.Instr(asBC_RDSPTR);
  2527. expr.bc.Instr(asBC_PopRPtr);
  2528. }
  2529. // There are no temporaries to release so we're done
  2530. }
  2531. else // if( !v->type.IsReference() )
  2532. {
  2533. ProcessPropertyGetAccessor(&expr, rnode);
  2534. // Prepare the value for assignment
  2535. IsVariableInitialized(&expr.type, rnode->firstChild);
  2536. if( v->type.IsPrimitive() )
  2537. {
  2538. if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr);
  2539. // Implicitly convert the value to the return type
  2540. ImplicitConversion(&expr, v->type, rnode->firstChild, asIC_IMPLICIT_CONV);
  2541. // Verify that the conversion was successful
  2542. if( expr.type.dataType != v->type )
  2543. {
  2544. asCString str;
  2545. str.Format(TXT_NO_CONVERSION_s_TO_s, expr.type.dataType.Format().AddressOf(), v->type.Format().AddressOf());
  2546. Error(str.AddressOf(), rnode);
  2547. r = -1;
  2548. }
  2549. else
  2550. {
  2551. ConvertToVariable(&expr);
  2552. // Clean up the local variables and process deferred parameters
  2553. DestroyVariables(&expr.bc);
  2554. ProcessDeferredParams(&expr);
  2555. ReleaseTemporaryVariable(expr.type, &expr.bc);
  2556. // Load the variable in the register
  2557. if( v->type.GetSizeOnStackDWords() == 1 )
  2558. expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset);
  2559. else
  2560. expr.bc.InstrSHORT(asBC_CpyVtoR8, expr.type.stackOffset);
  2561. }
  2562. }
  2563. else if( v->type.IsObject() )
  2564. {
  2565. // Value types are still returned on the heap, so we must
  2566. // copy the value to an object allocated on the heap here
  2567. PrepareArgument(&v->type, &expr, rnode->firstChild, false, 0, 0, true);
  2568. // Pop the reference to the temporary variable again
  2569. expr.bc.Pop(AS_PTR_SIZE);
  2570. // Clean up the local variables and process deferred parameters
  2571. DestroyVariables(&expr.bc);
  2572. ProcessDeferredParams(&expr);
  2573. // Load the object pointer into the object register
  2574. // LOADOBJ also clears the address in the variable
  2575. expr.bc.InstrSHORT(asBC_LOADOBJ, expr.type.stackOffset);
  2576. // LOADOBJ cleared the address in the variable so the object will not be freed
  2577. // here, but the temporary variable must still be freed so the slot can be reused
  2578. // By releasing without the bytecode we do just that.
  2579. ReleaseTemporaryVariable(expr.type, 0);
  2580. }
  2581. }
  2582. bc->AddCode(&expr.bc);
  2583. }
  2584. else
  2585. {
  2586. // For functions that don't return anything
  2587. // we just detroy the local variables
  2588. DestroyVariables(bc);
  2589. }
  2590. // Jump to the end of the function
  2591. bc->InstrINT(asBC_JMP, 0);
  2592. }
  2593. void asCCompiler::DestroyVariables(asCByteCode *bc)
  2594. {
  2595. // Call destructor on all variables except for the function parameters
  2596. // Put the clean-up in a block to allow exception handler to understand this
  2597. bc->Block(true);
  2598. asCVariableScope *vs = variables;
  2599. while( vs )
  2600. {
  2601. for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- )
  2602. if( vs->variables[n]->stackOffset > 0 )
  2603. CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc);
  2604. vs = vs->parent;
  2605. }
  2606. bc->Block(false);
  2607. }
  2608. void asCCompiler::AddVariableScope(bool isBreakScope, bool isContinueScope)
  2609. {
  2610. variables = asNEW(asCVariableScope)(variables);
  2611. variables->isBreakScope = isBreakScope;
  2612. variables->isContinueScope = isContinueScope;
  2613. }
  2614. void asCCompiler::RemoveVariableScope()
  2615. {
  2616. if( variables )
  2617. {
  2618. asCVariableScope *var = variables;
  2619. variables = variables->parent;
  2620. asDELETE(var,asCVariableScope);
  2621. }
  2622. }
  2623. void asCCompiler::Error(const char *msg, asCScriptNode *node)
  2624. {
  2625. asCString str;
  2626. int r = 0, c = 0;
  2627. asASSERT( node );
  2628. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  2629. builder->WriteError(script->name.AddressOf(), msg, r, c);
  2630. hasCompileErrors = true;
  2631. }
  2632. void asCCompiler::Warning(const char *msg, asCScriptNode *node)
  2633. {
  2634. asCString str;
  2635. int r = 0, c = 0;
  2636. asASSERT( node );
  2637. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  2638. builder->WriteWarning(script->name.AddressOf(), msg, r, c);
  2639. }
  2640. void asCCompiler::Information(const char *msg, asCScriptNode *node)
  2641. {
  2642. asCString str;
  2643. int r = 0, c = 0;
  2644. asASSERT( node );
  2645. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  2646. builder->WriteInfo(script->name.AddressOf(), msg, r, c, false);
  2647. }
  2648. void asCCompiler::PrintMatchingFuncs(asCArray<int> &funcs, asCScriptNode *node)
  2649. {
  2650. int r = 0, c = 0;
  2651. asASSERT( node );
  2652. if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c);
  2653. for( unsigned int n = 0; n < funcs.GetLength(); n++ )
  2654. {
  2655. asIScriptFunction *func = builder->GetFunctionDescription(funcs[n]);
  2656. builder->WriteInfo(script->name.AddressOf(), func->GetDeclaration(true), r, c, false);
  2657. }
  2658. }
  2659. int asCCompiler::AllocateVariable(const asCDataType &type, bool isTemporary, bool forceOnHeap)
  2660. {
  2661. return AllocateVariableNotIn(type, isTemporary, 0, forceOnHeap);
  2662. }
  2663. int asCCompiler::AllocateVariableNotIn(const asCDataType &type, bool isTemporary, asCArray<int> *vars, bool forceOnHeap)
  2664. {
  2665. asCDataType t(type);
  2666. if( t.IsPrimitive() && t.GetSizeOnStackDWords() == 1 )
  2667. t.SetTokenType(ttInt);
  2668. if( t.IsPrimitive() && t.GetSizeOnStackDWords() == 2 )
  2669. t.SetTokenType(ttDouble);
  2670. // Only null handles have the token type unrecognized token
  2671. asASSERT( t.IsObjectHandle() || t.GetTokenType() != ttUnrecognizedToken );
  2672. bool isOnHeap = true;
  2673. // TODO: Remove this once the bugs with value types on stack is fixed
  2674. // forceOnHeap = true;
  2675. if( t.IsPrimitive() ||
  2676. (t.GetObjectType() && (t.GetObjectType()->GetFlags() & asOBJ_VALUE) && !forceOnHeap) )
  2677. {
  2678. // Primitives and value types (unless overridden) are allocated on the stack
  2679. isOnHeap = false;
  2680. }
  2681. // Find a free location with the same type
  2682. for( asUINT n = 0; n < freeVariables.GetLength(); n++ )
  2683. {
  2684. int slot = freeVariables[n];
  2685. if( variableAllocations[slot].IsEqualExceptConst(t) &&
  2686. variableIsTemporary[slot] == isTemporary &&
  2687. variableIsOnHeap[slot] == isOnHeap )
  2688. {
  2689. // We can't return by slot, must count variable sizes
  2690. int offset = GetVariableOffset(slot);
  2691. // Verify that it is not in the list of used variables
  2692. bool isUsed = false;
  2693. if( vars )
  2694. {
  2695. for( asUINT m = 0; m < vars->GetLength(); m++ )
  2696. {
  2697. if( offset == (*vars)[m] )
  2698. {
  2699. isUsed = true;
  2700. break;
  2701. }
  2702. }
  2703. }
  2704. if( !isUsed )
  2705. {
  2706. if( n != freeVariables.GetLength() - 1 )
  2707. freeVariables[n] = freeVariables.PopLast();
  2708. else
  2709. freeVariables.PopLast();
  2710. if( isTemporary )
  2711. tempVariables.PushLast(offset);
  2712. return offset;
  2713. }
  2714. }
  2715. }
  2716. variableAllocations.PushLast(t);
  2717. variableIsTemporary.PushLast(isTemporary);
  2718. variableIsOnHeap.PushLast(isOnHeap);
  2719. int offset = GetVariableOffset((int)variableAllocations.GetLength()-1);
  2720. if( isTemporary )
  2721. tempVariables.PushLast(offset);
  2722. return offset;
  2723. }
  2724. int asCCompiler::GetVariableOffset(int varIndex)
  2725. {
  2726. // Return offset to the last dword on the stack
  2727. int varOffset = 1;
  2728. for( int n = 0; n < varIndex; n++ )
  2729. {
  2730. if( !variableIsOnHeap[n] && variableAllocations[n].IsObject() )
  2731. varOffset += variableAllocations[n].GetSizeInMemoryDWords();
  2732. else
  2733. varOffset += variableAllocations[n].GetSizeOnStackDWords();
  2734. }
  2735. if( varIndex < (int)variableAllocations.GetLength() )
  2736. {
  2737. int size;
  2738. if( !variableIsOnHeap[varIndex] && variableAllocations[varIndex].IsObject() )
  2739. size = variableAllocations[varIndex].GetSizeInMemoryDWords();
  2740. else
  2741. size = variableAllocations[varIndex].GetSizeOnStackDWords();
  2742. if( size > 1 )
  2743. varOffset += size-1;
  2744. }
  2745. return varOffset;
  2746. }
  2747. int asCCompiler::GetVariableSlot(int offset)
  2748. {
  2749. int varOffset = 1;
  2750. for( asUINT n = 0; n < variableAllocations.GetLength(); n++ )
  2751. {
  2752. if( !variableIsOnHeap[n] && variableAllocations[n].IsObject() )
  2753. varOffset += -1 + variableAllocations[n].GetSizeInMemoryDWords();
  2754. else
  2755. varOffset += -1 + variableAllocations[n].GetSizeOnStackDWords();
  2756. if( varOffset == offset )
  2757. return n;
  2758. varOffset++;
  2759. }
  2760. return -1;
  2761. }
  2762. bool asCCompiler::IsVariableOnHeap(int offset)
  2763. {
  2764. int varSlot = GetVariableSlot(offset);
  2765. if( varSlot < 0 )
  2766. {
  2767. // This happens for function arguments that are considered as on the heap
  2768. return true;
  2769. }
  2770. return variableIsOnHeap[varSlot];
  2771. }
  2772. void asCCompiler::DeallocateVariable(int offset)
  2773. {
  2774. // Remove temporary variable
  2775. int n;
  2776. for( n = 0; n < (int)tempVariables.GetLength(); n++ )
  2777. {
  2778. if( offset == tempVariables[n] )
  2779. {
  2780. if( n == (int)tempVariables.GetLength()-1 )
  2781. tempVariables.PopLast();
  2782. else
  2783. tempVariables[n] = tempVariables.PopLast();
  2784. break;
  2785. }
  2786. }
  2787. n = GetVariableSlot(offset);
  2788. if( n != -1 )
  2789. {
  2790. freeVariables.PushLast(n);
  2791. return;
  2792. }
  2793. // We might get here if the variable was implicitly declared
  2794. // because it was use before a formal declaration, in this case
  2795. // the offset is 0x7FFF
  2796. asASSERT(offset == 0x7FFF);
  2797. }
  2798. void asCCompiler::ReleaseTemporaryVariable(asCTypeInfo &t, asCByteCode *bc)
  2799. {
  2800. if( t.isTemporary )
  2801. {
  2802. ReleaseTemporaryVariable(t.stackOffset, bc);
  2803. t.isTemporary = false;
  2804. }
  2805. }
  2806. void asCCompiler::ReleaseTemporaryVariable(int offset, asCByteCode *bc)
  2807. {
  2808. if( bc )
  2809. {
  2810. // We need to call the destructor on the true variable type
  2811. int n = GetVariableSlot(offset);
  2812. asCDataType dt = variableAllocations[n];
  2813. bool isOnHeap = variableIsOnHeap[n];
  2814. // Call destructor
  2815. CallDestructor(dt, offset, isOnHeap, bc);
  2816. }
  2817. DeallocateVariable(offset);
  2818. }
  2819. void asCCompiler::Dereference(asSExprContext *ctx, bool generateCode)
  2820. {
  2821. if( ctx->type.dataType.IsReference() )
  2822. {
  2823. if( ctx->type.dataType.IsObject() )
  2824. {
  2825. ctx->type.dataType.MakeReference(false);
  2826. if( generateCode )
  2827. {
  2828. ctx->bc.Instr(asBC_CHKREF);
  2829. ctx->bc.Instr(asBC_RDSPTR);
  2830. }
  2831. }
  2832. else
  2833. {
  2834. // This should never happen as primitives are treated differently
  2835. asASSERT(false);
  2836. }
  2837. }
  2838. }
  2839. bool asCCompiler::IsVariableInitialized(asCTypeInfo *type, asCScriptNode *node)
  2840. {
  2841. // Temporary variables are assumed to be initialized
  2842. if( type->isTemporary ) return true;
  2843. // Verify that it is a variable
  2844. if( !type->isVariable ) return true;
  2845. // Find the variable
  2846. sVariable *v = variables->GetVariableByOffset(type->stackOffset);
  2847. // The variable isn't found if it is a constant, in which case it is guaranteed to be initialized
  2848. if( v == 0 ) return true;
  2849. if( v->isInitialized ) return true;
  2850. // Complex types don't need this test
  2851. if( v->type.IsObject() ) return true;
  2852. // Mark as initialized so that the user will not be bothered again
  2853. v->isInitialized = true;
  2854. // Write warning
  2855. asCString str;
  2856. str.Format(TXT_s_NOT_INITIALIZED, (const char *)v->name.AddressOf());
  2857. Warning(str.AddressOf(), node);
  2858. return false;
  2859. }
  2860. void asCCompiler::PrepareOperand(asSExprContext *ctx, asCScriptNode *node)
  2861. {
  2862. // Check if the variable is initialized (if it indeed is a variable)
  2863. IsVariableInitialized(&ctx->type, node);
  2864. asCDataType to = ctx->type.dataType;
  2865. to.MakeReference(false);
  2866. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV);
  2867. ProcessDeferredParams(ctx);
  2868. }
  2869. void asCCompiler::PrepareForAssignment(asCDataType *lvalue, asSExprContext *rctx, asCScriptNode *node, asSExprContext *lvalueExpr)
  2870. {
  2871. ProcessPropertyGetAccessor(rctx, node);
  2872. // Make sure the rvalue is initialized if it is a variable
  2873. IsVariableInitialized(&rctx->type, node);
  2874. if( lvalue->IsPrimitive() )
  2875. {
  2876. if( rctx->type.dataType.IsPrimitive() )
  2877. {
  2878. if( rctx->type.dataType.IsReference() )
  2879. {
  2880. // Cannot do implicit conversion of references so we first convert the reference to a variable
  2881. ConvertToVariableNotIn(rctx, lvalueExpr);
  2882. }
  2883. }
  2884. // Implicitly convert the value to the right type
  2885. asCArray<int> usedVars;
  2886. if( lvalueExpr ) lvalueExpr->bc.GetVarsUsed(usedVars);
  2887. ImplicitConversion(rctx, *lvalue, node, asIC_IMPLICIT_CONV, true, &usedVars);
  2888. // Check data type
  2889. if( !lvalue->IsEqualExceptRefAndConst(rctx->type.dataType) )
  2890. {
  2891. asCString str;
  2892. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format().AddressOf(), lvalue->Format().AddressOf());
  2893. Error(str.AddressOf(), node);
  2894. rctx->type.SetDummy();
  2895. }
  2896. // Make sure the rvalue is a variable
  2897. if( !rctx->type.isVariable )
  2898. ConvertToVariableNotIn(rctx, lvalueExpr);
  2899. }
  2900. else
  2901. {
  2902. asCDataType to = *lvalue;
  2903. to.MakeReference(false);
  2904. // TODO: ImplicitConversion should know to do this by itself
  2905. // First convert to a handle which will to a reference cast
  2906. if( !lvalue->IsObjectHandle() &&
  2907. (lvalue->GetObjectType()->flags & asOBJ_SCRIPT_OBJECT) )
  2908. to.MakeHandle(true);
  2909. // Don't allow the implicit conversion to create an object
  2910. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true, 0, false);
  2911. if( !lvalue->IsObjectHandle() &&
  2912. (lvalue->GetObjectType()->flags & asOBJ_SCRIPT_OBJECT) )
  2913. {
  2914. // Then convert to a reference, which will validate the handle
  2915. to.MakeHandle(false);
  2916. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true, 0, false);
  2917. }
  2918. // Check data type
  2919. if( !lvalue->IsEqualExceptRefAndConst(rctx->type.dataType) )
  2920. {
  2921. asCString str;
  2922. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format().AddressOf(), lvalue->Format().AddressOf());
  2923. Error(str.AddressOf(), node);
  2924. }
  2925. else
  2926. {
  2927. // If the assignment will be made with the copy behaviour then the rvalue must not be a reference
  2928. if( lvalue->IsObject() )
  2929. asASSERT(!rctx->type.dataType.IsReference());
  2930. }
  2931. }
  2932. }
  2933. bool asCCompiler::IsLValue(asCTypeInfo &type)
  2934. {
  2935. if( type.dataType.IsReadOnly() ) return false;
  2936. if( !type.dataType.IsObject() && !type.isVariable && !type.dataType.IsReference() ) return false;
  2937. if( type.isTemporary ) return false;
  2938. return true;
  2939. }
  2940. void asCCompiler::PerformAssignment(asCTypeInfo *lvalue, asCTypeInfo *rvalue, asCByteCode *bc, asCScriptNode *node)
  2941. {
  2942. if( lvalue->dataType.IsReadOnly() )
  2943. Error(TXT_REF_IS_READ_ONLY, node);
  2944. if( lvalue->dataType.IsPrimitive() )
  2945. {
  2946. if( lvalue->isVariable )
  2947. {
  2948. // Copy the value between the variables directly
  2949. if( lvalue->dataType.GetSizeInMemoryDWords() == 1 )
  2950. bc->InstrW_W(asBC_CpyVtoV4, lvalue->stackOffset, rvalue->stackOffset);
  2951. else
  2952. bc->InstrW_W(asBC_CpyVtoV8, lvalue->stackOffset, rvalue->stackOffset);
  2953. // Mark variable as initialized
  2954. sVariable *v = variables->GetVariableByOffset(lvalue->stackOffset);
  2955. if( v ) v->isInitialized = true;
  2956. }
  2957. else if( lvalue->dataType.IsReference() )
  2958. {
  2959. // Copy the value of the variable to the reference in the register
  2960. int s = lvalue->dataType.GetSizeInMemoryBytes();
  2961. if( s == 1 )
  2962. bc->InstrSHORT(asBC_WRTV1, rvalue->stackOffset);
  2963. else if( s == 2 )
  2964. bc->InstrSHORT(asBC_WRTV2, rvalue->stackOffset);
  2965. else if( s == 4 )
  2966. bc->InstrSHORT(asBC_WRTV4, rvalue->stackOffset);
  2967. else if( s == 8 )
  2968. bc->InstrSHORT(asBC_WRTV8, rvalue->stackOffset);
  2969. }
  2970. else
  2971. {
  2972. Error(TXT_NOT_VALID_LVALUE, node);
  2973. return;
  2974. }
  2975. }
  2976. else if( !lvalue->isExplicitHandle )
  2977. {
  2978. asSExprContext ctx(engine);
  2979. ctx.type = *lvalue;
  2980. Dereference(&ctx, true);
  2981. *lvalue = ctx.type;
  2982. bc->AddCode(&ctx.bc);
  2983. // TODO: Can't this leave deferred output params unhandled?
  2984. // TODO: Should find the opAssign method that implements the default copy behaviour.
  2985. // The beh->copy member will be removed.
  2986. asSTypeBehaviour *beh = lvalue->dataType.GetBehaviour();
  2987. if( beh->copy )
  2988. {
  2989. // Call the copy operator
  2990. bc->Call(asBC_CALLSYS, (asDWORD)beh->copy, 2*AS_PTR_SIZE);
  2991. bc->Instr(asBC_PshRPtr);
  2992. }
  2993. else
  2994. {
  2995. // Default copy operator
  2996. if( lvalue->dataType.GetSizeInMemoryDWords() == 0 ||
  2997. !(lvalue->dataType.GetObjectType()->flags & asOBJ_POD) )
  2998. {
  2999. Error(TXT_NO_DEFAULT_COPY_OP, node);
  3000. }
  3001. // Copy larger data types from a reference
  3002. bc->InstrSHORT_DW(asBC_COPY, (short)lvalue->dataType.GetSizeInMemoryDWords(), engine->GetTypeIdFromDataType(lvalue->dataType));
  3003. }
  3004. }
  3005. else
  3006. {
  3007. // TODO: The object handle can be stored in a variable as well
  3008. if( !lvalue->dataType.IsReference() )
  3009. {
  3010. Error(TXT_NOT_VALID_REFERENCE, node);
  3011. return;
  3012. }
  3013. // TODO: optimize: Convert to register based
  3014. bc->InstrPTR(asBC_REFCPY, lvalue->dataType.GetObjectType());
  3015. // Mark variable as initialized
  3016. if( variables )
  3017. {
  3018. sVariable *v = variables->GetVariableByOffset(lvalue->stackOffset);
  3019. if( v ) v->isInitialized = true;
  3020. }
  3021. }
  3022. }
  3023. bool asCCompiler::CompileRefCast(asSExprContext *ctx, const asCDataType &to, bool isExplicit, asCScriptNode *node, bool generateCode)
  3024. {
  3025. bool conversionDone = false;
  3026. asCArray<int> ops;
  3027. asUINT n;
  3028. if( ctx->type.dataType.GetObjectType()->flags & asOBJ_SCRIPT_OBJECT )
  3029. {
  3030. // We need it to be a reference
  3031. if( !ctx->type.dataType.IsReference() )
  3032. {
  3033. asCDataType to = ctx->type.dataType;
  3034. to.MakeReference(true);
  3035. ImplicitConversion(ctx, to, 0, isExplicit ? asIC_EXPLICIT_REF_CAST : asIC_IMPLICIT_CONV, generateCode);
  3036. }
  3037. if( isExplicit )
  3038. {
  3039. // Allow dynamic cast between object handles (only for script objects).
  3040. // At run time this may result in a null handle,
  3041. // which when used will throw an exception
  3042. conversionDone = true;
  3043. if( generateCode )
  3044. {
  3045. ctx->bc.InstrDWORD(asBC_Cast, engine->GetTypeIdFromDataType(to));
  3046. // Allocate a temporary variable for the returned object
  3047. int returnOffset = AllocateVariable(to, true);
  3048. // Move the pointer from the object register to the temporary variable
  3049. ctx->bc.InstrSHORT(asBC_STOREOBJ, (short)returnOffset);
  3050. ctx->bc.InstrSHORT(asBC_PSF, (short)returnOffset);
  3051. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3052. ctx->type.SetVariable(to, returnOffset, true);
  3053. ctx->type.dataType.MakeReference(true);
  3054. }
  3055. else
  3056. {
  3057. ctx->type.dataType = to;
  3058. ctx->type.dataType.MakeReference(true);
  3059. }
  3060. }
  3061. else
  3062. {
  3063. if( ctx->type.dataType.GetObjectType()->DerivesFrom(to.GetObjectType()) )
  3064. {
  3065. conversionDone = true;
  3066. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3067. }
  3068. }
  3069. }
  3070. else
  3071. {
  3072. // Find a suitable registered behaviour
  3073. asSTypeBehaviour *beh = &ctx->type.dataType.GetObjectType()->beh;
  3074. for( n = 0; n < beh->operators.GetLength(); n+= 2 )
  3075. {
  3076. if( (isExplicit && asBEHAVE_REF_CAST == beh->operators[n]) ||
  3077. asBEHAVE_IMPLICIT_REF_CAST == beh->operators[n] )
  3078. {
  3079. int funcId = beh->operators[n+1];
  3080. // Is the operator for the output type?
  3081. asCScriptFunction *func = engine->scriptFunctions[funcId];
  3082. if( func->returnType.GetObjectType() != to.GetObjectType() )
  3083. continue;
  3084. ops.PushLast(funcId);
  3085. }
  3086. }
  3087. // Should only have one behaviour for each output type
  3088. if( ops.GetLength() == 1 )
  3089. {
  3090. if( generateCode )
  3091. {
  3092. // TODO: optimize: Instead of producing bytecode for checking if the handle is
  3093. // null, we can create a special CALLSYS instruction that checks
  3094. // if the object pointer is null and if so sets the object register
  3095. // to null directly without executing the function.
  3096. //
  3097. // Alternatively I could force the ref cast behaviours be global
  3098. // functions with 1 parameter, even though they should still be
  3099. // registered with RegisterObjectBehaviour()
  3100. // Add code to avoid calling the cast behaviour if the handle is already null,
  3101. // because that will raise a null pointer exception due to the cast behaviour
  3102. // being a class method, and the this pointer cannot be null.
  3103. if( ctx->type.isVariable )
  3104. ctx->bc.Pop(AS_PTR_SIZE);
  3105. else
  3106. {
  3107. Dereference(ctx, true);
  3108. ConvertToVariable(ctx);
  3109. }
  3110. #ifdef AS_64BIT_PTR
  3111. int offset = AllocateVariable(asCDataType::CreatePrimitive(ttUInt64, false), true);
  3112. ctx->bc.InstrW_QW(asBC_SetV8, offset, 0);
  3113. ctx->bc.InstrW_W(asBC_CMPi64, ctx->type.stackOffset, offset);
  3114. DeallocateVariable(offset);
  3115. #else
  3116. int offset = AllocateVariable(asCDataType::CreatePrimitive(ttUInt, false), true);
  3117. ctx->bc.InstrW_DW(asBC_SetV4, (asWORD)offset, 0);
  3118. ctx->bc.InstrW_W(asBC_CMPi, ctx->type.stackOffset, offset);
  3119. DeallocateVariable(offset);
  3120. #endif
  3121. int afterLabel = nextLabel++;
  3122. ctx->bc.InstrDWORD(asBC_JZ, afterLabel);
  3123. // Call the cast operator
  3124. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  3125. ctx->bc.Instr(asBC_RDSPTR);
  3126. ctx->type.dataType.MakeReference(false);
  3127. asCTypeInfo objType = ctx->type;
  3128. asCArray<asSExprContext *> args;
  3129. MakeFunctionCall(ctx, ops[0], objType.dataType.GetObjectType(), args, node);
  3130. ctx->bc.Pop(AS_PTR_SIZE);
  3131. int endLabel = nextLabel++;
  3132. ctx->bc.InstrINT(asBC_JMP, endLabel);
  3133. ctx->bc.Label((short)afterLabel);
  3134. // Make a NULL pointer
  3135. #ifdef AS_64BIT_PTR
  3136. ctx->bc.InstrW_QW(asBC_SetV8, ctx->type.stackOffset, 0);
  3137. #else
  3138. ctx->bc.InstrW_DW(asBC_SetV4, ctx->type.stackOffset, 0);
  3139. #endif
  3140. ctx->bc.Label((short)endLabel);
  3141. // Since we're receiving a handle, we can release the original variable
  3142. ReleaseTemporaryVariable(objType, &ctx->bc);
  3143. // Push the reference to the handle on the stack
  3144. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  3145. }
  3146. else
  3147. {
  3148. asCScriptFunction *func = engine->scriptFunctions[ops[0]];
  3149. ctx->type.Set(func->returnType);
  3150. }
  3151. }
  3152. else if( ops.GetLength() > 1 )
  3153. {
  3154. // It shouldn't be possible to have more than one, should it?
  3155. asASSERT( false );
  3156. }
  3157. }
  3158. return conversionDone;
  3159. }
  3160. void asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const asCDataType &toOrig, asCScriptNode *node, EImplicitConv convType, bool generateCode, asCArray<int> *reservedVars)
  3161. {
  3162. asCDataType to = toOrig;
  3163. to.MakeReference(false);
  3164. asASSERT( !ctx->type.dataType.IsReference() );
  3165. // Start by implicitly converting constant values
  3166. if( ctx->type.isConstant )
  3167. ImplicitConversionConstant(ctx, to, node, convType);
  3168. // A primitive is const or not
  3169. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  3170. if( to == ctx->type.dataType )
  3171. return;
  3172. // Allow implicit conversion between numbers
  3173. if( generateCode )
  3174. {
  3175. // Convert smaller types to 32bit first
  3176. int s = ctx->type.dataType.GetSizeInMemoryBytes();
  3177. if( s < 4 )
  3178. {
  3179. ConvertToTempVariableNotIn(ctx, reservedVars);
  3180. if( ctx->type.dataType.IsIntegerType() )
  3181. {
  3182. if( s == 1 )
  3183. ctx->bc.InstrSHORT(asBC_sbTOi, ctx->type.stackOffset);
  3184. else if( s == 2 )
  3185. ctx->bc.InstrSHORT(asBC_swTOi, ctx->type.stackOffset);
  3186. ctx->type.dataType.SetTokenType(ttInt);
  3187. }
  3188. else if( ctx->type.dataType.IsUnsignedType() )
  3189. {
  3190. if( s == 1 )
  3191. ctx->bc.InstrSHORT(asBC_ubTOi, ctx->type.stackOffset);
  3192. else if( s == 2 )
  3193. ctx->bc.InstrSHORT(asBC_uwTOi, ctx->type.stackOffset);
  3194. ctx->type.dataType.SetTokenType(ttUInt);
  3195. }
  3196. }
  3197. if( (to.IsIntegerType() && to.GetSizeInMemoryDWords() == 1) ||
  3198. (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST) )
  3199. {
  3200. if( ctx->type.dataType.IsIntegerType() ||
  3201. ctx->type.dataType.IsUnsignedType() ||
  3202. ctx->type.dataType.IsEnumType() )
  3203. {
  3204. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  3205. {
  3206. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3207. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3208. }
  3209. else
  3210. {
  3211. ConvertToTempVariableNotIn(ctx, reservedVars);
  3212. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3213. int offset = AllocateVariableNotIn(to, true, reservedVars);
  3214. ctx->bc.InstrW_W(asBC_i64TOi, offset, ctx->type.stackOffset);
  3215. ctx->type.SetVariable(to, offset, true);
  3216. }
  3217. }
  3218. else if( ctx->type.dataType.IsFloatType() )
  3219. {
  3220. ConvertToTempVariableNotIn(ctx, reservedVars);
  3221. ctx->bc.InstrSHORT(asBC_fTOi, ctx->type.stackOffset);
  3222. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3223. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3224. }
  3225. else if( ctx->type.dataType.IsDoubleType() )
  3226. {
  3227. ConvertToTempVariableNotIn(ctx, reservedVars);
  3228. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3229. int offset = AllocateVariableNotIn(to, true, reservedVars);
  3230. ctx->bc.InstrW_W(asBC_dTOi, offset, ctx->type.stackOffset);
  3231. ctx->type.SetVariable(to, offset, true);
  3232. }
  3233. // Convert to smaller integer if necessary
  3234. int s = to.GetSizeInMemoryBytes();
  3235. if( s < 4 )
  3236. {
  3237. ConvertToTempVariableNotIn(ctx, reservedVars);
  3238. if( s == 1 )
  3239. ctx->bc.InstrSHORT(asBC_iTOb, ctx->type.stackOffset);
  3240. else if( s == 2 )
  3241. ctx->bc.InstrSHORT(asBC_iTOw, ctx->type.stackOffset);
  3242. }
  3243. }
  3244. if( to.IsIntegerType() && to.GetSizeInMemoryDWords() == 2 )
  3245. {
  3246. if( ctx->type.dataType.IsIntegerType() ||
  3247. ctx->type.dataType.IsUnsignedType() ||
  3248. ctx->type.dataType.IsEnumType() )
  3249. {
  3250. if( ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  3251. {
  3252. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3253. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3254. }
  3255. else
  3256. {
  3257. ConvertToTempVariableNotIn(ctx, reservedVars);
  3258. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3259. int offset = AllocateVariableNotIn(to, true, reservedVars);
  3260. if( ctx->type.dataType.IsUnsignedType() )
  3261. ctx->bc.InstrW_W(asBC_uTOi64, offset, ctx->type.stackOffset);
  3262. else
  3263. ctx->bc.InstrW_W(asBC_iTOi64, offset, ctx->type.stackOffset);
  3264. ctx->type.SetVariable(to, offset, true);
  3265. }
  3266. }
  3267. else if( ctx->type.dataType.IsFloatType() )
  3268. {
  3269. ConvertToTempVariableNotIn(ctx, reservedVars);
  3270. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3271. int offset = AllocateVariableNotIn(to, true, reservedVars);
  3272. ctx->bc.InstrW_W(asBC_fTOi64, offset, ctx->type.stackOffset);
  3273. ctx->type.SetVariable(to, offset, true);
  3274. }
  3275. else if( ctx->type.dataType.IsDoubleType() )
  3276. {
  3277. ConvertToTempVariableNotIn(ctx, reservedVars);
  3278. ctx->bc.InstrSHORT(asBC_dTOi64, ctx->type.stackOffset);
  3279. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3280. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3281. }
  3282. }
  3283. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 1 )
  3284. {
  3285. if( ctx->type.dataType.IsIntegerType() ||
  3286. ctx->type.dataType.IsUnsignedType() ||
  3287. ctx->type.dataType.IsEnumType() )
  3288. {
  3289. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  3290. {
  3291. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3292. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3293. }
  3294. else
  3295. {
  3296. ConvertToTempVariableNotIn(ctx, reservedVars);
  3297. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3298. int offset = AllocateVariableNotIn(to, true, reservedVars);
  3299. ctx->bc.InstrW_W(asBC_i64TOi, offset, ctx->type.stackOffset);
  3300. ctx->type.SetVariable(to, offset, true);
  3301. }
  3302. }
  3303. else if( ctx->type.dataType.IsFloatType() )
  3304. {
  3305. ConvertToTempVariableNotIn(ctx, reservedVars);
  3306. ctx->bc.InstrSHORT(asBC_fTOu, ctx->type.stackOffset);
  3307. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3308. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3309. }
  3310. else if( ctx->type.dataType.IsDoubleType() )
  3311. {
  3312. ConvertToTempVariableNotIn(ctx, reservedVars);
  3313. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3314. int offset = AllocateVariableNotIn(to, true, reservedVars);
  3315. ctx->bc.InstrW_W(asBC_dTOu, offset, ctx->type.stackOffset);
  3316. ctx->type.SetVariable(to, offset, true);
  3317. }
  3318. // Convert to smaller integer if necessary
  3319. int s = to.GetSizeInMemoryBytes();
  3320. if( s < 4 )
  3321. {
  3322. ConvertToTempVariableNotIn(ctx, reservedVars);
  3323. if( s == 1 )
  3324. ctx->bc.InstrSHORT(asBC_iTOb, ctx->type.stackOffset);
  3325. else if( s == 2 )
  3326. ctx->bc.InstrSHORT(asBC_iTOw, ctx->type.stackOffset);
  3327. }
  3328. }
  3329. if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 2 )
  3330. {
  3331. if( ctx->type.dataType.IsIntegerType() ||
  3332. ctx->type.dataType.IsUnsignedType() ||
  3333. ctx->type.dataType.IsEnumType() )
  3334. {
  3335. if( ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  3336. {
  3337. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3338. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3339. }
  3340. else
  3341. {
  3342. ConvertToTempVariableNotIn(ctx, reservedVars);
  3343. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3344. int offset = AllocateVariableNotIn(to, true, reservedVars);
  3345. if( ctx->type.dataType.IsUnsignedType() )
  3346. ctx->bc.InstrW_W(asBC_uTOi64, offset, ctx->type.stackOffset);
  3347. else
  3348. ctx->bc.InstrW_W(asBC_iTOi64, offset, ctx->type.stackOffset);
  3349. ctx->type.SetVariable(to, offset, true);
  3350. }
  3351. }
  3352. else if( ctx->type.dataType.IsFloatType() )
  3353. {
  3354. ConvertToTempVariableNotIn(ctx, reservedVars);
  3355. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3356. int offset = AllocateVariableNotIn(to, true, reservedVars);
  3357. ctx->bc.InstrW_W(asBC_fTOu64, offset, ctx->type.stackOffset);
  3358. ctx->type.SetVariable(to, offset, true);
  3359. }
  3360. else if( ctx->type.dataType.IsDoubleType() )
  3361. {
  3362. ConvertToTempVariableNotIn(ctx, reservedVars);
  3363. ctx->bc.InstrSHORT(asBC_dTOu64, ctx->type.stackOffset);
  3364. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3365. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3366. }
  3367. }
  3368. else if( to.IsFloatType() )
  3369. {
  3370. if( (ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsEnumType()) && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  3371. {
  3372. ConvertToTempVariableNotIn(ctx, reservedVars);
  3373. ctx->bc.InstrSHORT(asBC_iTOf, ctx->type.stackOffset);
  3374. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3375. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3376. }
  3377. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  3378. {
  3379. ConvertToTempVariableNotIn(ctx, reservedVars);
  3380. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3381. int offset = AllocateVariableNotIn(to, true, reservedVars);
  3382. ctx->bc.InstrW_W(asBC_i64TOf, offset, ctx->type.stackOffset);
  3383. ctx->type.SetVariable(to, offset, true);
  3384. }
  3385. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  3386. {
  3387. ConvertToTempVariableNotIn(ctx, reservedVars);
  3388. ctx->bc.InstrSHORT(asBC_uTOf, ctx->type.stackOffset);
  3389. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3390. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3391. }
  3392. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  3393. {
  3394. ConvertToTempVariableNotIn(ctx, reservedVars);
  3395. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3396. int offset = AllocateVariableNotIn(to, true, reservedVars);
  3397. ctx->bc.InstrW_W(asBC_u64TOf, offset, ctx->type.stackOffset);
  3398. ctx->type.SetVariable(to, offset, true);
  3399. }
  3400. else if( ctx->type.dataType.IsDoubleType() )
  3401. {
  3402. ConvertToTempVariableNotIn(ctx, reservedVars);
  3403. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3404. int offset = AllocateVariableNotIn(to, true, reservedVars);
  3405. ctx->bc.InstrW_W(asBC_dTOf, offset, ctx->type.stackOffset);
  3406. ctx->type.SetVariable(to, offset, true);
  3407. }
  3408. }
  3409. else if( to.IsDoubleType() )
  3410. {
  3411. if( (ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsEnumType()) && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  3412. {
  3413. ConvertToTempVariableNotIn(ctx, reservedVars);
  3414. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3415. int offset = AllocateVariableNotIn(to, true, reservedVars);
  3416. ctx->bc.InstrW_W(asBC_iTOd, offset, ctx->type.stackOffset);
  3417. ctx->type.SetVariable(to, offset, true);
  3418. }
  3419. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  3420. {
  3421. ConvertToTempVariableNotIn(ctx, reservedVars);
  3422. ctx->bc.InstrSHORT(asBC_i64TOd, ctx->type.stackOffset);
  3423. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3424. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3425. }
  3426. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  3427. {
  3428. ConvertToTempVariableNotIn(ctx, reservedVars);
  3429. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3430. int offset = AllocateVariableNotIn(to, true, reservedVars);
  3431. ctx->bc.InstrW_W(asBC_uTOd, offset, ctx->type.stackOffset);
  3432. ctx->type.SetVariable(to, offset, true);
  3433. }
  3434. else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  3435. {
  3436. ConvertToTempVariableNotIn(ctx, reservedVars);
  3437. ctx->bc.InstrSHORT(asBC_u64TOd, ctx->type.stackOffset);
  3438. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3439. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3440. }
  3441. else if( ctx->type.dataType.IsFloatType() )
  3442. {
  3443. ConvertToTempVariableNotIn(ctx, reservedVars);
  3444. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  3445. int offset = AllocateVariableNotIn(to, true, reservedVars);
  3446. ctx->bc.InstrW_W(asBC_fTOd, offset, ctx->type.stackOffset);
  3447. ctx->type.SetVariable(to, offset, true);
  3448. }
  3449. }
  3450. }
  3451. else
  3452. {
  3453. if( (to.IsIntegerType() || to.IsUnsignedType() ||
  3454. to.IsFloatType() || to.IsDoubleType() ||
  3455. (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST)) &&
  3456. (ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType() ||
  3457. ctx->type.dataType.IsFloatType() || ctx->type.dataType.IsDoubleType() ||
  3458. ctx->type.dataType.IsEnumType()) )
  3459. {
  3460. ctx->type.dataType.SetTokenType(to.GetTokenType());
  3461. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3462. }
  3463. }
  3464. // Primitive types on the stack, can be const or non-const
  3465. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  3466. }
  3467. void asCCompiler::ImplicitConversion(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode, asCArray<int> *reservedVars, bool allowObjectConstruct)
  3468. {
  3469. asASSERT( ctx->type.dataType.GetTokenType() != ttUnrecognizedToken ||
  3470. ctx->type.dataType.IsNullHandle() );
  3471. // No conversion from void to any other type
  3472. if( ctx->type.dataType.GetTokenType() == ttVoid )
  3473. return;
  3474. // Do we want a var type?
  3475. if( to.GetTokenType() == ttQuestion )
  3476. {
  3477. // Any type can be converted to a var type, but only when not generating code
  3478. asASSERT( !generateCode );
  3479. ctx->type.dataType = to;
  3480. return;
  3481. }
  3482. // Do we want a primitive?
  3483. else if( to.IsPrimitive() )
  3484. {
  3485. if( !ctx->type.dataType.IsPrimitive() )
  3486. ImplicitConvObjectToPrimitive(ctx, to, node, convType, generateCode, reservedVars);
  3487. else
  3488. ImplicitConvPrimitiveToPrimitive(ctx, to, node, convType, generateCode, reservedVars);
  3489. }
  3490. else // The target is a complex type
  3491. {
  3492. if( ctx->type.dataType.IsPrimitive() )
  3493. ImplicitConvPrimitiveToObject(ctx, to, node, convType, generateCode, reservedVars, allowObjectConstruct);
  3494. else
  3495. ImplicitConvObjectToObject(ctx, to, node, convType, generateCode, reservedVars, allowObjectConstruct);
  3496. }
  3497. }
  3498. void asCCompiler::ImplicitConvObjectToPrimitive(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode, asCArray<int> *reservedVars)
  3499. {
  3500. if( ctx->type.isExplicitHandle )
  3501. {
  3502. // An explicit handle cannot be converted to a primitive
  3503. if( convType != asIC_IMPLICIT_CONV && node )
  3504. {
  3505. asCString str;
  3506. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  3507. Error(str.AddressOf(), node);
  3508. }
  3509. return;
  3510. }
  3511. // TODO: Must use the const cast behaviour if the object is read-only
  3512. // Find matching value cast behaviours
  3513. // Here we're only interested in those that convert the type to a primitive type
  3514. asCArray<int> funcs;
  3515. asSTypeBehaviour *beh = ctx->type.dataType.GetBehaviour();
  3516. if( beh )
  3517. {
  3518. if( convType == asIC_EXPLICIT_VAL_CAST )
  3519. {
  3520. for( unsigned int n = 0; n < beh->operators.GetLength(); n += 2 )
  3521. {
  3522. // accept both implicit and explicit cast
  3523. if( (beh->operators[n] == asBEHAVE_VALUE_CAST ||
  3524. beh->operators[n] == asBEHAVE_IMPLICIT_VALUE_CAST) &&
  3525. builder->GetFunctionDescription(beh->operators[n+1])->returnType.IsPrimitive() )
  3526. funcs.PushLast(beh->operators[n+1]);
  3527. }
  3528. }
  3529. else
  3530. {
  3531. for( unsigned int n = 0; n < beh->operators.GetLength(); n += 2 )
  3532. {
  3533. // accept only implicit cast
  3534. if( beh->operators[n] == asBEHAVE_IMPLICIT_VALUE_CAST &&
  3535. builder->GetFunctionDescription(beh->operators[n+1])->returnType.IsPrimitive() )
  3536. funcs.PushLast(beh->operators[n+1]);
  3537. }
  3538. }
  3539. }
  3540. // This matrix describes the priorities of the types to search for, for each target type
  3541. // The first column is the target type, the priorities goes from left to right
  3542. eTokenType matchMtx[10][10] =
  3543. {
  3544. {ttDouble, ttFloat, ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8},
  3545. {ttFloat, ttDouble, ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8},
  3546. {ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8, ttDouble, ttFloat},
  3547. {ttUInt64, ttInt64, ttUInt, ttInt, ttUInt16, ttInt16, ttUInt8, ttInt8, ttDouble, ttFloat},
  3548. {ttInt, ttUInt, ttInt64, ttUInt64, ttInt16, ttUInt16, ttInt8, ttUInt8, ttDouble, ttFloat},
  3549. {ttUInt, ttInt, ttUInt64, ttInt64, ttUInt16, ttInt16, ttUInt8, ttInt8, ttDouble, ttFloat},
  3550. {ttInt16, ttUInt16, ttInt, ttUInt, ttInt64, ttUInt64, ttInt8, ttUInt8, ttDouble, ttFloat},
  3551. {ttUInt16, ttInt16, ttUInt, ttInt, ttUInt64, ttInt64, ttUInt8, ttInt8, ttDouble, ttFloat},
  3552. {ttInt8, ttUInt8, ttInt16, ttUInt16, ttInt, ttUInt, ttInt64, ttUInt64, ttDouble, ttFloat},
  3553. {ttUInt8, ttInt8, ttUInt16, ttInt16, ttUInt, ttInt, ttUInt64, ttInt64, ttDouble, ttFloat},
  3554. };
  3555. // Which row to use?
  3556. eTokenType *row = 0;
  3557. for( unsigned int type = 0; type < 10; type++ )
  3558. {
  3559. if( to.GetTokenType() == matchMtx[type][0] )
  3560. {
  3561. row = &matchMtx[type][0];
  3562. break;
  3563. }
  3564. }
  3565. // Find the best matching cast operator
  3566. int funcId = 0;
  3567. if( row )
  3568. {
  3569. asCDataType target(to);
  3570. // Priority goes from left to right in the matrix
  3571. for( unsigned int attempt = 0; attempt < 10 && funcId == 0; attempt++ )
  3572. {
  3573. target.SetTokenType(row[attempt]);
  3574. for( unsigned int n = 0; n < funcs.GetLength(); n++ )
  3575. {
  3576. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[n]);
  3577. if( descr->returnType.IsEqualExceptConst(target) )
  3578. {
  3579. funcId = funcs[n];
  3580. break;
  3581. }
  3582. }
  3583. }
  3584. }
  3585. // Did we find a suitable function?
  3586. if( funcId != 0 )
  3587. {
  3588. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  3589. if( generateCode )
  3590. {
  3591. asCTypeInfo objType = ctx->type;
  3592. Dereference(ctx, true);
  3593. PerformFunctionCall(funcId, ctx);
  3594. ReleaseTemporaryVariable(objType, &ctx->bc);
  3595. }
  3596. else
  3597. ctx->type.Set(descr->returnType);
  3598. // Allow one more implicit conversion to another primitive type
  3599. ImplicitConversion(ctx, to, node, convType, generateCode, reservedVars, false);
  3600. }
  3601. else
  3602. {
  3603. if( convType != asIC_IMPLICIT_CONV && node )
  3604. {
  3605. asCString str;
  3606. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  3607. Error(str.AddressOf(), node);
  3608. }
  3609. }
  3610. }
  3611. void asCCompiler::ImplicitConvObjectToObject(asSExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode, asCArray<int> *reservedVars, bool allowObjectConstruct)
  3612. {
  3613. // Convert null to any object type handle, but not to a non-handle type
  3614. if( ctx->type.IsNullConstant() )
  3615. {
  3616. if( to.IsObjectHandle() )
  3617. ctx->type.dataType = to;
  3618. return;
  3619. }
  3620. // First attempt to convert the base type without instanciating another instance
  3621. if( to.GetObjectType() != ctx->type.dataType.GetObjectType() )
  3622. {
  3623. // If the to type is an interface and the from type implements it, then we can convert it immediately
  3624. if( ctx->type.dataType.GetObjectType()->Implements(to.GetObjectType()) )
  3625. {
  3626. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3627. }
  3628. // If the to type is a class and the from type derives from it, then we can convert it immediately
  3629. if( ctx->type.dataType.GetObjectType()->DerivesFrom(to.GetObjectType()) )
  3630. {
  3631. ctx->type.dataType.SetObjectType(to.GetObjectType());
  3632. }
  3633. // If the types are not equal yet, then we may still be able to find a reference cast
  3634. if( ctx->type.dataType.GetObjectType() != to.GetObjectType() )
  3635. {
  3636. // A ref cast must not remove the constness
  3637. bool isConst = false;
  3638. if( (ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsHandleToConst()) ||
  3639. (!ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReadOnly()) )
  3640. isConst = true;
  3641. // We may still be able to find an implicit ref cast behaviour
  3642. CompileRefCast(ctx, to, convType == asIC_EXPLICIT_REF_CAST, node, generateCode);
  3643. ctx->type.dataType.MakeHandleToConst(isConst);
  3644. }
  3645. }
  3646. // If the base type is still different, and we are allowed to instance
  3647. // another object then we can try an implicit value cast
  3648. if( to.GetObjectType() != ctx->type.dataType.GetObjectType() && allowObjectConstruct )
  3649. {
  3650. // TODO: Implement support for implicit constructor/factory
  3651. asCArray<int> funcs;
  3652. asSTypeBehaviour *beh = ctx->type.dataType.GetBehaviour();
  3653. if( beh )
  3654. {
  3655. if( convType == asIC_EXPLICIT_VAL_CAST )
  3656. {
  3657. for( unsigned int n = 0; n < beh->operators.GetLength(); n += 2 )
  3658. {
  3659. // accept both implicit and explicit cast
  3660. if( (beh->operators[n] == asBEHAVE_VALUE_CAST ||
  3661. beh->operators[n] == asBEHAVE_IMPLICIT_VALUE_CAST) &&
  3662. builder->GetFunctionDescription(beh->operators[n+1])->returnType.GetObjectType() == to.GetObjectType() )
  3663. funcs.PushLast(beh->operators[n+1]);
  3664. }
  3665. }
  3666. else
  3667. {
  3668. for( unsigned int n = 0; n < beh->operators.GetLength(); n += 2 )
  3669. {
  3670. // accept only implicit cast
  3671. if( beh->operators[n] == asBEHAVE_IMPLICIT_VALUE_CAST &&
  3672. builder->GetFunctionDescription(beh->operators[n+1])->returnType.GetObjectType() == to.GetObjectType() )
  3673. funcs.PushLast(beh->operators[n+1]);
  3674. }
  3675. }
  3676. }
  3677. // TODO: If there are multiple valid value casts, then we must choose the most appropriate one
  3678. asASSERT( funcs.GetLength() <= 1 );
  3679. if( funcs.GetLength() == 1 )
  3680. {
  3681. asCScriptFunction *f = builder->GetFunctionDescription(funcs[0]);
  3682. if( generateCode )
  3683. {
  3684. asCTypeInfo objType = ctx->type;
  3685. Dereference(ctx, true);
  3686. PerformFunctionCall(funcs[0], ctx);
  3687. ReleaseTemporaryVariable(objType, &ctx->bc);
  3688. }
  3689. else
  3690. ctx->type.Set(f->returnType);
  3691. }
  3692. }
  3693. // If we still haven't converted the base type to the correct type, then there is no need to continue
  3694. if( to.GetObjectType() != ctx->type.dataType.GetObjectType() )
  3695. return;
  3696. // Convert matching function types
  3697. if( to.GetFuncDef() && ctx->type.dataType.GetFuncDef() &&
  3698. to.GetFuncDef() != ctx->type.dataType.GetFuncDef() )
  3699. {
  3700. asCScriptFunction *toFunc = to.GetFuncDef();
  3701. asCScriptFunction *fromFunc = ctx->type.dataType.GetFuncDef();
  3702. if( toFunc->IsSignatureExceptNameEqual(fromFunc) )
  3703. {
  3704. ctx->type.dataType.SetFuncDef(toFunc);
  3705. }
  3706. }
  3707. if( to.IsObjectHandle() )
  3708. {
  3709. // reference to handle -> handle
  3710. // reference -> handle
  3711. // object -> handle
  3712. // handle -> reference to handle
  3713. // reference -> reference to handle
  3714. // object -> reference to handle
  3715. // TODO: If the type is handle, then we can't use IsReadOnly to determine the constness of the basetype
  3716. // If the rvalue is a handle to a const object, then
  3717. // the lvalue must also be a handle to a const object
  3718. if( ctx->type.dataType.IsReadOnly() && !to.IsReadOnly() )
  3719. {
  3720. if( convType != asIC_IMPLICIT_CONV )
  3721. {
  3722. asASSERT(node);
  3723. asCString str;
  3724. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  3725. Error(str.AddressOf(), node);
  3726. }
  3727. }
  3728. if( !ctx->type.dataType.IsObjectHandle() )
  3729. {
  3730. // An object type can be directly converted to a handle of the same type
  3731. if( ctx->type.dataType.SupportHandles() )
  3732. {
  3733. ctx->type.dataType.MakeHandle(true);
  3734. }
  3735. if( ctx->type.dataType.IsObjectHandle() )
  3736. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  3737. if( to.IsHandleToConst() && ctx->type.dataType.IsObjectHandle() )
  3738. ctx->type.dataType.MakeHandleToConst(true);
  3739. }
  3740. else
  3741. {
  3742. // A handle to non-const can be converted to a
  3743. // handle to const, but not the other way
  3744. if( to.IsHandleToConst() )
  3745. ctx->type.dataType.MakeHandleToConst(true);
  3746. // A const handle can be converted to a non-const
  3747. // handle and vice versa as the handle is just a value
  3748. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  3749. }
  3750. if( to.IsReference() && !ctx->type.dataType.IsReference() )
  3751. {
  3752. if( generateCode )
  3753. {
  3754. // If the input type is a handle, then a simple ref copy is enough
  3755. bool isExplicitHandle = ctx->type.isExplicitHandle;
  3756. ctx->type.isExplicitHandle = ctx->type.dataType.IsObjectHandle();
  3757. // If the input type is read-only we'll need to temporarily
  3758. // remove this constness, otherwise the assignment will fail
  3759. bool typeIsReadOnly = ctx->type.dataType.IsReadOnly();
  3760. ctx->type.dataType.MakeReadOnly(false);
  3761. // If the object already is a temporary variable, then the copy
  3762. // doesn't have to be made as it is already a unique object
  3763. PrepareTemporaryObject(node, ctx, reservedVars);
  3764. ctx->type.dataType.MakeReadOnly(typeIsReadOnly);
  3765. ctx->type.isExplicitHandle = isExplicitHandle;
  3766. }
  3767. // A non-reference can be converted to a reference,
  3768. // by putting the value in a temporary variable
  3769. ctx->type.dataType.MakeReference(true);
  3770. // Since it is a new temporary variable it doesn't have to be const
  3771. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  3772. }
  3773. else if( !to.IsReference() && ctx->type.dataType.IsReference() )
  3774. {
  3775. Dereference(ctx, generateCode);
  3776. }
  3777. }
  3778. else
  3779. {
  3780. if( !to.IsReference() )
  3781. {
  3782. // reference to handle -> object
  3783. // handle -> object
  3784. // reference -> object
  3785. // An implicit handle can be converted to an object by adding a check for null pointer
  3786. if( ctx->type.dataType.IsObjectHandle() && !ctx->type.isExplicitHandle )
  3787. {
  3788. if( generateCode )
  3789. ctx->bc.Instr(asBC_CHKREF);
  3790. ctx->type.dataType.MakeHandle(false);
  3791. }
  3792. // A const object can be converted to a non-const object through a copy
  3793. if( ctx->type.dataType.IsReadOnly() && !to.IsReadOnly() &&
  3794. allowObjectConstruct )
  3795. {
  3796. // Does the object type allow a copy to be made?
  3797. if( ctx->type.dataType.CanBeCopied() )
  3798. {
  3799. if( generateCode )
  3800. {
  3801. // Make a temporary object with the copy
  3802. PrepareTemporaryObject(node, ctx, reservedVars);
  3803. }
  3804. // In case the object was already in a temporary variable, then the function
  3805. // didn't really do anything so we need to remove the constness here
  3806. ctx->type.dataType.MakeReadOnly(false);
  3807. }
  3808. }
  3809. if( ctx->type.dataType.IsReference() )
  3810. {
  3811. Dereference(ctx, generateCode);
  3812. // TODO: Can't this leave unhandled deferred output params?
  3813. }
  3814. // A non-const object can be converted to a const object directly
  3815. if( !ctx->type.dataType.IsReadOnly() && to.IsReadOnly() )
  3816. {
  3817. ctx->type.dataType.MakeReadOnly(true);
  3818. }
  3819. }
  3820. else
  3821. {
  3822. // reference to handle -> reference
  3823. // handle -> reference
  3824. // object -> reference
  3825. if( ctx->type.dataType.IsReference() )
  3826. {
  3827. // A reference to a handle can be converted to a reference to an object
  3828. // by first reading the address, then verifying that it is not null, then putting the address back on the stack
  3829. if( !to.IsObjectHandle() && ctx->type.dataType.IsObjectHandle() && !ctx->type.isExplicitHandle )
  3830. {
  3831. ctx->type.dataType.MakeHandle(false);
  3832. if( generateCode )
  3833. ctx->bc.Instr(asBC_ChkRefS);
  3834. }
  3835. // A reference to a non-const can be converted to a reference to a const
  3836. if( to.IsReadOnly() )
  3837. ctx->type.dataType.MakeReadOnly(true);
  3838. else if( ctx->type.dataType.IsReadOnly() )
  3839. {
  3840. // A reference to a const can be converted to a reference to a
  3841. // non-const by copying the object to a temporary variable
  3842. ctx->type.dataType.MakeReadOnly(false);
  3843. if( generateCode )
  3844. {
  3845. // If the object already is a temporary variable, then the copy
  3846. // doesn't have to be made as it is already a unique object
  3847. PrepareTemporaryObject(node, ctx, reservedVars);
  3848. }
  3849. }
  3850. }
  3851. else
  3852. {
  3853. // A value type allocated on the stack is differentiated
  3854. // by it not being a reference. But it can be handled as
  3855. // reference by pushing the pointer on the stack
  3856. if( (ctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_VALUE) &&
  3857. (ctx->type.isVariable || ctx->type.isTemporary) &&
  3858. !IsVariableOnHeap(ctx->type.stackOffset) )
  3859. {
  3860. // Actually the pointer is already pushed on the stack in
  3861. // CompileVariableAccess, so we don't need to do anything else
  3862. }
  3863. else if( generateCode )
  3864. {
  3865. // A non-reference can be converted to a reference,
  3866. // by putting the value in a temporary variable
  3867. // If the input type is read-only we'll need to temporarily
  3868. // remove this constness, otherwise the assignment will fail
  3869. bool typeIsReadOnly = ctx->type.dataType.IsReadOnly();
  3870. ctx->type.dataType.MakeReadOnly(false);
  3871. // If the object already is a temporary variable, then the copy
  3872. // doesn't have to be made as it is already a unique object
  3873. PrepareTemporaryObject(node, ctx, reservedVars);
  3874. ctx->type.dataType.MakeReadOnly(typeIsReadOnly);
  3875. }
  3876. // A handle can be converted to a reference, by checking for a null pointer
  3877. if( ctx->type.dataType.IsObjectHandle() )
  3878. {
  3879. if( generateCode )
  3880. ctx->bc.InstrSHORT(asBC_ChkNullV, ctx->type.stackOffset);
  3881. ctx->type.dataType.MakeHandle(false);
  3882. ctx->type.dataType.MakeReference(true);
  3883. // TODO: Make sure a handle to const isn't converted to non-const reference
  3884. }
  3885. else
  3886. {
  3887. // This may look strange as the conversion was to make the expression a reference
  3888. // but a value type allocated on the stack is a reference even without the type
  3889. // being marked as such.
  3890. ctx->type.dataType.MakeReference(IsVariableOnHeap(ctx->type.stackOffset));
  3891. }
  3892. // TODO: If the variable is an object allocated on the stack, this is not true
  3893. // Since it is a new temporary variable it doesn't have to be const
  3894. ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
  3895. }
  3896. }
  3897. }
  3898. }
  3899. void asCCompiler::ImplicitConvPrimitiveToObject(asSExprContext * /*ctx*/, const asCDataType & /*to*/, asCScriptNode * /*node*/, EImplicitConv /*isExplicit*/, bool /*generateCode*/, asCArray<int> * /*reservedVars*/, bool /*allowObjectConstruct*/)
  3900. {
  3901. // TODO: This function should call the constructor/factory that has been marked as available
  3902. // for implicit conversions. The code will likely be similar to CallCopyConstructor()
  3903. }
  3904. void asCCompiler::ImplicitConversionConstant(asSExprContext *from, const asCDataType &to, asCScriptNode *node, EImplicitConv convType)
  3905. {
  3906. asASSERT(from->type.isConstant);
  3907. // TODO: node should be the node of the value that is
  3908. // converted (not the operator that provokes the implicit
  3909. // conversion)
  3910. // If the base type is correct there is no more to do
  3911. if( to.IsEqualExceptRefAndConst(from->type.dataType) ) return;
  3912. // References cannot be constants
  3913. if( from->type.dataType.IsReference() ) return;
  3914. if( (to.IsIntegerType() && to.GetSizeInMemoryDWords() == 1) ||
  3915. (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST) )
  3916. {
  3917. if( from->type.dataType.IsFloatType() ||
  3918. from->type.dataType.IsDoubleType() ||
  3919. from->type.dataType.IsUnsignedType() ||
  3920. from->type.dataType.IsIntegerType() ||
  3921. from->type.dataType.IsEnumType() )
  3922. {
  3923. // Transform the value
  3924. // Float constants can be implicitly converted to int
  3925. if( from->type.dataType.IsFloatType() )
  3926. {
  3927. float fc = from->type.floatValue;
  3928. int ic = int(fc);
  3929. if( float(ic) != fc )
  3930. {
  3931. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  3932. }
  3933. from->type.intValue = ic;
  3934. }
  3935. // Double constants can be implicitly converted to int
  3936. else if( from->type.dataType.IsDoubleType() )
  3937. {
  3938. double fc = from->type.doubleValue;
  3939. int ic = int(fc);
  3940. if( double(ic) != fc )
  3941. {
  3942. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  3943. }
  3944. from->type.intValue = ic;
  3945. }
  3946. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  3947. {
  3948. // Verify that it is possible to convert to signed without getting negative
  3949. if( from->type.intValue < 0 )
  3950. {
  3951. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  3952. }
  3953. // Convert to 32bit
  3954. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  3955. from->type.intValue = from->type.byteValue;
  3956. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  3957. from->type.intValue = from->type.wordValue;
  3958. }
  3959. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  3960. {
  3961. // Convert to 32bit
  3962. from->type.intValue = int(from->type.qwordValue);
  3963. }
  3964. else if( from->type.dataType.IsIntegerType() &&
  3965. from->type.dataType.GetSizeInMemoryBytes() < 4 )
  3966. {
  3967. // Convert to 32bit
  3968. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  3969. from->type.intValue = (signed char)from->type.byteValue;
  3970. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  3971. from->type.intValue = (short)from->type.wordValue;
  3972. }
  3973. else if( from->type.dataType.IsEnumType() )
  3974. {
  3975. // Enum type is already an integer type
  3976. }
  3977. // Set the resulting type
  3978. if( to.IsEnumType() )
  3979. from->type.dataType = to;
  3980. else
  3981. from->type.dataType = asCDataType::CreatePrimitive(ttInt, true);
  3982. }
  3983. // Check if a downsize is necessary
  3984. if( to.IsIntegerType() &&
  3985. from->type.dataType.IsIntegerType() &&
  3986. from->type.dataType.GetSizeInMemoryBytes() > to.GetSizeInMemoryBytes() )
  3987. {
  3988. // Verify if it is possible
  3989. if( to.GetSizeInMemoryBytes() == 1 )
  3990. {
  3991. if( char(from->type.intValue) != from->type.intValue )
  3992. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  3993. from->type.byteValue = char(from->type.intValue);
  3994. }
  3995. else if( to.GetSizeInMemoryBytes() == 2 )
  3996. {
  3997. if( short(from->type.intValue) != from->type.intValue )
  3998. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  3999. from->type.wordValue = short(from->type.intValue);
  4000. }
  4001. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4002. }
  4003. }
  4004. else if( to.IsIntegerType() && to.GetSizeInMemoryDWords() == 2 )
  4005. {
  4006. // Float constants can be implicitly converted to int
  4007. if( from->type.dataType.IsFloatType() )
  4008. {
  4009. float fc = from->type.floatValue;
  4010. asINT64 ic = asINT64(fc);
  4011. if( float(ic) != fc )
  4012. {
  4013. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4014. }
  4015. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  4016. from->type.qwordValue = ic;
  4017. }
  4018. // Double constants can be implicitly converted to int
  4019. else if( from->type.dataType.IsDoubleType() )
  4020. {
  4021. double fc = from->type.doubleValue;
  4022. asINT64 ic = asINT64(fc);
  4023. if( double(ic) != fc )
  4024. {
  4025. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4026. }
  4027. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  4028. from->type.qwordValue = ic;
  4029. }
  4030. else if( from->type.dataType.IsUnsignedType() )
  4031. {
  4032. // Convert to 64bit
  4033. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4034. from->type.qwordValue = from->type.byteValue;
  4035. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4036. from->type.qwordValue = from->type.wordValue;
  4037. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  4038. from->type.qwordValue = from->type.dwordValue;
  4039. else if( from->type.dataType.GetSizeInMemoryBytes() == 8 )
  4040. {
  4041. if( asINT64(from->type.qwordValue) < 0 )
  4042. {
  4043. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  4044. }
  4045. }
  4046. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  4047. }
  4048. else if( from->type.dataType.IsEnumType() )
  4049. {
  4050. from->type.qwordValue = from->type.intValue;
  4051. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  4052. }
  4053. else if( from->type.dataType.IsIntegerType() )
  4054. {
  4055. // Convert to 64bit
  4056. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4057. from->type.qwordValue = (signed char)from->type.byteValue;
  4058. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4059. from->type.qwordValue = (short)from->type.wordValue;
  4060. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  4061. from->type.qwordValue = from->type.intValue;
  4062. from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true);
  4063. }
  4064. }
  4065. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 1 )
  4066. {
  4067. if( from->type.dataType.IsFloatType() )
  4068. {
  4069. float fc = from->type.floatValue;
  4070. asUINT uic = asUINT(fc);
  4071. if( float(uic) != fc )
  4072. {
  4073. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4074. }
  4075. from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true);
  4076. from->type.intValue = uic;
  4077. // Try once more, in case of a smaller type
  4078. ImplicitConversionConstant(from, to, node, convType);
  4079. }
  4080. else if( from->type.dataType.IsDoubleType() )
  4081. {
  4082. double fc = from->type.doubleValue;
  4083. asUINT uic = asUINT(fc);
  4084. if( double(uic) != fc )
  4085. {
  4086. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4087. }
  4088. from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true);
  4089. from->type.intValue = uic;
  4090. // Try once more, in case of a smaller type
  4091. ImplicitConversionConstant(from, to, node, convType);
  4092. }
  4093. else if( from->type.dataType.IsEnumType() )
  4094. {
  4095. from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true);
  4096. // Try once more, in case of a smaller type
  4097. ImplicitConversionConstant(from, to, node, convType);
  4098. }
  4099. else if( from->type.dataType.IsIntegerType() )
  4100. {
  4101. // Verify that it is possible to convert to unsigned without loosing negative
  4102. if( from->type.intValue < 0 )
  4103. {
  4104. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  4105. }
  4106. // Convert to 32bit
  4107. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4108. from->type.intValue = (signed char)from->type.byteValue;
  4109. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4110. from->type.intValue = (short)from->type.wordValue;
  4111. from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true);
  4112. // Try once more, in case of a smaller type
  4113. ImplicitConversionConstant(from, to, node, convType);
  4114. }
  4115. else if( from->type.dataType.IsUnsignedType() &&
  4116. from->type.dataType.GetSizeInMemoryBytes() < 4 )
  4117. {
  4118. // Convert to 32bit
  4119. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4120. from->type.dwordValue = from->type.byteValue;
  4121. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4122. from->type.dwordValue = from->type.wordValue;
  4123. from->type.dataType = asCDataType::CreatePrimitive(ttUInt, true);
  4124. // Try once more, in case of a smaller type
  4125. ImplicitConversionConstant(from, to, node, convType);
  4126. }
  4127. else if( from->type.dataType.IsUnsignedType() &&
  4128. from->type.dataType.GetSizeInMemoryBytes() > to.GetSizeInMemoryBytes() )
  4129. {
  4130. // Verify if it is possible
  4131. if( to.GetSizeInMemoryBytes() == 1 )
  4132. {
  4133. if( asBYTE(from->type.dwordValue) != from->type.dwordValue )
  4134. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  4135. from->type.byteValue = asBYTE(from->type.dwordValue);
  4136. }
  4137. else if( to.GetSizeInMemoryBytes() == 2 )
  4138. {
  4139. if( asWORD(from->type.dwordValue) != from->type.dwordValue )
  4140. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node);
  4141. from->type.wordValue = asWORD(from->type.dwordValue);
  4142. }
  4143. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4144. }
  4145. }
  4146. else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 2 )
  4147. {
  4148. if( from->type.dataType.IsFloatType() )
  4149. {
  4150. float fc = from->type.floatValue;
  4151. // Convert first to int64 then to uint64 to avoid negative float becoming 0 on gnuc base compilers
  4152. asQWORD uic = asQWORD(asINT64(fc));
  4153. #if !defined(_MSC_VER) || _MSC_VER > 1200 // MSVC++ 6
  4154. // MSVC6 doesn't support this conversion
  4155. if( float(uic) != fc )
  4156. {
  4157. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4158. }
  4159. #endif
  4160. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  4161. from->type.qwordValue = uic;
  4162. }
  4163. else if( from->type.dataType.IsDoubleType() )
  4164. {
  4165. double fc = from->type.doubleValue;
  4166. // Convert first to int64 then to uint64 to avoid negative float becoming 0 on gnuc base compilers
  4167. asQWORD uic = asQWORD(asINT64(fc));
  4168. #if !defined(_MSC_VER) || _MSC_VER > 1200 // MSVC++ 6
  4169. // MSVC6 doesn't support this conversion
  4170. if( double(uic) != fc )
  4171. {
  4172. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4173. }
  4174. #endif
  4175. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  4176. from->type.qwordValue = uic;
  4177. }
  4178. else if( from->type.dataType.IsEnumType() )
  4179. {
  4180. from->type.qwordValue = (asINT64)from->type.intValue;
  4181. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  4182. }
  4183. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  4184. {
  4185. // Convert to 64bit
  4186. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4187. from->type.qwordValue = (asINT64)(signed char)from->type.byteValue;
  4188. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4189. from->type.qwordValue = (asINT64)(short)from->type.wordValue;
  4190. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  4191. from->type.qwordValue = (asINT64)from->type.intValue;
  4192. // Verify that it is possible to convert to unsigned without loosing negative
  4193. if( asINT64(from->type.qwordValue) < 0 )
  4194. {
  4195. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  4196. }
  4197. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  4198. }
  4199. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  4200. {
  4201. // Verify that it is possible to convert to unsigned without loosing negative
  4202. if( asINT64(from->type.qwordValue) < 0 )
  4203. {
  4204. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node);
  4205. }
  4206. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  4207. }
  4208. else if( from->type.dataType.IsUnsignedType() )
  4209. {
  4210. // Convert to 64bit
  4211. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4212. from->type.qwordValue = from->type.byteValue;
  4213. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4214. from->type.qwordValue = from->type.wordValue;
  4215. else if( from->type.dataType.GetSizeInMemoryBytes() == 4 )
  4216. from->type.qwordValue = from->type.dwordValue;
  4217. from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true);
  4218. }
  4219. }
  4220. else if( to.IsFloatType() )
  4221. {
  4222. if( from->type.dataType.IsDoubleType() )
  4223. {
  4224. double ic = from->type.doubleValue;
  4225. float fc = float(ic);
  4226. if( double(fc) != ic )
  4227. {
  4228. asCString str;
  4229. str.Format(TXT_POSSIBLE_LOSS_OF_PRECISION);
  4230. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(str.AddressOf(), node);
  4231. }
  4232. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4233. from->type.floatValue = fc;
  4234. }
  4235. else if( from->type.dataType.IsEnumType() )
  4236. {
  4237. float fc = float(from->type.intValue);
  4238. if( int(fc) != from->type.intValue )
  4239. {
  4240. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4241. }
  4242. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4243. from->type.floatValue = fc;
  4244. }
  4245. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  4246. {
  4247. // Must properly convert value in case the from value is smaller
  4248. int ic;
  4249. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4250. ic = (signed char)from->type.byteValue;
  4251. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4252. ic = (short)from->type.wordValue;
  4253. else
  4254. ic = from->type.intValue;
  4255. float fc = float(ic);
  4256. if( int(fc) != ic )
  4257. {
  4258. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4259. }
  4260. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4261. from->type.floatValue = fc;
  4262. }
  4263. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  4264. {
  4265. float fc = float(asINT64(from->type.qwordValue));
  4266. if( asINT64(fc) != asINT64(from->type.qwordValue) )
  4267. {
  4268. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4269. }
  4270. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4271. from->type.floatValue = fc;
  4272. }
  4273. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  4274. {
  4275. // Must properly convert value in case the from value is smaller
  4276. unsigned int uic;
  4277. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4278. uic = from->type.byteValue;
  4279. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4280. uic = from->type.wordValue;
  4281. else
  4282. uic = from->type.dwordValue;
  4283. float fc = float(uic);
  4284. if( (unsigned int)(fc) != uic )
  4285. {
  4286. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4287. }
  4288. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4289. from->type.floatValue = fc;
  4290. }
  4291. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  4292. {
  4293. float fc = float((signed)from->type.qwordValue);
  4294. if( asQWORD(fc) != from->type.qwordValue )
  4295. {
  4296. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4297. }
  4298. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4299. from->type.floatValue = fc;
  4300. }
  4301. }
  4302. else if( to.IsDoubleType() )
  4303. {
  4304. if( from->type.dataType.IsFloatType() )
  4305. {
  4306. float ic = from->type.floatValue;
  4307. double fc = double(ic);
  4308. // Don't check for float->double
  4309. // if( float(fc) != ic )
  4310. // {
  4311. // acCString str;
  4312. // str.Format(TXT_NOT_EXACT_g_g_g, ic, fc, float(fc));
  4313. // if( !isExplicit ) Warning(str, node);
  4314. // }
  4315. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4316. from->type.doubleValue = fc;
  4317. }
  4318. else if( from->type.dataType.IsEnumType() )
  4319. {
  4320. double fc = double(from->type.intValue);
  4321. if( int(fc) != from->type.intValue )
  4322. {
  4323. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4324. }
  4325. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4326. from->type.doubleValue = fc;
  4327. }
  4328. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  4329. {
  4330. // Must properly convert value in case the from value is smaller
  4331. int ic;
  4332. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4333. ic = (signed char)from->type.byteValue;
  4334. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4335. ic = (short)from->type.wordValue;
  4336. else
  4337. ic = from->type.intValue;
  4338. double fc = double(ic);
  4339. if( int(fc) != ic )
  4340. {
  4341. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4342. }
  4343. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4344. from->type.doubleValue = fc;
  4345. }
  4346. else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  4347. {
  4348. double fc = double(asINT64(from->type.qwordValue));
  4349. if( asINT64(fc) != asINT64(from->type.qwordValue) )
  4350. {
  4351. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4352. }
  4353. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4354. from->type.doubleValue = fc;
  4355. }
  4356. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 )
  4357. {
  4358. // Must properly convert value in case the from value is smaller
  4359. unsigned int uic;
  4360. if( from->type.dataType.GetSizeInMemoryBytes() == 1 )
  4361. uic = from->type.byteValue;
  4362. else if( from->type.dataType.GetSizeInMemoryBytes() == 2 )
  4363. uic = from->type.wordValue;
  4364. else
  4365. uic = from->type.dwordValue;
  4366. double fc = double(uic);
  4367. if( (unsigned int)(fc) != uic )
  4368. {
  4369. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4370. }
  4371. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4372. from->type.doubleValue = fc;
  4373. }
  4374. else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 )
  4375. {
  4376. double fc = double((signed)from->type.qwordValue);
  4377. if( asQWORD(fc) != from->type.qwordValue )
  4378. {
  4379. if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node);
  4380. }
  4381. from->type.dataType = asCDataType::CreatePrimitive(to.GetTokenType(), true);
  4382. from->type.doubleValue = fc;
  4383. }
  4384. }
  4385. }
  4386. int asCCompiler::DoAssignment(asSExprContext *ctx, asSExprContext *lctx, asSExprContext *rctx, asCScriptNode *lexpr, asCScriptNode *rexpr, int op, asCScriptNode *opNode)
  4387. {
  4388. // Implicit handle types should always be treated as handles in assignments
  4389. if (lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE) )
  4390. {
  4391. lctx->type.dataType.MakeHandle(true);
  4392. lctx->type.isExplicitHandle = true;
  4393. }
  4394. // Urho3D: if there is a handle type, and it does not have an overloaded assignment operator, convert to an explicit handle
  4395. // for scripting convenience. (For the Urho3D handle types, value assignment is not supported)
  4396. if (lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle && !lctx->type.dataType.GetObjectType()->beh.copy)
  4397. lctx->type.isExplicitHandle = true;
  4398. // If the left hand expression is a property accessor, then that should be used
  4399. // to do the assignment instead of the ordinary operator. The exception is when
  4400. // the property accessor is for a handle property, and the operation is a value
  4401. // assignment.
  4402. if( (lctx->property_get || lctx->property_set) &&
  4403. !(lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle) )
  4404. {
  4405. if( op != ttAssignment )
  4406. {
  4407. // TODO: getset: We may actually be able to support this, if we can
  4408. // guarantee that the object reference will stay valid
  4409. // between the calls to the get and set accessors.
  4410. // Compound assignments are not allowed for properties
  4411. Error(TXT_COMPOUND_ASGN_WITH_PROP, opNode);
  4412. return -1;
  4413. }
  4414. // It is not allowed to do a handle assignment on a property accessor that
  4415. // doesn't take a handle in the set accessor.
  4416. if( lctx->property_set &&
  4417. lctx->type.isExplicitHandle &&
  4418. !engine->scriptFunctions[lctx->property_set]->parameterTypes[0].IsObjectHandle() )
  4419. {
  4420. Error(TXT_HANDLE_ASSIGN_ON_NON_HANDLE_PROP, opNode);
  4421. return -1;
  4422. }
  4423. MergeExprBytecodeAndType(ctx, lctx);
  4424. return ProcessPropertySetAccessor(ctx, rctx, opNode);
  4425. }
  4426. if( lctx->type.dataType.IsPrimitive() )
  4427. {
  4428. if( op != ttAssignment )
  4429. {
  4430. // Compute the operator before the assignment
  4431. asCTypeInfo lvalue = lctx->type;
  4432. if( lctx->type.isTemporary && !lctx->type.isVariable )
  4433. {
  4434. // The temporary variable must not be freed until the
  4435. // assignment has been performed. lvalue still holds
  4436. // the information about the temporary variable
  4437. lctx->type.isTemporary = false;
  4438. }
  4439. asSExprContext o(engine);
  4440. CompileOperator(opNode, lctx, rctx, &o);
  4441. MergeExprBytecode(rctx, &o);
  4442. rctx->type = o.type;
  4443. // Convert the rvalue to the right type and validate it
  4444. PrepareForAssignment(&lvalue.dataType, rctx, rexpr);
  4445. MergeExprBytecode(ctx, rctx);
  4446. lctx->type = lvalue;
  4447. // The lvalue continues the same, either it was a variable, or a reference in the register
  4448. }
  4449. else
  4450. {
  4451. // Convert the rvalue to the right type and validate it
  4452. PrepareForAssignment(&lctx->type.dataType, rctx, rexpr, lctx);
  4453. MergeExprBytecode(ctx, rctx);
  4454. MergeExprBytecode(ctx, lctx);
  4455. }
  4456. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  4457. PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode);
  4458. ctx->type = lctx->type;
  4459. }
  4460. else if( lctx->type.isExplicitHandle )
  4461. {
  4462. // Verify that the left hand value isn't a temporary variable
  4463. if( lctx->type.isTemporary )
  4464. {
  4465. Error(TXT_REF_IS_TEMP, lexpr);
  4466. return -1;
  4467. }
  4468. // Object handles don't have any compound assignment operators
  4469. if( op != ttAssignment )
  4470. {
  4471. asCString str;
  4472. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format().AddressOf());
  4473. Error(str.AddressOf(), lexpr);
  4474. return -1;
  4475. }
  4476. asCDataType dt = lctx->type.dataType;
  4477. dt.MakeReference(false);
  4478. PrepareArgument(&dt, rctx, rexpr, true, 1);
  4479. if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) )
  4480. {
  4481. asCString str;
  4482. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format().AddressOf(), lctx->type.dataType.Format().AddressOf());
  4483. Error(str.AddressOf(), rexpr);
  4484. return -1;
  4485. }
  4486. MergeExprBytecode(ctx, rctx);
  4487. MergeExprBytecode(ctx, lctx);
  4488. ctx->bc.InstrWORD(asBC_GETOBJREF, AS_PTR_SIZE);
  4489. PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode);
  4490. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  4491. ctx->type = rctx->type;
  4492. }
  4493. else // if( lctx->type.dataType.IsObject() )
  4494. {
  4495. // The lvalue reference may be marked as a temporary, if for example
  4496. // it was originated as a handle returned from a function. In such
  4497. // cases it must be possible to assign values to it anyway.
  4498. // TODO: Is there any situation where must not allow the assignment to a temporary reference?
  4499. /*
  4500. // Verify that the left hand value isn't a temporary variable
  4501. if( lctx->type.isTemporary )
  4502. {
  4503. Error(TXT_REF_IS_TEMP, lexpr);
  4504. return -1;
  4505. }
  4506. */
  4507. if( lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle )
  4508. {
  4509. // Convert the handle to a object reference
  4510. asCDataType to;
  4511. to = lctx->type.dataType;
  4512. to.MakeHandle(false);
  4513. ImplicitConversion(lctx, to, lexpr, asIC_IMPLICIT_CONV);
  4514. }
  4515. // Check for overloaded assignment operator
  4516. if( CompileOverloadedDualOperator(opNode, lctx, rctx, ctx) )
  4517. {
  4518. // An overloaded assignment operator was found (or a compilation error occured)
  4519. return 0;
  4520. }
  4521. // No registered operator was found. In case the operation is a direct
  4522. // assignment and the rvalue is the same type as the lvalue, then we can
  4523. // still use the byte-for-byte copy to do the assignment
  4524. if( op != ttAssignment )
  4525. {
  4526. asCString str;
  4527. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format().AddressOf());
  4528. Error(str.AddressOf(), lexpr);
  4529. return -1;
  4530. }
  4531. // If the left hand expression is simple, i.e. without any
  4532. // function calls or allocations of memory, then we can avoid
  4533. // doing a copy of the right hand expression (done by PrepareArgument).
  4534. // Instead the reference to the value can be placed directly on the
  4535. // stack.
  4536. //
  4537. // This optimization should only be done for value types, where
  4538. // the application developer is responsible for making the
  4539. // implementation safe against unwanted destruction of the input
  4540. // reference before the time.
  4541. bool simpleExpr = (lctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_VALUE) && lctx->bc.IsSimpleExpression();
  4542. // Implicitly convert the rvalue to the type of the lvalue
  4543. if( !lctx->type.dataType.IsEqualExceptRefAndConst(rctx->type.dataType) )
  4544. simpleExpr = false;
  4545. if( !simpleExpr )
  4546. {
  4547. asCDataType dt = lctx->type.dataType;
  4548. dt.MakeReference(true);
  4549. dt.MakeReadOnly(true);
  4550. PrepareArgument(&dt, rctx, rexpr, true, 1);
  4551. if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) )
  4552. {
  4553. asCString str;
  4554. str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format().AddressOf(), lctx->type.dataType.Format().AddressOf());
  4555. Error(str.AddressOf(), rexpr);
  4556. return -1;
  4557. }
  4558. }
  4559. else if( rctx->type.dataType.IsReference() && (!(rctx->type.isVariable || rctx->type.isTemporary) || IsVariableOnHeap(rctx->type.stackOffset)) )
  4560. rctx->bc.Instr(asBC_RDSPTR);
  4561. MergeExprBytecode(ctx, rctx);
  4562. MergeExprBytecode(ctx, lctx);
  4563. if( !simpleExpr )
  4564. {
  4565. if( (rctx->type.isVariable || rctx->type.isTemporary) && !IsVariableOnHeap(rctx->type.stackOffset) )
  4566. // TODO: optimize: Actually the reference can be pushed on the stack directly
  4567. // as the value allocated on the stack is guaranteed to be safe
  4568. ctx->bc.InstrWORD(asBC_GETREF, AS_PTR_SIZE);
  4569. else
  4570. ctx->bc.InstrWORD(asBC_GETOBJREF, AS_PTR_SIZE);
  4571. }
  4572. PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode);
  4573. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  4574. ctx->type = lctx->type;
  4575. }
  4576. return 0;
  4577. }
  4578. int asCCompiler::CompileAssignment(asCScriptNode *expr, asSExprContext *ctx)
  4579. {
  4580. asCScriptNode *lexpr = expr->firstChild;
  4581. if( lexpr->next )
  4582. {
  4583. if( globalExpression )
  4584. {
  4585. Error(TXT_ASSIGN_IN_GLOBAL_EXPR, expr);
  4586. ctx->type.SetDummy();
  4587. return -1;
  4588. }
  4589. // Compile the two expression terms
  4590. asSExprContext lctx(engine), rctx(engine);
  4591. int rr = CompileAssignment(lexpr->next->next, &rctx);
  4592. int lr = CompileCondition(lexpr, &lctx);
  4593. if( lr >= 0 && rr >= 0 )
  4594. return DoAssignment(ctx, &lctx, &rctx, lexpr, lexpr->next->next, lexpr->next->tokenType, lexpr->next);
  4595. // Since the operands failed, the assignment was not computed
  4596. ctx->type.SetDummy();
  4597. return -1;
  4598. }
  4599. return CompileCondition(lexpr, ctx);
  4600. }
  4601. int asCCompiler::CompileCondition(asCScriptNode *expr, asSExprContext *ctx)
  4602. {
  4603. asCTypeInfo ctype;
  4604. // Compile the conditional expression
  4605. asCScriptNode *cexpr = expr->firstChild;
  4606. if( cexpr->next )
  4607. {
  4608. //-------------------------------
  4609. // Compile the condition
  4610. asSExprContext e(engine);
  4611. int r = CompileExpression(cexpr, &e);
  4612. if( r < 0 )
  4613. e.type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  4614. if( r >= 0 && !e.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  4615. {
  4616. Error(TXT_EXPR_MUST_BE_BOOL, cexpr);
  4617. e.type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  4618. }
  4619. ctype = e.type;
  4620. ProcessPropertyGetAccessor(&e, cexpr);
  4621. if( e.type.dataType.IsReference() ) ConvertToVariable(&e);
  4622. ProcessDeferredParams(&e);
  4623. //-------------------------------
  4624. // Compile the left expression
  4625. asSExprContext le(engine);
  4626. int lr = CompileAssignment(cexpr->next, &le);
  4627. //-------------------------------
  4628. // Compile the right expression
  4629. asSExprContext re(engine);
  4630. int rr = CompileAssignment(cexpr->next->next, &re);
  4631. if( lr >= 0 && rr >= 0 )
  4632. {
  4633. ProcessPropertyGetAccessor(&le, cexpr->next);
  4634. ProcessPropertyGetAccessor(&re, cexpr->next->next);
  4635. bool isExplicitHandle = le.type.isExplicitHandle || re.type.isExplicitHandle;
  4636. // Allow a 0 in the first case to be implicitly converted to the second type
  4637. if( le.type.isConstant && le.type.intValue == 0 && le.type.dataType.IsUnsignedType() )
  4638. {
  4639. asCDataType to = re.type.dataType;
  4640. to.MakeReference(false);
  4641. to.MakeReadOnly(true);
  4642. ImplicitConversionConstant(&le, to, cexpr->next, asIC_IMPLICIT_CONV);
  4643. }
  4644. //---------------------------------
  4645. // Output the byte code
  4646. int afterLabel = nextLabel++;
  4647. int elseLabel = nextLabel++;
  4648. // If left expression is void, then we don't need to store the result
  4649. if( le.type.dataType.IsEqualExceptConst(asCDataType::CreatePrimitive(ttVoid, false)) )
  4650. {
  4651. // Put the code for the condition expression on the output
  4652. MergeExprBytecode(ctx, &e);
  4653. // Added the branch decision
  4654. ctx->type = e.type;
  4655. ConvertToVariable(ctx);
  4656. ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset);
  4657. ctx->bc.Instr(asBC_ClrHi);
  4658. ctx->bc.InstrDWORD(asBC_JZ, elseLabel);
  4659. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4660. // Add the left expression
  4661. MergeExprBytecode(ctx, &le);
  4662. ctx->bc.InstrINT(asBC_JMP, afterLabel);
  4663. // Add the right expression
  4664. ctx->bc.Label((short)elseLabel);
  4665. MergeExprBytecode(ctx, &re);
  4666. ctx->bc.Label((short)afterLabel);
  4667. // Make sure both expressions have the same type
  4668. if( le.type.dataType != re.type.dataType )
  4669. Error(TXT_BOTH_MUST_BE_SAME, expr);
  4670. // Set the type of the result
  4671. ctx->type = le.type;
  4672. }
  4673. else
  4674. {
  4675. // Allocate temporary variable and copy the result to that one
  4676. asCTypeInfo temp;
  4677. temp = le.type;
  4678. temp.dataType.MakeReference(false);
  4679. temp.dataType.MakeReadOnly(false);
  4680. // Make sure the variable isn't used in the initial expression
  4681. asCArray<int> vars;
  4682. e.bc.GetVarsUsed(vars);
  4683. int offset = AllocateVariableNotIn(temp.dataType, true, &vars);
  4684. temp.SetVariable(temp.dataType, offset, true);
  4685. // TODO: copy: Use copy constructor if available. See PrepareTemporaryObject()
  4686. CallDefaultConstructor(temp.dataType, offset, IsVariableOnHeap(offset), &ctx->bc, expr);
  4687. // Put the code for the condition expression on the output
  4688. MergeExprBytecode(ctx, &e);
  4689. // Add the branch decision
  4690. ctx->type = e.type;
  4691. ConvertToVariable(ctx);
  4692. ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset);
  4693. ctx->bc.Instr(asBC_ClrHi);
  4694. ctx->bc.InstrDWORD(asBC_JZ, elseLabel);
  4695. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  4696. // Assign the result of the left expression to the temporary variable
  4697. asCTypeInfo rtemp;
  4698. rtemp = temp;
  4699. if( rtemp.dataType.IsObjectHandle() )
  4700. rtemp.isExplicitHandle = true;
  4701. PrepareForAssignment(&rtemp.dataType, &le, cexpr->next);
  4702. MergeExprBytecode(ctx, &le);
  4703. if( !rtemp.dataType.IsPrimitive() )
  4704. {
  4705. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  4706. rtemp.dataType.MakeReference(IsVariableOnHeap(offset));
  4707. }
  4708. PerformAssignment(&rtemp, &le.type, &ctx->bc, cexpr->next);
  4709. if( !rtemp.dataType.IsPrimitive() )
  4710. ctx->bc.Pop(le.type.dataType.GetSizeOnStackDWords()); // Pop the original value
  4711. // Release the old temporary variable
  4712. ReleaseTemporaryVariable(le.type, &ctx->bc);
  4713. ctx->bc.InstrINT(asBC_JMP, afterLabel);
  4714. // Start of the right expression
  4715. ctx->bc.Label((short)elseLabel);
  4716. // Copy the result to the same temporary variable
  4717. PrepareForAssignment(&rtemp.dataType, &re, cexpr->next);
  4718. MergeExprBytecode(ctx, &re);
  4719. if( !rtemp.dataType.IsPrimitive() )
  4720. {
  4721. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  4722. rtemp.dataType.MakeReference(IsVariableOnHeap(offset));
  4723. }
  4724. PerformAssignment(&rtemp, &re.type, &ctx->bc, cexpr->next);
  4725. if( !rtemp.dataType.IsPrimitive() )
  4726. ctx->bc.Pop(le.type.dataType.GetSizeOnStackDWords()); // Pop the original value
  4727. // Release the old temporary variable
  4728. ReleaseTemporaryVariable(re.type, &ctx->bc);
  4729. ctx->bc.Label((short)afterLabel);
  4730. // Make sure both expressions have the same type
  4731. if( le.type.dataType != re.type.dataType )
  4732. Error(TXT_BOTH_MUST_BE_SAME, expr);
  4733. // Set the temporary variable as output
  4734. ctx->type = rtemp;
  4735. ctx->type.isExplicitHandle = isExplicitHandle;
  4736. if( !ctx->type.dataType.IsPrimitive() )
  4737. {
  4738. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  4739. ctx->type.dataType.MakeReference(IsVariableOnHeap(offset));
  4740. }
  4741. // Make sure the output isn't marked as being a literal constant
  4742. ctx->type.isConstant = false;
  4743. }
  4744. }
  4745. else
  4746. {
  4747. ctx->type.SetDummy();
  4748. return -1;
  4749. }
  4750. }
  4751. else
  4752. return CompileExpression(cexpr, ctx);
  4753. return 0;
  4754. }
  4755. int asCCompiler::CompileExpression(asCScriptNode *expr, asSExprContext *ctx)
  4756. {
  4757. asASSERT(expr->nodeType == snExpression);
  4758. // Count the nodes
  4759. int count = 0;
  4760. asCScriptNode *node = expr->firstChild;
  4761. while( node )
  4762. {
  4763. count++;
  4764. node = node->next;
  4765. }
  4766. // Convert to polish post fix, i.e: a+b => ab+
  4767. asCArray<asCScriptNode *> stack(count);
  4768. asCArray<asCScriptNode *> stack2(count);
  4769. asCArray<asCScriptNode *> postfix(count);
  4770. node = expr->firstChild;
  4771. while( node )
  4772. {
  4773. int precedence = GetPrecedence(node);
  4774. while( stack.GetLength() > 0 &&
  4775. precedence <= GetPrecedence(stack[stack.GetLength()-1]) )
  4776. stack2.PushLast(stack.PopLast());
  4777. stack.PushLast(node);
  4778. node = node->next;
  4779. }
  4780. while( stack.GetLength() > 0 )
  4781. stack2.PushLast(stack.PopLast());
  4782. // We need to swap operands so that the left
  4783. // operand is always computed before the right
  4784. SwapPostFixOperands(stack2, postfix);
  4785. // Compile the postfix formatted expression
  4786. return CompilePostFixExpression(&postfix, ctx);
  4787. }
  4788. void asCCompiler::SwapPostFixOperands(asCArray<asCScriptNode *> &postfix, asCArray<asCScriptNode *> &target)
  4789. {
  4790. if( postfix.GetLength() == 0 ) return;
  4791. asCScriptNode *node = postfix.PopLast();
  4792. if( node->nodeType == snExprTerm )
  4793. {
  4794. target.PushLast(node);
  4795. return;
  4796. }
  4797. SwapPostFixOperands(postfix, target);
  4798. SwapPostFixOperands(postfix, target);
  4799. target.PushLast(node);
  4800. }
  4801. int asCCompiler::CompilePostFixExpression(asCArray<asCScriptNode *> *postfix, asSExprContext *ctx)
  4802. {
  4803. // Shouldn't send any byte code
  4804. asASSERT(ctx->bc.GetLastInstr() == -1);
  4805. // Set the context to a dummy type to avoid further
  4806. // errors in case the expression fails to compile
  4807. ctx->type.SetDummy();
  4808. // Pop the last node
  4809. asCScriptNode *node = postfix->PopLast();
  4810. ctx->exprNode = node;
  4811. // If term, compile the term
  4812. if( node->nodeType == snExprTerm )
  4813. return CompileExpressionTerm(node, ctx);
  4814. // Compile the two expression terms
  4815. asSExprContext r(engine), l(engine);
  4816. int ret;
  4817. ret = CompilePostFixExpression(postfix, &l); if( ret < 0 ) return ret;
  4818. ret = CompilePostFixExpression(postfix, &r); if( ret < 0 ) return ret;
  4819. // Compile the operation
  4820. return CompileOperator(node, &l, &r, ctx);
  4821. }
  4822. int asCCompiler::CompileExpressionTerm(asCScriptNode *node, asSExprContext *ctx)
  4823. {
  4824. // Shouldn't send any byte code
  4825. asASSERT(ctx->bc.GetLastInstr() == -1);
  4826. // Set the type as a dummy by default, in case of any compiler errors
  4827. ctx->type.SetDummy();
  4828. // Compile the value node
  4829. asCScriptNode *vnode = node->firstChild;
  4830. while( vnode->nodeType != snExprValue )
  4831. vnode = vnode->next;
  4832. asSExprContext v(engine);
  4833. int r = CompileExpressionValue(vnode, &v); if( r < 0 ) return r;
  4834. // Compile post fix operators
  4835. asCScriptNode *pnode = vnode->next;
  4836. while( pnode )
  4837. {
  4838. r = CompileExpressionPostOp(pnode, &v); if( r < 0 ) return r;
  4839. pnode = pnode->next;
  4840. }
  4841. // Compile pre fix operators
  4842. pnode = vnode->prev;
  4843. while( pnode )
  4844. {
  4845. r = CompileExpressionPreOp(pnode, &v); if( r < 0 ) return r;
  4846. pnode = pnode->prev;
  4847. }
  4848. // Return the byte code and final type description
  4849. MergeExprBytecodeAndType(ctx, &v);
  4850. return 0;
  4851. }
  4852. int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &scope, asSExprContext *ctx, asCScriptNode *errNode, bool isOptional, bool noFunction, asCObjectType *objType)
  4853. {
  4854. bool found = false;
  4855. // It is a local variable or parameter?
  4856. // This is not accessible by default arg expressions
  4857. sVariable *v = 0;
  4858. if( !isCompilingDefaultArg && scope == "" && !objType )
  4859. v = variables->GetVariable(name.AddressOf());
  4860. if( v )
  4861. {
  4862. found = true;
  4863. if( v->isPureConstant )
  4864. ctx->type.SetConstantQW(v->type, v->constantValue);
  4865. else if( v->type.IsPrimitive() )
  4866. {
  4867. if( v->type.IsReference() )
  4868. {
  4869. // Copy the reference into the register
  4870. #if AS_PTR_SIZE == 1
  4871. ctx->bc.InstrSHORT(asBC_CpyVtoR4, (short)v->stackOffset);
  4872. #else
  4873. ctx->bc.InstrSHORT(asBC_CpyVtoR8, (short)v->stackOffset);
  4874. #endif
  4875. ctx->type.Set(v->type);
  4876. }
  4877. else
  4878. ctx->type.SetVariable(v->type, v->stackOffset, false);
  4879. }
  4880. else
  4881. {
  4882. ctx->bc.InstrSHORT(asBC_PSF, (short)v->stackOffset);
  4883. ctx->type.SetVariable(v->type, v->stackOffset, false);
  4884. // If the variable is allocated on the heap we have a reference,
  4885. // otherwise the actual object pointer is pushed on the stack.
  4886. if( v->onHeap || v->type.IsObjectHandle() ) ctx->type.dataType.MakeReference(true);
  4887. // Implicitly dereference handle parameters sent by reference
  4888. if( v->type.IsReference() && (!v->type.IsObject() || v->type.IsObjectHandle()) )
  4889. ctx->bc.Instr(asBC_RDSPTR);
  4890. }
  4891. }
  4892. // Is it a class member?
  4893. // This is not accessible by default arg expressions
  4894. if( !isCompilingDefaultArg && !found && ((objType) || (outFunc && outFunc->objectType && scope == "")) )
  4895. {
  4896. if( name == THIS_TOKEN && !objType )
  4897. {
  4898. asCDataType dt = asCDataType::CreateObject(outFunc->objectType, outFunc->isReadOnly);
  4899. // The object pointer is located at stack position 0
  4900. ctx->bc.InstrSHORT(asBC_PSF, 0);
  4901. ctx->type.SetVariable(dt, 0, false);
  4902. ctx->type.dataType.MakeReference(true);
  4903. found = true;
  4904. }
  4905. if( !found )
  4906. {
  4907. // See if there are any matching property accessors
  4908. asSExprContext access(engine);
  4909. if( objType )
  4910. access.type.Set(asCDataType::CreateObject(objType, false));
  4911. else
  4912. access.type.Set(asCDataType::CreateObject(outFunc->objectType, outFunc->isReadOnly));
  4913. access.type.dataType.MakeReference(true);
  4914. int r = 0;
  4915. if( errNode->next && errNode->next->tokenType == ttOpenBracket )
  4916. {
  4917. // This is an index access, check if there is a property accessor that takes an index arg
  4918. asSExprContext dummyArg(engine);
  4919. r = FindPropertyAccessor(name, &access, &dummyArg, errNode);
  4920. }
  4921. if( r == 0 )
  4922. {
  4923. // Normal property access
  4924. r = FindPropertyAccessor(name, &access, errNode);
  4925. }
  4926. if( r < 0 ) return -1;
  4927. if( access.property_get || access.property_set )
  4928. {
  4929. if( !objType )
  4930. {
  4931. // Prepare the bytecode for the member access
  4932. // This is only done when accessing through the implicit this pointer
  4933. ctx->bc.InstrSHORT(asBC_PSF, 0);
  4934. }
  4935. MergeExprBytecodeAndType(ctx, &access);
  4936. found = true;
  4937. }
  4938. }
  4939. if( !found )
  4940. {
  4941. asCDataType dt;
  4942. if( objType )
  4943. dt = asCDataType::CreateObject(objType, false);
  4944. else
  4945. dt = asCDataType::CreateObject(outFunc->objectType, false);
  4946. asCObjectProperty *prop = builder->GetObjectProperty(dt, name.AddressOf());
  4947. if( prop )
  4948. {
  4949. if( !objType )
  4950. {
  4951. // The object pointer is located at stack position 0
  4952. // This is only done when accessing through the implicit this pointer
  4953. ctx->bc.InstrSHORT(asBC_PSF, 0);
  4954. ctx->type.SetVariable(dt, 0, false);
  4955. ctx->type.dataType.MakeReference(true);
  4956. Dereference(ctx, true);
  4957. }
  4958. // TODO: This is the same as what is in CompileExpressionPostOp
  4959. // Put the offset on the stack
  4960. ctx->bc.InstrSHORT_DW(asBC_ADDSi, (short)prop->byteOffset, engine->GetTypeIdFromDataType(dt));
  4961. if( prop->type.IsReference() )
  4962. ctx->bc.Instr(asBC_RDSPTR);
  4963. // Reference to primitive must be stored in the temp register
  4964. if( prop->type.IsPrimitive() )
  4965. {
  4966. // TODO: optimize: The ADD offset command should store the reference in the register directly
  4967. ctx->bc.Instr(asBC_PopRPtr);
  4968. }
  4969. // Set the new type (keeping info about temp variable)
  4970. ctx->type.dataType = prop->type;
  4971. ctx->type.dataType.MakeReference(true);
  4972. ctx->type.isVariable = false;
  4973. if( ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle() )
  4974. {
  4975. // Objects that are members are not references
  4976. ctx->type.dataType.MakeReference(false);
  4977. }
  4978. // If the object reference is const, the property will also be const
  4979. ctx->type.dataType.MakeReadOnly(outFunc->isReadOnly);
  4980. found = true;
  4981. }
  4982. }
  4983. }
  4984. // Is it a global property?
  4985. if( !found && (scope == "" || scope == "::") && !objType )
  4986. {
  4987. // See if there are any matching global property accessors
  4988. asSExprContext access(engine);
  4989. int r = 0;
  4990. if( errNode->next && errNode->next->tokenType == ttOpenBracket )
  4991. {
  4992. // This is an index access, check if there is a property accessor that takes an index arg
  4993. asSExprContext dummyArg(engine);
  4994. r = FindPropertyAccessor(name, &access, &dummyArg, errNode);
  4995. }
  4996. if( r == 0 )
  4997. {
  4998. // Normal property access
  4999. r = FindPropertyAccessor(name, &access, errNode);
  5000. }
  5001. if( r < 0 ) return -1;
  5002. if( access.property_get || access.property_set )
  5003. {
  5004. // Prepare the bytecode for the function call
  5005. MergeExprBytecodeAndType(ctx, &access);
  5006. found = true;
  5007. }
  5008. // See if there is any matching global property
  5009. if( !found )
  5010. {
  5011. bool isCompiled = true;
  5012. bool isPureConstant = false;
  5013. asQWORD constantValue;
  5014. asCGlobalProperty *prop = builder->GetGlobalProperty(name.AddressOf(), &isCompiled, &isPureConstant, &constantValue);
  5015. if( prop )
  5016. {
  5017. found = true;
  5018. // Verify that the global property has been compiled already
  5019. if( isCompiled )
  5020. {
  5021. if( ctx->type.dataType.GetObjectType() && (ctx->type.dataType.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE) )
  5022. {
  5023. ctx->type.dataType.MakeHandle(true);
  5024. ctx->type.isExplicitHandle = true;
  5025. }
  5026. // If the global property is a pure constant
  5027. // we can allow the compiler to optimize it. Pure
  5028. // constants are global constant variables that were
  5029. // initialized by literal constants.
  5030. if( isPureConstant )
  5031. ctx->type.SetConstantQW(prop->type, constantValue);
  5032. else
  5033. {
  5034. ctx->type.Set(prop->type);
  5035. ctx->type.dataType.MakeReference(true);
  5036. if( ctx->type.dataType.IsPrimitive() )
  5037. {
  5038. // Load the address of the variable into the register
  5039. ctx->bc.InstrPTR(asBC_LDG, engine->globalProperties[prop->id]->GetAddressOfValue());
  5040. }
  5041. else
  5042. {
  5043. // Push the address of the variable on the stack
  5044. ctx->bc.InstrPTR(asBC_PGA, engine->globalProperties[prop->id]->GetAddressOfValue());
  5045. // If the object is a value type, then we must validate the existance,
  5046. // as it could potentially be accessed before it is initialized.
  5047. if( ctx->type.dataType.GetObjectType()->flags & asOBJ_VALUE ||
  5048. !ctx->type.dataType.IsObjectHandle() )
  5049. {
  5050. // TODO: optimize: This is not necessary for application registered properties
  5051. ctx->bc.Instr(asBC_ChkRefS);
  5052. }
  5053. }
  5054. }
  5055. }
  5056. else
  5057. {
  5058. asCString str;
  5059. str.Format(TXT_UNINITIALIZED_GLOBAL_VAR_s, prop->name.AddressOf());
  5060. Error(str.AddressOf(), errNode);
  5061. return -1;
  5062. }
  5063. }
  5064. }
  5065. }
  5066. // Is it the name of a global function?
  5067. if( !noFunction && !found && (scope == "" || scope == "::") && !objType )
  5068. {
  5069. asCArray<int> funcs;
  5070. builder->GetFunctionDescriptions(name.AddressOf(), funcs);
  5071. if( funcs.GetLength() > 1 )
  5072. {
  5073. // TODO: funcdef: If multiple functions are found, then the compiler should defer the decision
  5074. // to which one it should use until the value is actually used.
  5075. //
  5076. // - assigning the function pointer to a variable
  5077. // - performing an explicit cast
  5078. // - passing the function pointer to a function as parameter
  5079. asCString str;
  5080. str.Format(TXT_MULTIPLE_MATCHING_SIGNATURES_TO_s, name.AddressOf());
  5081. Error(str.AddressOf(), errNode);
  5082. return -1;
  5083. }
  5084. else if( funcs.GetLength() == 1 )
  5085. {
  5086. found = true;
  5087. // Push the function pointer on the stack
  5088. ctx->bc.InstrPTR(asBC_FuncPtr, engine->scriptFunctions[funcs[0]]);
  5089. ctx->type.Set(asCDataType::CreateFuncDef(engine->scriptFunctions[funcs[0]]));
  5090. }
  5091. }
  5092. // Is it an enum value?
  5093. if( !found && !objType )
  5094. {
  5095. asCObjectType *scopeType = 0;
  5096. if( scope != "" )
  5097. {
  5098. // resolve the type before the scope
  5099. scopeType = builder->GetObjectType( scope.AddressOf() );
  5100. }
  5101. asDWORD value = 0;
  5102. asCDataType dt;
  5103. if( scopeType && builder->GetEnumValueFromObjectType(scopeType, name.AddressOf(), dt, value) )
  5104. {
  5105. // scoped enum value found
  5106. found = true;
  5107. }
  5108. else if( scope == "" && !engine->ep.requireEnumScope )
  5109. {
  5110. // look for the enum value with no namespace
  5111. int e = builder->GetEnumValue(name.AddressOf(), dt, value);
  5112. if( e )
  5113. {
  5114. found = true;
  5115. if( e == 2 )
  5116. {
  5117. Error(TXT_FOUND_MULTIPLE_ENUM_VALUES, errNode);
  5118. }
  5119. }
  5120. }
  5121. if( found )
  5122. {
  5123. // an enum value was resolved
  5124. ctx->type.SetConstantDW(dt, value);
  5125. }
  5126. }
  5127. // The name doesn't match any variable
  5128. if( !found )
  5129. {
  5130. // Give dummy value
  5131. ctx->type.SetDummy();
  5132. if( !isOptional )
  5133. {
  5134. // Prepend the scope to the name for the error message
  5135. asCString ename;
  5136. if( scope != "" && scope != "::" )
  5137. ename = scope + "::";
  5138. else
  5139. ename = scope;
  5140. ename += name;
  5141. asCString str;
  5142. str.Format(TXT_s_NOT_DECLARED, ename.AddressOf());
  5143. Error(str.AddressOf(), errNode);
  5144. // Declare the variable now so that it will not be reported again
  5145. variables->DeclareVariable(name.AddressOf(), asCDataType::CreatePrimitive(ttInt, false), 0x7FFF, true);
  5146. // Mark the variable as initialized so that the user will not be bother by it again
  5147. sVariable *v = variables->GetVariable(name.AddressOf());
  5148. asASSERT(v);
  5149. if( v ) v->isInitialized = true;
  5150. }
  5151. // Return -1 to signal that the variable wasn't found
  5152. return -1;
  5153. }
  5154. return 0;
  5155. }
  5156. int asCCompiler::CompileExpressionValue(asCScriptNode *node, asSExprContext *ctx)
  5157. {
  5158. // Shouldn't receive any byte code
  5159. asASSERT(ctx->bc.GetLastInstr() == -1);
  5160. asCScriptNode *vnode = node->firstChild;
  5161. ctx->exprNode = vnode;
  5162. if( vnode->nodeType == snVariableAccess )
  5163. {
  5164. // Determine the scope resolution of the variable
  5165. asCString scope = GetScopeFromNode(vnode);
  5166. // Determine the name of the variable
  5167. vnode = vnode->lastChild;
  5168. asASSERT(vnode->nodeType == snIdentifier );
  5169. asCString name(&script->code[vnode->tokenPos], vnode->tokenLength);
  5170. return CompileVariableAccess(name, scope, ctx, node);
  5171. }
  5172. else if( vnode->nodeType == snConstant )
  5173. {
  5174. if( vnode->tokenType == ttIntConstant )
  5175. {
  5176. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  5177. asQWORD val = asStringScanUInt64(value.AddressOf(), 10, 0);
  5178. // Do we need 64 bits?
  5179. if( val>>32 )
  5180. ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), val);
  5181. else
  5182. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), asDWORD(val));
  5183. }
  5184. else if( vnode->tokenType == ttBitsConstant )
  5185. {
  5186. asCString value(&script->code[vnode->tokenPos+2], vnode->tokenLength-2);
  5187. // TODO: Check for overflow
  5188. asQWORD val = asStringScanUInt64(value.AddressOf(), 16, 0);
  5189. // Do we need 64 bits?
  5190. if( val>>32 )
  5191. ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), val);
  5192. else
  5193. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), asDWORD(val));
  5194. }
  5195. else if( vnode->tokenType == ttFloatConstant )
  5196. {
  5197. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  5198. // TODO: Check for overflow
  5199. size_t numScanned;
  5200. float v = float(asStringScanDouble(value.AddressOf(), &numScanned));
  5201. ctx->type.SetConstantF(asCDataType::CreatePrimitive(ttFloat, true), v);
  5202. #ifndef AS_USE_DOUBLE_AS_FLOAT
  5203. // Don't check this if we have double as float, because then the whole token would be scanned (i.e. no f suffix)
  5204. asASSERT(numScanned == vnode->tokenLength - 1);
  5205. #endif
  5206. }
  5207. else if( vnode->tokenType == ttDoubleConstant )
  5208. {
  5209. asCString value(&script->code[vnode->tokenPos], vnode->tokenLength);
  5210. // TODO: Check for overflow
  5211. size_t numScanned;
  5212. double v = asStringScanDouble(value.AddressOf(), &numScanned);
  5213. ctx->type.SetConstantD(asCDataType::CreatePrimitive(ttDouble, true), v);
  5214. asASSERT(numScanned == vnode->tokenLength);
  5215. }
  5216. else if( vnode->tokenType == ttTrue ||
  5217. vnode->tokenType == ttFalse )
  5218. {
  5219. #if AS_SIZEOF_BOOL == 1
  5220. ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), vnode->tokenType == ttTrue ? VALUE_OF_BOOLEAN_TRUE : 0);
  5221. #else
  5222. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), vnode->tokenType == ttTrue ? VALUE_OF_BOOLEAN_TRUE : 0);
  5223. #endif
  5224. }
  5225. else if( vnode->tokenType == ttStringConstant ||
  5226. vnode->tokenType == ttMultilineStringConstant ||
  5227. vnode->tokenType == ttHeredocStringConstant )
  5228. {
  5229. asCString str;
  5230. asCScriptNode *snode = vnode->firstChild;
  5231. if( script->code[snode->tokenPos] == '\'' && engine->ep.useCharacterLiterals )
  5232. {
  5233. // Treat the single quoted string as a single character literal
  5234. str.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2);
  5235. asDWORD val = 0;
  5236. if( str.GetLength() && (unsigned char)str[0] > 127 && engine->ep.scanner == 1 )
  5237. {
  5238. // This is the start of a UTF8 encoded character. We need to decode it
  5239. val = asStringDecodeUTF8(str.AddressOf(), 0);
  5240. if( val == (asDWORD)-1 )
  5241. Error(TXT_INVALID_CHAR_LITERAL, vnode);
  5242. }
  5243. else
  5244. {
  5245. val = ProcessStringConstant(str, snode);
  5246. if( val == (asDWORD)-1 )
  5247. Error(TXT_INVALID_CHAR_LITERAL, vnode);
  5248. }
  5249. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), val);
  5250. }
  5251. else
  5252. {
  5253. // Process the string constants
  5254. while( snode )
  5255. {
  5256. asCString cat;
  5257. if( snode->tokenType == ttStringConstant )
  5258. {
  5259. cat.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2);
  5260. ProcessStringConstant(cat, snode);
  5261. }
  5262. else if( snode->tokenType == ttMultilineStringConstant )
  5263. {
  5264. if( !engine->ep.allowMultilineStrings )
  5265. Error(TXT_MULTILINE_STRINGS_NOT_ALLOWED, snode);
  5266. cat.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2);
  5267. ProcessStringConstant(cat, snode);
  5268. }
  5269. else if( snode->tokenType == ttHeredocStringConstant )
  5270. {
  5271. cat.Assign(&script->code[snode->tokenPos+3], snode->tokenLength-6);
  5272. ProcessHeredocStringConstant(cat, snode);
  5273. }
  5274. str += cat;
  5275. snode = snode->next;
  5276. }
  5277. // Call the string factory function to create a string object
  5278. asCScriptFunction *descr = engine->stringFactory;
  5279. if( descr == 0 )
  5280. {
  5281. // Error
  5282. Error(TXT_STRINGS_NOT_RECOGNIZED, vnode);
  5283. // Give dummy value
  5284. ctx->type.SetDummy();
  5285. return -1;
  5286. }
  5287. else
  5288. {
  5289. // Register the constant string with the engine
  5290. int id = engine->AddConstantString(str.AddressOf(), str.GetLength());
  5291. ctx->bc.InstrWORD(asBC_STR, (asWORD)id);
  5292. PerformFunctionCall(descr->id, ctx);
  5293. }
  5294. }
  5295. }
  5296. else if( vnode->tokenType == ttNull )
  5297. {
  5298. #ifndef AS_64BIT_PTR
  5299. ctx->bc.InstrDWORD(asBC_PshC4, 0);
  5300. #else
  5301. ctx->bc.InstrQWORD(asBC_PshC8, 0);
  5302. #endif
  5303. ctx->type.SetNullConstant();
  5304. }
  5305. else
  5306. asASSERT(false);
  5307. }
  5308. else if( vnode->nodeType == snFunctionCall )
  5309. {
  5310. bool found = false;
  5311. // Determine the scope resolution
  5312. asCString scope = GetScopeFromNode(vnode);
  5313. if( outFunc && outFunc->objectType && scope != "::" )
  5314. {
  5315. // TODO: funcdef: There may be a local variable of a function type with the same name
  5316. // Check if a class method is being called
  5317. asCScriptNode *nm = vnode->lastChild->prev;
  5318. asCString name;
  5319. name.Assign(&script->code[nm->tokenPos], nm->tokenLength);
  5320. asCArray<int> funcs;
  5321. // If we're compiling a constructor and the name of the function called
  5322. // is 'super' then the base class' constructor is being called.
  5323. // super cannot be called from another scope, i.e. must not be prefixed
  5324. if( m_isConstructor && name == SUPER_TOKEN && nm->prev == 0 )
  5325. {
  5326. // Actually it is the base class' constructor that is being called,
  5327. // but as we won't use the actual function ids here we can take the
  5328. // object's own constructors and avoid the need to check if the
  5329. // object actually derives from any other class
  5330. funcs = outFunc->objectType->beh.constructors;
  5331. // Must not allow calling constructors multiple times
  5332. if( continueLabels.GetLength() > 0 )
  5333. {
  5334. // If a continue label is set we are in a loop
  5335. Error(TXT_CANNOT_CALL_CONSTRUCTOR_IN_LOOPS, vnode);
  5336. }
  5337. else if( breakLabels.GetLength() > 0 )
  5338. {
  5339. // TODO: inheritance: Should eventually allow constructors in switch statements
  5340. // If a break label is set we are either in a loop or a switch statements
  5341. Error(TXT_CANNOT_CALL_CONSTRUCTOR_IN_SWITCH, vnode);
  5342. }
  5343. else if( m_isConstructorCalled )
  5344. {
  5345. Error(TXT_CANNOT_CALL_CONSTRUCTOR_TWICE, vnode);
  5346. }
  5347. m_isConstructorCalled = true;
  5348. }
  5349. else
  5350. builder->GetObjectMethodDescriptions(name.AddressOf(), outFunc->objectType, funcs, false);
  5351. if( funcs.GetLength() )
  5352. {
  5353. asCDataType dt = asCDataType::CreateObject(outFunc->objectType, false);
  5354. // The object pointer is located at stack position 0
  5355. ctx->bc.InstrSHORT(asBC_PSF, 0);
  5356. ctx->type.SetVariable(dt, 0, false);
  5357. ctx->type.dataType.MakeReference(true);
  5358. // TODO: optimize: This adds a CHKREF. Is that really necessary?
  5359. Dereference(ctx, true);
  5360. CompileFunctionCall(vnode, ctx, outFunc->objectType, false, scope);
  5361. found = true;
  5362. }
  5363. }
  5364. if( !found )
  5365. CompileFunctionCall(vnode, ctx, 0, false, scope);
  5366. }
  5367. else if( vnode->nodeType == snConstructCall )
  5368. {
  5369. CompileConstructCall(vnode, ctx);
  5370. }
  5371. else if( vnode->nodeType == snAssignment )
  5372. {
  5373. asSExprContext e(engine);
  5374. int r = CompileAssignment(vnode, &e);
  5375. if( r < 0 )
  5376. {
  5377. ctx->type.SetDummy();
  5378. return r;
  5379. }
  5380. MergeExprBytecodeAndType(ctx, &e);
  5381. }
  5382. else if( vnode->nodeType == snCast )
  5383. {
  5384. // Implement the cast operator
  5385. CompileConversion(vnode, ctx);
  5386. }
  5387. else
  5388. asASSERT(false);
  5389. return 0;
  5390. }
  5391. asCString asCCompiler::GetScopeFromNode(asCScriptNode *node)
  5392. {
  5393. asCString scope;
  5394. asCScriptNode *sn = node->firstChild;
  5395. if( sn->tokenType == ttScope )
  5396. {
  5397. // Global scope
  5398. scope = "::";
  5399. sn = sn->next;
  5400. }
  5401. else if( sn->next && sn->next->tokenType == ttScope )
  5402. {
  5403. scope.Assign(&script->code[sn->tokenPos], sn->tokenLength);
  5404. sn = sn->next->next;
  5405. }
  5406. if( scope != "" )
  5407. {
  5408. // We don't support multiple levels of scope yet
  5409. if( sn->next && sn->next->tokenType == ttScope )
  5410. {
  5411. Error(TXT_INVALID_SCOPE, sn->next);
  5412. }
  5413. }
  5414. return scope;
  5415. }
  5416. asUINT asCCompiler::ProcessStringConstant(asCString &cstr, asCScriptNode *node, bool processEscapeSequences)
  5417. {
  5418. int charLiteral = -1;
  5419. // Process escape sequences
  5420. asCArray<char> str((int)cstr.GetLength());
  5421. for( asUINT n = 0; n < cstr.GetLength(); n++ )
  5422. {
  5423. #ifdef AS_DOUBLEBYTE_CHARSET
  5424. // Double-byte charset is only allowed for ASCII and not UTF16 encoded strings
  5425. if( (cstr[n] & 0x80) && engine->ep.scanner == 0 && engine->ep.stringEncoding != 1 )
  5426. {
  5427. // This is the lead character of a double byte character
  5428. // include the trail character without checking it's value.
  5429. str.PushLast(cstr[n]);
  5430. n++;
  5431. str.PushLast(cstr[n]);
  5432. continue;
  5433. }
  5434. #endif
  5435. asUINT val;
  5436. if( processEscapeSequences && cstr[n] == '\\' )
  5437. {
  5438. ++n;
  5439. if( n == cstr.GetLength() )
  5440. {
  5441. if( charLiteral == -1 ) charLiteral = 0;
  5442. return charLiteral;
  5443. }
  5444. // TODO: Consider deprecating use of hexadecimal escape sequences,
  5445. // as they do not guarantee proper unicode sequences
  5446. if( cstr[n] == 'x' || cstr[n] == 'X' )
  5447. {
  5448. ++n;
  5449. if( n == cstr.GetLength() ) break;
  5450. val = 0;
  5451. int c = engine->ep.stringEncoding == 1 ? 4 : 2;
  5452. for( ; c > 0 && n < cstr.GetLength(); c--, n++ )
  5453. {
  5454. if( cstr[n] >= '0' && cstr[n] <= '9' )
  5455. val = val*16 + cstr[n] - '0';
  5456. else if( cstr[n] >= 'a' && cstr[n] <= 'f' )
  5457. val = val*16 + cstr[n] - 'a' + 10;
  5458. else if( cstr[n] >= 'A' && cstr[n] <= 'F' )
  5459. val = val*16 + cstr[n] - 'A' + 10;
  5460. else
  5461. break;
  5462. }
  5463. // Rewind one, since the loop will increment it again
  5464. n--;
  5465. // Hexadecimal escape sequences produce exact value, even if it is not proper unicode chars
  5466. if( engine->ep.stringEncoding == 0 )
  5467. {
  5468. str.PushLast((asBYTE)val);
  5469. }
  5470. else
  5471. {
  5472. #ifndef AS_BIG_ENDIAN
  5473. str.PushLast((asBYTE)val);
  5474. str.PushLast((asBYTE)(val>>8));
  5475. #else
  5476. str.PushLast((asBYTE)(val>>8));
  5477. str.PushLast((asBYTE)val);
  5478. #endif
  5479. }
  5480. if( charLiteral == -1 ) charLiteral = val;
  5481. continue;
  5482. }
  5483. else if( cstr[n] == 'u' || cstr[n] == 'U' )
  5484. {
  5485. // \u expects 4 hex digits
  5486. // \U expects 8 hex digits
  5487. bool expect2 = cstr[n] == 'u';
  5488. int c = expect2 ? 4 : 8;
  5489. val = 0;
  5490. for( ; c > 0; c-- )
  5491. {
  5492. ++n;
  5493. if( n == cstr.GetLength() ) break;
  5494. if( cstr[n] >= '0' && cstr[n] <= '9' )
  5495. val = val*16 + cstr[n] - '0';
  5496. else if( cstr[n] >= 'a' && cstr[n] <= 'f' )
  5497. val = val*16 + cstr[n] - 'a' + 10;
  5498. else if( cstr[n] >= 'A' && cstr[n] <= 'F' )
  5499. val = val*16 + cstr[n] - 'A' + 10;
  5500. else
  5501. break;
  5502. }
  5503. if( c != 0 )
  5504. {
  5505. // Give warning about invalid code point
  5506. // TODO: Need code position for warning
  5507. asCString msg;
  5508. msg.Format(TXT_INVALID_UNICODE_FORMAT_EXPECTED_d, expect2 ? 4 : 8);
  5509. Warning(msg.AddressOf(), node);
  5510. continue;
  5511. }
  5512. }
  5513. else
  5514. {
  5515. if( cstr[n] == '"' )
  5516. val = '"';
  5517. else if( cstr[n] == '\'' )
  5518. val = '\'';
  5519. else if( cstr[n] == 'n' )
  5520. val = '\n';
  5521. else if( cstr[n] == 'r' )
  5522. val = '\r';
  5523. else if( cstr[n] == 't' )
  5524. val = '\t';
  5525. else if( cstr[n] == '0' )
  5526. val = '\0';
  5527. else if( cstr[n] == '\\' )
  5528. val = '\\';
  5529. else
  5530. {
  5531. // Invalid escape sequence
  5532. Warning(TXT_INVALID_ESCAPE_SEQUENCE, node);
  5533. continue;
  5534. }
  5535. }
  5536. }
  5537. else
  5538. {
  5539. if( engine->ep.scanner == 1 && (cstr[n] & 0x80) )
  5540. {
  5541. unsigned int len;
  5542. val = asStringDecodeUTF8(&cstr[n], &len);
  5543. if( val == 0xFFFFFFFF || len < 0 )
  5544. {
  5545. // Incorrect UTF8 encoding. Use only the first byte
  5546. // TODO: Need code position for warning
  5547. Warning(TXT_INVALID_UNICODE_SEQUENCE_IN_SRC, node);
  5548. val = (unsigned char)cstr[n];
  5549. }
  5550. else
  5551. n += len-1;
  5552. }
  5553. else
  5554. val = (unsigned char)cstr[n];
  5555. }
  5556. // Add the character to the final string
  5557. char encodedValue[5];
  5558. int len;
  5559. if( engine->ep.scanner == 1 && engine->ep.stringEncoding == 0 )
  5560. {
  5561. // Convert to UTF8 encoded
  5562. len = asStringEncodeUTF8(val, encodedValue);
  5563. }
  5564. else if( engine->ep.stringEncoding == 1 )
  5565. {
  5566. // Convert to 16bit wide character string (even if the script is scanned as ASCII)
  5567. len = asStringEncodeUTF16(val, encodedValue);
  5568. }
  5569. else
  5570. {
  5571. // Do not convert ASCII characters
  5572. encodedValue[0] = (asBYTE)val;
  5573. len = 1;
  5574. }
  5575. if( len < 0 )
  5576. {
  5577. // Give warning about invalid code point
  5578. // TODO: Need code position for warning
  5579. Warning(TXT_INVALID_UNICODE_VALUE, node);
  5580. }
  5581. else
  5582. {
  5583. // Add the encoded value to the final string
  5584. str.Concatenate(encodedValue, len);
  5585. if( charLiteral == -1 ) charLiteral = val;
  5586. }
  5587. }
  5588. cstr.Assign(str.AddressOf(), str.GetLength());
  5589. return charLiteral;
  5590. }
  5591. void asCCompiler::ProcessHeredocStringConstant(asCString &str, asCScriptNode *node)
  5592. {
  5593. // Remove first line if it only contains whitespace
  5594. int start;
  5595. for( start = 0; start < (int)str.GetLength(); start++ )
  5596. {
  5597. if( str[start] == '\n' )
  5598. {
  5599. // Remove the linebreak as well
  5600. start++;
  5601. break;
  5602. }
  5603. if( str[start] != ' ' &&
  5604. str[start] != '\t' &&
  5605. str[start] != '\r' )
  5606. {
  5607. // Don't remove anything
  5608. start = 0;
  5609. break;
  5610. }
  5611. }
  5612. // Remove last line break and the line after that if it only contains whitespaces
  5613. int end;
  5614. for( end = (int)str.GetLength() - 1; end >= 0; end-- )
  5615. {
  5616. if( str[end] == '\n' )
  5617. break;
  5618. if( str[end] != ' ' &&
  5619. str[end] != '\t' &&
  5620. str[end] != '\r' )
  5621. {
  5622. // Don't remove anything
  5623. end = (int)str.GetLength();
  5624. break;
  5625. }
  5626. }
  5627. if( end < 0 ) end = 0;
  5628. asCString tmp;
  5629. if( end > start )
  5630. tmp.Assign(&str[start], end-start);
  5631. ProcessStringConstant(tmp, node, false);
  5632. str = tmp;
  5633. }
  5634. void asCCompiler::CompileConversion(asCScriptNode *node, asSExprContext *ctx)
  5635. {
  5636. asSExprContext expr(engine);
  5637. asCDataType to;
  5638. bool anyErrors = false;
  5639. EImplicitConv convType;
  5640. if( node->nodeType == snConstructCall )
  5641. {
  5642. convType = asIC_EXPLICIT_VAL_CAST;
  5643. // Verify that there is only one argument
  5644. if( node->lastChild->firstChild == 0 ||
  5645. node->lastChild->firstChild != node->lastChild->lastChild )
  5646. {
  5647. Error(TXT_ONLY_ONE_ARGUMENT_IN_CAST, node->lastChild);
  5648. expr.type.SetDummy();
  5649. anyErrors = true;
  5650. }
  5651. else
  5652. {
  5653. // Compile the expression
  5654. int r = CompileAssignment(node->lastChild->firstChild, &expr);
  5655. if( r < 0 )
  5656. anyErrors = true;
  5657. }
  5658. // Determine the requested type
  5659. to = builder->CreateDataTypeFromNode(node->firstChild, script);
  5660. to.MakeReadOnly(true); // Default to const
  5661. asASSERT(to.IsPrimitive());
  5662. }
  5663. else
  5664. {
  5665. convType = asIC_EXPLICIT_REF_CAST;
  5666. // Compile the expression
  5667. int r = CompileAssignment(node->lastChild, &expr);
  5668. if( r < 0 )
  5669. anyErrors = true;
  5670. // Determine the requested type
  5671. to = builder->CreateDataTypeFromNode(node->firstChild, script);
  5672. to = builder->ModifyDataTypeFromNode(to, node->firstChild->next, script, 0, 0);
  5673. // If the type support object handles, then use it
  5674. if( to.SupportHandles() )
  5675. {
  5676. to.MakeHandle(true);
  5677. }
  5678. else if( !to.IsObjectHandle() )
  5679. {
  5680. // The cast<type> operator can only be used for reference casts
  5681. Error(TXT_ILLEGAL_TARGET_TYPE_FOR_REF_CAST, node->firstChild);
  5682. anyErrors = true;
  5683. }
  5684. }
  5685. if( anyErrors )
  5686. {
  5687. // Assume that the error can be fixed and allow the compilation to continue
  5688. ctx->type.SetConstantDW(to, 0);
  5689. return;
  5690. }
  5691. ProcessPropertyGetAccessor(&expr, node);
  5692. // We don't want a reference
  5693. if( expr.type.dataType.IsReference() )
  5694. {
  5695. if( expr.type.dataType.IsObject() )
  5696. Dereference(&expr, true);
  5697. else
  5698. ConvertToVariable(&expr);
  5699. }
  5700. ImplicitConversion(&expr, to, node, convType);
  5701. IsVariableInitialized(&expr.type, node);
  5702. // If no type conversion is really tried ignore it
  5703. if( to == expr.type.dataType )
  5704. {
  5705. // This will keep information about constant type
  5706. MergeExprBytecode(ctx, &expr);
  5707. ctx->type = expr.type;
  5708. return;
  5709. }
  5710. if( to.IsEqualExceptConst(expr.type.dataType) && to.IsPrimitive() )
  5711. {
  5712. MergeExprBytecode(ctx, &expr);
  5713. ctx->type = expr.type;
  5714. ctx->type.dataType.MakeReadOnly(true);
  5715. return;
  5716. }
  5717. // The implicit conversion already does most of the conversions permitted,
  5718. // here we'll only treat those conversions that require an explicit cast.
  5719. bool conversionOK = false;
  5720. if( !expr.type.isConstant )
  5721. {
  5722. if( !expr.type.dataType.IsObject() )
  5723. ConvertToTempVariable(&expr);
  5724. if( to.IsObjectHandle() &&
  5725. expr.type.dataType.IsObjectHandle() &&
  5726. !(!to.IsHandleToConst() && expr.type.dataType.IsHandleToConst()) )
  5727. {
  5728. conversionOK = CompileRefCast(&expr, to, true, node);
  5729. MergeExprBytecode(ctx, &expr);
  5730. ctx->type = expr.type;
  5731. }
  5732. }
  5733. if( conversionOK )
  5734. return;
  5735. // Conversion not available
  5736. ctx->type.SetDummy();
  5737. asCString strTo, strFrom;
  5738. strTo = to.Format();
  5739. strFrom = expr.type.dataType.Format();
  5740. asCString msg;
  5741. msg.Format(TXT_NO_CONVERSION_s_TO_s, strFrom.AddressOf(), strTo.AddressOf());
  5742. Error(msg.AddressOf(), node);
  5743. }
  5744. void asCCompiler::AfterFunctionCall(int funcID, asCArray<asSExprContext*> &args, asSExprContext *ctx, bool deferAll)
  5745. {
  5746. asCScriptFunction *descr = builder->GetFunctionDescription(funcID);
  5747. // Parameters that are sent by reference should be assigned
  5748. // to the evaluated expression if it is an lvalue
  5749. // Evaluate the arguments from last to first
  5750. int n = (int)descr->parameterTypes.GetLength() - 1;
  5751. for( ; n >= 0; n-- )
  5752. {
  5753. if( (descr->parameterTypes[n].IsReference() && (descr->inOutFlags[n] & asTM_OUTREF)) ||
  5754. (descr->parameterTypes[n].IsObject() && deferAll) )
  5755. {
  5756. asASSERT( !(descr->parameterTypes[n].IsReference() && (descr->inOutFlags[n] == asTM_OUTREF)) || args[n]->origExpr );
  5757. // For &inout, only store the argument if it is for a temporary variable
  5758. if( engine->ep.allowUnsafeReferences ||
  5759. descr->inOutFlags[n] != asTM_INOUTREF || args[n]->type.isTemporary )
  5760. {
  5761. // Store the argument for later processing
  5762. asSDeferredParam outParam;
  5763. outParam.argNode = args[n]->exprNode;
  5764. outParam.argType = args[n]->type;
  5765. outParam.argInOutFlags = descr->inOutFlags[n];
  5766. outParam.origExpr = args[n]->origExpr;
  5767. ctx->deferredParams.PushLast(outParam);
  5768. }
  5769. }
  5770. else
  5771. {
  5772. // Release the temporary variable now
  5773. ReleaseTemporaryVariable(args[n]->type, &ctx->bc);
  5774. }
  5775. // Move the argument's deferred expressions over to the final expression
  5776. for( asUINT m = 0; m < args[n]->deferredParams.GetLength(); m++ )
  5777. {
  5778. ctx->deferredParams.PushLast(args[n]->deferredParams[m]);
  5779. args[n]->deferredParams[m].origExpr = 0;
  5780. }
  5781. args[n]->deferredParams.SetLength(0);
  5782. }
  5783. }
  5784. void asCCompiler::ProcessDeferredParams(asSExprContext *ctx)
  5785. {
  5786. if( isProcessingDeferredParams ) return;
  5787. isProcessingDeferredParams = true;
  5788. for( asUINT n = 0; n < ctx->deferredParams.GetLength(); n++ )
  5789. {
  5790. asSDeferredParam outParam = ctx->deferredParams[n];
  5791. if( outParam.argInOutFlags < asTM_OUTREF ) // &in, or not reference
  5792. {
  5793. // Just release the variable
  5794. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  5795. }
  5796. else if( outParam.argInOutFlags == asTM_OUTREF )
  5797. {
  5798. asSExprContext *expr = outParam.origExpr;
  5799. outParam.origExpr = 0;
  5800. if( outParam.argType.dataType.IsObjectHandle() )
  5801. {
  5802. // Implicitly convert the value to a handle
  5803. if( expr->type.dataType.IsObjectHandle() )
  5804. expr->type.isExplicitHandle = true;
  5805. }
  5806. // Verify that the expression result in a lvalue, or a property accessor
  5807. if( IsLValue(expr->type) || expr->property_get || expr->property_set )
  5808. {
  5809. asSExprContext rctx(engine);
  5810. rctx.type = outParam.argType;
  5811. if( rctx.type.dataType.IsPrimitive() )
  5812. rctx.type.dataType.MakeReference(false);
  5813. else
  5814. {
  5815. rctx.bc.InstrSHORT(asBC_PSF, outParam.argType.stackOffset);
  5816. rctx.type.dataType.MakeReference(IsVariableOnHeap(outParam.argType.stackOffset));
  5817. if( expr->type.isExplicitHandle )
  5818. rctx.type.isExplicitHandle = true;
  5819. }
  5820. asSExprContext o(engine);
  5821. DoAssignment(&o, expr, &rctx, outParam.argNode, outParam.argNode, ttAssignment, outParam.argNode);
  5822. if( !o.type.dataType.IsPrimitive() ) o.bc.Pop(AS_PTR_SIZE);
  5823. MergeExprBytecode(ctx, &o);
  5824. }
  5825. else
  5826. {
  5827. // We must still evaluate the expression
  5828. MergeExprBytecode(ctx, expr);
  5829. if( !expr->type.isConstant )
  5830. ctx->bc.Pop(expr->type.dataType.GetSizeOnStackDWords());
  5831. // Give a warning
  5832. Warning(TXT_ARG_NOT_LVALUE, outParam.argNode);
  5833. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  5834. }
  5835. ReleaseTemporaryVariable(expr->type, &ctx->bc);
  5836. // Delete the original expression context
  5837. asDELETE(expr,asSExprContext);
  5838. }
  5839. else // &inout
  5840. {
  5841. if( outParam.argType.isTemporary )
  5842. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  5843. else if( !outParam.argType.isVariable )
  5844. {
  5845. if( outParam.argType.dataType.IsObject() &&
  5846. outParam.argType.dataType.GetBehaviour()->addref &&
  5847. outParam.argType.dataType.GetBehaviour()->release )
  5848. {
  5849. // Release the object handle that was taken to guarantee the reference
  5850. ReleaseTemporaryVariable(outParam.argType, &ctx->bc);
  5851. }
  5852. }
  5853. }
  5854. }
  5855. ctx->deferredParams.SetLength(0);
  5856. isProcessingDeferredParams = false;
  5857. }
  5858. void asCCompiler::CompileConstructCall(asCScriptNode *node, asSExprContext *ctx)
  5859. {
  5860. // The first node is a datatype node
  5861. asCString name;
  5862. asCTypeInfo tempObj;
  5863. bool onHeap = true;
  5864. asCArray<int> funcs;
  5865. // It is possible that the name is really a constructor
  5866. asCDataType dt;
  5867. dt = builder->CreateDataTypeFromNode(node->firstChild, script);
  5868. if( dt.IsPrimitive() )
  5869. {
  5870. // This is a cast to a primitive type
  5871. CompileConversion(node, ctx);
  5872. return;
  5873. }
  5874. if( globalExpression )
  5875. {
  5876. Error(TXT_FUNCTION_IN_GLOBAL_EXPR, node);
  5877. // Output dummy code
  5878. ctx->type.SetDummy();
  5879. return;
  5880. }
  5881. // Compile the arguments
  5882. asCArray<asSExprContext *> args;
  5883. asCArray<asCTypeInfo> temporaryVariables;
  5884. if( CompileArgumentList(node->lastChild, args) >= 0 )
  5885. {
  5886. // Check for a value cast behaviour
  5887. if( args.GetLength() == 1 && args[0]->type.dataType.GetObjectType() )
  5888. {
  5889. asSExprContext conv(engine);
  5890. conv.type = args[0]->type;
  5891. ImplicitConversion(&conv, dt, node->lastChild, asIC_EXPLICIT_VAL_CAST, false);
  5892. if( conv.type.dataType.IsEqualExceptRef(dt) )
  5893. {
  5894. ImplicitConversion(args[0], dt, node->lastChild, asIC_EXPLICIT_VAL_CAST);
  5895. ctx->bc.AddCode(&args[0]->bc);
  5896. ctx->type = args[0]->type;
  5897. asDELETE(args[0],asSExprContext);
  5898. return;
  5899. }
  5900. }
  5901. // Check for possible constructor/factory
  5902. name = dt.Format();
  5903. asSTypeBehaviour *beh = dt.GetBehaviour();
  5904. if( !(dt.GetObjectType()->flags & asOBJ_REF) )
  5905. {
  5906. funcs = beh->constructors;
  5907. // Value types and script types are allocated through the constructor
  5908. tempObj.dataType = dt;
  5909. tempObj.stackOffset = (short)AllocateVariable(dt, true);
  5910. tempObj.dataType.MakeReference(true);
  5911. tempObj.isTemporary = true;
  5912. tempObj.isVariable = true;
  5913. onHeap = IsVariableOnHeap(tempObj.stackOffset);
  5914. // Push the address of the object on the stack
  5915. if( onHeap )
  5916. ctx->bc.InstrSHORT(asBC_VAR, tempObj.stackOffset);
  5917. }
  5918. else
  5919. {
  5920. funcs = beh->factories;
  5921. }
  5922. // Special case: Allow calling func(void) with a void expression.
  5923. if( args.GetLength() == 1 && args[0]->type.dataType == asCDataType::CreatePrimitive(ttVoid, false) )
  5924. {
  5925. // Evaluate the expression before the function call
  5926. MergeExprBytecode(ctx, args[0]);
  5927. asDELETE(args[0],asSExprContext);
  5928. args.SetLength(0);
  5929. }
  5930. // Special case: If this is an object constructor and there are no arguments use the default constructor.
  5931. // If none has been registered, just allocate the variable and push it on the stack.
  5932. if( args.GetLength() == 0 )
  5933. {
  5934. asSTypeBehaviour *beh = tempObj.dataType.GetBehaviour();
  5935. if( beh && beh->construct == 0 && !(dt.GetObjectType()->flags & asOBJ_REF) )
  5936. {
  5937. // Call the default constructor
  5938. ctx->type = tempObj;
  5939. if( onHeap )
  5940. {
  5941. asASSERT(ctx->bc.GetLastInstr() == asBC_VAR);
  5942. ctx->bc.RemoveLastInstr();
  5943. }
  5944. CallDefaultConstructor(tempObj.dataType, tempObj.stackOffset, IsVariableOnHeap(tempObj.stackOffset), &ctx->bc, node);
  5945. // Push the reference on the stack
  5946. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  5947. return;
  5948. }
  5949. }
  5950. MatchFunctions(funcs, args, node, name.AddressOf(), NULL, false);
  5951. if( funcs.GetLength() != 1 )
  5952. {
  5953. // The error was reported by MatchFunctions()
  5954. // Dummy value
  5955. ctx->type.SetDummy();
  5956. }
  5957. else
  5958. {
  5959. int r = asSUCCESS;
  5960. // Add the default values for arguments not explicitly supplied
  5961. asCScriptFunction *func = (funcs[0] & 0xFFFF0000) == 0 ? engine->scriptFunctions[funcs[0]] : 0;
  5962. if( func && args.GetLength() < (asUINT)func->GetParamCount() )
  5963. r = CompileDefaultArgs(node, args, func);
  5964. if( r == asSUCCESS )
  5965. {
  5966. asCByteCode objBC(engine);
  5967. PrepareFunctionCall(funcs[0], &ctx->bc, args);
  5968. MoveArgsToStack(funcs[0], &ctx->bc, args, false);
  5969. if( !(dt.GetObjectType()->flags & asOBJ_REF) )
  5970. {
  5971. // If the object is allocated on the stack, then call the constructor as a normal function
  5972. if( onHeap )
  5973. {
  5974. int offset = 0;
  5975. asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]);
  5976. for( asUINT n = 0; n < args.GetLength(); n++ )
  5977. offset += descr->parameterTypes[n].GetSizeOnStackDWords();
  5978. ctx->bc.InstrWORD(asBC_GETREF, (asWORD)offset);
  5979. }
  5980. else
  5981. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  5982. PerformFunctionCall(funcs[0], ctx, onHeap, &args, tempObj.dataType.GetObjectType());
  5983. // The constructor doesn't return anything,
  5984. // so we have to manually inform the type of
  5985. // the return value
  5986. ctx->type = tempObj;
  5987. if( !onHeap )
  5988. ctx->type.dataType.MakeReference(false);
  5989. // Push the address of the object on the stack again
  5990. ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset);
  5991. }
  5992. else
  5993. {
  5994. // Call the factory to create the reference type
  5995. PerformFunctionCall(funcs[0], ctx, false, &args);
  5996. }
  5997. }
  5998. }
  5999. }
  6000. else
  6001. {
  6002. // Failed to compile the argument list, set the result to the dummy type
  6003. ctx->type.SetDummy();
  6004. }
  6005. // Cleanup
  6006. for( asUINT n = 0; n < args.GetLength(); n++ )
  6007. if( args[n] )
  6008. {
  6009. asDELETE(args[n],asSExprContext);
  6010. }
  6011. }
  6012. void asCCompiler::CompileFunctionCall(asCScriptNode *node, asSExprContext *ctx, asCObjectType *objectType, bool objIsConst, const asCString &scope)
  6013. {
  6014. asCString name;
  6015. asCTypeInfo tempObj;
  6016. asCArray<int> funcs;
  6017. int r = -1;
  6018. asCScriptNode *nm = node->lastChild->prev;
  6019. name.Assign(&script->code[nm->tokenPos], nm->tokenLength);
  6020. // TODO: funcdef: First check for a local variable of a function type
  6021. // Must not allow function names, nor global variables to be returned in this instance
  6022. asSExprContext funcPtr(engine);
  6023. if( objectType == 0 )
  6024. r = CompileVariableAccess(name, scope, &funcPtr, node, true, true);
  6025. if( r < 0 )
  6026. {
  6027. if( objectType )
  6028. {
  6029. // If we're compiling a constructor and the name of the function is super then
  6030. // the constructor of the base class is being called.
  6031. // super cannot be prefixed with a scope operator
  6032. if( m_isConstructor && name == SUPER_TOKEN && nm->prev == 0 )
  6033. {
  6034. // If the class is not derived from anyone else, calling super should give an error
  6035. if( objectType->derivedFrom )
  6036. funcs = objectType->derivedFrom->beh.constructors;
  6037. }
  6038. else
  6039. builder->GetObjectMethodDescriptions(name.AddressOf(), objectType, funcs, objIsConst, scope);
  6040. // It is still possible that there is a class member of a function type
  6041. if( funcs.GetLength() == 0 )
  6042. CompileVariableAccess(name, scope, &funcPtr, node, true, true, objectType);
  6043. }
  6044. else
  6045. {
  6046. builder->GetFunctionDescriptions(name.AddressOf(), funcs);
  6047. // TODO: funcdef: It is still possible that there is a global variable of a function type
  6048. }
  6049. }
  6050. if( funcs.GetLength() == 0 && funcPtr.type.dataType.GetFuncDef() )
  6051. {
  6052. funcs.PushLast(funcPtr.type.dataType.GetFuncDef()->id);
  6053. }
  6054. if( globalExpression )
  6055. {
  6056. Error(TXT_FUNCTION_IN_GLOBAL_EXPR, node);
  6057. // Output dummy code
  6058. ctx->type.SetDummy();
  6059. return;
  6060. }
  6061. // Compile the arguments
  6062. asCArray<asSExprContext *> args;
  6063. asCArray<asCTypeInfo> temporaryVariables;
  6064. if( CompileArgumentList(node->lastChild, args) >= 0 )
  6065. {
  6066. // Special case: Allow calling func(void) with a void expression.
  6067. if( args.GetLength() == 1 && args[0]->type.dataType == asCDataType::CreatePrimitive(ttVoid, false) )
  6068. {
  6069. // Evaluate the expression before the function call
  6070. MergeExprBytecode(ctx, args[0]);
  6071. asDELETE(args[0],asSExprContext);
  6072. args.SetLength(0);
  6073. }
  6074. MatchFunctions(funcs, args, node, name.AddressOf(), objectType, objIsConst, false, true, scope);
  6075. if( funcs.GetLength() != 1 )
  6076. {
  6077. // The error was reported by MatchFunctions()
  6078. // Dummy value
  6079. ctx->type.SetDummy();
  6080. }
  6081. else
  6082. {
  6083. int r = asSUCCESS;
  6084. // Add the default values for arguments not explicitly supplied
  6085. asCScriptFunction *func = (funcs[0] & 0xFFFF0000) == 0 ? engine->scriptFunctions[funcs[0]] : 0;
  6086. if( func && args.GetLength() < (asUINT)func->GetParamCount() )
  6087. r = CompileDefaultArgs(node, args, func);
  6088. // TODO: funcdef: Do we have to make sure the handle is stored in a temporary variable, or
  6089. // is it enough to make sure it is in a local variable?
  6090. // For function pointer we must guarantee that the function is safe, i.e.
  6091. // by first storing the function pointer in a local variable (if it isn't already in one)
  6092. if( r == asSUCCESS )
  6093. {
  6094. if( (funcs[0] & 0xFFFF0000) == 0 && engine->scriptFunctions[funcs[0]]->funcType == asFUNC_FUNCDEF )
  6095. {
  6096. if( objectType )
  6097. {
  6098. Dereference(ctx, true); // Dereference the object pointer to access the member
  6099. // The actual function should be called as if a global function
  6100. objectType = 0;
  6101. }
  6102. Dereference(&funcPtr, true);
  6103. ConvertToVariable(&funcPtr);
  6104. ctx->bc.AddCode(&funcPtr.bc);
  6105. if( !funcPtr.type.isTemporary )
  6106. ctx->bc.Pop(AS_PTR_SIZE);
  6107. }
  6108. MakeFunctionCall(ctx, funcs[0], objectType, args, node, false, 0, funcPtr.type.stackOffset);
  6109. // If the function pointer was copied to a local variable for the call, then
  6110. // release it again (temporary local variable)
  6111. if( (funcs[0] & 0xFFFF0000) == 0 && engine->scriptFunctions[funcs[0]]->funcType == asFUNC_FUNCDEF )
  6112. {
  6113. ReleaseTemporaryVariable(funcPtr.type, &ctx->bc);
  6114. }
  6115. }
  6116. }
  6117. }
  6118. else
  6119. {
  6120. // Failed to compile the argument list, set the dummy type and continue compilation
  6121. ctx->type.SetDummy();
  6122. }
  6123. // Cleanup
  6124. for( asUINT n = 0; n < args.GetLength(); n++ )
  6125. if( args[n] )
  6126. {
  6127. asDELETE(args[n],asSExprContext);
  6128. }
  6129. }
  6130. int asCCompiler::CompileExpressionPreOp(asCScriptNode *node, asSExprContext *ctx)
  6131. {
  6132. int op = node->tokenType;
  6133. IsVariableInitialized(&ctx->type, node);
  6134. if( op == ttHandle )
  6135. {
  6136. // Verify that the type allow its handle to be taken
  6137. if( ctx->type.isExplicitHandle || !ctx->type.dataType.IsObject() || !ctx->type.dataType.GetObjectType()->beh.addref || !ctx->type.dataType.GetObjectType()->beh.release )
  6138. {
  6139. Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node);
  6140. return -1;
  6141. }
  6142. // Objects that are not local variables are not references
  6143. if( !ctx->type.dataType.IsReference() && !(ctx->type.dataType.IsObject() && !ctx->type.isVariable) )
  6144. {
  6145. Error(TXT_NOT_VALID_REFERENCE, node);
  6146. return -1;
  6147. }
  6148. // If this is really an object then the handle created is a const handle
  6149. bool makeConst = !ctx->type.dataType.IsObjectHandle();
  6150. // Mark the type as an object handle
  6151. ctx->type.dataType.MakeHandle(true);
  6152. ctx->type.isExplicitHandle = true;
  6153. if( makeConst )
  6154. ctx->type.dataType.MakeReadOnly(true);
  6155. }
  6156. else if( (op == ttMinus || op == ttBitNot || op == ttInc || op == ttDec) && ctx->type.dataType.IsObject() )
  6157. {
  6158. // Look for the appropriate method
  6159. const char *opName = 0;
  6160. switch( op )
  6161. {
  6162. case ttMinus: opName = "opNeg"; break;
  6163. case ttBitNot: opName = "opCom"; break;
  6164. case ttInc: opName = "opPreInc"; break;
  6165. case ttDec: opName = "opPreDec"; break;
  6166. }
  6167. if( opName )
  6168. {
  6169. // TODO: Should convert this to something similar to CompileOverloadedDualOperator2
  6170. ProcessPropertyGetAccessor(ctx, node);
  6171. // Is it a const value?
  6172. bool isConst = false;
  6173. if( ctx->type.dataType.IsObjectHandle() )
  6174. isConst = ctx->type.dataType.IsHandleToConst();
  6175. else
  6176. isConst = ctx->type.dataType.IsReadOnly();
  6177. // 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
  6178. // Find the correct method
  6179. asCArray<int> funcs;
  6180. asCObjectType *ot = ctx->type.dataType.GetObjectType();
  6181. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  6182. {
  6183. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  6184. if( func->name == opName &&
  6185. func->parameterTypes.GetLength() == 0 &&
  6186. (!isConst || func->isReadOnly) )
  6187. {
  6188. funcs.PushLast(func->id);
  6189. }
  6190. }
  6191. // Did we find the method?
  6192. if( funcs.GetLength() == 1 )
  6193. {
  6194. asCTypeInfo objType = ctx->type;
  6195. asCArray<asSExprContext *> args;
  6196. MakeFunctionCall(ctx, funcs[0], objType.dataType.GetObjectType(), args, node);
  6197. ReleaseTemporaryVariable(objType, &ctx->bc);
  6198. return 0;
  6199. }
  6200. else if( funcs.GetLength() == 0 )
  6201. {
  6202. asCString str;
  6203. str = asCString(opName) + "()";
  6204. if( isConst )
  6205. str += " const";
  6206. str.Format(TXT_FUNCTION_s_NOT_FOUND, str.AddressOf());
  6207. Error(str.AddressOf(), node);
  6208. ctx->type.SetDummy();
  6209. return -1;
  6210. }
  6211. else if( funcs.GetLength() > 1 )
  6212. {
  6213. Error(TXT_MORE_THAN_ONE_MATCHING_OP, node);
  6214. PrintMatchingFuncs(funcs, node);
  6215. ctx->type.SetDummy();
  6216. return -1;
  6217. }
  6218. }
  6219. }
  6220. else if( op == ttPlus || op == ttMinus )
  6221. {
  6222. ProcessPropertyGetAccessor(ctx, node);
  6223. asCDataType to = ctx->type.dataType;
  6224. // TODO: The case -2147483648 gives an unecessary warning of changed sign for implicit conversion
  6225. if( ctx->type.dataType.IsUnsignedType() || ctx->type.dataType.IsEnumType() )
  6226. {
  6227. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  6228. to = asCDataType::CreatePrimitive(ttInt8, false);
  6229. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  6230. to = asCDataType::CreatePrimitive(ttInt16, false);
  6231. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 )
  6232. to = asCDataType::CreatePrimitive(ttInt, false);
  6233. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 8 )
  6234. to = asCDataType::CreatePrimitive(ttInt64, false);
  6235. else
  6236. {
  6237. Error(TXT_INVALID_TYPE, node);
  6238. return -1;
  6239. }
  6240. }
  6241. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  6242. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV);
  6243. if( !ctx->type.isConstant )
  6244. {
  6245. ConvertToTempVariable(ctx);
  6246. if( op == ttMinus )
  6247. {
  6248. if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  6249. ctx->bc.InstrSHORT(asBC_NEGi, ctx->type.stackOffset);
  6250. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  6251. ctx->bc.InstrSHORT(asBC_NEGi64, ctx->type.stackOffset);
  6252. else if( ctx->type.dataType.IsFloatType() )
  6253. ctx->bc.InstrSHORT(asBC_NEGf, ctx->type.stackOffset);
  6254. else if( ctx->type.dataType.IsDoubleType() )
  6255. ctx->bc.InstrSHORT(asBC_NEGd, ctx->type.stackOffset);
  6256. else
  6257. {
  6258. Error(TXT_ILLEGAL_OPERATION, node);
  6259. return -1;
  6260. }
  6261. return 0;
  6262. }
  6263. }
  6264. else
  6265. {
  6266. if( op == ttMinus )
  6267. {
  6268. if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  6269. ctx->type.intValue = -ctx->type.intValue;
  6270. else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  6271. ctx->type.qwordValue = -(asINT64)ctx->type.qwordValue;
  6272. else if( ctx->type.dataType.IsFloatType() )
  6273. ctx->type.floatValue = -ctx->type.floatValue;
  6274. else if( ctx->type.dataType.IsDoubleType() )
  6275. ctx->type.doubleValue = -ctx->type.doubleValue;
  6276. else
  6277. {
  6278. Error(TXT_ILLEGAL_OPERATION, node);
  6279. return -1;
  6280. }
  6281. return 0;
  6282. }
  6283. }
  6284. if( op == ttPlus )
  6285. {
  6286. if( !ctx->type.dataType.IsIntegerType() &&
  6287. !ctx->type.dataType.IsFloatType() &&
  6288. !ctx->type.dataType.IsDoubleType() )
  6289. {
  6290. Error(TXT_ILLEGAL_OPERATION, node);
  6291. return -1;
  6292. }
  6293. }
  6294. }
  6295. else if( op == ttNot )
  6296. {
  6297. if( ctx->type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) )
  6298. {
  6299. if( ctx->type.isConstant )
  6300. {
  6301. ctx->type.dwordValue = (ctx->type.dwordValue == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  6302. return 0;
  6303. }
  6304. ProcessPropertyGetAccessor(ctx, node);
  6305. ConvertToTempVariable(ctx);
  6306. ctx->bc.InstrSHORT(asBC_NOT, ctx->type.stackOffset);
  6307. }
  6308. else
  6309. {
  6310. Error(TXT_ILLEGAL_OPERATION, node);
  6311. return -1;
  6312. }
  6313. }
  6314. else if( op == ttBitNot )
  6315. {
  6316. ProcessPropertyGetAccessor(ctx, node);
  6317. asCDataType to = ctx->type.dataType;
  6318. if( ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsEnumType() )
  6319. {
  6320. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  6321. to = asCDataType::CreatePrimitive(ttUInt8, false);
  6322. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  6323. to = asCDataType::CreatePrimitive(ttUInt16, false);
  6324. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 )
  6325. to = asCDataType::CreatePrimitive(ttUInt, false);
  6326. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 8 )
  6327. to = asCDataType::CreatePrimitive(ttUInt64, false);
  6328. else
  6329. {
  6330. Error(TXT_INVALID_TYPE, node);
  6331. return -1;
  6332. }
  6333. }
  6334. if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx);
  6335. ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV);
  6336. if( ctx->type.dataType.IsUnsignedType() )
  6337. {
  6338. if( ctx->type.isConstant )
  6339. {
  6340. ctx->type.qwordValue = ~ctx->type.qwordValue;
  6341. return 0;
  6342. }
  6343. ConvertToTempVariable(ctx);
  6344. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  6345. ctx->bc.InstrSHORT(asBC_BNOT, ctx->type.stackOffset);
  6346. else
  6347. ctx->bc.InstrSHORT(asBC_BNOT64, ctx->type.stackOffset);
  6348. }
  6349. else
  6350. {
  6351. Error(TXT_ILLEGAL_OPERATION, node);
  6352. return -1;
  6353. }
  6354. }
  6355. else if( op == ttInc || op == ttDec )
  6356. {
  6357. // Need a reference to the primitive that will be updated
  6358. // The result of this expression is the same reference as before
  6359. if( globalExpression )
  6360. {
  6361. Error(TXT_INC_OP_IN_GLOBAL_EXPR, node);
  6362. return -1;
  6363. }
  6364. // Make sure the reference isn't a temporary variable
  6365. if( ctx->type.isTemporary )
  6366. {
  6367. Error(TXT_REF_IS_TEMP, node);
  6368. return -1;
  6369. }
  6370. if( ctx->type.dataType.IsReadOnly() )
  6371. {
  6372. Error(TXT_REF_IS_READ_ONLY, node);
  6373. return -1;
  6374. }
  6375. if( ctx->property_get || ctx->property_set )
  6376. {
  6377. Error(TXT_INVALID_REF_PROP_ACCESS, node);
  6378. return -1;
  6379. }
  6380. if( ctx->type.isVariable && !ctx->type.dataType.IsReference() )
  6381. ConvertToReference(ctx);
  6382. else if( !ctx->type.dataType.IsReference() )
  6383. {
  6384. Error(TXT_NOT_VALID_REFERENCE, node);
  6385. return -1;
  6386. }
  6387. if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt64, false)) ||
  6388. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt64, false)) )
  6389. {
  6390. if( op == ttInc )
  6391. ctx->bc.Instr(asBC_INCi64);
  6392. else
  6393. ctx->bc.Instr(asBC_DECi64);
  6394. }
  6395. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt, false)) ||
  6396. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt, false)) )
  6397. {
  6398. if( op == ttInc )
  6399. ctx->bc.Instr(asBC_INCi);
  6400. else
  6401. ctx->bc.Instr(asBC_DECi);
  6402. }
  6403. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt16, false)) ||
  6404. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt16, false)) )
  6405. {
  6406. if( op == ttInc )
  6407. ctx->bc.Instr(asBC_INCi16);
  6408. else
  6409. ctx->bc.Instr(asBC_DECi16);
  6410. }
  6411. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt8, false)) ||
  6412. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt8, false)) )
  6413. {
  6414. if( op == ttInc )
  6415. ctx->bc.Instr(asBC_INCi8);
  6416. else
  6417. ctx->bc.Instr(asBC_DECi8);
  6418. }
  6419. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttFloat, false)) )
  6420. {
  6421. if( op == ttInc )
  6422. ctx->bc.Instr(asBC_INCf);
  6423. else
  6424. ctx->bc.Instr(asBC_DECf);
  6425. }
  6426. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttDouble, false)) )
  6427. {
  6428. if( op == ttInc )
  6429. ctx->bc.Instr(asBC_INCd);
  6430. else
  6431. ctx->bc.Instr(asBC_DECd);
  6432. }
  6433. else
  6434. {
  6435. Error(TXT_ILLEGAL_OPERATION, node);
  6436. return -1;
  6437. }
  6438. }
  6439. else
  6440. {
  6441. // Unknown operator
  6442. asASSERT(false);
  6443. return -1;
  6444. }
  6445. return 0;
  6446. }
  6447. void asCCompiler::ConvertToReference(asSExprContext *ctx)
  6448. {
  6449. if( ctx->type.isVariable && !ctx->type.dataType.IsReference() )
  6450. {
  6451. ctx->bc.InstrSHORT(asBC_LDV, ctx->type.stackOffset);
  6452. ctx->type.dataType.MakeReference(true);
  6453. ctx->type.SetVariable(ctx->type.dataType, ctx->type.stackOffset, ctx->type.isTemporary);
  6454. }
  6455. }
  6456. int asCCompiler::FindPropertyAccessor(const asCString &name, asSExprContext *ctx, asCScriptNode *node)
  6457. {
  6458. return FindPropertyAccessor(name, ctx, 0, node);
  6459. }
  6460. int asCCompiler::FindPropertyAccessor(const asCString &name, asSExprContext *ctx, asSExprContext *arg, asCScriptNode *node)
  6461. {
  6462. if( engine->ep.propertyAccessorMode == 0 )
  6463. {
  6464. // Property accessors have been disabled by the application
  6465. return 0;
  6466. }
  6467. int getId = 0, setId = 0;
  6468. asCString getName = "get_" + name;
  6469. asCString setName = "set_" + name;
  6470. asCArray<int> multipleGetFuncs, multipleSetFuncs;
  6471. if( ctx->type.dataType.IsObject() )
  6472. {
  6473. // Check if the object has any methods with the property name prefixed by get_ or set_
  6474. asCObjectType *ot = ctx->type.dataType.GetObjectType();
  6475. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  6476. {
  6477. asCScriptFunction *f = engine->scriptFunctions[ot->methods[n]];
  6478. // TODO: The type of the parameter should match the argument (unless the arg is a dummy)
  6479. if( f->name == getName && (int)f->parameterTypes.GetLength() == (arg?1:0) )
  6480. {
  6481. if( getId == 0 )
  6482. getId = ot->methods[n];
  6483. else
  6484. {
  6485. if( multipleGetFuncs.GetLength() == 0 )
  6486. multipleGetFuncs.PushLast(getId);
  6487. multipleGetFuncs.PushLast(ot->methods[n]);
  6488. }
  6489. }
  6490. // TODO: getset: If the parameter is a reference, it must not be an out reference. Should we allow inout ref?
  6491. if( f->name == setName && (int)f->parameterTypes.GetLength() == (arg?2:1) )
  6492. {
  6493. if( setId == 0 )
  6494. setId = ot->methods[n];
  6495. else
  6496. {
  6497. if( multipleSetFuncs.GetLength() == 0 )
  6498. multipleSetFuncs.PushLast(setId);
  6499. multipleSetFuncs.PushLast(ot->methods[n]);
  6500. }
  6501. }
  6502. }
  6503. }
  6504. else
  6505. {
  6506. // Look for appropriate global functions.
  6507. asCArray<int> funcs;
  6508. asUINT n;
  6509. builder->GetFunctionDescriptions(getName.AddressOf(), funcs);
  6510. for( n = 0; n < funcs.GetLength(); n++ )
  6511. {
  6512. asCScriptFunction *f = engine->scriptFunctions[funcs[n]];
  6513. // TODO: The type of the parameter should match the argument (unless the arg is a dummy)
  6514. if( (int)f->parameterTypes.GetLength() == (arg?1:0) )
  6515. {
  6516. if( getId == 0 )
  6517. getId = funcs[n];
  6518. else
  6519. {
  6520. if( multipleGetFuncs.GetLength() == 0 )
  6521. multipleGetFuncs.PushLast(getId);
  6522. multipleGetFuncs.PushLast(funcs[n]);
  6523. }
  6524. }
  6525. }
  6526. funcs.SetLength(0);
  6527. builder->GetFunctionDescriptions(setName.AddressOf(), funcs);
  6528. for( n = 0; n < funcs.GetLength(); n++ )
  6529. {
  6530. asCScriptFunction *f = engine->scriptFunctions[funcs[n]];
  6531. // TODO: getset: If the parameter is a reference, it must not be an out reference. Should we allow inout ref?
  6532. if( (int)f->parameterTypes.GetLength() == (arg?2:1) )
  6533. {
  6534. if( setId == 0 )
  6535. setId = funcs[n];
  6536. else
  6537. {
  6538. if( multipleSetFuncs.GetLength() == 0 )
  6539. multipleSetFuncs.PushLast(getId);
  6540. multipleSetFuncs.PushLast(funcs[n]);
  6541. }
  6542. }
  6543. }
  6544. }
  6545. // Check for multiple matches
  6546. if( multipleGetFuncs.GetLength() > 0 )
  6547. {
  6548. asCString str;
  6549. str.Format(TXT_MULTIPLE_PROP_GET_ACCESSOR_FOR_s, name.AddressOf());
  6550. Error(str.AddressOf(), node);
  6551. PrintMatchingFuncs(multipleGetFuncs, node);
  6552. return -1;
  6553. }
  6554. if( multipleSetFuncs.GetLength() > 0 )
  6555. {
  6556. asCString str;
  6557. str.Format(TXT_MULTIPLE_PROP_SET_ACCESSOR_FOR_s, name.AddressOf());
  6558. Error(str.AddressOf(), node);
  6559. PrintMatchingFuncs(multipleSetFuncs, node);
  6560. return -1;
  6561. }
  6562. // Check for type compatibility between get and set accessor
  6563. if( getId && setId )
  6564. {
  6565. asCScriptFunction *getFunc = engine->scriptFunctions[getId];
  6566. asCScriptFunction *setFunc = engine->scriptFunctions[setId];
  6567. // It is permitted for a getter to return a handle and the setter to take a reference
  6568. int idx = (arg?1:0);
  6569. if( !getFunc->returnType.IsEqualExceptRefAndConst(setFunc->parameterTypes[idx]) &&
  6570. !((getFunc->returnType.IsObjectHandle() && !setFunc->parameterTypes[idx].IsObjectHandle()) &&
  6571. (getFunc->returnType.GetObjectType() == setFunc->parameterTypes[idx].GetObjectType())) )
  6572. {
  6573. asCString str;
  6574. str.Format(TXT_GET_SET_ACCESSOR_TYPE_MISMATCH_FOR_s, name.AddressOf());
  6575. Error(str.AddressOf(), node);
  6576. asCArray<int> funcs;
  6577. funcs.PushLast(getId);
  6578. funcs.PushLast(setId);
  6579. PrintMatchingFuncs(funcs, node);
  6580. return -1;
  6581. }
  6582. }
  6583. // Check if we are within one of the accessors
  6584. int realGetId = getId;
  6585. int realSetId = setId;
  6586. if( outFunc->objectType )
  6587. {
  6588. // The property accessors would be virtual functions, so we need to find the real implementation
  6589. asCScriptFunction *getFunc = getId ? engine->scriptFunctions[getId] : 0;
  6590. if( getFunc &&
  6591. getFunc->funcType == asFUNC_VIRTUAL &&
  6592. outFunc->objectType->DerivesFrom(getFunc->objectType) )
  6593. realGetId = outFunc->objectType->virtualFunctionTable[getFunc->vfTableIdx]->id;
  6594. asCScriptFunction *setFunc = setId ? engine->scriptFunctions[setId] : 0;
  6595. if( setFunc &&
  6596. setFunc->funcType == asFUNC_VIRTUAL &&
  6597. outFunc->objectType->DerivesFrom(setFunc->objectType) )
  6598. realSetId = outFunc->objectType->virtualFunctionTable[setFunc->vfTableIdx]->id;
  6599. }
  6600. if( (realGetId && realGetId == outFunc->id) ||
  6601. (realSetId && realSetId == outFunc->id) )
  6602. {
  6603. // Avoid recursive call, by not treating this as a property accessor call.
  6604. // This will also allow having the real property with the same name as the accessors.
  6605. getId = 0;
  6606. setId = 0;
  6607. }
  6608. // Check if the application has disabled script written property accessors
  6609. if( engine->ep.propertyAccessorMode == 1 )
  6610. {
  6611. if( getId && engine->scriptFunctions[getId]->funcType != asFUNC_SYSTEM )
  6612. getId = 0;
  6613. if( setId && engine->scriptFunctions[setId]->funcType != asFUNC_SYSTEM )
  6614. setId = 0;
  6615. }
  6616. if( getId || setId )
  6617. {
  6618. // Property accessors were found, but we don't know which is to be used yet, so
  6619. // we just prepare the bytecode for the method call, and then store the function ids
  6620. // so that the right one can be used when we get there.
  6621. ctx->property_get = getId;
  6622. ctx->property_set = setId;
  6623. if( ctx->type.dataType.IsObject() )
  6624. {
  6625. // If the object is read-only then we need to remember that
  6626. if( (!ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReadOnly()) ||
  6627. (ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsHandleToConst()) )
  6628. ctx->property_const = true;
  6629. else
  6630. ctx->property_const = false;
  6631. // If the object is a handle then we need to remember that
  6632. ctx->property_handle = ctx->type.dataType.IsObjectHandle();
  6633. ctx->property_ref = ctx->type.dataType.IsReference();
  6634. }
  6635. // The setter's parameter type is used as the property type,
  6636. // unless only the getter is available
  6637. asCDataType dt;
  6638. if( setId )
  6639. dt = engine->scriptFunctions[setId]->parameterTypes[(arg?1:0)];
  6640. else
  6641. dt = engine->scriptFunctions[getId]->returnType;
  6642. // Just change the type, the context must still maintain information
  6643. // about previous variable offset and the indicator of temporary variable.
  6644. int offset = ctx->type.stackOffset;
  6645. bool isTemp = ctx->type.isTemporary;
  6646. ctx->type.Set(dt);
  6647. ctx->type.stackOffset = (short)offset;
  6648. ctx->type.isTemporary = isTemp;
  6649. ctx->exprNode = node;
  6650. // Store the argument for later use
  6651. if( arg )
  6652. {
  6653. ctx->property_arg = asNEW(asSExprContext)(engine);
  6654. MergeExprBytecodeAndType(ctx->property_arg, arg);
  6655. }
  6656. return 1;
  6657. }
  6658. // No accessor was found
  6659. return 0;
  6660. }
  6661. int asCCompiler::ProcessPropertySetAccessor(asSExprContext *ctx, asSExprContext *arg, asCScriptNode *node)
  6662. {
  6663. // TODO: A lot of this code is similar to ProcessPropertyGetAccessor. Can we unify them?
  6664. if( !ctx->property_set )
  6665. {
  6666. Error(TXT_PROPERTY_HAS_NO_SET_ACCESSOR, node);
  6667. return -1;
  6668. }
  6669. asCTypeInfo objType = ctx->type;
  6670. asCScriptFunction *func = engine->scriptFunctions[ctx->property_set];
  6671. // Make sure the arg match the property
  6672. asCArray<int> funcs;
  6673. funcs.PushLast(ctx->property_set);
  6674. asCArray<asSExprContext *> args;
  6675. if( ctx->property_arg )
  6676. args.PushLast(ctx->property_arg);
  6677. args.PushLast(arg);
  6678. MatchFunctions(funcs, args, node, func->GetName(), func->objectType, ctx->property_const);
  6679. if( funcs.GetLength() == 0 )
  6680. {
  6681. // MatchFunctions already reported the error
  6682. if( ctx->property_arg )
  6683. {
  6684. asDELETE(ctx->property_arg, asSExprContext);
  6685. ctx->property_arg = 0;
  6686. }
  6687. return -1;
  6688. }
  6689. if( func->objectType )
  6690. {
  6691. // Setup the context with the original type so the method call gets built correctly
  6692. ctx->type.dataType = asCDataType::CreateObject(func->objectType, ctx->property_const);
  6693. if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
  6694. if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
  6695. // Don't allow the call if the object is read-only and the property accessor is not const
  6696. if( ctx->property_const && !func->isReadOnly )
  6697. {
  6698. Error(TXT_NON_CONST_METHOD_ON_CONST_OBJ, node);
  6699. asCArray<int> funcs;
  6700. funcs.PushLast(ctx->property_set);
  6701. PrintMatchingFuncs(funcs, node);
  6702. }
  6703. }
  6704. // Call the accessor
  6705. MakeFunctionCall(ctx, ctx->property_set, func->objectType, args, node);
  6706. if( func->objectType )
  6707. {
  6708. // TODO: This is from CompileExpressionPostOp, can we unify the code?
  6709. if( objType.isTemporary &&
  6710. ctx->type.dataType.IsReference() &&
  6711. !ctx->type.isVariable ) // If the resulting type is a variable, then the reference is not a member
  6712. {
  6713. // Remember the original object's variable, so that it can be released
  6714. // later on when the reference to its member goes out of scope
  6715. ctx->type.isTemporary = true;
  6716. ctx->type.stackOffset = objType.stackOffset;
  6717. }
  6718. else
  6719. {
  6720. // As the method didn't return a reference to a member
  6721. // we can safely release the original object now
  6722. ReleaseTemporaryVariable(objType, &ctx->bc);
  6723. }
  6724. }
  6725. ctx->property_get = 0;
  6726. ctx->property_set = 0;
  6727. if( ctx->property_arg )
  6728. {
  6729. asDELETE(ctx->property_arg, asSExprContext);
  6730. ctx->property_arg = 0;
  6731. }
  6732. return 0;
  6733. }
  6734. void asCCompiler::ProcessPropertyGetAccessor(asSExprContext *ctx, asCScriptNode *node)
  6735. {
  6736. // If no property accessor has been prepared then don't do anything
  6737. if( !ctx->property_get && !ctx->property_set )
  6738. return;
  6739. if( !ctx->property_get )
  6740. {
  6741. // Raise error on missing accessor
  6742. Error(TXT_PROPERTY_HAS_NO_GET_ACCESSOR, node);
  6743. ctx->type.SetDummy();
  6744. return;
  6745. }
  6746. asCTypeInfo objType = ctx->type;
  6747. asCScriptFunction *func = engine->scriptFunctions[ctx->property_get];
  6748. // Make sure the arg match the property
  6749. asCArray<int> funcs;
  6750. funcs.PushLast(ctx->property_get);
  6751. asCArray<asSExprContext *> args;
  6752. if( ctx->property_arg )
  6753. args.PushLast(ctx->property_arg);
  6754. MatchFunctions(funcs, args, node, func->GetName(), func->objectType, ctx->property_const);
  6755. if( funcs.GetLength() == 0 )
  6756. {
  6757. // MatchFunctions already reported the error
  6758. if( ctx->property_arg )
  6759. {
  6760. asDELETE(ctx->property_arg, asSExprContext);
  6761. ctx->property_arg = 0;
  6762. }
  6763. ctx->type.SetDummy();
  6764. return;
  6765. }
  6766. if( func->objectType )
  6767. {
  6768. // Setup the context with the original type so the method call gets built correctly
  6769. ctx->type.dataType = asCDataType::CreateObject(func->objectType, ctx->property_const);
  6770. if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
  6771. if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
  6772. // Don't allow the call if the object is read-only and the property accessor is not const
  6773. if( ctx->property_const && !func->isReadOnly )
  6774. {
  6775. Error(TXT_NON_CONST_METHOD_ON_CONST_OBJ, node);
  6776. asCArray<int> funcs;
  6777. funcs.PushLast(ctx->property_get);
  6778. PrintMatchingFuncs(funcs, node);
  6779. }
  6780. }
  6781. // Call the accessor
  6782. MakeFunctionCall(ctx, ctx->property_get, func->objectType, args, node);
  6783. if( func->objectType )
  6784. {
  6785. // TODO: This is from CompileExpressionPostOp, can we unify the code?
  6786. if( objType.isTemporary &&
  6787. ctx->type.dataType.IsReference() &&
  6788. !ctx->type.isVariable ) // If the resulting type is a variable, then the reference is not a member
  6789. {
  6790. // Remember the original object's variable, so that it can be released
  6791. // later on when the reference to its member goes out of scope
  6792. ctx->type.isTemporary = true;
  6793. ctx->type.stackOffset = objType.stackOffset;
  6794. }
  6795. else
  6796. {
  6797. // As the method didn't return a reference to a member
  6798. // we can safely release the original object now
  6799. ReleaseTemporaryVariable(objType, &ctx->bc);
  6800. }
  6801. }
  6802. ctx->property_get = 0;
  6803. ctx->property_set = 0;
  6804. if( ctx->property_arg )
  6805. {
  6806. asDELETE(ctx->property_arg, asSExprContext);
  6807. ctx->property_arg = 0;
  6808. }
  6809. }
  6810. int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ctx)
  6811. {
  6812. int op = node->tokenType;
  6813. // Check if the variable is initialized (if it indeed is a variable)
  6814. IsVariableInitialized(&ctx->type, node);
  6815. if( (op == ttInc || op == ttDec) && ctx->type.dataType.IsObject() )
  6816. {
  6817. const char *opName = 0;
  6818. switch( op )
  6819. {
  6820. case ttInc: opName = "opPostInc"; break;
  6821. case ttDec: opName = "opPostDec"; break;
  6822. }
  6823. if( opName )
  6824. {
  6825. // TODO: Should convert this to something similar to CompileOverloadedDualOperator2
  6826. ProcessPropertyGetAccessor(ctx, node);
  6827. // Is it a const value?
  6828. bool isConst = false;
  6829. if( ctx->type.dataType.IsObjectHandle() )
  6830. isConst = ctx->type.dataType.IsHandleToConst();
  6831. else
  6832. isConst = ctx->type.dataType.IsReadOnly();
  6833. // 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
  6834. // Find the correct method
  6835. asCArray<int> funcs;
  6836. asCObjectType *ot = ctx->type.dataType.GetObjectType();
  6837. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  6838. {
  6839. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  6840. if( func->name == opName &&
  6841. func->parameterTypes.GetLength() == 0 &&
  6842. (!isConst || func->isReadOnly) )
  6843. {
  6844. funcs.PushLast(func->id);
  6845. }
  6846. }
  6847. // Did we find the method?
  6848. if( funcs.GetLength() == 1 )
  6849. {
  6850. asCTypeInfo objType = ctx->type;
  6851. asCArray<asSExprContext *> args;
  6852. MakeFunctionCall(ctx, funcs[0], objType.dataType.GetObjectType(), args, node);
  6853. ReleaseTemporaryVariable(objType, &ctx->bc);
  6854. return 0;
  6855. }
  6856. else if( funcs.GetLength() == 0 )
  6857. {
  6858. asCString str;
  6859. str = asCString(opName) + "()";
  6860. if( isConst )
  6861. str += " const";
  6862. str.Format(TXT_FUNCTION_s_NOT_FOUND, str.AddressOf());
  6863. Error(str.AddressOf(), node);
  6864. ctx->type.SetDummy();
  6865. return -1;
  6866. }
  6867. else if( funcs.GetLength() > 1 )
  6868. {
  6869. Error(TXT_MORE_THAN_ONE_MATCHING_OP, node);
  6870. PrintMatchingFuncs(funcs, node);
  6871. ctx->type.SetDummy();
  6872. return -1;
  6873. }
  6874. }
  6875. }
  6876. else if( op == ttInc || op == ttDec )
  6877. {
  6878. if( globalExpression )
  6879. {
  6880. Error(TXT_INC_OP_IN_GLOBAL_EXPR, node);
  6881. return -1;
  6882. }
  6883. // Make sure the reference isn't a temporary variable
  6884. if( ctx->type.isTemporary )
  6885. {
  6886. Error(TXT_REF_IS_TEMP, node);
  6887. return -1;
  6888. }
  6889. if( ctx->type.dataType.IsReadOnly() )
  6890. {
  6891. Error(TXT_REF_IS_READ_ONLY, node);
  6892. return -1;
  6893. }
  6894. if( ctx->property_get || ctx->property_set )
  6895. {
  6896. Error(TXT_INVALID_REF_PROP_ACCESS, node);
  6897. return -1;
  6898. }
  6899. if( ctx->type.isVariable && !ctx->type.dataType.IsReference() )
  6900. ConvertToReference(ctx);
  6901. else if( !ctx->type.dataType.IsReference() )
  6902. {
  6903. Error(TXT_NOT_VALID_REFERENCE, node);
  6904. return -1;
  6905. }
  6906. // Copy the value to a temp before changing it
  6907. ConvertToTempVariable(ctx);
  6908. // Increment the value pointed to by the reference still in the register
  6909. asEBCInstr iInc = asBC_INCi, iDec = asBC_DECi;
  6910. if( ctx->type.dataType.IsDoubleType() )
  6911. {
  6912. iInc = asBC_INCd;
  6913. iDec = asBC_DECd;
  6914. }
  6915. else if( ctx->type.dataType.IsFloatType() )
  6916. {
  6917. iInc = asBC_INCf;
  6918. iDec = asBC_DECf;
  6919. }
  6920. else if( ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType() )
  6921. {
  6922. if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt16, false)) ||
  6923. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt16, false)) )
  6924. {
  6925. iInc = asBC_INCi16;
  6926. iDec = asBC_DECi16;
  6927. }
  6928. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt8, false)) ||
  6929. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt8, false)) )
  6930. {
  6931. iInc = asBC_INCi8;
  6932. iDec = asBC_DECi8;
  6933. }
  6934. else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt64, false)) ||
  6935. ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt64, false)) )
  6936. {
  6937. iInc = asBC_INCi64;
  6938. iDec = asBC_DECi64;
  6939. }
  6940. }
  6941. else
  6942. {
  6943. Error(TXT_ILLEGAL_OPERATION, node);
  6944. return -1;
  6945. }
  6946. if( op == ttInc ) ctx->bc.Instr(iInc); else ctx->bc.Instr(iDec);
  6947. }
  6948. else if( op == ttDot )
  6949. {
  6950. if( node->firstChild->nodeType == snIdentifier )
  6951. {
  6952. ProcessPropertyGetAccessor(ctx, node);
  6953. // Get the property name
  6954. asCString name(&script->code[node->firstChild->tokenPos], node->firstChild->tokenLength);
  6955. // We need to look for get/set property accessors.
  6956. // If found, the context stores information on the get/set accessors
  6957. // until it is known which is to be used.
  6958. int r = 0;
  6959. if( node->next && node->next->tokenType == ttOpenBracket )
  6960. {
  6961. // The property accessor should take an index arg
  6962. asSExprContext dummyArg(engine);
  6963. r = FindPropertyAccessor(name, ctx, &dummyArg, node);
  6964. }
  6965. if( r == 0 )
  6966. r = FindPropertyAccessor(name, ctx, node);
  6967. if( r != 0 )
  6968. return r;
  6969. if( !ctx->type.dataType.IsPrimitive() )
  6970. Dereference(ctx, true);
  6971. if( ctx->type.dataType.IsObjectHandle() )
  6972. {
  6973. // Convert the handle to a normal object
  6974. asCDataType dt = ctx->type.dataType;
  6975. dt.MakeHandle(false);
  6976. ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV);
  6977. }
  6978. // Find the property offset and type
  6979. if( ctx->type.dataType.IsObject() )
  6980. {
  6981. bool isConst = ctx->type.dataType.IsReadOnly();
  6982. asCObjectProperty *prop = builder->GetObjectProperty(ctx->type.dataType, name.AddressOf());
  6983. if( prop )
  6984. {
  6985. // Is the property access allowed?
  6986. if( prop->isPrivate && (!outFunc || outFunc->objectType != ctx->type.dataType.GetObjectType()) )
  6987. {
  6988. asCString msg;
  6989. msg.Format(TXT_PRIVATE_PROP_ACCESS_s, name.AddressOf());
  6990. Error(msg.AddressOf(), node);
  6991. }
  6992. // Put the offset on the stack
  6993. ctx->bc.InstrSHORT_DW(asBC_ADDSi, (short)prop->byteOffset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(ctx->type.dataType.GetObjectType(), false)));
  6994. if( prop->type.IsReference() )
  6995. ctx->bc.Instr(asBC_RDSPTR);
  6996. // Reference to primitive must be stored in the temp register
  6997. if( prop->type.IsPrimitive() )
  6998. {
  6999. ctx->bc.Instr(asBC_PopRPtr);
  7000. }
  7001. // Set the new type (keeping info about temp variable)
  7002. ctx->type.dataType = prop->type;
  7003. ctx->type.dataType.MakeReference(true);
  7004. ctx->type.isVariable = false;
  7005. if( ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle() )
  7006. {
  7007. // Objects that are members are not references
  7008. ctx->type.dataType.MakeReference(false);
  7009. }
  7010. ctx->type.dataType.MakeReadOnly(isConst ? true : prop->type.IsReadOnly());
  7011. }
  7012. else
  7013. {
  7014. asCString str;
  7015. str.Format(TXT_s_NOT_MEMBER_OF_s, name.AddressOf(), ctx->type.dataType.Format().AddressOf());
  7016. Error(str.AddressOf(), node);
  7017. return -1;
  7018. }
  7019. }
  7020. else
  7021. {
  7022. asCString str;
  7023. str.Format(TXT_s_NOT_MEMBER_OF_s, name.AddressOf(), ctx->type.dataType.Format().AddressOf());
  7024. Error(str.AddressOf(), node);
  7025. return -1;
  7026. }
  7027. }
  7028. else
  7029. {
  7030. if( globalExpression )
  7031. {
  7032. Error(TXT_METHOD_IN_GLOBAL_EXPR, node);
  7033. return -1;
  7034. }
  7035. // Make sure it is an object we are accessing
  7036. if( !ctx->type.dataType.IsObject() )
  7037. {
  7038. asCString str;
  7039. str.Format(TXT_ILLEGAL_OPERATION_ON_s, ctx->type.dataType.Format().AddressOf());
  7040. Error(str.AddressOf(), node);
  7041. return -1;
  7042. }
  7043. // Process the get property accessor
  7044. ProcessPropertyGetAccessor(ctx, node);
  7045. bool isConst = false;
  7046. if( ctx->type.dataType.IsObjectHandle() )
  7047. isConst = ctx->type.dataType.IsHandleToConst();
  7048. else
  7049. isConst = ctx->type.dataType.IsReadOnly();
  7050. asCObjectType *trueObj = ctx->type.dataType.GetObjectType();
  7051. asCTypeInfo objType = ctx->type;
  7052. // Compile function call
  7053. CompileFunctionCall(node->firstChild, ctx, trueObj, isConst);
  7054. // If the method returned a reference, then we can't release the original
  7055. // object yet, because the reference may be to a member of it
  7056. if( objType.isTemporary &&
  7057. (ctx->type.dataType.IsReference() || (ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle())) &&
  7058. !ctx->type.isVariable ) // If the resulting type is a variable, then the reference is not a member
  7059. {
  7060. // Remember the original object's variable, so that it can be released
  7061. // later on when the reference to its member goes out of scope
  7062. ctx->type.isTemporary = true;
  7063. ctx->type.stackOffset = objType.stackOffset;
  7064. }
  7065. else
  7066. {
  7067. // As the method didn't return a reference to a member
  7068. // we can safely release the original object now
  7069. ReleaseTemporaryVariable(objType, &ctx->bc);
  7070. }
  7071. }
  7072. }
  7073. else if( op == ttOpenBracket )
  7074. {
  7075. // If the property access takes an index arg, then we should use that instead of processing it now
  7076. asCString propertyName;
  7077. if( (ctx->property_get && engine->scriptFunctions[ctx->property_get]->GetParamCount() == 1) ||
  7078. (ctx->property_set && engine->scriptFunctions[ctx->property_set]->GetParamCount() == 2) )
  7079. {
  7080. // Determine the name of the property accessor
  7081. asCScriptFunction *func = 0;
  7082. if( ctx->property_get )
  7083. func = engine->scriptFunctions[ctx->property_get];
  7084. else
  7085. func = engine->scriptFunctions[ctx->property_get];
  7086. propertyName = func->GetName();
  7087. propertyName = propertyName.SubString(4);
  7088. // Set the original type of the expression so we can re-evaluate the property accessor
  7089. if( func->objectType )
  7090. {
  7091. ctx->type.dataType = asCDataType::CreateObject(func->objectType, ctx->property_const);
  7092. if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true);
  7093. if( ctx->property_ref ) ctx->type.dataType.MakeReference(true);
  7094. }
  7095. ctx->property_get = ctx->property_set = 0;
  7096. if( ctx->property_arg )
  7097. {
  7098. asDELETE(ctx->property_arg, asSExprContext);
  7099. ctx->property_arg = 0;
  7100. }
  7101. }
  7102. else
  7103. {
  7104. if( !ctx->type.dataType.IsObject() )
  7105. {
  7106. asCString str;
  7107. str.Format(TXT_OBJECT_DOESNT_SUPPORT_INDEX_OP, ctx->type.dataType.Format().AddressOf());
  7108. Error(str.AddressOf(), node);
  7109. return -1;
  7110. }
  7111. ProcessPropertyGetAccessor(ctx, node);
  7112. }
  7113. Dereference(ctx, true);
  7114. // Compile the expression
  7115. asSExprContext expr(engine);
  7116. CompileAssignment(node->firstChild, &expr);
  7117. // Check for the existence of the opIndex method
  7118. asSExprContext lctx(engine);
  7119. MergeExprBytecodeAndType(&lctx, ctx);
  7120. int r = 0;
  7121. if( propertyName == "" )
  7122. r = CompileOverloadedDualOperator2(node, "opIndex", &lctx, &expr, ctx);
  7123. if( r == 0 )
  7124. {
  7125. // Check for accessors methods for the opIndex
  7126. r = FindPropertyAccessor(propertyName == "" ? "opIndex" : propertyName.AddressOf(), &lctx, &expr, node);
  7127. if( r == 0 )
  7128. {
  7129. asCString str;
  7130. str.Format(TXT_OBJECT_DOESNT_SUPPORT_INDEX_OP, ctx->type.dataType.Format().AddressOf());
  7131. Error(str.AddressOf(), node);
  7132. return -1;
  7133. }
  7134. else if( r < 0 )
  7135. return -1;
  7136. MergeExprBytecodeAndType(ctx, &lctx);
  7137. }
  7138. }
  7139. return 0;
  7140. }
  7141. int asCCompiler::GetPrecedence(asCScriptNode *op)
  7142. {
  7143. // x * y, x / y, x % y
  7144. // x + y, x - y
  7145. // x <= y, x < y, x >= y, x > y
  7146. // x = =y, x != y, x xor y, x is y, x !is y
  7147. // x and y
  7148. // x or y
  7149. // The following are not used in this function,
  7150. // but should have lower precedence than the above
  7151. // x ? y : z
  7152. // x = y
  7153. // The expression term have the highest precedence
  7154. if( op->nodeType == snExprTerm )
  7155. return 1;
  7156. // Evaluate operators by token
  7157. int tokenType = op->tokenType;
  7158. if( tokenType == ttStar || tokenType == ttSlash || tokenType == ttPercent )
  7159. return 0;
  7160. if( tokenType == ttPlus || tokenType == ttMinus )
  7161. return -1;
  7162. if( tokenType == ttBitShiftLeft ||
  7163. tokenType == ttBitShiftRight ||
  7164. tokenType == ttBitShiftRightArith )
  7165. return -2;
  7166. if( tokenType == ttAmp )
  7167. return -3;
  7168. if( tokenType == ttBitXor )
  7169. return -4;
  7170. if( tokenType == ttBitOr )
  7171. return -5;
  7172. if( tokenType == ttLessThanOrEqual ||
  7173. tokenType == ttLessThan ||
  7174. tokenType == ttGreaterThanOrEqual ||
  7175. tokenType == ttGreaterThan )
  7176. return -6;
  7177. if( tokenType == ttEqual || tokenType == ttNotEqual || tokenType == ttXor || tokenType == ttIs || tokenType == ttNotIs )
  7178. return -7;
  7179. if( tokenType == ttAnd )
  7180. return -8;
  7181. if( tokenType == ttOr )
  7182. return -9;
  7183. // Unknown operator
  7184. asASSERT(false);
  7185. return 0;
  7186. }
  7187. int asCCompiler::MatchArgument(asCArray<int> &funcs, asCArray<int> &matches, const asCTypeInfo *argType, int paramNum, bool allowObjectConstruct)
  7188. {
  7189. bool isExactMatch = false;
  7190. bool isMatchExceptConst = false;
  7191. bool isMatchWithBaseType = false;
  7192. bool isMatchExceptSign = false;
  7193. bool isMatchNotVarType = false;
  7194. asUINT n;
  7195. matches.SetLength(0);
  7196. for( n = 0; n < funcs.GetLength(); n++ )
  7197. {
  7198. asCScriptFunction *desc = builder->GetFunctionDescription(funcs[n]);
  7199. // Does the function have arguments enough?
  7200. if( (int)desc->parameterTypes.GetLength() <= paramNum )
  7201. continue;
  7202. // Can we make the match by implicit conversion?
  7203. asSExprContext ti(engine);
  7204. ti.type = *argType;
  7205. if( argType->dataType.IsPrimitive() ) ti.type.dataType.MakeReference(false);
  7206. ImplicitConversion(&ti, desc->parameterTypes[paramNum], 0, asIC_IMPLICIT_CONV, false, 0, allowObjectConstruct);
  7207. // If the function parameter is an inout-reference then it must not be possible to call the
  7208. // function with an incorrect argument type, even though the type can normally be converted.
  7209. if( desc->parameterTypes[paramNum].IsReference() &&
  7210. desc->inOutFlags[paramNum] == asTM_INOUTREF &&
  7211. desc->parameterTypes[paramNum].GetTokenType() != ttQuestion )
  7212. {
  7213. if( desc->parameterTypes[paramNum].IsPrimitive() &&
  7214. desc->parameterTypes[paramNum].GetTokenType() != argType->dataType.GetTokenType() )
  7215. continue;
  7216. if( desc->parameterTypes[paramNum].IsEnumType() &&
  7217. desc->parameterTypes[paramNum].GetObjectType() != argType->dataType.GetObjectType() )
  7218. continue;
  7219. }
  7220. // How well does the argument match the function parameter?
  7221. if( desc->parameterTypes[paramNum].IsEqualExceptRef(ti.type.dataType) )
  7222. {
  7223. // Is it an exact match?
  7224. if( argType->dataType.IsEqualExceptRef(ti.type.dataType) )
  7225. {
  7226. if( !isExactMatch ) matches.SetLength(0);
  7227. isExactMatch = true;
  7228. matches.PushLast(funcs[n]);
  7229. continue;
  7230. }
  7231. if( !isExactMatch )
  7232. {
  7233. // Is it a match except const?
  7234. if( argType->dataType.IsEqualExceptRefAndConst(ti.type.dataType) )
  7235. {
  7236. if( !isMatchExceptConst ) matches.SetLength(0);
  7237. isMatchExceptConst = true;
  7238. matches.PushLast(funcs[n]);
  7239. continue;
  7240. }
  7241. if( !isMatchExceptConst )
  7242. {
  7243. // Is it a size promotion, e.g. int8 -> int?
  7244. if( argType->dataType.IsSamePrimitiveBaseType(ti.type.dataType) ||
  7245. (argType->dataType.IsEnumType() && ti.type.dataType.IsIntegerType()) )
  7246. {
  7247. if( !isMatchWithBaseType ) matches.SetLength(0);
  7248. isMatchWithBaseType = true;
  7249. matches.PushLast(funcs[n]);
  7250. continue;
  7251. }
  7252. if( !isMatchWithBaseType )
  7253. {
  7254. // Conversion between signed and unsigned integer is better than between integer and float
  7255. // Is it a match except for sign?
  7256. if( (argType->dataType.IsIntegerType() && ti.type.dataType.IsUnsignedType()) ||
  7257. (argType->dataType.IsUnsignedType() && ti.type.dataType.IsIntegerType()) ||
  7258. (argType->dataType.IsEnumType() && ti.type.dataType.IsUnsignedType()) )
  7259. {
  7260. if( !isMatchExceptSign ) matches.SetLength(0);
  7261. isMatchExceptSign = true;
  7262. matches.PushLast(funcs[n]);
  7263. continue;
  7264. }
  7265. if( !isMatchExceptSign )
  7266. {
  7267. // If there was any match without a var type it has higher priority
  7268. if( desc->parameterTypes[paramNum].GetTokenType() != ttQuestion )
  7269. {
  7270. if( !isMatchNotVarType ) matches.SetLength(0);
  7271. isMatchNotVarType = true;
  7272. matches.PushLast(funcs[n]);
  7273. continue;
  7274. }
  7275. // Implicit conversion to ?& has the smallest priority
  7276. if( !isMatchNotVarType )
  7277. matches.PushLast(funcs[n]);
  7278. }
  7279. }
  7280. }
  7281. }
  7282. }
  7283. }
  7284. return (int)matches.GetLength();
  7285. }
  7286. void asCCompiler::PrepareArgument2(asSExprContext *ctx, asSExprContext *arg, asCDataType *paramType, bool isFunction, int refType, asCArray<int> *reservedVars)
  7287. {
  7288. // Reference parameters whose value won't be used don't evaluate the expression
  7289. if( paramType->IsReference() && !(refType & asTM_INREF) )
  7290. {
  7291. // Store the original bytecode so that it can be reused when processing the deferred output parameter
  7292. asSExprContext *orig = asNEW(asSExprContext)(engine);
  7293. MergeExprBytecodeAndType(orig, arg);
  7294. arg->origExpr = orig;
  7295. }
  7296. PrepareArgument(paramType, arg, arg->exprNode, isFunction, refType, reservedVars);
  7297. // arg still holds the original expression for output parameters
  7298. ctx->bc.AddCode(&arg->bc);
  7299. }
  7300. bool asCCompiler::CompileOverloadedDualOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  7301. {
  7302. ctx->exprNode = node;
  7303. // What type of operator is it?
  7304. int token = node->tokenType;
  7305. if( token == ttUnrecognizedToken )
  7306. {
  7307. // This happens when the compiler is inferring an assignment
  7308. // operation from another action, for example in preparing a value
  7309. // as a function argument
  7310. token = ttAssignment;
  7311. }
  7312. // boolean operators are not overloadable
  7313. if( token == ttAnd ||
  7314. token == ttOr ||
  7315. token == ttXor )
  7316. return false;
  7317. // Dual operators can also be implemented as class methods
  7318. if( token == ttEqual ||
  7319. token == ttNotEqual )
  7320. {
  7321. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  7322. // Find the matching opEquals method
  7323. int r = CompileOverloadedDualOperator2(node, "opEquals", lctx, rctx, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  7324. if( r == 0 )
  7325. {
  7326. // Try again by switching the order of the operands
  7327. r = CompileOverloadedDualOperator2(node, "opEquals", rctx, lctx, ctx, true, asCDataType::CreatePrimitive(ttBool, false));
  7328. }
  7329. if( r == 1 )
  7330. {
  7331. if( token == ttNotEqual )
  7332. ctx->bc.InstrSHORT(asBC_NOT, ctx->type.stackOffset);
  7333. // Success, don't continue
  7334. return true;
  7335. }
  7336. else if( r < 0 )
  7337. {
  7338. // Compiler error, don't continue
  7339. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  7340. return true;
  7341. }
  7342. }
  7343. if( token == ttEqual ||
  7344. token == ttNotEqual ||
  7345. token == ttLessThan ||
  7346. token == ttLessThanOrEqual ||
  7347. token == ttGreaterThan ||
  7348. token == ttGreaterThanOrEqual )
  7349. {
  7350. bool swappedOrder = false;
  7351. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  7352. // Find the matching opCmp method
  7353. int r = CompileOverloadedDualOperator2(node, "opCmp", lctx, rctx, ctx, true, asCDataType::CreatePrimitive(ttInt, false));
  7354. if( r == 0 )
  7355. {
  7356. // Try again by switching the order of the operands
  7357. swappedOrder = true;
  7358. r = CompileOverloadedDualOperator2(node, "opCmp", rctx, lctx, ctx, true, asCDataType::CreatePrimitive(ttInt, false));
  7359. }
  7360. if( r == 1 )
  7361. {
  7362. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  7363. int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, false), true);
  7364. ctx->bc.InstrW_DW(asBC_CMPIi, ctx->type.stackOffset, 0);
  7365. if( token == ttEqual )
  7366. ctx->bc.Instr(asBC_TZ);
  7367. else if( token == ttNotEqual )
  7368. ctx->bc.Instr(asBC_TNZ);
  7369. else if( (token == ttLessThan && !swappedOrder) ||
  7370. (token == ttGreaterThan && swappedOrder) )
  7371. ctx->bc.Instr(asBC_TS);
  7372. else if( (token == ttLessThanOrEqual && !swappedOrder) ||
  7373. (token == ttGreaterThanOrEqual && swappedOrder) )
  7374. ctx->bc.Instr(asBC_TNP);
  7375. else if( (token == ttGreaterThan && !swappedOrder) ||
  7376. (token == ttLessThan && swappedOrder) )
  7377. ctx->bc.Instr(asBC_TP);
  7378. else if( (token == ttGreaterThanOrEqual && !swappedOrder) ||
  7379. (token == ttLessThanOrEqual && swappedOrder) )
  7380. ctx->bc.Instr(asBC_TNS);
  7381. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  7382. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, false), a, true);
  7383. // Success, don't continue
  7384. return true;
  7385. }
  7386. else if( r < 0 )
  7387. {
  7388. // Compiler error, don't continue
  7389. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  7390. return true;
  7391. }
  7392. }
  7393. // The rest of the operators are not commutative, and doesn't require specific return type
  7394. const char *op = 0, *op_r = 0;
  7395. switch( token )
  7396. {
  7397. case ttPlus: op = "opAdd"; op_r = "opAdd_r"; break;
  7398. case ttMinus: op = "opSub"; op_r = "opSub_r"; break;
  7399. case ttStar: op = "opMul"; op_r = "opMul_r"; break;
  7400. case ttSlash: op = "opDiv"; op_r = "opDiv_r"; break;
  7401. case ttPercent: op = "opMod"; op_r = "opMod_r"; break;
  7402. case ttBitOr: op = "opOr"; op_r = "opOr_r"; break;
  7403. case ttAmp: op = "opAnd"; op_r = "opAnd_r"; break;
  7404. case ttBitXor: op = "opXor"; op_r = "opXor_r"; break;
  7405. case ttBitShiftLeft: op = "opShl"; op_r = "opShl_r"; break;
  7406. case ttBitShiftRight: op = "opShr"; op_r = "opShr_r"; break;
  7407. case ttBitShiftRightArith: op = "opUShr"; op_r = "opUShr_r"; break;
  7408. }
  7409. // TODO: Might be interesting to support a concatenation operator, e.g. ~
  7410. if( op && op_r )
  7411. {
  7412. // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used
  7413. // Find the matching operator method
  7414. int r = CompileOverloadedDualOperator2(node, op, lctx, rctx, ctx);
  7415. if( r == 0 )
  7416. {
  7417. // Try again by switching the order of the operands, and using the reversed operator
  7418. r = CompileOverloadedDualOperator2(node, op_r, rctx, lctx, ctx);
  7419. }
  7420. if( r == 1 )
  7421. {
  7422. // Success, don't continue
  7423. return true;
  7424. }
  7425. else if( r < 0 )
  7426. {
  7427. // Compiler error, don't continue
  7428. ctx->type.SetDummy();
  7429. return true;
  7430. }
  7431. }
  7432. // Assignment operators
  7433. op = 0;
  7434. switch( token )
  7435. {
  7436. case ttAssignment: op = "opAssign"; break;
  7437. case ttAddAssign: op = "opAddAssign"; break;
  7438. case ttSubAssign: op = "opSubAssign"; break;
  7439. case ttMulAssign: op = "opMulAssign"; break;
  7440. case ttDivAssign: op = "opDivAssign"; break;
  7441. case ttModAssign: op = "opModAssign"; break;
  7442. case ttOrAssign: op = "opOrAssign"; break;
  7443. case ttAndAssign: op = "opAndAssign"; break;
  7444. case ttXorAssign: op = "opXorAssign"; break;
  7445. case ttShiftLeftAssign: op = "opShlAssign"; break;
  7446. case ttShiftRightLAssign: op = "opShrAssign"; break;
  7447. case ttShiftRightAAssign: op = "opUShrAssign"; break;
  7448. }
  7449. if( op )
  7450. {
  7451. // TODO: Shouldn't accept const lvalue with the assignment operators
  7452. // Find the matching operator method
  7453. int r = CompileOverloadedDualOperator2(node, op, lctx, rctx, ctx);
  7454. if( r == 1 )
  7455. {
  7456. // Success, don't continue
  7457. return true;
  7458. }
  7459. else if( r < 0 )
  7460. {
  7461. // Compiler error, don't continue
  7462. ctx->type.SetDummy();
  7463. return true;
  7464. }
  7465. }
  7466. // No suitable operator was found
  7467. return false;
  7468. }
  7469. // Returns negative on compile error
  7470. // zero on no matching operator
  7471. // one on matching operator
  7472. int asCCompiler::CompileOverloadedDualOperator2(asCScriptNode *node, const char *methodName, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx, bool specificReturn, const asCDataType &returnType)
  7473. {
  7474. // Find the matching method
  7475. if( lctx->type.dataType.IsObject() && !lctx->type.isExplicitHandle )
  7476. {
  7477. // Is the left value a const?
  7478. bool isConst = false;
  7479. if( lctx->type.dataType.IsObjectHandle() )
  7480. isConst = lctx->type.dataType.IsHandleToConst();
  7481. else
  7482. isConst = lctx->type.dataType.IsReadOnly();
  7483. asCArray<int> funcs;
  7484. asCObjectType *ot = lctx->type.dataType.GetObjectType();
  7485. for( asUINT n = 0; n < ot->methods.GetLength(); n++ )
  7486. {
  7487. asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]];
  7488. if( func->name == methodName &&
  7489. (!specificReturn || func->returnType == returnType) &&
  7490. func->parameterTypes.GetLength() == 1 &&
  7491. (!isConst || func->isReadOnly) )
  7492. {
  7493. // Make sure the method is accessible by the module
  7494. asCConfigGroup *group = engine->FindConfigGroupForFunction(func->id);
  7495. if( !group || group->HasModuleAccess(builder->module->name.AddressOf()) )
  7496. funcs.PushLast(func->id);
  7497. }
  7498. }
  7499. // Which is the best matching function?
  7500. asCArray<int> ops;
  7501. MatchArgument(funcs, ops, &rctx->type, 0);
  7502. // If the object is not const, then we need to prioritize non-const methods
  7503. if( !isConst )
  7504. FilterConst(ops);
  7505. // Did we find an operator?
  7506. if( ops.GetLength() == 1 )
  7507. {
  7508. // Process the lctx expression as get accessor
  7509. ProcessPropertyGetAccessor(lctx, node);
  7510. // Merge the bytecode so that it forms lvalue.methodName(rvalue)
  7511. asCTypeInfo objType = lctx->type;
  7512. asCArray<asSExprContext *> args;
  7513. args.PushLast(rctx);
  7514. MergeExprBytecode(ctx, lctx);
  7515. ctx->type = lctx->type;
  7516. MakeFunctionCall(ctx, ops[0], objType.dataType.GetObjectType(), args, node);
  7517. // If the method returned a reference, then we can't release the original
  7518. // object yet, because the reference may be to a member of it
  7519. if( objType.isTemporary &&
  7520. (ctx->type.dataType.IsReference() || (ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle())) &&
  7521. !ctx->type.isVariable ) // If the resulting type is a variable, then the reference is not to a member
  7522. {
  7523. // Remember the object's variable, so that it can be released
  7524. // later on when the reference to its member goes out of scope
  7525. ctx->type.isTemporary = true;
  7526. ctx->type.stackOffset = objType.stackOffset;
  7527. }
  7528. else
  7529. {
  7530. // As the index operator didn't return a reference to a
  7531. // member we can release the original object now
  7532. ReleaseTemporaryVariable(objType, &ctx->bc);
  7533. }
  7534. // Found matching operator
  7535. return 1;
  7536. }
  7537. else if( ops.GetLength() > 1 )
  7538. {
  7539. Error(TXT_MORE_THAN_ONE_MATCHING_OP, node);
  7540. PrintMatchingFuncs(ops, node);
  7541. ctx->type.SetDummy();
  7542. // Compiler error
  7543. return -1;
  7544. }
  7545. }
  7546. // No matching operator
  7547. return 0;
  7548. }
  7549. void asCCompiler::MakeFunctionCall(asSExprContext *ctx, int funcId, asCObjectType *objectType, asCArray<asSExprContext*> &args, asCScriptNode * /*node*/, bool useVariable, int stackOffset, int funcPtrVar)
  7550. {
  7551. if( objectType )
  7552. {
  7553. Dereference(ctx, true);
  7554. // This following warning was removed as there may be valid reasons
  7555. // for calling non-const methods on temporary objects, and we shouldn't
  7556. // warn when there is no way of removing the warning.
  7557. /*
  7558. // Warn if the method is non-const and the object is temporary
  7559. // since the changes will be lost when the object is destroyed.
  7560. // If the object is accessed through a handle, then it is assumed
  7561. // the object is not temporary, even though the handle is.
  7562. if( ctx->type.isTemporary &&
  7563. !ctx->type.dataType.IsObjectHandle() &&
  7564. !engine->scriptFunctions[funcId]->isReadOnly )
  7565. {
  7566. Warning("A non-const method is called on temporary object. Changes to the object may be lost.", node);
  7567. Information(engine->scriptFunctions[funcId]->GetDeclaration(), node);
  7568. }
  7569. */ }
  7570. asCByteCode objBC(engine);
  7571. objBC.AddCode(&ctx->bc);
  7572. PrepareFunctionCall(funcId, &ctx->bc, args);
  7573. // Verify if any of the args variable offsets are used in the other code.
  7574. // If they are exchange the offset for a new one
  7575. asUINT n;
  7576. for( n = 0; n < args.GetLength(); n++ )
  7577. {
  7578. if( args[n]->type.isTemporary && objBC.IsVarUsed(args[n]->type.stackOffset) )
  7579. {
  7580. // Release the current temporary variable
  7581. ReleaseTemporaryVariable(args[n]->type, 0);
  7582. asCArray<int> usedVars;
  7583. objBC.GetVarsUsed(usedVars);
  7584. ctx->bc.GetVarsUsed(usedVars);
  7585. asCDataType dt = args[n]->type.dataType;
  7586. dt.MakeReference(false);
  7587. int newOffset = AllocateVariableNotIn(dt, true, &usedVars, IsVariableOnHeap(args[n]->type.stackOffset));
  7588. asASSERT( IsVariableOnHeap(args[n]->type.stackOffset) == IsVariableOnHeap(newOffset) );
  7589. ctx->bc.ExchangeVar(args[n]->type.stackOffset, newOffset);
  7590. args[n]->type.stackOffset = (short)newOffset;
  7591. args[n]->type.isTemporary = true;
  7592. args[n]->type.isVariable = true;
  7593. }
  7594. }
  7595. ctx->bc.AddCode(&objBC);
  7596. MoveArgsToStack(funcId, &ctx->bc, args, objectType ? true : false);
  7597. PerformFunctionCall(funcId, ctx, false, &args, 0, useVariable, stackOffset, funcPtrVar);
  7598. }
  7599. int asCCompiler::CompileOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  7600. {
  7601. IsVariableInitialized(&lctx->type, node);
  7602. IsVariableInitialized(&rctx->type, node);
  7603. if( lctx->type.isExplicitHandle || rctx->type.isExplicitHandle ||
  7604. node->tokenType == ttIs || node->tokenType == ttNotIs )
  7605. {
  7606. CompileOperatorOnHandles(node, lctx, rctx, ctx);
  7607. return 0;
  7608. }
  7609. else
  7610. {
  7611. // Compile an overloaded operator for the two operands
  7612. if( CompileOverloadedDualOperator(node, lctx, rctx, ctx) )
  7613. return 0;
  7614. // If both operands are objects, then we shouldn't continue
  7615. if( lctx->type.dataType.IsObject() && rctx->type.dataType.IsObject() )
  7616. {
  7617. asCString str;
  7618. str.Format(TXT_NO_MATCHING_OP_FOUND_FOR_TYPES_s_AND_s, lctx->type.dataType.Format().AddressOf(), rctx->type.dataType.Format().AddressOf());
  7619. Error(str.AddressOf(), node);
  7620. ctx->type.SetDummy();
  7621. return -1;
  7622. }
  7623. // Process the property get accessors (if any)
  7624. ProcessPropertyGetAccessor(lctx, node);
  7625. ProcessPropertyGetAccessor(rctx, node);
  7626. // Make sure we have two variables or constants
  7627. if( lctx->type.dataType.IsReference() ) ConvertToVariableNotIn(lctx, rctx);
  7628. if( rctx->type.dataType.IsReference() ) ConvertToVariableNotIn(rctx, lctx);
  7629. // Make sure lctx doesn't end up with a variable used in rctx
  7630. if( lctx->type.isTemporary && rctx->bc.IsVarUsed(lctx->type.stackOffset) )
  7631. {
  7632. asCArray<int> vars;
  7633. rctx->bc.GetVarsUsed(vars);
  7634. int offset = AllocateVariableNotIn(lctx->type.dataType, true, &vars);
  7635. rctx->bc.ExchangeVar(lctx->type.stackOffset, offset);
  7636. ReleaseTemporaryVariable(offset, 0);
  7637. }
  7638. // Math operators
  7639. // + - * / % += -= *= /= %=
  7640. int op = node->tokenType;
  7641. if( op == ttPlus || op == ttAddAssign ||
  7642. op == ttMinus || op == ttSubAssign ||
  7643. op == ttStar || op == ttMulAssign ||
  7644. op == ttSlash || op == ttDivAssign ||
  7645. op == ttPercent || op == ttModAssign )
  7646. {
  7647. CompileMathOperator(node, lctx, rctx, ctx);
  7648. return 0;
  7649. }
  7650. // Bitwise operators
  7651. // << >> >>> & | ^ <<= >>= >>>= &= |= ^=
  7652. if( op == ttAmp || op == ttAndAssign ||
  7653. op == ttBitOr || op == ttOrAssign ||
  7654. op == ttBitXor || op == ttXorAssign ||
  7655. op == ttBitShiftLeft || op == ttShiftLeftAssign ||
  7656. op == ttBitShiftRight || op == ttShiftRightLAssign ||
  7657. op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  7658. {
  7659. CompileBitwiseOperator(node, lctx, rctx, ctx);
  7660. return 0;
  7661. }
  7662. // Comparison operators
  7663. // == != < > <= >=
  7664. if( op == ttEqual || op == ttNotEqual ||
  7665. op == ttLessThan || op == ttLessThanOrEqual ||
  7666. op == ttGreaterThan || op == ttGreaterThanOrEqual )
  7667. {
  7668. CompileComparisonOperator(node, lctx, rctx, ctx);
  7669. return 0;
  7670. }
  7671. // Boolean operators
  7672. // && || ^^
  7673. if( op == ttAnd || op == ttOr || op == ttXor )
  7674. {
  7675. CompileBooleanOperator(node, lctx, rctx, ctx);
  7676. return 0;
  7677. }
  7678. }
  7679. asASSERT(false);
  7680. return -1;
  7681. }
  7682. void asCCompiler::ConvertToTempVariableNotIn(asSExprContext *ctx, asSExprContext *exclude)
  7683. {
  7684. asCArray<int> excludeVars;
  7685. if( exclude ) exclude->bc.GetVarsUsed(excludeVars);
  7686. ConvertToTempVariableNotIn(ctx, &excludeVars);
  7687. }
  7688. void asCCompiler::ConvertToTempVariableNotIn(asSExprContext *ctx, asCArray<int> *reservedVars)
  7689. {
  7690. // This is only used for primitive types and null handles
  7691. asASSERT( ctx->type.dataType.IsPrimitive() || ctx->type.dataType.IsNullHandle() );
  7692. ConvertToVariableNotIn(ctx, reservedVars);
  7693. if( !ctx->type.isTemporary )
  7694. {
  7695. if( ctx->type.dataType.IsPrimitive() )
  7696. {
  7697. // Copy the variable to a temporary variable
  7698. int offset = AllocateVariableNotIn(ctx->type.dataType, true, reservedVars);
  7699. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  7700. ctx->bc.InstrW_W(asBC_CpyVtoV4, offset, ctx->type.stackOffset);
  7701. else
  7702. ctx->bc.InstrW_W(asBC_CpyVtoV8, offset, ctx->type.stackOffset);
  7703. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  7704. }
  7705. else
  7706. {
  7707. // We should never get here
  7708. asASSERT(false);
  7709. }
  7710. }
  7711. }
  7712. void asCCompiler::ConvertToTempVariable(asSExprContext *ctx)
  7713. {
  7714. ConvertToTempVariableNotIn(ctx, (asCArray<int>*)0);
  7715. }
  7716. void asCCompiler::ConvertToVariable(asSExprContext *ctx)
  7717. {
  7718. ConvertToVariableNotIn(ctx, (asCArray<int>*)0);
  7719. }
  7720. void asCCompiler::ConvertToVariableNotIn(asSExprContext *ctx, asCArray<int> *reservedVars)
  7721. {
  7722. // We should never get here while the context is still an unprocessed property accessor
  7723. asASSERT(ctx->property_get == 0 && ctx->property_set == 0);
  7724. asCArray<int> excludeVars;
  7725. if( reservedVars ) excludeVars.Concatenate(*reservedVars);
  7726. int offset;
  7727. if( !ctx->type.isVariable &&
  7728. (ctx->type.dataType.IsObjectHandle() ||
  7729. (ctx->type.dataType.IsObject() && ctx->type.dataType.SupportHandles())) )
  7730. {
  7731. offset = AllocateVariableNotIn(ctx->type.dataType, true, &excludeVars);
  7732. if( ctx->type.IsNullConstant() )
  7733. {
  7734. #ifdef AS_64BIT_PTR
  7735. ctx->bc.InstrSHORT_QW(asBC_SetV8, (short)offset, 0);
  7736. #else
  7737. ctx->bc.InstrSHORT_DW(asBC_SetV4, (short)offset, 0);
  7738. #endif
  7739. }
  7740. else
  7741. {
  7742. // Copy the object handle to a variable
  7743. ctx->bc.InstrSHORT(asBC_PSF, (short)offset);
  7744. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetObjectType());
  7745. ctx->bc.Pop(AS_PTR_SIZE);
  7746. }
  7747. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  7748. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  7749. ctx->type.dataType.MakeHandle(true);
  7750. }
  7751. else if( (!ctx->type.isVariable || ctx->type.dataType.IsReference()) &&
  7752. ctx->type.dataType.IsPrimitive() )
  7753. {
  7754. if( ctx->type.isConstant )
  7755. {
  7756. offset = AllocateVariableNotIn(ctx->type.dataType, true, &excludeVars);
  7757. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  7758. ctx->bc.InstrSHORT_B(asBC_SetV1, (short)offset, ctx->type.byteValue);
  7759. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  7760. ctx->bc.InstrSHORT_W(asBC_SetV2, (short)offset, ctx->type.wordValue);
  7761. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 )
  7762. ctx->bc.InstrSHORT_DW(asBC_SetV4, (short)offset, ctx->type.dwordValue);
  7763. else
  7764. ctx->bc.InstrSHORT_QW(asBC_SetV8, (short)offset, ctx->type.qwordValue);
  7765. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  7766. return;
  7767. }
  7768. else
  7769. {
  7770. asASSERT(ctx->type.dataType.IsPrimitive());
  7771. asASSERT(ctx->type.dataType.IsReference());
  7772. ctx->type.dataType.MakeReference(false);
  7773. offset = AllocateVariableNotIn(ctx->type.dataType, true, &excludeVars);
  7774. // Read the value from the address in the register directly into the variable
  7775. if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 )
  7776. ctx->bc.InstrSHORT(asBC_RDR1, (short)offset);
  7777. else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 )
  7778. ctx->bc.InstrSHORT(asBC_RDR2, (short)offset);
  7779. else if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  7780. ctx->bc.InstrSHORT(asBC_RDR4, (short)offset);
  7781. else
  7782. ctx->bc.InstrSHORT(asBC_RDR8, (short)offset);
  7783. }
  7784. ReleaseTemporaryVariable(ctx->type, &ctx->bc);
  7785. ctx->type.SetVariable(ctx->type.dataType, offset, true);
  7786. }
  7787. }
  7788. void asCCompiler::ConvertToVariableNotIn(asSExprContext *ctx, asSExprContext *exclude)
  7789. {
  7790. asCArray<int> excludeVars;
  7791. if( exclude ) exclude->bc.GetVarsUsed(excludeVars);
  7792. ConvertToVariableNotIn(ctx, &excludeVars);
  7793. }
  7794. void asCCompiler::CompileMathOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  7795. {
  7796. // TODO: If a constant is only using 32bits, then a 32bit operation is preferred
  7797. // Implicitly convert the operands to a number type
  7798. asCDataType to;
  7799. if( lctx->type.dataType.IsDoubleType() || rctx->type.dataType.IsDoubleType() )
  7800. to.SetTokenType(ttDouble);
  7801. else if( lctx->type.dataType.IsFloatType() || rctx->type.dataType.IsFloatType() )
  7802. to.SetTokenType(ttFloat);
  7803. else if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 || rctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  7804. {
  7805. if( lctx->type.dataType.IsIntegerType() || rctx->type.dataType.IsIntegerType() )
  7806. to.SetTokenType(ttInt64);
  7807. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  7808. to.SetTokenType(ttUInt64);
  7809. }
  7810. else
  7811. {
  7812. if( lctx->type.dataType.IsIntegerType() || rctx->type.dataType.IsIntegerType() ||
  7813. lctx->type.dataType.IsEnumType() || rctx->type.dataType.IsEnumType() )
  7814. to.SetTokenType(ttInt);
  7815. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  7816. to.SetTokenType(ttUInt);
  7817. }
  7818. // If doing an operation with double constant and float variable, the constant should be converted to float
  7819. if( (lctx->type.isConstant && lctx->type.dataType.IsDoubleType() && !rctx->type.isConstant && rctx->type.dataType.IsFloatType()) ||
  7820. (rctx->type.isConstant && rctx->type.dataType.IsDoubleType() && !lctx->type.isConstant && lctx->type.dataType.IsFloatType()) )
  7821. to.SetTokenType(ttFloat);
  7822. // Do the actual conversion
  7823. asCArray<int> reservedVars;
  7824. rctx->bc.GetVarsUsed(reservedVars);
  7825. lctx->bc.GetVarsUsed(reservedVars);
  7826. if( lctx->type.dataType.IsReference() )
  7827. ConvertToVariableNotIn(lctx, &reservedVars);
  7828. if( rctx->type.dataType.IsReference() )
  7829. ConvertToVariableNotIn(rctx, &reservedVars);
  7830. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true, &reservedVars);
  7831. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true, &reservedVars);
  7832. // Verify that the conversion was successful
  7833. if( !lctx->type.dataType.IsIntegerType() &&
  7834. !lctx->type.dataType.IsUnsignedType() &&
  7835. !lctx->type.dataType.IsFloatType() &&
  7836. !lctx->type.dataType.IsDoubleType() )
  7837. {
  7838. asCString str;
  7839. str.Format(TXT_NO_CONVERSION_s_TO_MATH_TYPE, lctx->type.dataType.Format().AddressOf());
  7840. Error(str.AddressOf(), node);
  7841. ctx->type.SetDummy();
  7842. return;
  7843. }
  7844. if( !rctx->type.dataType.IsIntegerType() &&
  7845. !rctx->type.dataType.IsUnsignedType() &&
  7846. !rctx->type.dataType.IsFloatType() &&
  7847. !rctx->type.dataType.IsDoubleType() )
  7848. {
  7849. asCString str;
  7850. str.Format(TXT_NO_CONVERSION_s_TO_MATH_TYPE, rctx->type.dataType.Format().AddressOf());
  7851. Error(str.AddressOf(), node);
  7852. ctx->type.SetDummy();
  7853. return;
  7854. }
  7855. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  7856. // Verify if we are dividing with a constant zero
  7857. int op = node->tokenType;
  7858. if( rctx->type.isConstant && rctx->type.qwordValue == 0 &&
  7859. (op == ttSlash || op == ttDivAssign ||
  7860. op == ttPercent || op == ttModAssign) )
  7861. {
  7862. Error(TXT_DIVIDE_BY_ZERO, node);
  7863. }
  7864. if( !isConstant )
  7865. {
  7866. ConvertToVariableNotIn(lctx, rctx);
  7867. ConvertToVariableNotIn(rctx, lctx);
  7868. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  7869. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  7870. if( op == ttAddAssign || op == ttSubAssign ||
  7871. op == ttMulAssign || op == ttDivAssign ||
  7872. op == ttModAssign )
  7873. {
  7874. // Merge the operands in the different order so that they are evaluated correctly
  7875. MergeExprBytecode(ctx, rctx);
  7876. MergeExprBytecode(ctx, lctx);
  7877. }
  7878. else
  7879. {
  7880. MergeExprBytecode(ctx, lctx);
  7881. MergeExprBytecode(ctx, rctx);
  7882. }
  7883. ProcessDeferredParams(ctx);
  7884. asEBCInstr instruction = asBC_ADDi;
  7885. if( lctx->type.dataType.IsIntegerType() ||
  7886. lctx->type.dataType.IsUnsignedType() )
  7887. {
  7888. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  7889. {
  7890. if( op == ttPlus || op == ttAddAssign )
  7891. instruction = asBC_ADDi;
  7892. else if( op == ttMinus || op == ttSubAssign )
  7893. instruction = asBC_SUBi;
  7894. else if( op == ttStar || op == ttMulAssign )
  7895. instruction = asBC_MULi;
  7896. else if( op == ttSlash || op == ttDivAssign )
  7897. {
  7898. if( lctx->type.dataType.IsIntegerType() )
  7899. instruction = asBC_DIVi;
  7900. else
  7901. instruction = asBC_DIVu;
  7902. }
  7903. else if( op == ttPercent || op == ttModAssign )
  7904. {
  7905. if( lctx->type.dataType.IsIntegerType() )
  7906. instruction = asBC_MODi;
  7907. else
  7908. instruction = asBC_MODu;
  7909. }
  7910. }
  7911. else
  7912. {
  7913. if( op == ttPlus || op == ttAddAssign )
  7914. instruction = asBC_ADDi64;
  7915. else if( op == ttMinus || op == ttSubAssign )
  7916. instruction = asBC_SUBi64;
  7917. else if( op == ttStar || op == ttMulAssign )
  7918. instruction = asBC_MULi64;
  7919. else if( op == ttSlash || op == ttDivAssign )
  7920. {
  7921. if( lctx->type.dataType.IsIntegerType() )
  7922. instruction = asBC_DIVi64;
  7923. else
  7924. instruction = asBC_DIVu64;
  7925. }
  7926. else if( op == ttPercent || op == ttModAssign )
  7927. {
  7928. if( lctx->type.dataType.IsIntegerType() )
  7929. instruction = asBC_MODi64;
  7930. else
  7931. instruction = asBC_MODu64;
  7932. }
  7933. }
  7934. }
  7935. else if( lctx->type.dataType.IsFloatType() )
  7936. {
  7937. if( op == ttPlus || op == ttAddAssign )
  7938. instruction = asBC_ADDf;
  7939. else if( op == ttMinus || op == ttSubAssign )
  7940. instruction = asBC_SUBf;
  7941. else if( op == ttStar || op == ttMulAssign )
  7942. instruction = asBC_MULf;
  7943. else if( op == ttSlash || op == ttDivAssign )
  7944. instruction = asBC_DIVf;
  7945. else if( op == ttPercent || op == ttModAssign )
  7946. instruction = asBC_MODf;
  7947. }
  7948. else if( lctx->type.dataType.IsDoubleType() )
  7949. {
  7950. if( op == ttPlus || op == ttAddAssign )
  7951. instruction = asBC_ADDd;
  7952. else if( op == ttMinus || op == ttSubAssign )
  7953. instruction = asBC_SUBd;
  7954. else if( op == ttStar || op == ttMulAssign )
  7955. instruction = asBC_MULd;
  7956. else if( op == ttSlash || op == ttDivAssign )
  7957. instruction = asBC_DIVd;
  7958. else if( op == ttPercent || op == ttModAssign )
  7959. instruction = asBC_MODd;
  7960. }
  7961. else
  7962. {
  7963. // Shouldn't be possible
  7964. asASSERT(false);
  7965. }
  7966. // Do the operation
  7967. int a = AllocateVariable(lctx->type.dataType, true);
  7968. int b = lctx->type.stackOffset;
  7969. int c = rctx->type.stackOffset;
  7970. ctx->bc.InstrW_W_W(instruction, a, b, c);
  7971. ctx->type.SetVariable(lctx->type.dataType, a, true);
  7972. }
  7973. else
  7974. {
  7975. // Both values are constants
  7976. if( lctx->type.dataType.IsIntegerType() ||
  7977. lctx->type.dataType.IsUnsignedType() )
  7978. {
  7979. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  7980. {
  7981. int v = 0;
  7982. if( op == ttPlus )
  7983. v = lctx->type.intValue + rctx->type.intValue;
  7984. else if( op == ttMinus )
  7985. v = lctx->type.intValue - rctx->type.intValue;
  7986. else if( op == ttStar )
  7987. v = lctx->type.intValue * rctx->type.intValue;
  7988. else if( op == ttSlash )
  7989. {
  7990. if( rctx->type.intValue == 0 )
  7991. v = 0;
  7992. else
  7993. if( lctx->type.dataType.IsIntegerType() )
  7994. v = lctx->type.intValue / rctx->type.intValue;
  7995. else
  7996. v = lctx->type.dwordValue / rctx->type.dwordValue;
  7997. }
  7998. else if( op == ttPercent )
  7999. {
  8000. if( rctx->type.intValue == 0 )
  8001. v = 0;
  8002. else
  8003. if( lctx->type.dataType.IsIntegerType() )
  8004. v = lctx->type.intValue % rctx->type.intValue;
  8005. else
  8006. v = lctx->type.dwordValue % rctx->type.dwordValue;
  8007. }
  8008. ctx->type.SetConstantDW(lctx->type.dataType, v);
  8009. // If the right value is greater than the left value in a minus operation, then we need to convert the type to int
  8010. if( lctx->type.dataType.GetTokenType() == ttUInt && op == ttMinus && lctx->type.intValue < rctx->type.intValue )
  8011. ctx->type.dataType.SetTokenType(ttInt);
  8012. }
  8013. else
  8014. {
  8015. asQWORD v = 0;
  8016. if( op == ttPlus )
  8017. v = lctx->type.qwordValue + rctx->type.qwordValue;
  8018. else if( op == ttMinus )
  8019. v = lctx->type.qwordValue - rctx->type.qwordValue;
  8020. else if( op == ttStar )
  8021. v = lctx->type.qwordValue * rctx->type.qwordValue;
  8022. else if( op == ttSlash )
  8023. {
  8024. if( rctx->type.qwordValue == 0 )
  8025. v = 0;
  8026. else
  8027. if( lctx->type.dataType.IsIntegerType() )
  8028. v = asINT64(lctx->type.qwordValue) / asINT64(rctx->type.qwordValue);
  8029. else
  8030. v = lctx->type.qwordValue / rctx->type.qwordValue;
  8031. }
  8032. else if( op == ttPercent )
  8033. {
  8034. if( rctx->type.qwordValue == 0 )
  8035. v = 0;
  8036. else
  8037. if( lctx->type.dataType.IsIntegerType() )
  8038. v = asINT64(lctx->type.qwordValue) % asINT64(rctx->type.qwordValue);
  8039. else
  8040. v = lctx->type.qwordValue % rctx->type.qwordValue;
  8041. }
  8042. ctx->type.SetConstantQW(lctx->type.dataType, v);
  8043. // If the right value is greater than the left value in a minus operation, then we need to convert the type to int
  8044. if( lctx->type.dataType.GetTokenType() == ttUInt64 && op == ttMinus && lctx->type.qwordValue < rctx->type.qwordValue )
  8045. ctx->type.dataType.SetTokenType(ttInt64);
  8046. }
  8047. }
  8048. else if( lctx->type.dataType.IsFloatType() )
  8049. {
  8050. float v = 0.0f;
  8051. if( op == ttPlus )
  8052. v = lctx->type.floatValue + rctx->type.floatValue;
  8053. else if( op == ttMinus )
  8054. v = lctx->type.floatValue - rctx->type.floatValue;
  8055. else if( op == ttStar )
  8056. v = lctx->type.floatValue * rctx->type.floatValue;
  8057. else if( op == ttSlash )
  8058. {
  8059. if( rctx->type.floatValue == 0 )
  8060. v = 0;
  8061. else
  8062. v = lctx->type.floatValue / rctx->type.floatValue;
  8063. }
  8064. else if( op == ttPercent )
  8065. {
  8066. if( rctx->type.floatValue == 0 )
  8067. v = 0;
  8068. else
  8069. v = fmodf(lctx->type.floatValue, rctx->type.floatValue);
  8070. }
  8071. ctx->type.SetConstantF(lctx->type.dataType, v);
  8072. }
  8073. else if( lctx->type.dataType.IsDoubleType() )
  8074. {
  8075. double v = 0.0;
  8076. if( op == ttPlus )
  8077. v = lctx->type.doubleValue + rctx->type.doubleValue;
  8078. else if( op == ttMinus )
  8079. v = lctx->type.doubleValue - rctx->type.doubleValue;
  8080. else if( op == ttStar )
  8081. v = lctx->type.doubleValue * rctx->type.doubleValue;
  8082. else if( op == ttSlash )
  8083. {
  8084. if( rctx->type.doubleValue == 0 )
  8085. v = 0;
  8086. else
  8087. v = lctx->type.doubleValue / rctx->type.doubleValue;
  8088. }
  8089. else if( op == ttPercent )
  8090. {
  8091. if( rctx->type.doubleValue == 0 )
  8092. v = 0;
  8093. else
  8094. v = fmod(lctx->type.doubleValue, rctx->type.doubleValue);
  8095. }
  8096. ctx->type.SetConstantD(lctx->type.dataType, v);
  8097. }
  8098. else
  8099. {
  8100. // Shouldn't be possible
  8101. asASSERT(false);
  8102. }
  8103. }
  8104. }
  8105. void asCCompiler::CompileBitwiseOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  8106. {
  8107. // TODO: If a constant is only using 32bits, then a 32bit operation is preferred
  8108. int op = node->tokenType;
  8109. if( op == ttAmp || op == ttAndAssign ||
  8110. op == ttBitOr || op == ttOrAssign ||
  8111. op == ttBitXor || op == ttXorAssign )
  8112. {
  8113. // Convert left hand operand to integer if it's not already one
  8114. asCDataType to;
  8115. if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 ||
  8116. rctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  8117. to.SetTokenType(ttUInt64);
  8118. else
  8119. to.SetTokenType(ttUInt);
  8120. // Do the actual conversion
  8121. asCArray<int> reservedVars;
  8122. rctx->bc.GetVarsUsed(reservedVars);
  8123. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true, &reservedVars);
  8124. // Verify that the conversion was successful
  8125. if( !lctx->type.dataType.IsUnsignedType() )
  8126. {
  8127. asCString str;
  8128. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  8129. Error(str.AddressOf(), node);
  8130. }
  8131. // Convert right hand operand to same type as left hand operand
  8132. asCArray<int> vars;
  8133. lctx->bc.GetVarsUsed(vars);
  8134. ImplicitConversion(rctx, lctx->type.dataType, node, asIC_IMPLICIT_CONV, true, &vars);
  8135. if( !rctx->type.dataType.IsEqualExceptRef(lctx->type.dataType) )
  8136. {
  8137. asCString str;
  8138. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format().AddressOf(), lctx->type.dataType.Format().AddressOf());
  8139. Error(str.AddressOf(), node);
  8140. }
  8141. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  8142. if( !isConstant )
  8143. {
  8144. ConvertToVariableNotIn(lctx, rctx);
  8145. ConvertToVariableNotIn(rctx, lctx);
  8146. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  8147. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  8148. if( op == ttAndAssign || op == ttOrAssign || op == ttXorAssign )
  8149. {
  8150. // Compound assignments execute the right hand value first
  8151. MergeExprBytecode(ctx, rctx);
  8152. MergeExprBytecode(ctx, lctx);
  8153. }
  8154. else
  8155. {
  8156. MergeExprBytecode(ctx, lctx);
  8157. MergeExprBytecode(ctx, rctx);
  8158. }
  8159. ProcessDeferredParams(ctx);
  8160. asEBCInstr instruction = asBC_BAND;
  8161. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  8162. {
  8163. if( op == ttAmp || op == ttAndAssign )
  8164. instruction = asBC_BAND;
  8165. else if( op == ttBitOr || op == ttOrAssign )
  8166. instruction = asBC_BOR;
  8167. else if( op == ttBitXor || op == ttXorAssign )
  8168. instruction = asBC_BXOR;
  8169. }
  8170. else
  8171. {
  8172. if( op == ttAmp || op == ttAndAssign )
  8173. instruction = asBC_BAND64;
  8174. else if( op == ttBitOr || op == ttOrAssign )
  8175. instruction = asBC_BOR64;
  8176. else if( op == ttBitXor || op == ttXorAssign )
  8177. instruction = asBC_BXOR64;
  8178. }
  8179. // Do the operation
  8180. int a = AllocateVariable(lctx->type.dataType, true);
  8181. int b = lctx->type.stackOffset;
  8182. int c = rctx->type.stackOffset;
  8183. ctx->bc.InstrW_W_W(instruction, a, b, c);
  8184. ctx->type.SetVariable(lctx->type.dataType, a, true);
  8185. }
  8186. else
  8187. {
  8188. if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  8189. {
  8190. asQWORD v = 0;
  8191. if( op == ttAmp )
  8192. v = lctx->type.qwordValue & rctx->type.qwordValue;
  8193. else if( op == ttBitOr )
  8194. v = lctx->type.qwordValue | rctx->type.qwordValue;
  8195. else if( op == ttBitXor )
  8196. v = lctx->type.qwordValue ^ rctx->type.qwordValue;
  8197. // Remember the result
  8198. ctx->type.SetConstantQW(lctx->type.dataType, v);
  8199. }
  8200. else
  8201. {
  8202. asDWORD v = 0;
  8203. if( op == ttAmp )
  8204. v = lctx->type.dwordValue & rctx->type.dwordValue;
  8205. else if( op == ttBitOr )
  8206. v = lctx->type.dwordValue | rctx->type.dwordValue;
  8207. else if( op == ttBitXor )
  8208. v = lctx->type.dwordValue ^ rctx->type.dwordValue;
  8209. // Remember the result
  8210. ctx->type.SetConstantDW(lctx->type.dataType, v);
  8211. }
  8212. }
  8213. }
  8214. else if( op == ttBitShiftLeft || op == ttShiftLeftAssign ||
  8215. op == ttBitShiftRight || op == ttShiftRightLAssign ||
  8216. op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  8217. {
  8218. // Don't permit object to primitive conversion, since we don't know which integer type is the correct one
  8219. if( lctx->type.dataType.IsObject() )
  8220. {
  8221. asCString str;
  8222. str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format().AddressOf());
  8223. Error(str.AddressOf(), node);
  8224. // Set an integer value and allow the compiler to continue
  8225. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), 0);
  8226. return;
  8227. }
  8228. // Convert left hand operand to integer if it's not already one
  8229. asCDataType to = lctx->type.dataType;
  8230. if( lctx->type.dataType.IsUnsignedType() &&
  8231. lctx->type.dataType.GetSizeInMemoryBytes() < 4 )
  8232. {
  8233. to = asCDataType::CreatePrimitive(ttUInt, false);
  8234. }
  8235. else if( !lctx->type.dataType.IsUnsignedType() )
  8236. {
  8237. asCDataType to;
  8238. if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  8239. to.SetTokenType(ttInt64);
  8240. else
  8241. to.SetTokenType(ttInt);
  8242. }
  8243. // Do the actual conversion
  8244. asCArray<int> reservedVars;
  8245. rctx->bc.GetVarsUsed(reservedVars);
  8246. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true, &reservedVars);
  8247. // Verify that the conversion was successful
  8248. if( lctx->type.dataType != to )
  8249. {
  8250. asCString str;
  8251. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  8252. Error(str.AddressOf(), node);
  8253. }
  8254. // Right operand must be 32bit uint
  8255. asCArray<int> vars;
  8256. lctx->bc.GetVarsUsed(vars);
  8257. ImplicitConversion(rctx, asCDataType::CreatePrimitive(ttUInt, true), node, asIC_IMPLICIT_CONV, true, &vars);
  8258. if( !rctx->type.dataType.IsUnsignedType() )
  8259. {
  8260. asCString str;
  8261. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format().AddressOf(), "uint");
  8262. Error(str.AddressOf(), node);
  8263. }
  8264. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  8265. if( !isConstant )
  8266. {
  8267. ConvertToVariableNotIn(lctx, rctx);
  8268. ConvertToVariableNotIn(rctx, lctx);
  8269. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  8270. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  8271. if( op == ttShiftLeftAssign || op == ttShiftRightLAssign || op == ttShiftRightAAssign )
  8272. {
  8273. // Compound assignments execute the right hand value first
  8274. MergeExprBytecode(ctx, rctx);
  8275. MergeExprBytecode(ctx, lctx);
  8276. }
  8277. else
  8278. {
  8279. MergeExprBytecode(ctx, lctx);
  8280. MergeExprBytecode(ctx, rctx);
  8281. }
  8282. ProcessDeferredParams(ctx);
  8283. asEBCInstr instruction = asBC_BSLL;
  8284. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  8285. {
  8286. if( op == ttBitShiftLeft || op == ttShiftLeftAssign )
  8287. instruction = asBC_BSLL;
  8288. else if( op == ttBitShiftRight || op == ttShiftRightLAssign )
  8289. instruction = asBC_BSRL;
  8290. else if( op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  8291. instruction = asBC_BSRA;
  8292. }
  8293. else
  8294. {
  8295. if( op == ttBitShiftLeft || op == ttShiftLeftAssign )
  8296. instruction = asBC_BSLL64;
  8297. else if( op == ttBitShiftRight || op == ttShiftRightLAssign )
  8298. instruction = asBC_BSRL64;
  8299. else if( op == ttBitShiftRightArith || op == ttShiftRightAAssign )
  8300. instruction = asBC_BSRA64;
  8301. }
  8302. // Do the operation
  8303. int a = AllocateVariable(lctx->type.dataType, true);
  8304. int b = lctx->type.stackOffset;
  8305. int c = rctx->type.stackOffset;
  8306. ctx->bc.InstrW_W_W(instruction, a, b, c);
  8307. ctx->type.SetVariable(lctx->type.dataType, a, true);
  8308. }
  8309. else
  8310. {
  8311. if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  8312. {
  8313. asDWORD v = 0;
  8314. if( op == ttBitShiftLeft )
  8315. v = lctx->type.dwordValue << rctx->type.dwordValue;
  8316. else if( op == ttBitShiftRight )
  8317. v = lctx->type.dwordValue >> rctx->type.dwordValue;
  8318. else if( op == ttBitShiftRightArith )
  8319. v = lctx->type.intValue >> rctx->type.dwordValue;
  8320. ctx->type.SetConstantDW(lctx->type.dataType, v);
  8321. }
  8322. else
  8323. {
  8324. asQWORD v = 0;
  8325. if( op == ttBitShiftLeft )
  8326. v = lctx->type.qwordValue << rctx->type.dwordValue;
  8327. else if( op == ttBitShiftRight )
  8328. v = lctx->type.qwordValue >> rctx->type.dwordValue;
  8329. else if( op == ttBitShiftRightArith )
  8330. v = asINT64(lctx->type.qwordValue) >> rctx->type.dwordValue;
  8331. ctx->type.SetConstantQW(lctx->type.dataType, v);
  8332. }
  8333. }
  8334. }
  8335. }
  8336. void asCCompiler::CompileComparisonOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  8337. {
  8338. // Both operands must be of the same type
  8339. // Implicitly convert the operands to a number type
  8340. asCDataType to;
  8341. if( lctx->type.dataType.IsDoubleType() || rctx->type.dataType.IsDoubleType() )
  8342. to.SetTokenType(ttDouble);
  8343. else if( lctx->type.dataType.IsFloatType() || rctx->type.dataType.IsFloatType() )
  8344. to.SetTokenType(ttFloat);
  8345. else if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 || rctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  8346. {
  8347. if( lctx->type.dataType.IsIntegerType() || rctx->type.dataType.IsIntegerType() )
  8348. to.SetTokenType(ttInt64);
  8349. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  8350. to.SetTokenType(ttUInt64);
  8351. }
  8352. else
  8353. {
  8354. if( lctx->type.dataType.IsIntegerType() || rctx->type.dataType.IsIntegerType() ||
  8355. lctx->type.dataType.IsEnumType() || rctx->type.dataType.IsEnumType() )
  8356. to.SetTokenType(ttInt);
  8357. else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() )
  8358. to.SetTokenType(ttUInt);
  8359. else if( lctx->type.dataType.IsBooleanType() || rctx->type.dataType.IsBooleanType() )
  8360. to.SetTokenType(ttBool);
  8361. }
  8362. // If doing an operation with double constant and float variable, the constant should be converted to float
  8363. if( (lctx->type.isConstant && lctx->type.dataType.IsDoubleType() && !rctx->type.isConstant && rctx->type.dataType.IsFloatType()) ||
  8364. (rctx->type.isConstant && rctx->type.dataType.IsDoubleType() && !lctx->type.isConstant && lctx->type.dataType.IsFloatType()) )
  8365. to.SetTokenType(ttFloat);
  8366. // Is it an operation on signed values?
  8367. bool signMismatch = false;
  8368. if( !lctx->type.dataType.IsUnsignedType() || !rctx->type.dataType.IsUnsignedType() )
  8369. {
  8370. if( lctx->type.dataType.GetTokenType() == ttUInt64 )
  8371. {
  8372. if( !lctx->type.isConstant )
  8373. signMismatch = true;
  8374. else if( lctx->type.qwordValue & (I64(1)<<63) )
  8375. signMismatch = true;
  8376. }
  8377. if( lctx->type.dataType.GetTokenType() == ttUInt )
  8378. {
  8379. if( !lctx->type.isConstant )
  8380. signMismatch = true;
  8381. else if( lctx->type.dwordValue & (1<<31) )
  8382. signMismatch = true;
  8383. }
  8384. if( rctx->type.dataType.GetTokenType() == ttUInt64 )
  8385. {
  8386. if( !rctx->type.isConstant )
  8387. signMismatch = true;
  8388. else if( rctx->type.qwordValue & (I64(1)<<63) )
  8389. signMismatch = true;
  8390. }
  8391. if( rctx->type.dataType.GetTokenType() == ttUInt )
  8392. {
  8393. if( !rctx->type.isConstant )
  8394. signMismatch = true;
  8395. else if( rctx->type.dwordValue & (1<<31) )
  8396. signMismatch = true;
  8397. }
  8398. }
  8399. // Check for signed/unsigned mismatch
  8400. if( signMismatch )
  8401. Warning(TXT_SIGNED_UNSIGNED_MISMATCH, node);
  8402. // Do the actual conversion
  8403. asCArray<int> reservedVars;
  8404. rctx->bc.GetVarsUsed(reservedVars);
  8405. if( lctx->type.dataType.IsReference() )
  8406. ConvertToVariableNotIn(lctx, &reservedVars);
  8407. if( rctx->type.dataType.IsReference() )
  8408. ConvertToVariableNotIn(rctx, &reservedVars);
  8409. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true, &reservedVars);
  8410. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV);
  8411. // Verify that the conversion was successful
  8412. bool ok = true;
  8413. if( !lctx->type.dataType.IsEqualExceptConst(to) )
  8414. {
  8415. asCString str;
  8416. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  8417. Error(str.AddressOf(), node);
  8418. ok = false;
  8419. }
  8420. if( !rctx->type.dataType.IsEqualExceptConst(to) )
  8421. {
  8422. asCString str;
  8423. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  8424. Error(str.AddressOf(), node);
  8425. ok = false;
  8426. }
  8427. if( !ok )
  8428. {
  8429. // It wasn't possible to get two valid operands, so we just return
  8430. // a boolean result and let the compiler continue.
  8431. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true);
  8432. return;
  8433. }
  8434. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  8435. int op = node->tokenType;
  8436. if( !isConstant )
  8437. {
  8438. if( to.IsBooleanType() )
  8439. {
  8440. int op = node->tokenType;
  8441. if( op == ttEqual || op == ttNotEqual )
  8442. {
  8443. // Must convert to temporary variable, because we are changing the value before comparison
  8444. ConvertToTempVariableNotIn(lctx, rctx);
  8445. ConvertToTempVariableNotIn(rctx, lctx);
  8446. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  8447. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  8448. // Make sure they are equal if not false
  8449. lctx->bc.InstrWORD(asBC_NOT, lctx->type.stackOffset);
  8450. rctx->bc.InstrWORD(asBC_NOT, rctx->type.stackOffset);
  8451. MergeExprBytecode(ctx, lctx);
  8452. MergeExprBytecode(ctx, rctx);
  8453. ProcessDeferredParams(ctx);
  8454. int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, true), true);
  8455. int b = lctx->type.stackOffset;
  8456. int c = rctx->type.stackOffset;
  8457. if( op == ttEqual )
  8458. {
  8459. ctx->bc.InstrW_W(asBC_CMPi,b,c);
  8460. ctx->bc.Instr(asBC_TZ);
  8461. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  8462. }
  8463. else if( op == ttNotEqual )
  8464. {
  8465. ctx->bc.InstrW_W(asBC_CMPi,b,c);
  8466. ctx->bc.Instr(asBC_TNZ);
  8467. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  8468. }
  8469. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  8470. }
  8471. else
  8472. {
  8473. // TODO: Use TXT_ILLEGAL_OPERATION_ON
  8474. Error(TXT_ILLEGAL_OPERATION, node);
  8475. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), 0);
  8476. }
  8477. }
  8478. else
  8479. {
  8480. ConvertToVariableNotIn(lctx, rctx);
  8481. ConvertToVariableNotIn(rctx, lctx);
  8482. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  8483. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  8484. MergeExprBytecode(ctx, lctx);
  8485. MergeExprBytecode(ctx, rctx);
  8486. ProcessDeferredParams(ctx);
  8487. asEBCInstr iCmp = asBC_CMPi, iT = asBC_TZ;
  8488. if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  8489. iCmp = asBC_CMPi;
  8490. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  8491. iCmp = asBC_CMPu;
  8492. else if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  8493. iCmp = asBC_CMPi64;
  8494. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  8495. iCmp = asBC_CMPu64;
  8496. else if( lctx->type.dataType.IsFloatType() )
  8497. iCmp = asBC_CMPf;
  8498. else if( lctx->type.dataType.IsDoubleType() )
  8499. iCmp = asBC_CMPd;
  8500. else
  8501. asASSERT(false);
  8502. if( op == ttEqual )
  8503. iT = asBC_TZ;
  8504. else if( op == ttNotEqual )
  8505. iT = asBC_TNZ;
  8506. else if( op == ttLessThan )
  8507. iT = asBC_TS;
  8508. else if( op == ttLessThanOrEqual )
  8509. iT = asBC_TNP;
  8510. else if( op == ttGreaterThan )
  8511. iT = asBC_TP;
  8512. else if( op == ttGreaterThanOrEqual )
  8513. iT = asBC_TNS;
  8514. int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, true), true);
  8515. int b = lctx->type.stackOffset;
  8516. int c = rctx->type.stackOffset;
  8517. ctx->bc.InstrW_W(iCmp, b, c);
  8518. ctx->bc.Instr(iT);
  8519. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  8520. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  8521. }
  8522. }
  8523. else
  8524. {
  8525. if( to.IsBooleanType() )
  8526. {
  8527. int op = node->tokenType;
  8528. if( op == ttEqual || op == ttNotEqual )
  8529. {
  8530. // Make sure they are equal if not false
  8531. if( lctx->type.dwordValue != 0 ) lctx->type.dwordValue = VALUE_OF_BOOLEAN_TRUE;
  8532. if( rctx->type.dwordValue != 0 ) rctx->type.dwordValue = VALUE_OF_BOOLEAN_TRUE;
  8533. asDWORD v = 0;
  8534. if( op == ttEqual )
  8535. {
  8536. v = lctx->type.intValue - rctx->type.intValue;
  8537. if( v == 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  8538. }
  8539. else if( op == ttNotEqual )
  8540. {
  8541. v = lctx->type.intValue - rctx->type.intValue;
  8542. if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  8543. }
  8544. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), v);
  8545. }
  8546. else
  8547. {
  8548. // TODO: Use TXT_ILLEGAL_OPERATION_ON
  8549. Error(TXT_ILLEGAL_OPERATION, node);
  8550. }
  8551. }
  8552. else
  8553. {
  8554. int i = 0;
  8555. if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  8556. {
  8557. int v = lctx->type.intValue - rctx->type.intValue;
  8558. if( v < 0 ) i = -1;
  8559. if( v > 0 ) i = 1;
  8560. }
  8561. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  8562. {
  8563. asDWORD v1 = lctx->type.dwordValue;
  8564. asDWORD v2 = rctx->type.dwordValue;
  8565. if( v1 < v2 ) i = -1;
  8566. if( v1 > v2 ) i = 1;
  8567. }
  8568. else if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  8569. {
  8570. asINT64 v = asINT64(lctx->type.qwordValue) - asINT64(rctx->type.qwordValue);
  8571. if( v < 0 ) i = -1;
  8572. if( v > 0 ) i = 1;
  8573. }
  8574. else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 )
  8575. {
  8576. asQWORD v1 = lctx->type.qwordValue;
  8577. asQWORD v2 = rctx->type.qwordValue;
  8578. if( v1 < v2 ) i = -1;
  8579. if( v1 > v2 ) i = 1;
  8580. }
  8581. else if( lctx->type.dataType.IsFloatType() )
  8582. {
  8583. float v = lctx->type.floatValue - rctx->type.floatValue;
  8584. if( v < 0 ) i = -1;
  8585. if( v > 0 ) i = 1;
  8586. }
  8587. else if( lctx->type.dataType.IsDoubleType() )
  8588. {
  8589. double v = lctx->type.doubleValue - rctx->type.doubleValue;
  8590. if( v < 0 ) i = -1;
  8591. if( v > 0 ) i = 1;
  8592. }
  8593. if( op == ttEqual )
  8594. i = (i == 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  8595. else if( op == ttNotEqual )
  8596. i = (i != 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  8597. else if( op == ttLessThan )
  8598. i = (i < 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  8599. else if( op == ttLessThanOrEqual )
  8600. i = (i <= 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  8601. else if( op == ttGreaterThan )
  8602. i = (i > 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  8603. else if( op == ttGreaterThanOrEqual )
  8604. i = (i >= 0 ? VALUE_OF_BOOLEAN_TRUE : 0);
  8605. ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), i);
  8606. }
  8607. }
  8608. }
  8609. void asCCompiler::PushVariableOnStack(asSExprContext *ctx, bool asReference)
  8610. {
  8611. // Put the result on the stack
  8612. ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset);
  8613. if( asReference )
  8614. ctx->type.dataType.MakeReference(true);
  8615. else
  8616. {
  8617. if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 )
  8618. ctx->bc.Instr(asBC_RDS4);
  8619. else
  8620. ctx->bc.Instr(asBC_RDS8);
  8621. }
  8622. }
  8623. void asCCompiler::CompileBooleanOperator(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  8624. {
  8625. // Both operands must be booleans
  8626. asCDataType to;
  8627. to.SetTokenType(ttBool);
  8628. // Do the actual conversion
  8629. asCArray<int> reservedVars;
  8630. rctx->bc.GetVarsUsed(reservedVars);
  8631. lctx->bc.GetVarsUsed(reservedVars);
  8632. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true, &reservedVars);
  8633. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true, &reservedVars);
  8634. // Verify that the conversion was successful
  8635. if( !lctx->type.dataType.IsBooleanType() )
  8636. {
  8637. asCString str;
  8638. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format().AddressOf(), "bool");
  8639. Error(str.AddressOf(), node);
  8640. // Force the conversion to allow compilation to proceed
  8641. lctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  8642. }
  8643. if( !rctx->type.dataType.IsBooleanType() )
  8644. {
  8645. asCString str;
  8646. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format().AddressOf(), "bool");
  8647. Error(str.AddressOf(), node);
  8648. // Force the conversion to allow compilation to proceed
  8649. rctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true);
  8650. }
  8651. bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
  8652. ctx->type.Set(asCDataType::CreatePrimitive(ttBool, true));
  8653. // What kind of operator is it?
  8654. int op = node->tokenType;
  8655. if( op == ttXor )
  8656. {
  8657. if( !isConstant )
  8658. {
  8659. // Must convert to temporary variable, because we are changing the value before comparison
  8660. ConvertToTempVariableNotIn(lctx, rctx);
  8661. ConvertToTempVariableNotIn(rctx, lctx);
  8662. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  8663. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  8664. // Make sure they are equal if not false
  8665. lctx->bc.InstrWORD(asBC_NOT, lctx->type.stackOffset);
  8666. rctx->bc.InstrWORD(asBC_NOT, rctx->type.stackOffset);
  8667. MergeExprBytecode(ctx, lctx);
  8668. MergeExprBytecode(ctx, rctx);
  8669. ProcessDeferredParams(ctx);
  8670. int a = AllocateVariable(ctx->type.dataType, true);
  8671. int b = lctx->type.stackOffset;
  8672. int c = rctx->type.stackOffset;
  8673. ctx->bc.InstrW_W_W(asBC_BXOR,a,b,c);
  8674. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  8675. }
  8676. else
  8677. {
  8678. // Make sure they are equal if not false
  8679. #if AS_SIZEOF_BOOL == 1
  8680. if( lctx->type.byteValue != 0 ) lctx->type.byteValue = VALUE_OF_BOOLEAN_TRUE;
  8681. if( rctx->type.byteValue != 0 ) rctx->type.byteValue = VALUE_OF_BOOLEAN_TRUE;
  8682. asBYTE v = 0;
  8683. v = lctx->type.byteValue - rctx->type.byteValue;
  8684. if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  8685. ctx->type.isConstant = true;
  8686. ctx->type.byteValue = v;
  8687. #else
  8688. if( lctx->type.dwordValue != 0 ) lctx->type.dwordValue = VALUE_OF_BOOLEAN_TRUE;
  8689. if( rctx->type.dwordValue != 0 ) rctx->type.dwordValue = VALUE_OF_BOOLEAN_TRUE;
  8690. asDWORD v = 0;
  8691. v = lctx->type.intValue - rctx->type.intValue;
  8692. if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0;
  8693. ctx->type.isConstant = true;
  8694. ctx->type.dwordValue = v;
  8695. #endif
  8696. }
  8697. }
  8698. else if( op == ttAnd ||
  8699. op == ttOr )
  8700. {
  8701. if( !isConstant )
  8702. {
  8703. // If or-operator and first value is 1 the second value shouldn't be calculated
  8704. // if and-operator and first value is 0 the second value shouldn't be calculated
  8705. ConvertToVariable(lctx);
  8706. ReleaseTemporaryVariable(lctx->type, &lctx->bc);
  8707. MergeExprBytecode(ctx, lctx);
  8708. int offset = AllocateVariable(asCDataType::CreatePrimitive(ttBool, false), true);
  8709. int label1 = nextLabel++;
  8710. int label2 = nextLabel++;
  8711. if( op == ttAnd )
  8712. {
  8713. ctx->bc.InstrSHORT(asBC_CpyVtoR4, lctx->type.stackOffset);
  8714. ctx->bc.Instr(asBC_ClrHi);
  8715. ctx->bc.InstrDWORD(asBC_JNZ, label1);
  8716. ctx->bc.InstrW_DW(asBC_SetV4, (asWORD)offset, 0);
  8717. ctx->bc.InstrINT(asBC_JMP, label2);
  8718. }
  8719. else if( op == ttOr )
  8720. {
  8721. ctx->bc.InstrSHORT(asBC_CpyVtoR4, lctx->type.stackOffset);
  8722. ctx->bc.Instr(asBC_ClrHi);
  8723. ctx->bc.InstrDWORD(asBC_JZ, label1);
  8724. #if AS_SIZEOF_BOOL == 1
  8725. ctx->bc.InstrSHORT_B(asBC_SetV1, (short)offset, VALUE_OF_BOOLEAN_TRUE);
  8726. #else
  8727. ctx->bc.InstrSHORT_DW(asBC_SetV4, (short)offset, VALUE_OF_BOOLEAN_TRUE);
  8728. #endif
  8729. ctx->bc.InstrINT(asBC_JMP, label2);
  8730. }
  8731. ctx->bc.Label((short)label1);
  8732. ConvertToVariable(rctx);
  8733. ReleaseTemporaryVariable(rctx->type, &rctx->bc);
  8734. rctx->bc.InstrW_W(asBC_CpyVtoV4, offset, rctx->type.stackOffset);
  8735. MergeExprBytecode(ctx, rctx);
  8736. ctx->bc.Label((short)label2);
  8737. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, false), offset, true);
  8738. }
  8739. else
  8740. {
  8741. #if AS_SIZEOF_BOOL == 1
  8742. asBYTE v = 0;
  8743. if( op == ttAnd )
  8744. v = lctx->type.byteValue && rctx->type.byteValue;
  8745. else if( op == ttOr )
  8746. v = lctx->type.byteValue || rctx->type.byteValue;
  8747. // Remember the result
  8748. ctx->type.isConstant = true;
  8749. ctx->type.byteValue = v;
  8750. #else
  8751. asDWORD v = 0;
  8752. if( op == ttAnd )
  8753. v = lctx->type.dwordValue && rctx->type.dwordValue;
  8754. else if( op == ttOr )
  8755. v = lctx->type.dwordValue || rctx->type.dwordValue;
  8756. // Remember the result
  8757. ctx->type.isConstant = true;
  8758. ctx->type.dwordValue = v;
  8759. #endif
  8760. }
  8761. }
  8762. }
  8763. void asCCompiler::CompileOperatorOnHandles(asCScriptNode *node, asSExprContext *lctx, asSExprContext *rctx, asSExprContext *ctx)
  8764. {
  8765. // Process the property accessor as get
  8766. ProcessPropertyGetAccessor(lctx, node);
  8767. ProcessPropertyGetAccessor(rctx, node);
  8768. // Make sure lctx doesn't end up with a variable used in rctx
  8769. if( lctx->type.isTemporary && rctx->bc.IsVarUsed(lctx->type.stackOffset) )
  8770. {
  8771. asCArray<int> vars;
  8772. rctx->bc.GetVarsUsed(vars);
  8773. int offset = AllocateVariable(lctx->type.dataType, true);
  8774. rctx->bc.ExchangeVar(lctx->type.stackOffset, offset);
  8775. ReleaseTemporaryVariable(offset, 0);
  8776. }
  8777. // Warn if not both operands are explicit handles
  8778. if( (node->tokenType == ttEqual || node->tokenType == ttNotEqual) &&
  8779. ((!lctx->type.isExplicitHandle && !(lctx->type.dataType.GetObjectType() && (lctx->type.dataType.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE))) ||
  8780. (!rctx->type.isExplicitHandle && !(rctx->type.dataType.GetObjectType() && (rctx->type.dataType.GetObjectType()->flags & asOBJ_IMPLICIT_HANDLE)))) )
  8781. {
  8782. Warning(TXT_HANDLE_COMPARISON, node);
  8783. }
  8784. // Implicitly convert null to the other type
  8785. asCDataType to;
  8786. if( lctx->type.IsNullConstant() )
  8787. to = rctx->type.dataType;
  8788. else if( rctx->type.IsNullConstant() )
  8789. to = lctx->type.dataType;
  8790. else
  8791. {
  8792. // TODO: Use the common base type
  8793. to = lctx->type.dataType;
  8794. }
  8795. // Need to pop the value if it is a null constant
  8796. if( lctx->type.IsNullConstant() )
  8797. lctx->bc.Pop(AS_PTR_SIZE);
  8798. if( rctx->type.IsNullConstant() )
  8799. rctx->bc.Pop(AS_PTR_SIZE);
  8800. // Convert both sides to explicit handles
  8801. to.MakeHandle(true);
  8802. to.MakeReference(false);
  8803. // Do the conversion
  8804. ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV);
  8805. ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV);
  8806. // Both operands must be of the same type
  8807. // Verify that the conversion was successful
  8808. if( !lctx->type.dataType.IsEqualExceptConst(to) )
  8809. {
  8810. asCString str;
  8811. str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  8812. Error(str.AddressOf(), node);
  8813. }
  8814. if( !rctx->type.dataType.IsEqualExceptConst(to) )
  8815. {
  8816. asCString str;
  8817. str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format().AddressOf(), to.Format().AddressOf());
  8818. Error(str.AddressOf(), node);
  8819. }
  8820. ctx->type.Set(asCDataType::CreatePrimitive(ttBool, true));
  8821. int op = node->tokenType;
  8822. if( op == ttEqual || op == ttNotEqual || op == ttIs || op == ttNotIs )
  8823. {
  8824. // If the object handle already is in a variable we must manually pop it from the stack
  8825. if( lctx->type.isVariable )
  8826. lctx->bc.Pop(AS_PTR_SIZE);
  8827. if( rctx->type.isVariable )
  8828. rctx->bc.Pop(AS_PTR_SIZE);
  8829. // TODO: optimize: Treat the object handles as two integers, i.e. don't do REFCPY
  8830. ConvertToVariableNotIn(lctx, rctx);
  8831. ConvertToVariable(rctx);
  8832. MergeExprBytecode(ctx, lctx);
  8833. MergeExprBytecode(ctx, rctx);
  8834. int a = AllocateVariable(ctx->type.dataType, true);
  8835. int b = lctx->type.stackOffset;
  8836. int c = rctx->type.stackOffset;
  8837. // TODO: When saving the bytecode we must be able to determine that this is
  8838. // a comparison with a pointer, so that the instruction can be adapted
  8839. // to the pointer size on the platform that will execute it.
  8840. #ifdef AS_64BIT_PTR
  8841. ctx->bc.InstrW_W(asBC_CMPi64, b, c);
  8842. #else
  8843. ctx->bc.InstrW_W(asBC_CMPi, b, c);
  8844. #endif
  8845. if( op == ttEqual || op == ttIs )
  8846. ctx->bc.Instr(asBC_TZ);
  8847. else if( op == ttNotEqual || op == ttNotIs )
  8848. ctx->bc.Instr(asBC_TNZ);
  8849. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a);
  8850. ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true);
  8851. ReleaseTemporaryVariable(lctx->type, &ctx->bc);
  8852. ReleaseTemporaryVariable(rctx->type, &ctx->bc);
  8853. ProcessDeferredParams(ctx);
  8854. }
  8855. else
  8856. {
  8857. // TODO: Use TXT_ILLEGAL_OPERATION_ON
  8858. Error(TXT_ILLEGAL_OPERATION, node);
  8859. }
  8860. }
  8861. void asCCompiler::PerformFunctionCall(int funcId, asSExprContext *ctx, bool isConstructor, asCArray<asSExprContext*> *args, asCObjectType *objType, bool useVariable, int varOffset, int funcPtrVar)
  8862. {
  8863. asCScriptFunction *descr = builder->GetFunctionDescription(funcId);
  8864. // Check if the function is private
  8865. if( descr->isPrivate && descr->GetObjectType() != outFunc->GetObjectType() )
  8866. {
  8867. asCString msg;
  8868. msg.Format(TXT_PRIVATE_METHOD_CALL_s, descr->GetDeclarationStr().AddressOf());
  8869. Error(msg.AddressOf(), ctx->exprNode);
  8870. }
  8871. int argSize = descr->GetSpaceNeededForArguments();
  8872. if( descr->objectType && descr->returnType.IsReference() &&
  8873. !ctx->type.isVariable && (ctx->type.dataType.IsObjectHandle() || ctx->type.dataType.SupportHandles()) &&
  8874. !(ctx->type.dataType.GetObjectType()->GetFlags() & asOBJ_SCOPED) )
  8875. {
  8876. // The class method we're calling is returning a reference, which may be to a member of the object.
  8877. // In order to guarantee the lifetime of the reference, we must hold a local reference to the object.
  8878. // TODO: optimize: This can be avoided for local variables (non-handles) as they have a well defined life time
  8879. int tempRef = AllocateVariable(ctx->type.dataType, true);
  8880. ctx->bc.InstrSHORT(asBC_PSF, (short)tempRef);
  8881. ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetObjectType());
  8882. // Add the release of this reference, as a deferred expression
  8883. asSDeferredParam deferred;
  8884. deferred.origExpr = 0;
  8885. deferred.argInOutFlags = asTM_INREF;
  8886. deferred.argNode = 0;
  8887. deferred.argType.SetVariable(ctx->type.dataType, tempRef, true);
  8888. ctx->deferredParams.PushLast(deferred);
  8889. }
  8890. ctx->type.Set(descr->returnType);
  8891. if( isConstructor )
  8892. {
  8893. // Sometimes the value types are allocated on the heap,
  8894. // which is when this way of constructing them is used.
  8895. asASSERT(useVariable == false);
  8896. ctx->bc.Alloc(asBC_ALLOC, objType, descr->id, argSize+AS_PTR_SIZE);
  8897. // The instruction has already moved the returned object to the variable
  8898. ctx->type.Set(asCDataType::CreatePrimitive(ttVoid, false));
  8899. // Clean up arguments
  8900. if( args )
  8901. AfterFunctionCall(funcId, *args, ctx, false);
  8902. ProcessDeferredParams(ctx);
  8903. return;
  8904. }
  8905. else if( descr->funcType == asFUNC_IMPORTED )
  8906. ctx->bc.Call(asBC_CALLBND , descr->id, argSize + (descr->objectType ? AS_PTR_SIZE : 0));
  8907. // TODO: Maybe we need two different byte codes
  8908. else if( descr->funcType == asFUNC_INTERFACE || descr->funcType == asFUNC_VIRTUAL )
  8909. ctx->bc.Call(asBC_CALLINTF, descr->id, argSize + (descr->objectType ? AS_PTR_SIZE : 0));
  8910. else if( descr->funcType == asFUNC_SCRIPT )
  8911. ctx->bc.Call(asBC_CALL , descr->id, argSize + (descr->objectType ? AS_PTR_SIZE : 0));
  8912. else if( descr->funcType == asFUNC_SYSTEM )
  8913. ctx->bc.Call(asBC_CALLSYS , descr->id, argSize + (descr->objectType ? AS_PTR_SIZE : 0));
  8914. else if( descr->funcType == asFUNC_FUNCDEF )
  8915. ctx->bc.CallPtr(asBC_CallPtr, funcPtrVar, argSize);
  8916. if( ctx->type.dataType.IsObject() && !descr->returnType.IsReference() )
  8917. {
  8918. int returnOffset = 0;
  8919. if( useVariable )
  8920. {
  8921. // Use the given variable
  8922. returnOffset = varOffset;
  8923. ctx->type.SetVariable(descr->returnType, returnOffset, false);
  8924. }
  8925. else
  8926. {
  8927. // Allocate a temporary variable for the returned object
  8928. // The returned object will actually be allocated on the heap, so
  8929. // we must force the allocation of the variable to do the same
  8930. returnOffset = AllocateVariable(descr->returnType, true, true);
  8931. ctx->type.SetVariable(descr->returnType, returnOffset, true);
  8932. }
  8933. ctx->type.dataType.MakeReference(true);
  8934. // Move the pointer from the object register to the temporary variable
  8935. ctx->bc.InstrSHORT(asBC_STOREOBJ, (short)returnOffset);
  8936. // Clean up arguments
  8937. if( args )
  8938. AfterFunctionCall(funcId, *args, ctx, false);
  8939. ProcessDeferredParams(ctx);
  8940. ctx->bc.InstrSHORT(asBC_PSF, (short)returnOffset);
  8941. }
  8942. else if( descr->returnType.IsReference() )
  8943. {
  8944. asASSERT(useVariable == false);
  8945. // We cannot clean up the arguments yet, because the
  8946. // reference might be pointing to one of them.
  8947. // Clean up arguments
  8948. if( args )
  8949. AfterFunctionCall(funcId, *args, ctx, true);
  8950. // Do not process the output parameters yet, because it
  8951. // might invalidate the returned reference
  8952. if( descr->returnType.IsPrimitive() )
  8953. ctx->type.Set(descr->returnType);
  8954. else
  8955. {
  8956. ctx->bc.Instr(asBC_PshRPtr);
  8957. if( descr->returnType.IsObject() && !descr->returnType.IsObjectHandle() )
  8958. {
  8959. // We are getting the pointer to the object
  8960. // not a pointer to a object variable
  8961. ctx->type.dataType.MakeReference(false);
  8962. }
  8963. }
  8964. }
  8965. else
  8966. {
  8967. asASSERT(useVariable == false);
  8968. if( descr->returnType.GetSizeInMemoryBytes() )
  8969. {
  8970. // Allocate a temporary variable to hold the value, but make sure
  8971. // the temporary variable isn't used in any of the deferred arguments
  8972. asCArray<int> vars;
  8973. for( asUINT n = 0; args && n < args->GetLength(); n++ )
  8974. {
  8975. asSExprContext *expr = (*args)[n]->origExpr;
  8976. if( expr )
  8977. expr->bc.GetVarsUsed(vars);
  8978. }
  8979. int offset = AllocateVariableNotIn(descr->returnType, true, &vars);
  8980. ctx->type.SetVariable(descr->returnType, offset, true);
  8981. // Move the value from the return register to the variable
  8982. if( descr->returnType.GetSizeOnStackDWords() == 1 )
  8983. ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)offset);
  8984. else if( descr->returnType.GetSizeOnStackDWords() == 2 )
  8985. ctx->bc.InstrSHORT(asBC_CpyRtoV8, (short)offset);
  8986. }
  8987. else
  8988. ctx->type.Set(descr->returnType);
  8989. // Clean up arguments
  8990. if( args )
  8991. AfterFunctionCall(funcId, *args, ctx, false);
  8992. ProcessDeferredParams(ctx);
  8993. }
  8994. }
  8995. // This only merges the bytecode, but doesn't modify the type of the final context
  8996. void asCCompiler::MergeExprBytecode(asSExprContext *before, asSExprContext *after)
  8997. {
  8998. before->bc.AddCode(&after->bc);
  8999. for( asUINT n = 0; n < after->deferredParams.GetLength(); n++ )
  9000. {
  9001. before->deferredParams.PushLast(after->deferredParams[n]);
  9002. after->deferredParams[n].origExpr = 0;
  9003. }
  9004. after->deferredParams.SetLength(0);
  9005. }
  9006. // This merges both bytecode and the type of the final context
  9007. void asCCompiler::MergeExprBytecodeAndType(asSExprContext *before, asSExprContext *after)
  9008. {
  9009. MergeExprBytecode(before, after);
  9010. before->type = after->type;
  9011. before->property_get = after->property_get;
  9012. before->property_set = after->property_set;
  9013. before->property_const = after->property_const;
  9014. before->property_handle = after->property_handle;
  9015. before->property_ref = after->property_ref;
  9016. before->property_arg = after->property_arg;
  9017. before->exprNode = after->exprNode;
  9018. after->property_arg = 0;
  9019. // Do not copy the origExpr member
  9020. }
  9021. void asCCompiler::FilterConst(asCArray<int> &funcs)
  9022. {
  9023. if( funcs.GetLength() == 0 ) return;
  9024. // This is only done for object methods
  9025. asCScriptFunction *desc = builder->GetFunctionDescription(funcs[0]);
  9026. if( desc->objectType == 0 ) return;
  9027. // Check if there are any non-const matches
  9028. asUINT n;
  9029. bool foundNonConst = false;
  9030. for( n = 0; n < funcs.GetLength(); n++ )
  9031. {
  9032. desc = builder->GetFunctionDescription(funcs[n]);
  9033. if( !desc->isReadOnly )
  9034. {
  9035. foundNonConst = true;
  9036. break;
  9037. }
  9038. }
  9039. if( foundNonConst )
  9040. {
  9041. // Remove all const methods
  9042. for( n = 0; n < funcs.GetLength(); n++ )
  9043. {
  9044. desc = builder->GetFunctionDescription(funcs[n]);
  9045. if( desc->isReadOnly )
  9046. {
  9047. if( n == funcs.GetLength() - 1 )
  9048. funcs.PopLast();
  9049. else
  9050. funcs[n] = funcs.PopLast();
  9051. n--;
  9052. }
  9053. }
  9054. }
  9055. }
  9056. END_AS_NAMESPACE