fppas2js.pp 314 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826
  1. {
  2. This file is part of the Free Component Library (FCL)
  3. Copyright (c) 2014 by Michael Van Canneyt
  4. Pascal to Javascript converter class.
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************
  11. }(*
  12. Abstract:
  13. Converts TPasElements into TJSElements.
  14. Works:
  15. - units, programs
  16. - unit interface function
  17. - uses list
  18. - use $impl for implementation declarations, can be disabled
  19. - interface vars
  20. - only double, no other float type
  21. - only string, no other string type
  22. - modifier public to protect from removing by optimizer
  23. - implementation vars
  24. - external vars
  25. - initialization section
  26. - option to add "use strict";
  27. - procedures
  28. - params
  29. - local vars
  30. - default values
  31. - function results
  32. - modifier external 'name'
  33. - local const: declare in singleton parent function as local var
  34. - give procedure overloads in module unique names by appending $1, $2, ...
  35. - give nested procedure overloads unique names by appending $1, $2, ...
  36. - untyped parameter
  37. - varargs
  38. - modifier public to protect from removing by optimizer
  39. - assign statements
  40. - char
  41. - literals
  42. - ord(char) -> char.charCodeAt()
  43. - chr(integer) -> String.fromCharCode(integer)
  44. - string
  45. - literals
  46. - setlength(s,newlen) -> s.length == newlen
  47. - read and write char aString[]
  48. - allow only String, no ShortString, AnsiString, UnicodeString,...
  49. - allow type casting string to external class name 'String'
  50. - for loop
  51. - if loopvar is used afterwards append if($loopend>i)i--;
  52. - repeat..until
  53. - while..do
  54. - try..finally
  55. - try..except, try..except on else
  56. - raise, raise E
  57. - asm..end
  58. - assembler; asm..end;
  59. - break
  60. - continue
  61. - procedure str, function str
  62. - type alias
  63. - inc/dec to += -=
  64. - case-of
  65. - convert "a div b" to "Math.floor(a / b)"
  66. - and, or, xor, not: logical and bitwise
  67. - typecast boolean to integer and back
  68. - rename name conflicts with js identifiers: apply, bind, call, prototype, ...
  69. - record
  70. - types and vars
  71. - assign
  72. - clone record member
  73. - clone set member
  74. - clone when passing as argument
  75. - equal, not equal
  76. - classes
  77. - declare using createClass
  78. - constructor
  79. - destructor
  80. - vars, init on create, clear references on destroy
  81. - class vars
  82. - ancestor
  83. - virtual, override, abstract
  84. - "is" operator
  85. - "as" operator
  86. - call inherited "inherited;", "inherited funcname;"
  87. - call class method
  88. - read/write class var
  89. - property
  90. - param list
  91. - property of type array
  92. - class property
  93. - accessors non static
  94. - Assigned()
  95. - default property
  96. - type casts
  97. - overloads, reintroduce append $1, $2, ...
  98. - reintroduced variables
  99. - external vars and methods
  100. - const
  101. - dynamic arrays
  102. - arrays can be null
  103. - init as "arr = []" so typeof works
  104. - SetLength(arr,len) becomes arr = SetLength(arr,len,defaultvalue)
  105. - length(), low(), high(), assigned(), concat()
  106. - assign nil -> [] so typeof works
  107. - read, write element arr[index]
  108. - multi dimensional [index1,index2] -> [index1][index2]
  109. - array of record
  110. - equal, unequal nil -> rtl.length(array)==0 or >0
  111. - when passing nil to an array argument, pass []
  112. - allow type casting array to external class name 'Array'
  113. - type cast array to array of same dimensions and compatible element type
  114. - function copy(array,start=0,count=max): array
  115. - procedure insert(item,var array,const position)
  116. - procedure delete(var array,const start,count)
  117. - static arrays
  118. - range: enumtype
  119. - init as arr = rtl.arrayNewMultiDim([dim1,dim2,...],value)
  120. - init with expression
  121. - length(1-dim array)
  122. - low(1-dim array), high(1-dim array)
  123. - open arrays
  124. - as dynamic arrays
  125. - enums
  126. - type with values and names
  127. - option to write numbers instead of variables
  128. - ord(), low(), high(), pred(), succ()
  129. - type cast alias to enumtype
  130. - type cast number to enumtype
  131. - sets
  132. - set of enum
  133. - include, exclude, clone when referenced
  134. - assign := set state referenced
  135. - constant set: enums, enum vars, ranges
  136. - set operators +, -, *, ><, =, <>, >=, <=
  137. - in-operator
  138. - low(), high()
  139. - when passing as argument set state referenced
  140. - with-do using local var
  141. - with record do i:=v;
  142. - with classinstance do begin create; i:=v; f(); i:=a[]; end;
  143. - pass by reference
  144. - pass local var to a var/out parameter
  145. - pass variable to a var/out parameter
  146. - pass reference to a var/out parameter
  147. - pass array element to a var/out parameter
  148. - procedure types
  149. - implemented as immutable wrapper function
  150. - assign := nil, proctype (not clone), @function, @method
  151. - call explicit and implicit
  152. - compare equal and notequal with nil, proctype, address, function
  153. - assigned(proctype)
  154. - pass as argument
  155. - methods
  156. - mode delphi: proctype:=proc
  157. - mode delphi: functype=funcresulttype
  158. - nested functions
  159. - class-of
  160. - assign := nil, var
  161. - call class method
  162. - call constructor
  163. - operators =, <>
  164. - class var, property, method
  165. - Self in class method
  166. - typecast
  167. - class external
  168. - JS object or function as ancestor
  169. - does not descend from TObject
  170. - all members become external. case sensitive
  171. - has no hidden values like $class, $ancestor, $unitname, $init, $final
  172. - can be ancestor of a pascal class (not descend from TObject).
  173. - pascal class descendant can override methods
  174. - property works as normal, replaced by getter and setter
  175. - class-of
  176. - class var/function: works as in JS.
  177. - is and as operators
  178. - destructor forbidden
  179. - constructor must not be virtual
  180. - constructor 'new' -> new extclass(params)
  181. - identifiers are renamed to avoid clashes with external names
  182. - call inherited
  183. - Pascal descendant can override newinstance
  184. - any class can be typecasted to any root class
  185. - class instances cannot access external class members (e.g. static class functions)
  186. - external class bracket accessor, getter/setter has external name '[]'
  187. - external class 'Array' bracket operator [integer] type jsvalue
  188. - external class 'Object' bracket operator [string] type jsvalue
  189. - jsvalue
  190. - init as undefined
  191. - assign to jsvalue := integer, string, boolean, double, char
  192. - type cast base types to jsvalue
  193. - type cast jsvalue to base type
  194. integer: Math.floor(jsvalue) may return NaN
  195. boolean: !(jsvalue == false) works for numbers too 0==false
  196. double: rtl.getNumber(jsvalue) typeof(n)=="number"?n:NaN;
  197. string: ""+jsvalue
  198. char: rtl.getChar(jsvalue) ((typeof(c)!="string") && (c.length==1)) ? c : ""
  199. - enums: assign to jsvalue, typecast jsvalue to enum
  200. - class instance: assign to jsvalue, typecast jsvalue to a class
  201. - class of: assign to jsvalue, typecast jsvalue to a class-of
  202. - array of jsvalue,
  203. allow to assign any array to an array of jsvalue
  204. allow type casting to any array
  205. - parameter, result type, assign from/to untyped
  206. - operators equal, not equal
  207. - callback: assign to jsvalue, equal, not equal
  208. - ECMAScript6:
  209. - use 0b for binary literals
  210. - use 0o for octal literals
  211. ToDos:
  212. - -Jirtl.js-
  213. - make -Jirtl.js default for -Jc and -Tnodejs, needs #IFDEF in cfg
  214. - remove 'Object' array workaround
  215. - FuncName:= (instead of Result:=)
  216. - ord(s[i]) -> s.charCodeAt(i)
  217. - $modeswitch -> define <modeswitch>
  218. - $modeswitch- -> turn off
  219. - integer range
  220. - @@ compare method in delphi mode
  221. - make records more lightweight
  222. - dotted unit names, namespaces
  223. - type alias type
  224. - RTTI
  225. - enumeration for..in..do
  226. - pointer of record
  227. - nested types in class
  228. - asm: pas() - useful for overloads and protect an identifier from optimization
  229. - source maps
  230. Not in Version 1.0:
  231. - write, writeln
  232. - arrays
  233. - static array: non 0 start index, length
  234. - array of static array: setlength
  235. - array range char, char range, integer range, enum range
  236. - array of const
  237. - sets
  238. - set of char, boolean, integer range, char range, enum range
  239. - set of (enum,enum2) - anonymous enumtype
  240. - call array of proc element without ()
  241. - record const
  242. - enums with custom values
  243. - library
  244. - option typecast checking
  245. - option verify method calls -CR
  246. - option range checking -Cr
  247. - option overflow checking -Co
  248. - optimizations:
  249. - set operators on literals without temporary arrays, a in [b], [a]*b<>[]
  250. - use a number for small sets
  251. -O1 insert local/unit vars for global type references:
  252. at start of intf var $r1;
  253. at end of impl: $r1=path;
  254. -O1 insert unit vars for complex literals
  255. -O1 no function Result var when assigned only once
  256. - SetLength(scope.a,l) -> read scope only once, same for
  257. Include, Exclude, Inc, Dec
  258. -O1 replace constant expression with result
  259. -O1 pass array element by ref: when index is constant, use that directly
  260. - objects, interfaces, advanced records
  261. - class helpers, type helpers, record helpers,
  262. - generics
  263. - operator overloading
  264. - inline
  265. - anonymous functions
  266. Compile flags for debugging: -d<x>
  267. VerbosePas2JS
  268. *)
  269. unit fppas2js;
  270. {$mode objfpc}{$H+}
  271. {$inline on}
  272. interface
  273. uses
  274. Classes, SysUtils, math, contnrs, jsbase, jstree, PasTree, PScanner,
  275. PasResolver;
  276. // message numbers
  277. const
  278. nPasElementNotSupported = 4001;
  279. nIdentifierNotFound = 4002;
  280. nUnaryOpcodeNotSupported = 4003;
  281. nBinaryOpcodeNotSupported = 4004;
  282. nInvalidNumber = 4005;
  283. nInitializedArraysNotSupported = 4006;
  284. nMemberExprMustBeIdentifier = 4007;
  285. nCantWriteSetLiteral = 4008;
  286. nVariableIdentifierExpected = 4009;
  287. nExpectedXButFoundY = 4010;
  288. nInvalidFunctionReference = 4011;
  289. nMissingExternalName = 4012;
  290. nVirtualMethodNameMustMatchExternal = 4013;
  291. nInvalidVariableModifier = 4014;
  292. nNoArgumentsAllowedForExternalObjectConstructor = 4015;
  293. nNewInstanceFunctionMustBeVirtual = 4016;
  294. nNewInstanceFunctionMustHaveTwoParameters = 4017;
  295. nNewInstanceFunctionMustNotHaveOverloads = 4018;
  296. nBracketAccessorOfExternalClassMustHaveOneParameter = 4019;
  297. // resourcestring patterns of messages
  298. resourcestring
  299. sPasElementNotSupported = 'Pascal element not supported: %s';
  300. sIdentifierNotFound = 'Identifier not found "%s"';
  301. sUnaryOpcodeNotSupported = 'Unary OpCode not yet supported "%s"';
  302. sBinaryOpcodeNotSupported = 'Binary OpCode not yet supported "%s"';
  303. sInvalidNumber = 'Invalid number "%s"';
  304. sInitializedArraysNotSupported = 'Initialized array variables not yet supported';
  305. sMemberExprMustBeIdentifier = 'Member expression must be an identifier';
  306. sCantWriteSetLiteral = 'Cannot write set literal';
  307. sVariableIdentifierExpected = 'Variable identifier expected';
  308. sExpectedXButFoundY = 'Expected %s, but found %s';
  309. sInvalidFunctionReference = 'Invalid function reference';
  310. sMissingExternalName = 'Missing external name';
  311. sVirtualMethodNameMustMatchExternal = 'Virtual method name must match external';
  312. sInvalidVariableModifier = 'Invalid variable modifier "%s"';
  313. sNoArgumentsAllowedForExternalObjectConstructor = 'no arguments allowed for external object constructor';
  314. sNewInstanceFunctionMustBeVirtual = 'NewInstance function must be virtual';
  315. sNewInstanceFunctionMustHaveTwoParameters = 'NewInstance function must have two parameters';
  316. sNewInstanceFunctionMustNotHaveOverloads = 'NewInstance function must not have overloads';
  317. sBracketAccessorOfExternalClassMustHaveOneParameter = 'Bracket accessor of external class must have one parameter';
  318. const
  319. ExtClassBracketAccessor = '[]'; // external name '[]' marks the array param getter/setter
  320. type
  321. TPas2JSBuiltInName = (
  322. pbifnArray_Concat,
  323. pbifnArray_Copy,
  324. pbifnArray_Length,
  325. pbifnArray_NewMultiDim,
  326. pbifnArray_SetLength,
  327. pbifnAs,
  328. pbifnAsExt,
  329. pbifnClassInstanceFree,
  330. pbifnClassInstanceNew,
  331. pbifnCreateClass,
  332. pbifnCreateClassExt,
  333. pbifnGetChar,
  334. pbifnGetNumber,
  335. pbifnGetObject,
  336. pbifnIs,
  337. pbifnIsExt,
  338. pbifnProcType_Create,
  339. pbifnProcType_Equal,
  340. pbifnProgramMain,
  341. pbifnRecordEqual,
  342. pbifnSetCharAt,
  343. pbifnSet_Clone,
  344. pbifnSet_Create,
  345. pbifnSet_Difference,
  346. pbifnSet_Equal,
  347. pbifnSet_Exclude,
  348. pbifnSet_GreaterEqual,
  349. pbifnSet_Include,
  350. pbifnSet_Intersect,
  351. pbifnSet_LowerEqual,
  352. pbifnSet_NotEqual,
  353. pbifnSet_Reference,
  354. pbifnSet_SymDiffSet,
  355. pbifnSet_Union,
  356. pbifnSpaceLeft,
  357. pbifnUnitInit,
  358. pbivnExceptObject,
  359. pbivnImplementation,
  360. pbivnLoopEnd,
  361. pbivnModules,
  362. pbivnPtrClass,
  363. pbivnRTL,
  364. pbivnWith
  365. );
  366. const
  367. Pas2JSBuiltInNames: array[TPas2JSBuiltInName] of string = (
  368. 'arrayConcat', // rtl.arrayConcat
  369. 'arrayCopy', // rtl.arrayCopy
  370. 'length', // rtl.length
  371. 'arrayNewMultiDim', // rtl.arrayNewMultiDim
  372. 'arraySetLength', // rtl.arraySetLength
  373. 'as', // rtl.as
  374. 'asExt', // rtl.asExt
  375. '$destroy',
  376. '$create',
  377. 'createClass', // rtl.createClass
  378. 'createClassExt', // rtl.createClassExt
  379. 'getChar', // rtl.getChar
  380. 'getNumber', // rtl.getNumber
  381. 'getObject', // rtl.getObject
  382. 'is', // rtl.is
  383. 'isExt', // rtl.isExt
  384. 'createCallback', // rtl.createCallback
  385. 'eqCallback', // rtl.eqCallback
  386. '$main',
  387. '$equal',
  388. 'setCharAt', // rtl.setCharAt
  389. 'cloneSet', // rtl.cloneSet
  390. 'createSet', // rtl.createSet [...]
  391. 'diffSet', // rtl.diffSet -
  392. 'eqSet', // rtl.eqSet =
  393. 'excludeSet', // rtl.excludeSet
  394. 'geSet', // rtl.geSet superset >=
  395. 'includeSet', // rtl.includeSet
  396. 'intersectSet', // rtl.intersectSet *
  397. 'leSet', // rtl.leSet subset <=
  398. 'neSet', // rtl.neSet <>
  399. 'refSet', // rtl.refSet
  400. 'symDiffSet', // rtl.symDiffSet >< (symmetrical difference)
  401. 'unionSet', // rtl.unionSet +
  402. 'spaceLeft', // rtl.spaceLeft
  403. '$init',
  404. '$e',
  405. '$impl',
  406. '$loopend',
  407. 'pas',
  408. '$class',
  409. 'rtl',
  410. '$with'
  411. );
  412. JSReservedWords: array[0..106] of string = (
  413. // keep sorted, first uppercase, then lowercase !
  414. 'Array',
  415. 'ArrayBuffer',
  416. 'Boolean',
  417. 'DataView',
  418. 'Date',
  419. 'Error',
  420. 'EvalError',
  421. 'Float32Array',
  422. 'Float64Array',
  423. 'Generator',
  424. 'GeneratorFunction',
  425. 'Infinity',
  426. 'Int16Array',
  427. 'Int32Array',
  428. 'Int8Array',
  429. 'InternalError',
  430. 'JSON',
  431. 'Map',
  432. 'Math',
  433. 'NaN',
  434. 'Number',
  435. 'Object',
  436. 'Promise',
  437. 'Proxy',
  438. 'RangeError',
  439. 'ReferenceError',
  440. 'Reflect',
  441. 'RegExp',
  442. 'Set',
  443. 'String',
  444. 'Symbol',
  445. 'SyntaxError',
  446. 'TypeError',
  447. 'URIError',
  448. 'Uint16Array',
  449. 'Uint32Array',
  450. 'Uint8Array',
  451. 'Uint8ClampedArray',
  452. 'WeakMap',
  453. 'WeakSet',
  454. '__extends',
  455. '_super',
  456. 'anonymous',
  457. 'apply',
  458. 'arguments',
  459. 'array',
  460. 'await',
  461. 'bind',
  462. 'break',
  463. 'call',
  464. 'case',
  465. 'catch',
  466. 'class',
  467. 'constructor',
  468. 'continue',
  469. 'decodeURI',
  470. 'decodeURIComponent',
  471. 'default',
  472. 'delete',
  473. 'do',
  474. 'each',
  475. 'else',
  476. 'encodeURI',
  477. 'encodeURIComponent',
  478. 'enum',
  479. 'escape',
  480. 'eval',
  481. 'export',
  482. 'extends',
  483. 'false',
  484. 'for',
  485. 'function',
  486. 'getPrototypeOf',
  487. 'if',
  488. 'implements',
  489. 'import',
  490. 'in',
  491. 'instanceof',
  492. 'interface',
  493. 'isFinite',
  494. 'isNaN',
  495. 'isPrototypeOf',
  496. 'let',
  497. 'new',
  498. 'null',
  499. 'package',
  500. 'parseFloat',
  501. 'parseInt',
  502. 'private',
  503. 'protected',
  504. 'prototype',
  505. 'public',
  506. 'return',
  507. 'static',
  508. 'super',
  509. 'switch',
  510. 'this',
  511. 'throw',
  512. 'true',
  513. 'try',
  514. 'undefined',
  515. 'unescape',
  516. 'uneval',
  517. 'var',
  518. 'while',
  519. 'with',
  520. 'yield'
  521. );
  522. const
  523. ClassVarModifiersType = [vmClass,vmStatic];
  524. LowJSInteger = -$10000000000000;
  525. HighJSInteger = $fffffffffffff;
  526. LowJSBoolean = false;
  527. HighJSBoolean = true;
  528. Type
  529. { EPas2JS }
  530. EPas2JS = Class(Exception)
  531. public
  532. PasElement: TPasElement;
  533. MsgNumber: integer;
  534. Args: TMessageArgs;
  535. Id: int64;
  536. MsgType: TMessageType;
  537. end;
  538. //------------------------------------------------------------------------------
  539. // Pas2js built-in types
  540. type
  541. TPas2jsBaseType = (
  542. pbtNone,
  543. pbtJSValue
  544. );
  545. TPas2jsBaseTypes = set of TPas2jsBaseType;
  546. const
  547. Pas2jsBaseTypeNames: array[TPas2jsBaseType] of string = (
  548. 'None',
  549. 'JSValue'
  550. );
  551. btAllJSValueSrcTypes = [btNil,btUntyped]+btAllInteger
  552. +btAllStringAndChars+btAllFloats+btAllBooleans;
  553. btAllJSValueTypeCastTo = btAllInteger
  554. +btAllStringAndChars+btAllFloats+btAllBooleans;
  555. //------------------------------------------------------------------------------
  556. // Element CustomData
  557. type
  558. { TPas2JsElementData }
  559. TPas2JsElementData = Class(TPasElementBase)
  560. private
  561. FElement: TPasElement;
  562. procedure SetElement(const AValue: TPasElement);
  563. public
  564. Owner: TObject; // e.g. a TPasToJSConverter
  565. Next: TPas2JsElementData; // TPasToJSConverter uses this for its memory chain
  566. constructor Create; virtual;
  567. destructor Destroy; override;
  568. property Element: TPasElement read FElement write SetElement; // can be TPasElement
  569. end;
  570. TPas2JsElementDataClass = class of TPas2JsElementData;
  571. { TP2JConstExprData - CustomData of a const TPasExpr }
  572. TP2JConstExprData = Class(TPas2JsElementData)
  573. public
  574. // Element is TPasExpr
  575. Value: TJSValue;
  576. destructor Destroy; override;
  577. end;
  578. TPas2JSClassScope = class(TPasClassScope)
  579. public
  580. NewInstanceFunction: TPasClassFunction;
  581. end;
  582. { TPas2JSWithExprScope }
  583. TPas2JSWithExprScope = class(TPasWithExprScope)
  584. public
  585. WithVarName: string;
  586. end;
  587. { TResElDataPas2JSBaseType - CustomData for compiler built-in types (TPasUnresolvedSymbolRef), e.g. jsvalue }
  588. TResElDataPas2JSBaseType = class(TResElDataBaseType)
  589. public
  590. JSBaseType: TPas2jsBaseType;
  591. end;
  592. //------------------------------------------------------------------------------
  593. // TPas2JSResolver
  594. const
  595. DefaultPasResolverOptions = [
  596. proFixCaseOfOverrides,
  597. proClassPropertyNonStatic,
  598. proPropertyAsVarParam,
  599. proClassOfIs,
  600. proExtClassInstanceNoTypeMembers,
  601. proOpenAsDynArrays,
  602. proProcTypeWithoutIsNested
  603. ];
  604. type
  605. TPas2JSResolver = class(TPasResolver)
  606. private
  607. FJSBaseTypes: array[TPas2jsBaseType] of TPasUnresolvedSymbolRef;
  608. FExternalNames: TFPHashList; // list of list of TPasIdentifier
  609. FFirstElementData, FLastElementData: TPas2JsElementData;
  610. function GetJSBaseTypes(aBaseType: TPas2jsBaseType): TPasUnresolvedSymbolRef; inline;
  611. procedure InternalAdd(Item: TPasIdentifier);
  612. procedure OnClearHashItem(Item, Dummy: pointer);
  613. protected
  614. FOverloadScopes: TFPList; // list of TPasIdentifierScope
  615. function GetOverloadIndex(Identifier: TPasIdentifier;
  616. StopAt: TPasElement): integer;
  617. function GetOverloadIndex(El: TPasElement): integer;
  618. function RenameOverload(El: TPasElement): boolean;
  619. procedure RenameOverloadsInSection(aSection: TPasSection);
  620. procedure RenameOverloads(DeclEl: TPasElement; Declarations: TFPList);
  621. procedure RenameSubOverloads(Declarations: TFPList);
  622. procedure PushOverloadScope(Scope: TPasIdentifierScope);
  623. procedure PopOverloadScope;
  624. procedure ResolveImplAsm(El: TPasImplAsmStatement); override;
  625. procedure FinishModule(CurModule: TPasModule); override;
  626. procedure FinishClassType(El: TPasClassType); override;
  627. procedure FinishVariable(El: TPasVariable); override;
  628. procedure FinishProcedureType(El: TPasProcedureType); override;
  629. procedure FinishPropertyOfClass(PropEl: TPasProperty); override;
  630. procedure CheckNewInstanceFunction(ClassScope: TPas2JSClassScope); virtual;
  631. function AddExternalName(const aName: string; El: TPasElement): TPasIdentifier; virtual;
  632. function FindExternalName(const aName: String): TPasIdentifier; virtual;
  633. procedure AddExternalPath(aName: string; El: TPasElement);
  634. procedure ClearElementData; virtual;
  635. protected
  636. // additional base types
  637. function AddJSBaseType(const aName: string; Typ: TPas2jsBaseType): TResElDataPas2JSBaseType;
  638. function IsJSBaseType(TypeEl: TPasType; Typ: TPas2jsBaseType): boolean;
  639. function IsJSBaseType(const TypeResolved: TPasResolverResult;
  640. Typ: TPas2jsBaseType; HasValue: boolean = false): boolean;
  641. function CheckAssignCompatibilityCustom(const LHS,
  642. RHS: TPasResolverResult; ErrorEl: TPasElement;
  643. RaiseOnIncompatible: boolean; var Handled: boolean): integer; override;
  644. function CheckTypeCastClassInstanceToClass(const FromClassRes,
  645. ToClassRes: TPasResolverResult; ErrorEl: TPasElement): integer; override;
  646. function CheckEqualCompatibilityCustomType(const LHS,
  647. RHS: TPasResolverResult; ErrorEl: TPasElement;
  648. RaiseOnIncompatible: boolean): integer; override;
  649. function ResolveBracketOperatorClass(Params: TParamsExpr;
  650. const ResolvedValue: TPasResolverResult; ClassScope: TPasClassScope;
  651. Access: TResolvedRefAccess): boolean; override;
  652. procedure ComputeArrayParams_Class(Params: TParamsExpr; var
  653. ResolvedEl: TPasResolverResult; ClassScope: TPasClassScope;
  654. Flags: TPasResolverComputeFlags; StartEl: TPasElement); override;
  655. public
  656. constructor Create;
  657. destructor Destroy; override;
  658. // base types
  659. procedure AddObjFPCBuiltInIdentifiers(
  660. const TheBaseTypes: TResolveBaseTypes=btAllStandardTypes;
  661. const TheBaseProcs: TResolverBuiltInProcs=bfAllStandardProcs); override;
  662. function CheckTypeCastRes(const FromResolved,
  663. ToResolved: TPasResolverResult; ErrorEl: TPasElement;
  664. RaiseOnError: boolean): integer; override;
  665. property JSBaseTypes[aBaseType: TPas2jsBaseType]: TPasUnresolvedSymbolRef read GetJSBaseTypes;
  666. // compute literals and constants
  667. function ExtractPasStringLiteral(El: TPasElement; const S: String): TJSString; virtual;
  668. function ComputeConst(Expr: TPasExpr; StoreCustomData: boolean): TJSValue; virtual;
  669. function ComputeConstString(Expr: TPasExpr; StoreCustomData, NotEmpty: boolean): String; virtual;
  670. function IsExternalBracketAccessor(El: TPasElement): boolean;
  671. // CustomData
  672. function GetElementData(El: TPasElementBase;
  673. DataClass: TPas2JsElementDataClass): TPas2JsElementData; virtual;
  674. procedure AddElementData(Data: TPas2JsElementData); virtual;
  675. function CreateElementData(DataClass: TPas2JsElementDataClass;
  676. El: TPasElement): TPas2JsElementData; virtual;
  677. end;
  678. //------------------------------------------------------------------------------
  679. // TConvertContext
  680. type
  681. TCtxJSElementKind = (
  682. cjkRoot,
  683. cjkObject,
  684. cjkFunction,
  685. cjkArray,
  686. cjkDot);
  687. TCtxAccess = (
  688. caRead, // normal read
  689. caAssign, // needs setter
  690. caByReference // needs path, getter and setter
  691. );
  692. TFunctionContext = Class;
  693. { TConvertContext }
  694. TConvertContextClass = Class of TConvertContext;
  695. TConvertContext = Class(TObject)
  696. public
  697. PasElement: TPasElement;
  698. JSElement: TJSElement;
  699. Resolver: TPas2JSResolver;
  700. Parent: TConvertContext;
  701. Kind: TCtxJSElementKind;
  702. IsSingleton: boolean;
  703. Access: TCtxAccess;
  704. AccessContext: TConvertContext;
  705. TmpVarCount: integer;
  706. constructor Create(PasEl: TPasElement; JSEl: TJSElement; aParent: TConvertContext); virtual;
  707. function GetRootModule: TPasModule;
  708. function GetThis: TPasElement;
  709. function GetThisContext: TFunctionContext;
  710. function GetContextOfType(aType: TConvertContextClass): TConvertContext;
  711. function CreateLocalIdentifier(const Prefix: string): string;
  712. function CurrentModeswitches: TModeSwitches;
  713. function GetSingletonFunc: TFunctionContext;
  714. end;
  715. { TRootContext }
  716. TRootContext = Class(TConvertContext)
  717. public
  718. constructor Create(PasEl: TPasElement; JSEl: TJSElement; aParent: TConvertContext); override;
  719. end;
  720. { TFunctionContext }
  721. TFunctionContext = Class(TConvertContext)
  722. public
  723. This: TPasElement;
  724. constructor Create(PasEl: TPasElement; JSEl: TJSElement; aParent: TConvertContext); override;
  725. end;
  726. { TObjectContext }
  727. TObjectContext = Class(TConvertContext)
  728. public
  729. constructor Create(PasEl: TPasElement; JSEl: TJSElement; aParent: TConvertContext); override;
  730. end;
  731. { TInterfaceContext }
  732. TInterfaceContext = Class(TFunctionContext)
  733. public
  734. constructor Create(PasEl: TPasElement; JSEl: TJSElement; aParent: TConvertContext); override;
  735. end;
  736. { TDotContext - used for converting eopSubIdent }
  737. TDotContext = Class(TConvertContext)
  738. public
  739. LeftResolved: TPasResolverResult;
  740. constructor Create(PasEl: TPasElement; JSEl: TJSElement; aParent: TConvertContext); override;
  741. end;
  742. { TAssignContext - used for left side of an assign statement }
  743. TAssignContext = Class(TConvertContext)
  744. public
  745. // set when creating:
  746. LeftResolved: TPasResolverResult;
  747. RightResolved: TPasResolverResult;
  748. RightSide: TJSElement;
  749. // created by ConvertElement:
  750. PropertyEl: TPasProperty;
  751. Setter: TPasElement;
  752. Call: TJSCallExpression;
  753. constructor Create(PasEl: TPasElement; JSEl: TJSElement; aParent: TConvertContext); override;
  754. end;
  755. { TParamContext }
  756. TParamContext = Class(TConvertContext)
  757. public
  758. // set when creating:
  759. Arg: TPasArgument;
  760. Expr: TPasExpr;
  761. ResolvedExpr: TPasResolverResult;
  762. // created by ConvertElement:
  763. Getter: TJSElement;
  764. Setter: TJSElement;
  765. ReusingReference: boolean; // true = result is a reference, do not create another
  766. constructor Create(PasEl: TPasElement; JSEl: TJSElement; aParent: TConvertContext); override;
  767. end;
  768. //------------------------------------------------------------------------------
  769. // TPasToJSConverter
  770. type
  771. TPasToJsConverterOption = (
  772. coLowerCase, // lowercase all identifiers, except conflicts with JS reserved words
  773. coSwitchStatement, // convert case-of into switch instead of if-then-else
  774. coEnumNumbers, // use enum numbers instead of names
  775. coUseStrict // insert 'use strict'
  776. );
  777. TPasToJsConverterOptions = set of TPasToJsConverterOption;
  778. TPas2JSIsElementUsedEvent = function(Sender: TObject; El: TPasElement): boolean of object;
  779. TPasToJsPlatform = (
  780. PlatformBrowser,
  781. PlatformNodeJS
  782. );
  783. TPasToJsPlatforms = set of TPasToJsPlatform;
  784. const
  785. PasToJsPlatformNames: array[TPasToJsPlatform] of string = (
  786. 'Browser',
  787. 'NodeJS'
  788. );
  789. type
  790. TPasToJsProcessor = (
  791. ProcessorECMAScript5,
  792. ProcessorECMAScript6
  793. );
  794. TPasToJsProcessors = set of TPasToJsProcessor;
  795. const
  796. PasToJsProcessorNames: array[TPasToJsProcessor] of string = (
  797. 'ECMAScript5',
  798. 'ECMAScript6'
  799. );
  800. type
  801. TJSReservedWordList = array of String;
  802. TRefPathKind = (
  803. rpkPath, // e.g. "TObject"
  804. rpkPathWithDot, // e.g. "TObject."
  805. rpkPathAndName // e.g. "TObject.ClassName"
  806. );
  807. { TPasToJSConverter }
  808. TPasToJSConverter = Class(TObject)
  809. private
  810. // inline at top, only functions declared after the inline implementation actually use it
  811. function GetUseEnumNumbers: boolean; inline;
  812. function GetUseLowerCase: boolean; inline;
  813. function GetUseSwitchStatement: boolean; inline;
  814. private
  815. type
  816. TForLoopFindData = record
  817. ForLoop: TPasImplForLoop;
  818. LoopVar: TPasElement;
  819. FoundLoop: boolean;
  820. LoopVarWrite: boolean; // true if first acces of LoopVar after loop is a write
  821. LoopVarRead: boolean; // true if first acces of LoopVar after loop is a read
  822. end;
  823. PForLoopFindData = ^TForLoopFindData;
  824. procedure ForLoop_OnProcBodyElement(El: TPasElement; arg: pointer);
  825. private
  826. type
  827. TTryExceptFindData = record
  828. HasRaiseWithoutObject: boolean;
  829. end;
  830. PTryExceptFindData = ^TTryExceptFindData;
  831. procedure TryExcept_OnElement(El: TPasElement; arg: pointer);
  832. private
  833. FBuiltInNames: array[TPas2JSBuiltInName] of string;
  834. FOnIsElementUsed: TPas2JSIsElementUsedEvent;
  835. FOptions: TPasToJsConverterOptions;
  836. FPreservedWords: TJSReservedWordList; // sorted with CompareStr
  837. FTargetPlatform: TPasToJsPlatform;
  838. FTargetProcessor: TPasToJsProcessor;
  839. Function CreateBuiltInIdentifierExpr(AName: string): TJSPrimaryExpressionIdent;
  840. Function CreateDeclNameExpression(El: TPasElement; const Name: string;
  841. AContext: TConvertContext): TJSPrimaryExpressionIdent;
  842. Function CreateIdentifierExpr(AName: string; El: TPasElement; AContext: TConvertContext): TJSPrimaryExpressionIdent;
  843. Function CreateSwitchStatement(El: TPasImplCaseOf; AContext: TConvertContext): TJSElement;
  844. Function CreateTypeDecl(El: TPasType; AContext: TConvertContext): TJSElement;
  845. Function CreateVarDecl(El: TPasVariable; AContext: TConvertContext): TJSElement;
  846. Procedure AddToSourceElements(Src: TJSSourceElements; El: TJSElement);
  847. procedure RemoveFromSourceElements(Src: TJSSourceElements;
  848. El: TJSElement);
  849. function GetBuildInNames(bin: TPas2JSBuiltInName): string;
  850. procedure SetBuildInNames(bin: TPas2JSBuiltInName; const AValue: string);
  851. procedure SetPreservedWords(const AValue: TJSReservedWordList);
  852. procedure SetUseEnumNumbers(const AValue: boolean);
  853. procedure SetUseLowerCase(const AValue: boolean);
  854. procedure SetUseSwitchStatement(const AValue: boolean);
  855. protected
  856. // Error functions
  857. Procedure DoError(Id: int64; Const Msg : String);
  858. Procedure DoError(Id: int64; Const Msg : String; Const Args : Array of Const);
  859. Procedure DoError(Id: int64; MsgNumber: integer; const MsgPattern: string; Const Args : Array of Const; El: TPasElement);
  860. procedure RaiseNotSupported(El: TPasElement; AContext: TConvertContext; Id: int64; const Msg: string = '');
  861. procedure RaiseIdentifierNotFound(Identifier: string; El: TPasElement; Id: int64);
  862. procedure RaiseInconsistency(Id: int64);
  863. // Computation, value conversions
  864. Function GetExpressionValueType(El: TPasExpr; AContext: TConvertContext ): TJSType; virtual;
  865. Function GetPasIdentValueType(AName: String; AContext: TConvertContext): TJSType; virtual;
  866. Function ComputeConstString(Expr: TPasExpr; AContext: TConvertContext; NotEmpty: boolean): String; virtual;
  867. Function IsExternalClassConstructor(El: TPasElement): boolean;
  868. // Name mangling
  869. Function TransformVariableName(El: TPasElement; Const AName: String; AContext : TConvertContext): String; virtual;
  870. Function TransformVariableName(El: TPasElement; AContext : TConvertContext) : String; virtual;
  871. Function TransformModuleName(El: TPasModule; AContext : TConvertContext) : String; virtual;
  872. Function IsPreservedWord(const aName: string): boolean; virtual;
  873. // Never create an element manually, always use the below functions
  874. Function IsElementUsed(El: TPasElement): boolean; virtual;
  875. Function CreateElement(C: TJSElementClass; Src: TPasElement): TJSElement; virtual;
  876. Function CreateFreeOrNewInstanceExpr(Ref: TResolvedReference;
  877. AContext : TConvertContext): TJSCallExpression; virtual;
  878. Function CreateFunction(El: TPasElement; WithBody: boolean = true): TJSFunctionDeclarationStatement;
  879. Procedure CreateProcedureCall(var Call: TJSCallExpression; Args: TParamsExpr;
  880. TargetProc: TPasProcedureType; AContext: TConvertContext); virtual;
  881. Procedure CreateProcedureCallArgs(Elements: TJSArrayLiteralElements;
  882. Args: TParamsExpr; TargetProc: TPasProcedureType; AContext: TConvertContext); virtual;
  883. Function CreateProcCallArg(El: TPasExpr; TargetArg: TPasArgument;
  884. AContext: TConvertContext): TJSElement; virtual;
  885. Function CreateProcCallArgRef(El: TPasExpr; ResolvedEl: TPasResolverResult;
  886. TargetArg: TPasArgument; AContext: TConvertContext): TJSElement; virtual;
  887. Function CreateUnary(Members: array of string; E: TJSElement): TJSUnary;
  888. Function CreateMemberExpression(Members: array of string): TJSDotMemberExpression;
  889. Function CreateCallExpression(El: TPasElement): TJSCallExpression;
  890. Function CreateUsesList(UsesSection: TPasSection; AContext : TConvertContext): TJSArrayLiteral;
  891. Procedure AddToStatementList(var First, Last: TJSStatementList;
  892. Add: TJSElement; Src: TPasElement);
  893. Function CreateValInit(PasType: TPasType; Expr: TPasElement; El: TPasElement; AContext: TConvertContext): TJSElement; virtual;
  894. Function CreateVarInit(El: TPasVariable; AContext: TConvertContext): TJSElement; virtual;
  895. Function CreateLiteralNumber(El: TPasElement; const n: TJSNumber): TJSLiteral; virtual;
  896. Function CreateLiteralString(El: TPasElement; const s: string): TJSLiteral; virtual;
  897. Function CreateLiteralJSString(El: TPasElement; const s: TJSString): TJSLiteral; virtual;
  898. Function CreateLiteralBoolean(El: TPasElement; b: boolean): TJSLiteral; virtual;
  899. Function CreateLiteralNull(El: TPasElement): TJSLiteral; virtual;
  900. Function CreateLiteralUndefined(El: TPasElement): TJSLiteral; virtual;
  901. Function CreateRecordInit(aRecord: TPasRecordType; Expr: TPasElement;
  902. El: TPasElement; AContext: TConvertContext): TJSElement; virtual;
  903. Function CreateArrayInit(ArrayType: TPasArrayType; Expr: TPasElement;
  904. El: TPasElement; AContext: TConvertContext): TJSElement; virtual;
  905. Function CreateCmpArrayWithNil(El: TPasElement; JSArray: TJSElement; OpCode: TExprOpCode): TJSElement; virtual;
  906. Function CreateReferencePath(El: TPasElement; AContext : TConvertContext;
  907. Kind: TRefPathKind; Full: boolean = false; Ref: TResolvedReference = nil): string; virtual;
  908. Function CreateReferencePathExpr(El: TPasElement; AContext : TConvertContext; Full: boolean = false; Ref: TResolvedReference = nil): TJSPrimaryExpressionIdent; virtual;
  909. Function CreateImplementationSection(El: TPasModule; Src: TJSSourceElements; AContext: TConvertContext): TJSElement;
  910. Procedure CreateInitSection(El: TPasModule; Src: TJSSourceElements; AContext: TConvertContext);
  911. Function CreateDotExpression(aParent: TPasElement; Left, Right: TJSElement): TJSElement; virtual;
  912. Function CreateReferencedSet(El: TPasElement; SetExpr: TJSElement): TJSElement; virtual;
  913. Function CreateCloneRecord(El: TPasElement; ResolvedEl: TPasResolverResult;
  914. RecordExpr: TJSElement; AContext: TConvertContext): TJSElement; virtual;
  915. Function CreateCallback(El: TPasElement; ResolvedEl: TPasResolverResult;
  916. AContext: TConvertContext): TJSElement; virtual;
  917. Function CreateAssignStatement(LeftEl: TPasElement; AssignContext: TAssignContext): TJSElement; virtual;
  918. // Statements
  919. Function ConvertImplBlockElements(El: TPasImplBlock; AContext: TConvertContext; NilIfEmpty: boolean): TJSElement; virtual;
  920. Function ConvertBeginEndStatement(El: TPasImplBeginBlock; AContext: TConvertContext; NilIfEmpty: boolean): TJSElement; virtual;
  921. Function ConvertStatement(El: TPasImplStatement; AContext: TConvertContext ): TJSElement; virtual;
  922. Function ConvertAssignStatement(El: TPasImplAssign; AContext: TConvertContext): TJSElement; virtual;
  923. Function ConvertRaiseStatement(El: TPasImplRaise; AContext: TConvertContext ): TJSElement; virtual;
  924. Function ConvertIfStatement(El: TPasImplIfElse; AContext: TConvertContext ): TJSElement; virtual;
  925. Function ConvertWhileStatement(El: TPasImplWhileDo; AContext: TConvertContext): TJSElement; virtual;
  926. Function ConvertRepeatStatement(El: TPasImplRepeatUntil; AContext: TConvertContext): TJSElement; virtual;
  927. Function ConvertForStatement(El: TPasImplForLoop; AContext: TConvertContext): TJSElement; virtual;
  928. Function ConvertFinalizationSection(El: TFinalizationSection; AContext: TConvertContext): TJSElement; virtual;
  929. Function ConvertInitializationSection(El: TInitializationSection; AContext: TConvertContext): TJSElement; virtual;
  930. Function ConvertSimpleStatement(El: TPasImplSimple; AContext: TConvertContext): TJSElement; virtual;
  931. Function ConvertWithStatement(El: TPasImplWithDo; AContext: TConvertContext): TJSElement; virtual;
  932. Function ConvertTryStatement(El: TPasImplTry; AContext: TConvertContext ): TJSElement; virtual;
  933. Function ConvertExceptOn(El: TPasImplExceptOn; AContext: TConvertContext): TJSElement;
  934. Function ConvertCaseOfStatement(El: TPasImplCaseOf; AContext: TConvertContext): TJSElement;
  935. Function ConvertAsmStatement(El: TPasImplAsmStatement; AContext: TConvertContext): TJSElement;
  936. // Expressions
  937. Function ConvertArrayValues(El: TArrayValues; AContext: TConvertContext): TJSElement; virtual;
  938. Function ConvertInheritedExpression(El: TInheritedExpr; AContext: TConvertContext): TJSElement; virtual;
  939. Function ConvertNilExpr(El: TNilExpr; AContext: TConvertContext): TJSElement; virtual;
  940. Function ConvertParamsExpression(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  941. Function ConvertArrayParams(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  942. Function ConvertFuncParams(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  943. Function ConvertExternalConstructor(Left: TPasElement;
  944. Ref: TResolvedReference; ParamsExpr: TParamsExpr;
  945. AContext : TConvertContext): TJSElement; virtual;
  946. Function ConvertTypeCastToBaseType(El: TParamsExpr; AContext: TConvertContext; BaseTypeData: TResElDataBaseType): TJSElement; virtual;
  947. Function ConvertSetLiteral(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  948. Function ConvertOpenArrayParam(ElType: TPasType; El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  949. Function ConvertBuiltInLength(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  950. Function ConvertBuiltInSetLength(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  951. Function ConvertBuiltInExcludeInclude(El: TParamsExpr; AContext: TConvertContext; IsInclude: boolean): TJSElement; virtual;
  952. Function ConvertBuiltInContinue(El: TPasExpr; AContext: TConvertContext): TJSElement; virtual;
  953. Function ConvertBuiltInBreak(El: TPasExpr; AContext: TConvertContext): TJSElement; virtual;
  954. Function ConvertBuiltInExit(El: TPasExpr; AContext: TConvertContext): TJSElement; virtual;
  955. Function ConvertBuiltInIncDec(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  956. Function ConvertBuiltInAssigned(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  957. Function ConvertBuiltInChr(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  958. Function ConvertBuiltInOrd(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  959. Function ConvertBuiltInLow(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  960. Function ConvertBuiltInHigh(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  961. Function ConvertBuiltInPred(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  962. Function ConvertBuiltInSucc(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  963. Function ConvertBuiltInStrProc(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  964. Function ConvertBuiltInStrFunc(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  965. Function ConvertBuiltInStrParam(El: TPasExpr; AContext: TConvertContext; IsStrFunc, IsFirst: boolean): TJSElement; virtual;
  966. Function ConvertBuiltInConcatArray(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  967. Function ConvertBuiltInCopyArray(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  968. Function ConvertBuiltInInsertArray(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  969. Function ConvertBuiltInDeleteArray(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  970. Function ConvertRecordValues(El: TRecordValues; AContext: TConvertContext): TJSElement; virtual;
  971. Function ConvertSelfExpression(El: TSelfExpr; AContext: TConvertContext): TJSElement; virtual;
  972. Function ConvertBinaryExpression(El: TBinaryExpr; AContext: TConvertContext): TJSElement; virtual;
  973. Function ConvertBinaryExpressionRes(El: TBinaryExpr; AContext: TConvertContext;
  974. const LeftResolved, RightResolved: TPasResolverResult; var A,B: TJSElement): TJSElement; virtual;
  975. Function ConvertSubIdentExpression(El: TBinaryExpr; AContext: TConvertContext): TJSElement; virtual;
  976. Function ConvertBoolConstExpression(El: TBoolConstExpr; AContext: TConvertContext): TJSElement; virtual;
  977. Function ConvertPrimitiveExpression(El: TPrimitiveExpr; AContext: TConvertContext): TJSElement; virtual;
  978. Function ConvertIdentifierExpr(El: TPrimitiveExpr; AContext : TConvertContext): TJSElement; virtual;
  979. Function ConvertUnaryExpression(El: TUnaryExpr; AContext: TConvertContext): TJSElement; virtual;
  980. // Convert declarations
  981. Function ConvertElement(El : TPasElement; AContext: TConvertContext) : TJSElement; virtual;
  982. Function ConvertProperty(El: TPasProperty; AContext: TConvertContext ): TJSElement; virtual;
  983. Function ConvertCommand(El: TPasImplCommand; AContext: TConvertContext): TJSElement; virtual;
  984. Function ConvertCommands(El: TPasImplCommands; AContext: TConvertContext): TJSElement; virtual;
  985. Function ConvertConst(El: TPasConst; AContext: TConvertContext): TJSElement; virtual;
  986. Function ConvertDeclarations(El: TPasDeclarations; AContext: TConvertContext): TJSElement; virtual;
  987. Function ConvertExportSymbol(El: TPasExportSymbol; AContext: TConvertContext): TJSElement; virtual;
  988. Function ConvertExpression(El: TPasExpr; AContext: TConvertContext): TJSElement; virtual;
  989. Function ConvertImplBlock(El: TPasImplBlock; AContext: TConvertContext ): TJSElement; virtual;
  990. Function ConvertLabelMark(El: TPasImplLabelMark; AContext: TConvertContext): TJSElement; virtual;
  991. Function ConvertLabels(El: TPasLabels; AContext: TConvertContext): TJSElement; virtual;
  992. Function ConvertModule(El: TPasModule; AContext: TConvertContext): TJSElement; virtual;
  993. Function ConvertPackage(El: TPasPackage; AContext: TConvertContext): TJSElement; virtual;
  994. Function ConvertProcedure(El: TPasProcedure; AContext: TConvertContext): TJSElement; virtual;
  995. Function ConvertResString(El: TPasResString; AContext: TConvertContext): TJSElement; virtual;
  996. Function ConvertVariable(El: TPasVariable; AContext: TConvertContext): TJSElement; virtual;
  997. Function ConvertRecordType(El: TPasRecordType; AContext: TConvertContext): TJSElement; virtual;
  998. Function ConvertClassType(El: TPasClassType; AContext: TConvertContext): TJSElement; virtual;
  999. Function ConvertClassExternalType(El: TPasClassType; AContext: TConvertContext): TJSElement; virtual;
  1000. Function ConvertEnumType(El: TPasEnumType; AContext: TConvertContext): TJSElement; virtual;
  1001. Public
  1002. Constructor Create;
  1003. destructor Destroy; override;
  1004. Function ConvertPasElement(El: TPasElement; Resolver: TPas2JSResolver) : TJSElement;
  1005. // options
  1006. Property Options: TPasToJsConverterOptions read FOptions write FOptions;
  1007. Property TargetPlatform: TPasToJsPlatform read FTargetPlatform write FTargetPlatform;
  1008. Property TargetProcessor: TPasToJsProcessor read FTargetProcessor write FTargetProcessor;
  1009. Property UseLowerCase: boolean read GetUseLowerCase write SetUseLowerCase default true;
  1010. Property UseSwitchStatement: boolean read GetUseSwitchStatement write SetUseSwitchStatement;// default false, because slower than "if" in many engines
  1011. Property UseEnumNumbers: boolean read GetUseEnumNumbers write SetUseEnumNumbers; // default false
  1012. Property OnIsElementUsed: TPas2JSIsElementUsedEvent read FOnIsElementUsed write FOnIsElementUsed;
  1013. Property PreservedWords: TJSReservedWordList read FPreservedWords write SetPreservedWords;
  1014. // names
  1015. Property BuildInNames[bin: TPas2JSBuiltInName]: string read GetBuildInNames write SetBuildInNames;
  1016. end;
  1017. var
  1018. JSTypeCaptions: array[TJSType] of string = (
  1019. 'undefined',
  1020. 'null',
  1021. 'boolean',
  1022. 'number',
  1023. 'string',
  1024. 'object',
  1025. 'reference',
  1026. 'completion'
  1027. );
  1028. function CodePointToJSString(u: cardinal): TJSString;
  1029. function PosLast(c: char; const s: string): integer;
  1030. implementation
  1031. const
  1032. TempRefObjGetterName = 'get';
  1033. TempRefObjSetterName = 'set';
  1034. TempRefObjSetterArgName = 'v';
  1035. function CodePointToJSString(u: cardinal): TJSString;
  1036. begin
  1037. if u < $10000 then
  1038. // Note: codepoints $D800 - $DFFF are reserved
  1039. Result:=WideChar(u)
  1040. else
  1041. Result:=WideChar($D800+((u - $10000) shr 10))+WideChar($DC00+((u - $10000) and $3ff));
  1042. end;
  1043. function PosLast(c: char; const s: string): integer;
  1044. begin
  1045. Result:=length(s);
  1046. while (Result>0) and (s[Result]<>c) do dec(Result);
  1047. end;
  1048. { TPas2JSResolver }
  1049. // inline
  1050. function TPas2JSResolver.GetJSBaseTypes(aBaseType: TPas2jsBaseType
  1051. ): TPasUnresolvedSymbolRef;
  1052. begin
  1053. Result:=TPasUnresolvedSymbolRef(FJSBaseTypes[aBaseType]);
  1054. end;
  1055. procedure TPas2JSResolver.InternalAdd(Item: TPasIdentifier);
  1056. var
  1057. Index: Integer;
  1058. OldItem: TPasIdentifier;
  1059. aName: ShortString;
  1060. begin
  1061. aName:=Item.Identifier;
  1062. Index:=FExternalNames.FindIndexOf(aName);
  1063. {$IFDEF VerbosePasResolver}
  1064. if Item.Owner<>nil then
  1065. raise Exception.Create('20170322235419');
  1066. Item.Owner:=Self;
  1067. {$ENDIF}
  1068. //writeln(' Index=',Index);
  1069. if Index>=0 then
  1070. begin
  1071. // insert LIFO - last in, first out
  1072. OldItem:=TPasIdentifier(FExternalNames.List^[Index].Data);
  1073. {$IFDEF VerbosePasResolver}
  1074. if OldItem.Identifier<>aName then
  1075. raise Exception.Create('20170322235429');
  1076. {$ENDIF}
  1077. Item.NextSameIdentifier:=OldItem;
  1078. FExternalNames.List^[Index].Data:=Item;
  1079. end
  1080. else
  1081. begin
  1082. FExternalNames.Add(aName, Item);
  1083. {$IFDEF VerbosePasResolver}
  1084. if FindExternalName(Item.Identifier)<>Item then
  1085. raise Exception.Create('20170322235433');
  1086. {$ENDIF}
  1087. end;
  1088. end;
  1089. procedure TPas2JSResolver.OnClearHashItem(Item, Dummy: pointer);
  1090. var
  1091. PasIdentifier: TPasIdentifier absolute Item;
  1092. Ident: TPasIdentifier;
  1093. begin
  1094. if Dummy=nil then ;
  1095. //writeln('TPas2JSResolver.OnClearItem ',PasIdentifier.Identifier+':'+PasIdentifier.ClassName);
  1096. while PasIdentifier<>nil do
  1097. begin
  1098. Ident:=PasIdentifier;
  1099. PasIdentifier:=PasIdentifier.NextSameIdentifier;
  1100. Ident.Free;
  1101. end;
  1102. end;
  1103. function TPas2JSResolver.GetOverloadIndex(Identifier: TPasIdentifier;
  1104. StopAt: TPasElement): integer;
  1105. // if not found return number of overloads
  1106. // if found return index in overloads
  1107. var
  1108. El: TPasElement;
  1109. ProcScope: TPasProcedureScope;
  1110. C: TClass;
  1111. begin
  1112. Result:=0;
  1113. // iterate from last added to first added
  1114. while Identifier<>nil do
  1115. begin
  1116. El:=Identifier.Element;
  1117. Identifier:=Identifier.NextSameIdentifier;
  1118. if El=StopAt then
  1119. begin
  1120. Result:=0;
  1121. continue;
  1122. end;
  1123. C:=El.ClassType;
  1124. if C=TPasClassType then
  1125. begin
  1126. if TPasClassType(El).IsForward then
  1127. continue;
  1128. end
  1129. else if C.InheritsFrom(TPasProcedure) then
  1130. begin
  1131. if TPasProcedure(El).IsOverride then
  1132. continue;
  1133. // Note: external proc pollute the name space
  1134. ProcScope:=TPasProcedureScope(El.CustomData);
  1135. if ProcScope.DeclarationProc<>nil then
  1136. // implementation proc -> only count the header -> skip
  1137. continue;
  1138. end;
  1139. inc(Result);
  1140. end;
  1141. end;
  1142. function TPas2JSResolver.GetOverloadIndex(El: TPasElement): integer;
  1143. var
  1144. i: Integer;
  1145. Identifier: TPasIdentifier;
  1146. begin
  1147. Result:=0;
  1148. for i:=FOverloadScopes.Count-1 downto 0 do
  1149. begin
  1150. // find last added
  1151. Identifier:=TPasIdentifierScope(FOverloadScopes[i]).FindLocalIdentifier(El.Name);
  1152. // add count or index
  1153. inc(Result,GetOverloadIndex(Identifier,El));
  1154. end;
  1155. // find in external names
  1156. Identifier:=FindExternalName(El.Name);
  1157. // add count or index
  1158. inc(Result,GetOverloadIndex(Identifier,El));
  1159. end;
  1160. function TPas2JSResolver.RenameOverload(El: TPasElement): boolean;
  1161. var
  1162. OverloadIndex: Integer;
  1163. NewName: String;
  1164. begin
  1165. // => count overloads in this section
  1166. OverloadIndex:=GetOverloadIndex(El);
  1167. if OverloadIndex=0 then
  1168. exit(false); // there is no overload
  1169. if (El.ClassType=TPasClassFunction)
  1170. and (TPas2JSClassScope(TPasClassType(El.Parent).CustomData).NewInstanceFunction=El) then
  1171. RaiseMsg(20170324234324,nNewInstanceFunctionMustNotHaveOverloads,
  1172. sNewInstanceFunctionMustNotHaveOverloads,[],El);
  1173. NewName:=El.Name+'$'+IntToStr(OverloadIndex);
  1174. {$IFDEF VerbosePas2JS}
  1175. writeln('TPas2JSResolver.RenameOverload "',El.Name,'" has overload. NewName="',NewName,'"');
  1176. {$ENDIF}
  1177. El.Name:=NewName;
  1178. Result:=true;
  1179. end;
  1180. procedure TPas2JSResolver.RenameOverloadsInSection(aSection: TPasSection);
  1181. var
  1182. ImplSection: TImplementationSection;
  1183. SectionClass: TClass;
  1184. begin
  1185. if aSection=nil then exit;
  1186. PushOverloadScope(aSection.CustomData as TPasIdentifierScope);
  1187. RenameOverloads(aSection,aSection.Declarations);
  1188. SectionClass:=aSection.ClassType;
  1189. if SectionClass=TInterfaceSection then
  1190. begin
  1191. // unit interface
  1192. // first rename all overloads in interface and implementation
  1193. ImplSection:=(aSection.Parent as TPasModule).ImplementationSection;
  1194. if ImplSection<>nil then
  1195. begin
  1196. PushOverloadScope(ImplSection.CustomData as TPasIdentifierScope);
  1197. RenameOverloads(ImplSection,ImplSection.Declarations);
  1198. end;
  1199. // and then rename all nested overloads (e.g. methods)
  1200. // Important: nested overloads must check both interface and implementation
  1201. RenameSubOverloads(aSection.Declarations);
  1202. if ImplSection<>nil then
  1203. begin
  1204. RenameSubOverloads(ImplSection.Declarations);
  1205. PopOverloadScope;
  1206. end;
  1207. end
  1208. else
  1209. begin
  1210. // program or library
  1211. RenameSubOverloads(aSection.Declarations);
  1212. end;
  1213. PopOverloadScope;
  1214. {$IFDEF VerbosePas2JS}
  1215. writeln('TPas2JSResolver.RenameOverloadsInSection END ',GetObjName(aSection));
  1216. {$ENDIF}
  1217. end;
  1218. procedure TPas2JSResolver.RenameOverloads(DeclEl: TPasElement;
  1219. Declarations: TFPList);
  1220. var
  1221. i: Integer;
  1222. El: TPasElement;
  1223. Proc: TPasProcedure;
  1224. ProcScope: TPasProcedureScope;
  1225. begin
  1226. //IsExternalClass:=(DeclEl is TPasClassType) and (TPasClassType(DeclEl).IsExternal);
  1227. if DeclEl=nil then;
  1228. for i:=0 to Declarations.Count-1 do
  1229. begin
  1230. El:=TPasElement(Declarations[i]);
  1231. if (El is TPasProcedure) then
  1232. begin
  1233. Proc:=TPasProcedure(El);
  1234. if Proc.IsOverride or Proc.IsExternal then
  1235. continue;
  1236. // Note: Pascal names of external procs are not in the JS, so no need to rename them
  1237. ProcScope:=Proc.CustomData as TPasProcedureScope;
  1238. //writeln('TPas2JSResolver.RenameOverloads Proc=',Proc.Name,' DeclarationProc=',GetObjName(ProcScope.DeclarationProc),' ImplProc=',GetObjName(ProcScope.ImplProc),' ClassScope=',GetObjName(ProcScope.ClassScope));
  1239. if ProcScope.DeclarationProc<>nil then
  1240. begin
  1241. if ProcScope.ImplProc<>nil then
  1242. RaiseInternalError(20170221110853);
  1243. // proc implementation (not forward) -> skip
  1244. continue;
  1245. end;
  1246. // proc declaration (header, not body)
  1247. if RenameOverload(Proc) then
  1248. if ProcScope.ImplProc<>nil then
  1249. ProcScope.ImplProc.Name:=Proc.Name;
  1250. end;
  1251. end;
  1252. {$IFDEF VerbosePas2JS}
  1253. writeln('TPas2JSResolver.RenameOverloads END ',GetObjName(DeclEl));
  1254. {$ENDIF}
  1255. end;
  1256. procedure TPas2JSResolver.RenameSubOverloads(Declarations: TFPList);
  1257. var
  1258. i, OldScopeCount: Integer;
  1259. El: TPasElement;
  1260. Proc, ImplProc: TPasProcedure;
  1261. ProcScope: TPasProcedureScope;
  1262. ClassScope, aScope: TPasClassScope;
  1263. ClassEl: TPasClassType;
  1264. C: TClass;
  1265. begin
  1266. for i:=0 to Declarations.Count-1 do
  1267. begin
  1268. El:=TPasElement(Declarations[i]);
  1269. C:=El.ClassType;
  1270. if C.InheritsFrom(TPasProcedure) then
  1271. begin
  1272. Proc:=TPasProcedure(El);
  1273. if Proc.IsAbstract or Proc.IsExternal then continue;
  1274. ProcScope:=Proc.CustomData as TPasProcedureScope;
  1275. {$IFDEF VerbosePas2JS}
  1276. writeln('TPas2JSResolver.RenameSubOverloads Proc=',Proc.Name,' DeclarationProc=',GetObjName(ProcScope.DeclarationProc),' ImplProc=',GetObjName(ProcScope.ImplProc),' ClassScope=',GetObjName(ProcScope.ClassScope));
  1277. {$ENDIF}
  1278. if ProcScope.DeclarationProc<>nil then
  1279. // proc implementation (not forward) -> skip
  1280. continue;
  1281. ImplProc:=Proc;
  1282. if ProcScope.ImplProc<>nil then
  1283. begin
  1284. // this proc has a separate implementation
  1285. // -> switch to implementation
  1286. ImplProc:=ProcScope.ImplProc;
  1287. ProcScope:=ImplProc.CustomData as TPasProcedureScope;
  1288. end;
  1289. PushOverloadScope(ProcScope);
  1290. // first rename all overloads on this level
  1291. RenameOverloads(ImplProc.Body,ImplProc.Body.Declarations);
  1292. // then process nested procedures
  1293. RenameSubOverloads(ImplProc.Body.Declarations);
  1294. PopOverloadScope;
  1295. end
  1296. else if C=TPasClassType then
  1297. begin
  1298. ClassEl:=TPasClassType(El);
  1299. if ClassEl.IsForward then continue;
  1300. ClassScope:=El.CustomData as TPas2JSClassScope;
  1301. OldScopeCount:=FOverloadScopes.Count;
  1302. // add class and ancestors scopes
  1303. aScope:=ClassScope;
  1304. repeat
  1305. PushOverloadScope(aScope);
  1306. aScope:=aScope.AncestorScope;
  1307. until aScope=nil;
  1308. // first rename all overloads on this level
  1309. RenameOverloads(ClassEl,ClassEl.Members);
  1310. // then process nested procedures
  1311. RenameSubOverloads(ClassEl.Members);
  1312. while FOverloadScopes.Count>OldScopeCount do
  1313. PopOverloadScope;
  1314. end
  1315. else if C=TPasConst then
  1316. RenameOverload(El)
  1317. else if C.InheritsFrom(TPasVariable) and (El.Parent.ClassType=TPasClassType) then
  1318. RenameOverload(El);
  1319. end;
  1320. {$IFDEF VerbosePas2JS}
  1321. writeln('TPas2JSResolver.RenameSubOverloads END');
  1322. {$ENDIF}
  1323. end;
  1324. procedure TPas2JSResolver.PushOverloadScope(Scope: TPasIdentifierScope);
  1325. begin
  1326. FOverloadScopes.Add(Scope);
  1327. end;
  1328. procedure TPas2JSResolver.PopOverloadScope;
  1329. begin
  1330. FOverloadScopes.Delete(FOverloadScopes.Count-1);
  1331. end;
  1332. procedure TPas2JSResolver.ResolveImplAsm(El: TPasImplAsmStatement);
  1333. {type
  1334. TAsmToken = (
  1335. atNone,
  1336. atWord,
  1337. atDot,
  1338. atRoundBracketOpen,
  1339. atRoundBracketClose
  1340. );
  1341. procedure Next;
  1342. begin
  1343. end;}
  1344. var
  1345. Lines: TStrings;
  1346. begin
  1347. Lines:=El.Tokens;
  1348. if Lines=nil then exit;
  1349. end;
  1350. procedure TPas2JSResolver.FinishModule(CurModule: TPasModule);
  1351. var
  1352. ModuleClass: TClass;
  1353. begin
  1354. inherited FinishModule(CurModule);
  1355. FOverloadScopes:=TFPList.Create;
  1356. try
  1357. ModuleClass:=CurModule.ClassType;
  1358. if ModuleClass=TPasModule then
  1359. begin
  1360. RenameOverloadsInSection(CurModule.InterfaceSection);
  1361. // Note: ImplementationSection is child of InterfaceSection
  1362. end
  1363. else if ModuleClass=TPasProgram then
  1364. RenameOverloadsInSection(TPasProgram(CurModule).ProgramSection)
  1365. else if CurModule.ClassType=TPasLibrary then
  1366. RenameOverloadsInSection(TPasLibrary(CurModule).LibrarySection)
  1367. else
  1368. RaiseNotYetImplemented(20170221000032,CurModule);
  1369. finally
  1370. FOverloadScopes.Free;
  1371. end;
  1372. end;
  1373. procedure TPas2JSResolver.FinishClassType(El: TPasClassType);
  1374. begin
  1375. inherited FinishClassType(El);
  1376. if El.IsExternal then
  1377. begin
  1378. if El.ExternalName='' then
  1379. RaiseMsg(20170321151109,nMissingExternalName,sMissingExternalName,[],El);
  1380. AddExternalPath(El.ExternalName,El);
  1381. end;
  1382. end;
  1383. procedure TPas2JSResolver.FinishVariable(El: TPasVariable);
  1384. const
  1385. ClassFieldModifiersAllowed = [vmClass,vmStatic,vmExternal,vmPublic];
  1386. RecordVarModifiersAllowed = [];
  1387. LocalVarModifiersAllowed = [];
  1388. ImplementationVarModifiersAllowed = [];
  1389. SectionVarModifiersAllowed = [vmExternal,vmPublic];
  1390. procedure RaiseVarModifierNotSupported(const Allowed: TVariableModifiers);
  1391. var
  1392. s: String;
  1393. m: TVariableModifier;
  1394. begin
  1395. s:='';
  1396. for m in TVariableModifiers do
  1397. if (m in El.VarModifiers) and not (m in Allowed) then
  1398. begin
  1399. str(m,s);
  1400. RaiseMsg(20170322134418,nInvalidVariableModifier,
  1401. sInvalidVariableModifier,[VariableModifierNames[m]],El);
  1402. end;
  1403. end;
  1404. var
  1405. ExtName: String;
  1406. ParentC: TClass;
  1407. begin
  1408. inherited FinishVariable(El);
  1409. ParentC:=El.Parent.ClassType;
  1410. if (ParentC=TPasClassType) then
  1411. begin
  1412. // class member
  1413. RaiseVarModifierNotSupported(ClassFieldModifiersAllowed);
  1414. if TPasClassType(El.Parent).IsExternal then
  1415. begin
  1416. // external class -> make variable external
  1417. if not (vmExternal in El.VarModifiers) then
  1418. begin
  1419. if (El.ClassType=TPasVariable) or (El.ClassType=TPasConst) then
  1420. begin
  1421. if El.ExportName<>nil then
  1422. RaiseMsg(20170322134321,nInvalidVariableModifier,
  1423. sInvalidVariableModifier,['export name'],El.ExportName);
  1424. El.ExportName:=TPrimitiveExpr.Create(El,pekString,''''+El.Name+'''');
  1425. end;
  1426. Include(El.VarModifiers,vmExternal);
  1427. end;
  1428. end;
  1429. end
  1430. else if ParentC=TPasRecordType then
  1431. // record member
  1432. RaiseVarModifierNotSupported(RecordVarModifiersAllowed)
  1433. else if ParentC=TProcedureBody then
  1434. // local var
  1435. RaiseVarModifierNotSupported(LocalVarModifiersAllowed)
  1436. else if ParentC=TImplementationSection then
  1437. // implementation var
  1438. RaiseVarModifierNotSupported(ImplementationVarModifiersAllowed)
  1439. else if ParentC.InheritsFrom(TPasSection) then
  1440. begin
  1441. // interface/program/library var
  1442. RaiseVarModifierNotSupported(SectionVarModifiersAllowed);
  1443. end
  1444. else
  1445. begin
  1446. {$IFDEF VerbosePas2JS}
  1447. writeln('TPas2JSResolver.FinishVariable ',GetObjName(El),' Parent=',GetObjName(El.Parent));
  1448. {$ENDIF}
  1449. RaiseNotYetImplemented(20170324151259,El);
  1450. end;
  1451. if vmExternal in El.VarModifiers then
  1452. begin
  1453. // compute constant
  1454. if El.LibraryName<>nil then
  1455. RaiseMsg(20170227094227,nPasElementNotSupported,sPasElementNotSupported,
  1456. ['library'],El.ExportName);
  1457. if El.ExportName=nil then
  1458. RaiseMsg(20170227100750,nMissingExternalName,sMissingExternalName,[],El);
  1459. ExtName:=ComputeConstString(El.ExportName,true,true);
  1460. // add external name to FExternalNames
  1461. if (El.Parent is TPasSection)
  1462. or ((El.ClassType=TPasConst) and (El.Parent is TPasProcedure)) then
  1463. AddExternalPath(ExtName,El.ExportName);
  1464. end;
  1465. end;
  1466. procedure TPas2JSResolver.FinishProcedureType(El: TPasProcedureType);
  1467. var
  1468. Proc: TPasProcedure;
  1469. pm: TProcedureModifier;
  1470. ExtName: String;
  1471. C: TClass;
  1472. AClass: TPasClassType;
  1473. ClassScope: TPas2JSClassScope;
  1474. begin
  1475. inherited FinishProcedureType(El);
  1476. if El.Parent is TPasProcedure then
  1477. begin
  1478. Proc:=TPasProcedure(El.Parent);
  1479. // calling convention
  1480. if Proc.CallingConvention<>ccDefault then
  1481. RaiseMsg(20170211214731,nPasElementNotSupported,sPasElementNotSupported,
  1482. [cCallingConventions[Proc.CallingConvention]],Proc);
  1483. for pm in TProcedureModifiers do
  1484. if (pm in Proc.Modifiers)
  1485. and (not (pm in [pmVirtual, pmAbstract, pmOverride,
  1486. pmOverload, pmReintroduce,
  1487. pmAssembler, pmVarargs, pmPublic,
  1488. pmExternal, pmForward])) then
  1489. RaiseNotYetImplemented(20170208142159,El,'modifier '+ModifierNames[pm]);
  1490. // check pmPublic
  1491. if [pmPublic,pmExternal]<=Proc.Modifiers then
  1492. RaiseMsg(20170324150149,nInvalidXModifierY,
  1493. sInvalidXModifierY,[Proc.ElementTypeName,'public, external'],Proc);
  1494. if (Proc.PublicName<>nil) then
  1495. RaiseMsg(20170324150417,nPasElementNotSupported,sPasElementNotSupported,
  1496. ['public name'],Proc.PublicName);
  1497. if (Proc.Parent.ClassType=TPasClassType) then
  1498. begin
  1499. // class member
  1500. AClass:=TPasClassType(Proc.Parent);
  1501. ClassScope:=AClass.CustomData as TPas2JSClassScope;
  1502. if AClass.IsExternal then
  1503. begin
  1504. // external class -> make method external
  1505. if not (pmExternal in Proc.Modifiers) then
  1506. begin
  1507. if Proc.LibrarySymbolName<>nil then
  1508. RaiseMsg(20170322142158,nInvalidXModifierY,
  1509. sInvalidXModifierY,[Proc.ElementTypeName,'symbol name'],Proc.LibrarySymbolName);
  1510. Proc.Modifiers:=Proc.Modifiers+[pmExternal];
  1511. Proc.LibrarySymbolName:=TPrimitiveExpr.Create(El,pekString,''''+Proc.Name+'''');
  1512. end;
  1513. C:=Proc.ClassType;
  1514. if (C=TPasProcedure) or (C=TPasFunction)
  1515. or (C=TPasClassProcedure) or (C=TPasClassFunction) then
  1516. // ok
  1517. else if C=TPasConstructor then
  1518. begin
  1519. if Proc.IsVirtual then
  1520. // constructor of external class can't be overriden -> forbid virtual
  1521. RaiseMsg(20170323100447,nInvalidXModifierY,sInvalidXModifierY,
  1522. [Proc.ElementTypeName,'virtual,external'],Proc);
  1523. if CompareText(Proc.Name,'new')=0 then
  1524. begin
  1525. ExtName:=ComputeConstString(Proc.LibrarySymbolName,true,true);
  1526. if ExtName<>Proc.Name then
  1527. RaiseMsg(20170323083511,nVirtualMethodNameMustMatchExternal,
  1528. sVirtualMethodNameMustMatchExternal,[],Proc.LibrarySymbolName);
  1529. end
  1530. else if El.Args.Count>0 then
  1531. RaiseMsg(20170322164357,nNoArgumentsAllowedForExternalObjectConstructor,
  1532. sNoArgumentsAllowedForExternalObjectConstructor,[],TPasArgument(El.Args[0]));
  1533. if pmVirtual in Proc.Modifiers then
  1534. RaiseMsg(20170322183141,nInvalidXModifierY,sInvalidXModifierY,
  1535. [Proc.ElementTypeName,'virtual'],Proc.ProcType);
  1536. end
  1537. else
  1538. RaiseMsg(20170322163210,nPasElementNotSupported,sPasElementNotSupported,
  1539. [Proc.ElementTypeName],Proc);
  1540. end
  1541. else
  1542. begin
  1543. // Pascal class
  1544. if (ClassScope.NewInstanceFunction=nil)
  1545. and (ClassScope.AncestorScope<>nil)
  1546. and (TPasClassType(ClassScope.AncestorScope.Element).IsExternal)
  1547. and (Proc.ClassType=TPasClassFunction)
  1548. and (Proc.Visibility in [visProtected,visPublic,visPublished])
  1549. and (TPasClassFunction(Proc).FuncType.ResultEl.ResultType=AClass)
  1550. and ([pmOverride,pmExternal]*Proc.Modifiers=[]) then
  1551. begin
  1552. // The first non private class function in a Pascal class descending
  1553. // from an external class
  1554. // -> this is the NewInstance function
  1555. ClassScope.NewInstanceFunction:=TPasClassFunction(Proc);
  1556. CheckNewInstanceFunction(ClassScope);
  1557. end;
  1558. end;
  1559. end;
  1560. if pmExternal in Proc.Modifiers then
  1561. begin
  1562. // external proc
  1563. // external override -> unneeded information, probably a bug
  1564. if Proc.IsOverride then
  1565. RaiseMsg(20170321101715,nInvalidXModifierY,sInvalidXModifierY,
  1566. [Proc.ElementTypeName,'override,external'],Proc);
  1567. if Proc.LibraryExpr<>nil then
  1568. RaiseMsg(20170211220712,nPasElementNotSupported,sPasElementNotSupported,
  1569. ['library'],Proc.LibraryExpr);
  1570. if Proc.LibrarySymbolName=nil then
  1571. RaiseMsg(20170227095454,nMissingExternalName,sMissingExternalName,
  1572. ['missing external name'],Proc);
  1573. for pm in [pmAssembler,pmForward,pmNoReturn,pmInline] do
  1574. if pm in Proc.Modifiers then
  1575. RaiseMsg(20170323100842,nInvalidXModifierY,sInvalidXModifierY,
  1576. [Proc.ElementTypeName,ModifierNames[pm]],Proc);
  1577. // compute external name
  1578. ExtName:=ComputeConstString(Proc.LibrarySymbolName,true,true);
  1579. // a virtual must have the external name, so that override works
  1580. if Proc.IsVirtual and (Proc.Name<>ExtName) then
  1581. RaiseMsg(20170321090049,nVirtualMethodNameMustMatchExternal,
  1582. sVirtualMethodNameMustMatchExternal,[],Proc.LibrarySymbolName);
  1583. if Proc.Parent is TPasSection then
  1584. AddExternalPath(ExtName,Proc.LibrarySymbolName);
  1585. exit;
  1586. end;
  1587. end;
  1588. end;
  1589. procedure TPas2JSResolver.FinishPropertyOfClass(PropEl: TPasProperty);
  1590. var
  1591. Getter, Setter: TPasElement;
  1592. GetterIsBracketAccessor, SetterIsBracketAccessor: Boolean;
  1593. Arg: TPasArgument;
  1594. ArgResolved: TPasResolverResult;
  1595. begin
  1596. inherited FinishPropertyOfClass(PropEl);
  1597. Getter:=GetPasPropertyGetter(PropEl);
  1598. GetterIsBracketAccessor:=IsExternalBracketAccessor(Getter);
  1599. Setter:=GetPasPropertySetter(PropEl);
  1600. SetterIsBracketAccessor:=IsExternalBracketAccessor(Setter);
  1601. if GetterIsBracketAccessor then
  1602. begin
  1603. if PropEl.Args.Count<>1 then
  1604. RaiseMsg(20170403001743,nBracketAccessorOfExternalClassMustHaveOneParameter,
  1605. sBracketAccessorOfExternalClassMustHaveOneParameter,
  1606. [],PropEl);
  1607. end;
  1608. if SetterIsBracketAccessor then
  1609. begin
  1610. if PropEl.Args.Count<>1 then
  1611. RaiseMsg(20170403001806,nBracketAccessorOfExternalClassMustHaveOneParameter,
  1612. sBracketAccessorOfExternalClassMustHaveOneParameter,
  1613. [],PropEl);
  1614. end;
  1615. if GetterIsBracketAccessor or SetterIsBracketAccessor then
  1616. begin
  1617. Arg:=TPasArgument(PropEl.Args[0]);
  1618. if not (Arg.Access in [argDefault,argConst]) then
  1619. RaiseMsg(20170403090225,nXExpectedButYFound,sXExpectedButYFound,
  1620. ['default or "const"',AccessNames[Arg.Access]],PropEl);
  1621. ComputeElement(Arg,ArgResolved,[rcType],Arg);
  1622. if not (ArgResolved.BaseType in (btAllInteger+btAllStringAndChars+btAllBooleans+btAllFloats)) then
  1623. RaiseMsg(20170403090628,nIncompatibleTypesGotExpected,
  1624. sIncompatibleTypesGotExpected,
  1625. [GetResolverResultDescription(ArgResolved,true),'string'],Arg);
  1626. end;
  1627. end;
  1628. procedure TPas2JSResolver.CheckNewInstanceFunction(ClassScope: TPas2JSClassScope
  1629. );
  1630. var
  1631. Proc: TPasClassFunction;
  1632. Args: TFPList;
  1633. Arg: TPasArgument;
  1634. ResolvedArg: TPasResolverResult;
  1635. begin
  1636. Proc:=ClassScope.NewInstanceFunction;
  1637. // proc modifiers override and external were already checked
  1638. // visibility was already checked
  1639. // function result type was already checked
  1640. if not Proc.IsVirtual then
  1641. RaiseMsg(20170324231040,nNewInstanceFunctionMustBeVirtual,
  1642. sNewInstanceFunctionMustBeVirtual,[],Proc);
  1643. Args:=Proc.ProcType.Args;
  1644. if Args.Count<2 then
  1645. RaiseMsg(20170324232247,nNewInstanceFunctionMustHaveTwoParameters,
  1646. sNewInstanceFunctionMustHaveTwoParameters,[],Proc.ProcType);
  1647. // first param must be a string
  1648. Arg:=TPasArgument(Args[0]);
  1649. if Arg.Access<>argDefault then
  1650. RaiseMsg(20170324232655,nIncompatibleTypeArgNo,sIncompatibleTypeArgNo,
  1651. ['1',AccessNames[Arg.Access],'default (none)'],Arg);
  1652. if Arg.ArgType=nil then
  1653. RaiseMsg(20170324233201,nIncompatibleTypeArgNo,sIncompatibleTypeArgNo,
  1654. ['1','untyped','String'],Arg);
  1655. ComputeElement(Arg.ArgType,ResolvedArg,[rcType]);
  1656. if ResolvedArg.BaseType<>btString then
  1657. RaiseMsg(20170324233348,nIncompatibleTypeArgNo,sIncompatibleTypeArgNo,
  1658. ['1',GetResolverResultDescription(ResolvedArg),'String'],Arg);
  1659. // second param must be const untyped
  1660. Arg:=TPasArgument(Args[1]);
  1661. if Arg.Access<>argConst then
  1662. RaiseMsg(20170324233457,nIncompatibleTypeArgNo,sIncompatibleTypeArgNo,
  1663. ['2',AccessNames[Arg.Access],'const'],Arg);
  1664. if Arg.ArgType<>nil then
  1665. RaiseMsg(20170324233508,nIncompatibleTypeArgNo,sIncompatibleTypeArgNo,
  1666. ['2','type','untyped'],Arg);
  1667. end;
  1668. function TPas2JSResolver.AddExternalName(const aName: string; El: TPasElement
  1669. ): TPasIdentifier;
  1670. var
  1671. Item: TPasIdentifier;
  1672. begin
  1673. //writeln('TPas2JSResolver.AddExternalIdentifier Name="',aName,'" El=',GetObjName(El));
  1674. Item:=TPasIdentifier.Create;
  1675. Item.Identifier:=aName;
  1676. Item.Element:=El;
  1677. InternalAdd(Item);
  1678. //writeln('TPas2JSResolver.AddExternalIdentifier END');
  1679. Result:=Item;
  1680. end;
  1681. function TPas2JSResolver.FindExternalName(const aName: String
  1682. ): TPasIdentifier;
  1683. begin
  1684. Result:=TPasIdentifier(FExternalNames.Find(aName));
  1685. {$IFDEF VerbosePasResolver}
  1686. if (Result<>nil) and (Result.Owner<>Self) then
  1687. begin
  1688. writeln('TPas2JSResolver.FindExternalName Result.Owner<>Self Owner='+GetObjName(Result.Owner));
  1689. raise Exception.Create('20170322235814');
  1690. end;
  1691. {$ENDIF}
  1692. end;
  1693. procedure TPas2JSResolver.AddExternalPath(aName: string; El: TPasElement);
  1694. // add aName and the first identifier of aName
  1695. var
  1696. p: PChar;
  1697. l: integer;
  1698. begin
  1699. aName:=Trim(aName);
  1700. if aName='' then exit;
  1701. AddExternalName(aName,El);
  1702. p:=PChar(aName);
  1703. while p^ in ['a'..'z','A'..'Z','0'..'9','_','$'] do inc(p);
  1704. l:=p-PChar(aName);
  1705. if l=length(aName) then exit;
  1706. AddExternalName(LeftStr(aName,l),El);
  1707. end;
  1708. procedure TPas2JSResolver.ClearElementData;
  1709. var
  1710. Data, Next: TPas2JsElementData;
  1711. begin
  1712. Data:=FFirstElementData;
  1713. while Data<>nil do
  1714. begin
  1715. Next:=Data.Next;
  1716. Data.Free;
  1717. Data:=Next;
  1718. end;
  1719. FFirstElementData:=nil;
  1720. FLastElementData:=nil;
  1721. FExternalNames.ForEachCall(@OnClearHashItem,nil);
  1722. FExternalNames.Clear;
  1723. end;
  1724. function TPas2JSResolver.AddJSBaseType(const aName: string; Typ: TPas2jsBaseType
  1725. ): TResElDataPas2JSBaseType;
  1726. var
  1727. El: TPasUnresolvedSymbolRef;
  1728. begin
  1729. El:=AddCustomBaseType(aName,TResElDataPas2JSBaseType);
  1730. if Typ<>pbtNone then
  1731. FJSBaseTypes[Typ]:=El;
  1732. Result:=TResElDataPas2JSBaseType(El.CustomData);
  1733. Result.JSBaseType:=Typ;
  1734. end;
  1735. function TPas2JSResolver.IsJSBaseType(TypeEl: TPasType; Typ: TPas2jsBaseType
  1736. ): boolean;
  1737. begin
  1738. Result:=(TypeEl is TPasUnresolvedSymbolRef)
  1739. and (CompareText(TypeEl.Name,Pas2jsBaseTypeNames[Typ])=0)
  1740. and (TypeEl.CustomData is TResElDataPas2JSBaseType);
  1741. end;
  1742. function TPas2JSResolver.IsJSBaseType(const TypeResolved: TPasResolverResult;
  1743. Typ: TPas2jsBaseType; HasValue: boolean): boolean;
  1744. begin
  1745. if (TypeResolved.BaseType<>btCustom) or not IsJSBaseType(TypeResolved.TypeEl,Typ) then
  1746. exit(false);
  1747. if HasValue and not (rrfReadable in TypeResolved.Flags) then
  1748. exit(false);
  1749. Result:=true;
  1750. end;
  1751. function TPas2JSResolver.CheckAssignCompatibilityCustom(const LHS,
  1752. RHS: TPasResolverResult; ErrorEl: TPasElement; RaiseOnIncompatible: boolean;
  1753. var Handled: boolean): integer;
  1754. var
  1755. LeftBaseType: TPas2jsBaseType;
  1756. LArray: TPasArrayType;
  1757. ElTypeResolved: TPasResolverResult;
  1758. begin
  1759. Result:=cIncompatible;
  1760. if LHS.BaseType=btCustom then
  1761. begin
  1762. if not (LHS.TypeEl is TPasUnresolvedSymbolRef) then
  1763. begin
  1764. {$IFDEF VerbosePas2JS}
  1765. writeln('TPas2JSResolver.CheckAssignCompatibilityCustomBaseType LHS=',GetResolverResultDesc(LHS));
  1766. {$ENDIF}
  1767. RaiseInternalError(20170325114554);
  1768. end;
  1769. if not (LHS.TypeEl.CustomData is TResElDataPas2JSBaseType) then
  1770. exit;
  1771. Handled:=true;
  1772. LeftBaseType:=TResElDataPas2JSBaseType(LHS.TypeEl.CustomData).JSBaseType;
  1773. if LeftBaseType=pbtJSValue then
  1774. begin
  1775. // assign to a JSValue
  1776. if rrfReadable in RHS.Flags then
  1777. begin
  1778. // RHS is a value
  1779. if (RHS.BaseType in btAllJSValueSrcTypes) then
  1780. Result:=cExact+1 // type cast to JSValue
  1781. else if RHS.BaseType=btCustom then
  1782. begin
  1783. if IsJSBaseType(RHS,pbtJSValue) then
  1784. Result:=cExact;
  1785. end
  1786. else if RHS.BaseType=btContext then
  1787. Result:=cExact+1;
  1788. end
  1789. else if RHS.BaseType=btContext then
  1790. begin
  1791. // RHS is not a value
  1792. if RHS.IdentEl<>nil then
  1793. begin
  1794. if RHS.IdentEl.ClassType=TPasClassType then
  1795. Result:=cExact+1; // RHS is a class
  1796. end;
  1797. end;
  1798. end;
  1799. end
  1800. else if (LHS.BaseType=btContext) and (LHS.TypeEl.ClassType=TPasArrayType)
  1801. and (rrfReadable in RHS.Flags) then
  1802. begin
  1803. LArray:=TPasArrayType(LHS.TypeEl);
  1804. if length(LArray.Ranges)>0 then
  1805. exit;
  1806. if (RHS.BaseType<>btContext) or (RHS.TypeEl.ClassType<>TPasArrayType) then
  1807. exit;
  1808. ComputeElement(LArray.ElType,ElTypeResolved,[rcType]);
  1809. if IsJSBaseType(ElTypeResolved,pbtJSValue) then
  1810. begin
  1811. // array of jsvalue := array
  1812. Handled:=true;
  1813. Result:=cExact+1;
  1814. end;
  1815. end;
  1816. if RaiseOnIncompatible then ;
  1817. if ErrorEl=nil then ;
  1818. end;
  1819. function TPas2JSResolver.CheckTypeCastClassInstanceToClass(const FromClassRes,
  1820. ToClassRes: TPasResolverResult; ErrorEl: TPasElement): integer;
  1821. var
  1822. ToClass: TPasClassType;
  1823. ClassScope: TPasClassScope;
  1824. begin
  1825. if FromClassRes.BaseType=btNil then exit(cExact);
  1826. ToClass:=(ToClassRes.TypeEl as TPasClassType);
  1827. ClassScope:=ToClass.CustomData as TPasClassScope;
  1828. if ClassScope.AncestorScope=nil then
  1829. // type cast to root class
  1830. Result:=cExact+1
  1831. else
  1832. Result:=cIncompatible;
  1833. if ErrorEl=nil then ;
  1834. end;
  1835. function TPas2JSResolver.CheckEqualCompatibilityCustomType(const LHS,
  1836. RHS: TPasResolverResult; ErrorEl: TPasElement; RaiseOnIncompatible: boolean
  1837. ): integer;
  1838. var
  1839. LeftBaseType: TPas2jsBaseType;
  1840. begin
  1841. Result:=cIncompatible;
  1842. if LHS.BaseType=btCustom then
  1843. begin
  1844. if not (LHS.TypeEl is TPasUnresolvedSymbolRef) then
  1845. begin
  1846. {$IFDEF VerbosePas2JS}
  1847. writeln('TPas2JSResolver.CheckEqualCompatibilityCustomType LHS=',GetResolverResultDesc(LHS));
  1848. {$ENDIF}
  1849. RaiseInternalError(20170330005841);
  1850. end;
  1851. if not (LHS.TypeEl.CustomData is TResElDataPas2JSBaseType) then
  1852. exit;
  1853. LeftBaseType:=TResElDataPas2JSBaseType(LHS.TypeEl.CustomData).JSBaseType;
  1854. if LeftBaseType=pbtJSValue then
  1855. begin
  1856. if (rrfReadable in LHS.Flags) then
  1857. begin
  1858. if (rrfReadable in RHS.Flags) then
  1859. begin
  1860. if RHS.BaseType in btAllJSValueSrcTypes then
  1861. Result:=cExact
  1862. else if RHS.BaseType=btCustom then
  1863. begin
  1864. if IsJSBaseType(RHS,pbtJSValue) then
  1865. Result:=cExact;
  1866. end
  1867. else if RHS.BaseType=btContext then
  1868. Result:=cExact+1;
  1869. end
  1870. else if RHS.BaseType=btContext then
  1871. begin
  1872. // right side is not a value
  1873. if RHS.IdentEl<>nil then
  1874. begin
  1875. if RHS.IdentEl.ClassType=TPasClassType then
  1876. Result:=cExact+1; // RHS is a class
  1877. end;
  1878. end;
  1879. end;
  1880. end;
  1881. end
  1882. else if RHS.BaseType=btCustom then
  1883. exit(CheckEqualCompatibilityCustomType(RHS,LHS,ErrorEl,RaiseOnIncompatible))
  1884. else
  1885. RaiseInternalError(20170330005725);
  1886. end;
  1887. function TPas2JSResolver.ResolveBracketOperatorClass(Params: TParamsExpr;
  1888. const ResolvedValue: TPasResolverResult; ClassScope: TPasClassScope;
  1889. Access: TResolvedRefAccess): boolean;
  1890. var
  1891. ParamResolved: TPasResolverResult;
  1892. Param: TPasExpr;
  1893. aClass: TPasClassType;
  1894. begin
  1895. if ClassScope.DefaultProperty=nil then
  1896. begin
  1897. aClass:=TPasClassType(ClassScope.Element);
  1898. if IsExternalClassName(aClass,'Array') then
  1899. begin
  1900. if ResolvedValue.IdentEl is TPasType then
  1901. RaiseMsg(20170402194000,nIllegalQualifier,sIllegalQualifier,['['],Params);
  1902. if length(Params.Params)<>1 then
  1903. RaiseMsg(20170402194059,nWrongNumberOfParametersForArray,
  1904. sWrongNumberOfParametersForArray,[],Params);
  1905. // check first param is an integer value
  1906. Param:=Params.Params[0];
  1907. ComputeElement(Param,ParamResolved,[]);
  1908. if (not (rrfReadable in ParamResolved.Flags))
  1909. or not (ParamResolved.BaseType in btAllInteger) then
  1910. CheckRaiseTypeArgNo(20170402194221,1,Param,ParamResolved,'integer',true);
  1911. AccessExpr(Param,rraRead);
  1912. exit(true);
  1913. end
  1914. else if IsExternalClassName(aClass,'Object') then
  1915. begin
  1916. if ResolvedValue.IdentEl is TPasType then
  1917. RaiseMsg(20170402194453,nIllegalQualifier,sIllegalQualifier,['['],Params);
  1918. if length(Params.Params)<>1 then
  1919. RaiseMsg(20170402194456,nWrongNumberOfParametersForArray,
  1920. sWrongNumberOfParametersForArray,[],Params);
  1921. // check first param is a string value
  1922. Param:=Params.Params[0];
  1923. ComputeElement(Param,ParamResolved,[]);
  1924. if (not (rrfReadable in ParamResolved.Flags))
  1925. or not (ParamResolved.BaseType in btAllStringAndChars) then
  1926. CheckRaiseTypeArgNo(20170402194511,1,Param,ParamResolved,'string',true);
  1927. AccessExpr(Param,rraRead);
  1928. exit(true);
  1929. end;
  1930. end;
  1931. Result:=inherited ResolveBracketOperatorClass(Params, ResolvedValue, ClassScope, Access);
  1932. end;
  1933. procedure TPas2JSResolver.ComputeArrayParams_Class(Params: TParamsExpr;
  1934. var ResolvedEl: TPasResolverResult; ClassScope: TPasClassScope;
  1935. Flags: TPasResolverComputeFlags; StartEl: TPasElement);
  1936. var
  1937. aClass: TPasClassType;
  1938. OrigResolved: TPasResolverResult;
  1939. begin
  1940. aClass:=TPasClassType(ClassScope.Element);
  1941. if IsExternalClassName(aClass,'Array') or IsExternalClassName(aClass,'Object') then
  1942. begin
  1943. if [rcConstant,rcType]*Flags<>[] then
  1944. RaiseConstantExprExp(20170402202137,Params);
  1945. OrigResolved:=ResolvedEl;
  1946. SetResolverTypeExpr(ResolvedEl,btCustom,JSBaseTypes[pbtJSValue],[rrfReadable,rrfWritable]);
  1947. // identifier and value is the array/object itself
  1948. ResolvedEl.IdentEl:=OrigResolved.IdentEl;
  1949. ResolvedEl.ExprEl:=OrigResolved.ExprEl;
  1950. ResolvedEl.Flags:=OrigResolved.Flags+[rrfReadable,rrfWritable];
  1951. exit;
  1952. end;
  1953. inherited ComputeArrayParams_Class(Params, ResolvedEl, ClassScope, Flags,
  1954. StartEl);
  1955. end;
  1956. constructor TPas2JSResolver.Create;
  1957. var
  1958. bt: TPas2jsBaseType;
  1959. begin
  1960. inherited;
  1961. FExternalNames:=TFPHashList.Create;
  1962. StoreSrcColumns:=true;
  1963. Options:=Options+DefaultPasResolverOptions;
  1964. ScopeClass_Class:=TPas2JSClassScope;
  1965. ScopeClass_WithExpr:=TPas2JSWithExprScope;
  1966. for bt in [pbtJSValue] do
  1967. AddJSBaseType(Pas2jsBaseTypeNames[bt],bt);
  1968. end;
  1969. destructor TPas2JSResolver.Destroy;
  1970. begin
  1971. ClearElementData;
  1972. FreeAndNil(FExternalNames);
  1973. inherited Destroy;
  1974. end;
  1975. procedure TPas2JSResolver.AddObjFPCBuiltInIdentifiers(
  1976. const TheBaseTypes: TResolveBaseTypes;
  1977. const TheBaseProcs: TResolverBuiltInProcs);
  1978. begin
  1979. inherited AddObjFPCBuiltInIdentifiers(
  1980. TheBaseTypes
  1981. -btAllStrings+[btString] // allow only String
  1982. -btAllFloats+[btDouble] // allow only Double
  1983. ,TheBaseProcs);
  1984. end;
  1985. function TPas2JSResolver.CheckTypeCastRes(const FromResolved,
  1986. ToResolved: TPasResolverResult; ErrorEl: TPasElement; RaiseOnError: boolean
  1987. ): integer;
  1988. var
  1989. JSBaseType: TPas2jsBaseType;
  1990. C: TClass;
  1991. ToClass: TPasClassType;
  1992. begin
  1993. Result:=cIncompatible;
  1994. {$IFDEF VerbosePas2JS}
  1995. writeln('TPas2JSResolver.CheckTypeCastCustomBaseType To=',GetResolverResultDesc(ToResolved),' From=',GetResolverResultDesc(FromResolved));
  1996. {$ENDIF}
  1997. if rrfReadable in FromResolved.Flags then
  1998. begin
  1999. if (ToResolved.BaseType=btCustom) then
  2000. begin
  2001. if not (ToResolved.TypeEl is TPasUnresolvedSymbolRef) then
  2002. RaiseInternalError(20170325142826);
  2003. if (ToResolved.TypeEl.CustomData is TResElDataPas2JSBaseType) then
  2004. begin
  2005. // type cast to pas2js type, e.g. JSValue(V)
  2006. JSBaseType:=TResElDataPas2JSBaseType(ToResolved.TypeEl.CustomData).JSBaseType;
  2007. if JSBaseType=pbtJSValue then
  2008. begin
  2009. if rrfReadable in FromResolved.Flags then
  2010. begin
  2011. if (FromResolved.BaseType in btAllJSValueSrcTypes) then
  2012. Result:=cExact+1 // type cast to JSValue
  2013. else if FromResolved.BaseType=btCustom then
  2014. begin
  2015. if IsJSBaseType(FromResolved,pbtJSValue) then
  2016. Result:=cExact;
  2017. end
  2018. else if FromResolved.BaseType=btContext then
  2019. Result:=cExact+1;
  2020. end;
  2021. end;
  2022. exit;
  2023. end;
  2024. end
  2025. else if FromResolved.BaseType=btCustom then
  2026. begin
  2027. if not (FromResolved.TypeEl is TPasUnresolvedSymbolRef) then
  2028. RaiseInternalError(20170325143016);
  2029. if (FromResolved.TypeEl.CustomData is TResElDataPas2JSBaseType) then
  2030. begin
  2031. // type cast a pas2js value, e.g. T(jsvalue)
  2032. if not (rrfReadable in FromResolved.Flags) then
  2033. exit;
  2034. JSBaseType:=TResElDataPas2JSBaseType(FromResolved.TypeEl.CustomData).JSBaseType;
  2035. if JSBaseType=pbtJSValue then
  2036. begin
  2037. if (ToResolved.BaseType in btAllJSValueTypeCastTo) then
  2038. Result:=cExact+1 // type cast JSValue to simple base type
  2039. else if ToResolved.BaseType=btContext then
  2040. begin
  2041. C:=ToResolved.TypeEl.ClassType;
  2042. if (C=TPasClassType)
  2043. or (C=TPasClassOfType)
  2044. or (C=TPasEnumType) then
  2045. Result:=cExact+1;
  2046. end;
  2047. end;
  2048. exit;
  2049. end;
  2050. end
  2051. else if ToResolved.BaseType=btContext then
  2052. begin
  2053. C:=ToResolved.TypeEl.ClassType;
  2054. if C=TPasClassType then
  2055. begin
  2056. ToClass:=TPasClassType(ToResolved.TypeEl);
  2057. if ToClass.IsExternal then
  2058. begin
  2059. if IsExternalClassName(ToClass,'String')
  2060. and (FromResolved.BaseType in btAllStringAndChars) then
  2061. exit(cExact);
  2062. if IsExternalClassName(ToClass,'Array')
  2063. and ((FromResolved.BaseType=btArray)
  2064. or (FromResolved.BaseType=btContext)) then
  2065. exit(cExact);
  2066. end;
  2067. end
  2068. else if C=TPasArrayType then
  2069. begin
  2070. if (FromResolved.BaseType=btContext)
  2071. and (FromResolved.TypeEl.ClassType=TPasClassType)
  2072. and TPasClassType(FromResolved.TypeEl).IsExternal
  2073. and IsExternalClassName(TPasClassType(FromResolved.TypeEl),'Array') then
  2074. begin
  2075. // type cast external Array to an array
  2076. exit(cExact+1);
  2077. end;
  2078. end;
  2079. end;
  2080. end;
  2081. Result:=inherited CheckTypeCastRes(FromResolved,ToResolved,ErrorEl,RaiseOnError);
  2082. end;
  2083. function TPas2JSResolver.ExtractPasStringLiteral(El: TPasElement;
  2084. const S: String): TJSString;
  2085. { Extracts the value from a Pascal string literal
  2086. S is a Pascal string literal e.g. 'Line'#10
  2087. '' empty string
  2088. '''' => "'"
  2089. #decimal
  2090. #$hex
  2091. ^l l is a letter a-z
  2092. }
  2093. var
  2094. p, StartP: PChar;
  2095. c: Char;
  2096. i: Integer;
  2097. begin
  2098. Result:='';
  2099. {$IFDEF VerbosePas2JS}
  2100. writeln('TPasToJSConverter.ExtractPasStringLiteral "',S,'"');
  2101. {$ENDIF}
  2102. if S='' then
  2103. RaiseInternalError(20170207154543);
  2104. p:=PChar(S);
  2105. repeat
  2106. case p^ of
  2107. #0: break;
  2108. '''':
  2109. begin
  2110. inc(p);
  2111. StartP:=p;
  2112. repeat
  2113. c:=p^;
  2114. case c of
  2115. #0:
  2116. RaiseInternalError(20170207155120);
  2117. '''':
  2118. begin
  2119. if p>StartP then
  2120. Result:=Result+TJSString(copy(S,StartP-PChar(S)+1,p-StartP));
  2121. inc(p);
  2122. StartP:=p;
  2123. if p^<>'''' then
  2124. break;
  2125. Result:=Result+'''';
  2126. inc(p);
  2127. StartP:=p;
  2128. end;
  2129. else
  2130. inc(p);
  2131. end;
  2132. until false;
  2133. if p>StartP then
  2134. Result:=Result+TJSString(copy(S,StartP-PChar(S)+1,p-StartP));
  2135. end;
  2136. '#':
  2137. begin
  2138. inc(p);
  2139. if p^='$' then
  2140. begin
  2141. // #$hexnumber
  2142. inc(p);
  2143. StartP:=p;
  2144. i:=0;
  2145. repeat
  2146. c:=p^;
  2147. case c of
  2148. #0: break;
  2149. '0'..'9': i:=i*16+ord(c)-ord('0');
  2150. 'a'..'f': i:=i*16+ord(c)-ord('a')+10;
  2151. 'A'..'F': i:=i*16+ord(c)-ord('A')+10;
  2152. else break;
  2153. end;
  2154. if i>$10ffff then
  2155. RaiseNotYetImplemented(20170207164657,El,'maximum codepoint is $10ffff');
  2156. inc(p);
  2157. until false;
  2158. if p=StartP then
  2159. RaiseInternalError(20170207164956);
  2160. Result:=Result+CodePointToJSString(i);
  2161. end
  2162. else
  2163. begin
  2164. // #decimalnumber
  2165. StartP:=p;
  2166. i:=0;
  2167. repeat
  2168. c:=p^;
  2169. case c of
  2170. #0: break;
  2171. '0'..'9': i:=i*10+ord(c)-ord('0');
  2172. else break;
  2173. end;
  2174. if i>$10ffff then
  2175. RaiseNotYetImplemented(20170207171140,El,'maximum codepoint is $10ffff');
  2176. inc(p);
  2177. until false;
  2178. if p=StartP then
  2179. RaiseInternalError(20170207171148);
  2180. Result:=Result+CodePointToJSString(i);
  2181. end;
  2182. end;
  2183. '^':
  2184. begin
  2185. // ^A is #1
  2186. inc(p);
  2187. c:=p^;
  2188. case c of
  2189. 'a'..'z': Result:=Result+TJSChar(ord(c)-ord('a')+1);
  2190. 'A'..'Z': Result:=Result+TJSChar(ord(c)-ord('A')+1);
  2191. else RaiseInternalError(20170207160412);
  2192. end;
  2193. inc(p);
  2194. end;
  2195. else
  2196. RaiseNotYetImplemented(20170207154653,El,'ord='+IntToStr(ord(p^)));
  2197. end;
  2198. until false;
  2199. {$IFDEF VerbosePas2JS}
  2200. writeln('TPasToJSConverter.ExtractPasStringLiteral Result="',Result,'"');
  2201. {$ENDIF}
  2202. end;
  2203. function TPas2JSResolver.ComputeConst(Expr: TPasExpr; StoreCustomData: boolean
  2204. ): TJSValue;
  2205. var
  2206. Prim: TPrimitiveExpr;
  2207. V: TJSValue;
  2208. ConstData: TP2JConstExprData;
  2209. begin
  2210. Result:=nil;
  2211. if Expr=nil then
  2212. RaiseInternalError(20170215123600);
  2213. if StoreCustomData and (Expr.CustomData is TPasElementBase) then
  2214. begin
  2215. ConstData:=TP2JConstExprData(GetElementData(
  2216. TPasElementBase(Expr.CustomData),TP2JConstExprData));
  2217. if ConstData<>nil then
  2218. begin
  2219. // use stored result
  2220. Result:=ConstData.Value;
  2221. exit;
  2222. end;
  2223. end;
  2224. V:=nil;
  2225. try
  2226. if Expr.ClassType=TPrimitiveExpr then
  2227. begin
  2228. Prim:=TPrimitiveExpr(Expr);
  2229. if Prim.Kind=pekString then
  2230. V:=TJSValue.Create(ExtractPasStringLiteral(Prim,Prim.Value))
  2231. else
  2232. RaiseNotYetImplemented(20170215124733,Prim);
  2233. end
  2234. else
  2235. RaiseNotYetImplemented(20170215124746,Expr);
  2236. Result:=V;
  2237. if StoreCustomData then
  2238. begin
  2239. // store result
  2240. ConstData:=TP2JConstExprData(CreateElementData(TP2JConstExprData,Expr));
  2241. ConstData.Value:=V;
  2242. end;
  2243. finally
  2244. if Result=nil then
  2245. V.Free;
  2246. end;
  2247. end;
  2248. function TPas2JSResolver.ComputeConstString(Expr: TPasExpr; StoreCustomData,
  2249. NotEmpty: boolean): String;
  2250. var
  2251. V: TJSValue;
  2252. begin
  2253. V:=ComputeConst(Expr,StoreCustomData);
  2254. if V.ValueType<>jsbase.jstString then
  2255. RaiseNotYetImplemented(20170320220728,Expr,'expected string constant');
  2256. if V.ValueType<>jstString then
  2257. RaiseMsg(20170211221121,nExpectedXButFoundY,sExpectedXButFoundY,['string literal',JSTypeCaptions[V.ValueType]],Expr);
  2258. if NotEmpty and (V.AsString='') then
  2259. RaiseMsg(20170321085318,nExpectedXButFoundY,sExpectedXButFoundY,['string literal','empty'],Expr);
  2260. Result:=String(V.AsString);
  2261. end;
  2262. function TPas2JSResolver.IsExternalBracketAccessor(El: TPasElement): boolean;
  2263. var
  2264. ExtName: String;
  2265. begin
  2266. if (not (El is TPasProcedure)) or (TPasProcedure(El).LibrarySymbolName=nil) then
  2267. exit(false);
  2268. ExtName:=ComputeConstString(TPasProcedure(El).LibrarySymbolName,false,false);
  2269. Result:=ExtName=ExtClassBracketAccessor;
  2270. end;
  2271. function TPas2JSResolver.GetElementData(El: TPasElementBase;
  2272. DataClass: TPas2JsElementDataClass): TPas2JsElementData;
  2273. begin
  2274. Result:=nil;
  2275. repeat
  2276. if El.InheritsFrom(DataClass) then
  2277. exit(TPas2JsElementData(El));
  2278. if El.CustomData=nil then exit;
  2279. El:=El.CustomData as TPasElementBase;
  2280. until false;
  2281. end;
  2282. procedure TPas2JSResolver.AddElementData(Data: TPas2JsElementData);
  2283. begin
  2284. Data.Owner:=Self;
  2285. if FFirstElementData<>nil then
  2286. begin
  2287. FLastElementData.Next:=Data;
  2288. FLastElementData:=Data;
  2289. end
  2290. else
  2291. begin
  2292. FFirstElementData:=Data;
  2293. FLastElementData:=Data;
  2294. end;
  2295. end;
  2296. function TPas2JSResolver.CreateElementData(DataClass: TPas2JsElementDataClass;
  2297. El: TPasElement): TPas2JsElementData;
  2298. begin
  2299. Result:=DataClass.Create;
  2300. Result.Element:=El;
  2301. AddElementData(Result);
  2302. end;
  2303. { TP2JConstExprData }
  2304. destructor TP2JConstExprData.Destroy;
  2305. begin
  2306. FreeAndNil(Value);
  2307. inherited Destroy;
  2308. end;
  2309. { TParamContext }
  2310. constructor TParamContext.Create(PasEl: TPasElement; JSEl: TJSElement;
  2311. aParent: TConvertContext);
  2312. begin
  2313. inherited Create(PasEl, JSEl, aParent);
  2314. Access:=caAssign;
  2315. AccessContext:=Self;
  2316. end;
  2317. { TPas2JsElementData }
  2318. procedure TPas2JsElementData.SetElement(const AValue: TPasElement);
  2319. var
  2320. Data: TPasElementBase;
  2321. begin
  2322. if FElement=AValue then Exit;
  2323. if FElement<>nil then
  2324. begin
  2325. Data:=FElement;
  2326. while Data.CustomData<>Self do
  2327. if Data.CustomData is TPasElementBase then
  2328. Data:=TPasElementBase(Data.CustomData)
  2329. else
  2330. begin
  2331. {$IFDEF VerbosePas2JS}
  2332. writeln('TPas2JsElementData.SetElement REMOVE ',ClassName);
  2333. writeln(' ',GetObjName(Data.CustomData));
  2334. {$ENDIF}
  2335. raise EPas2JS.Create('');
  2336. end;
  2337. Data.CustomData:=CustomData;
  2338. TPasElement(FElement).Release;
  2339. end;
  2340. FElement:=AValue;
  2341. if FElement<>nil then
  2342. begin
  2343. TPasElement(FElement).AddRef;
  2344. Data:=FElement;
  2345. while Data.CustomData is TPasElementBase do
  2346. Data:=TPasElementBase(Data.CustomData);
  2347. if Data.CustomData<>nil then
  2348. begin
  2349. {$IFDEF VerbosePas2JS}
  2350. writeln('TPas2JsElementData.SetElement INSERT ',ClassName);
  2351. writeln(' ',GetObjName(Data.CustomData));
  2352. {$ENDIF}
  2353. raise EPas2JS.Create('');
  2354. end;
  2355. Data.CustomData:=Self;
  2356. end;
  2357. end;
  2358. constructor TPas2JsElementData.Create;
  2359. begin
  2360. end;
  2361. destructor TPas2JsElementData.Destroy;
  2362. begin
  2363. Element:=nil;
  2364. Next:=nil;
  2365. Owner:=nil;
  2366. inherited Destroy;
  2367. end;
  2368. { TAssignContext }
  2369. constructor TAssignContext.Create(PasEl: TPasElement; JSEl: TJSElement;
  2370. aParent: TConvertContext);
  2371. begin
  2372. inherited Create(PasEl, JSEl, aParent);
  2373. Access:=caAssign;
  2374. AccessContext:=Self;
  2375. end;
  2376. { TDotContext }
  2377. constructor TDotContext.Create(PasEl: TPasElement; JSEl: TJSElement;
  2378. aParent: TConvertContext);
  2379. begin
  2380. inherited Create(PasEl, JSEl, aParent);
  2381. Kind:=cjkDot;
  2382. end;
  2383. { TInterfaceContext }
  2384. constructor TInterfaceContext.Create(PasEl: TPasElement; JSEl: TJSElement;
  2385. aParent: TConvertContext);
  2386. begin
  2387. inherited;
  2388. IsSingleton:=true;
  2389. end;
  2390. { TObjectContext }
  2391. constructor TObjectContext.Create(PasEl: TPasElement; JSEl: TJSElement;
  2392. aParent: TConvertContext);
  2393. begin
  2394. inherited;
  2395. Kind:=cjkObject;
  2396. end;
  2397. { TFunctionContext }
  2398. constructor TFunctionContext.Create(PasEl: TPasElement; JSEl: TJSElement;
  2399. aParent: TConvertContext);
  2400. begin
  2401. inherited;
  2402. Kind:=cjkFunction;
  2403. end;
  2404. { TRootContext }
  2405. constructor TRootContext.Create(PasEl: TPasElement; JSEl: TJSElement;
  2406. aParent: TConvertContext);
  2407. begin
  2408. inherited;
  2409. Kind:=cjkRoot;
  2410. end;
  2411. { TConvertContext }
  2412. constructor TConvertContext.Create(PasEl: TPasElement; JSEl: TJSElement;
  2413. aParent: TConvertContext);
  2414. begin
  2415. PasElement:=PasEl;
  2416. JSElement:=JsEl;
  2417. Parent:=aParent;
  2418. if Parent<>nil then
  2419. begin
  2420. Resolver:=Parent.Resolver;
  2421. Access:=aParent.Access;
  2422. AccessContext:=aParent.AccessContext;
  2423. end;
  2424. end;
  2425. function TConvertContext.GetRootModule: TPasModule;
  2426. var
  2427. aContext: TConvertContext;
  2428. begin
  2429. aContext:=Self;
  2430. while aContext.Parent<>nil do
  2431. aContext:=aContext.Parent;
  2432. if aContext.PasElement is TPasModule then
  2433. Result:=TPasModule(aContext.PasElement)
  2434. else
  2435. Result:=nil;
  2436. end;
  2437. function TConvertContext.GetThis: TPasElement;
  2438. var
  2439. ctx: TFunctionContext;
  2440. begin
  2441. ctx:=GetThisContext;
  2442. if ctx<>nil then
  2443. Result:=ctx.This
  2444. else
  2445. Result:=nil;
  2446. end;
  2447. function TConvertContext.GetThisContext: TFunctionContext;
  2448. begin
  2449. Result:=TFunctionContext(GetContextOfType(TFunctionContext));
  2450. end;
  2451. function TConvertContext.GetContextOfType(aType: TConvertContextClass
  2452. ): TConvertContext;
  2453. var
  2454. ctx: TConvertContext;
  2455. begin
  2456. Result:=nil;
  2457. ctx:=Self;
  2458. repeat
  2459. if ctx is aType then
  2460. exit(ctx);
  2461. ctx:=ctx.Parent;
  2462. until ctx=nil;
  2463. end;
  2464. function TConvertContext.CreateLocalIdentifier(const Prefix: string): string;
  2465. begin
  2466. inc(TmpVarCount);
  2467. Result:=Prefix+IntToStr(TmpVarCount);
  2468. end;
  2469. function TConvertContext.CurrentModeswitches: TModeSwitches;
  2470. begin
  2471. if Resolver=nil then
  2472. Result:=OBJFPCModeSwitches
  2473. else
  2474. Result:=Resolver.CurrentParser.CurrentModeswitches;
  2475. end;
  2476. function TConvertContext.GetSingletonFunc: TFunctionContext;
  2477. var
  2478. Ctx: TConvertContext;
  2479. begin
  2480. Ctx:=Self;
  2481. while (Ctx<>nil) do
  2482. begin
  2483. if Ctx.IsSingleton and (Ctx.JSElement<>nil) and (Ctx is TFunctionContext) then
  2484. exit(TFunctionContext(Ctx));
  2485. Ctx:=Ctx.Parent;
  2486. end;
  2487. end;
  2488. { TPasToJSConverter }
  2489. // inline
  2490. function TPasToJSConverter.GetUseEnumNumbers: boolean;
  2491. begin
  2492. Result:=coEnumNumbers in FOptions;
  2493. end;
  2494. // inline
  2495. function TPasToJSConverter.GetUseLowerCase: boolean;
  2496. begin
  2497. Result:=coLowerCase in FOptions;
  2498. end;
  2499. // inline
  2500. function TPasToJSConverter.GetUseSwitchStatement: boolean;
  2501. begin
  2502. Result:=coSwitchStatement in FOptions;
  2503. end;
  2504. procedure TPasToJSConverter.AddToSourceElements(Src: TJSSourceElements;
  2505. El: TJSElement);
  2506. Var
  2507. List : TJSStatementList;
  2508. AddEl : TJSElement;
  2509. begin
  2510. While El<>nil do
  2511. begin
  2512. if El is TJSStatementList then
  2513. begin
  2514. List:=El as TJSStatementList;
  2515. // List.A is first statement, List.B is next in list, chained.
  2516. // -> add A, continue with B and free List
  2517. AddEl:=List.A;
  2518. El:=List.B;
  2519. List.A:=Nil;
  2520. List.B:=Nil;
  2521. FreeAndNil(List);
  2522. end
  2523. else
  2524. begin
  2525. AddEl:=El;
  2526. El:=Nil;
  2527. end;
  2528. Src.Statements.AddNode.Node:=AddEl;
  2529. end;
  2530. end;
  2531. procedure TPasToJSConverter.RemoveFromSourceElements(Src: TJSSourceElements;
  2532. El: TJSElement);
  2533. var
  2534. Statements: TJSElementNodes;
  2535. i: Integer;
  2536. begin
  2537. Statements:=Src.Statements;
  2538. for i:=Statements.Count-1 downto 0 do
  2539. if Statements[i].Node=El then
  2540. Statements.Delete(i);
  2541. end;
  2542. function TPasToJSConverter.GetBuildInNames(bin: TPas2JSBuiltInName): string;
  2543. begin
  2544. Result:=FBuiltInNames[bin];
  2545. end;
  2546. procedure TPasToJSConverter.SetBuildInNames(bin: TPas2JSBuiltInName;
  2547. const AValue: string);
  2548. begin
  2549. FBuiltInNames[bin]:=AValue;
  2550. end;
  2551. procedure TPasToJSConverter.SetPreservedWords(const AValue: TJSReservedWordList
  2552. );
  2553. var
  2554. i: Integer;
  2555. begin
  2556. if FPreservedWords=AValue then Exit;
  2557. for i:=0 to length(AValue)-2 do
  2558. if CompareStr(AValue[i],AValue[i+1])>=0 then
  2559. raise Exception.Create('TPasToJSConverter.SetPreservedWords "'+AValue[i]+'" >= "'+AValue[i+1]+'"');
  2560. FPreservedWords:=AValue;
  2561. end;
  2562. function TPasToJSConverter.ConvertModule(El: TPasModule;
  2563. AContext: TConvertContext): TJSElement;
  2564. (* Format:
  2565. rtl.module('<unitname>',
  2566. [<interface uses1>,<uses2>, ...],
  2567. function(){
  2568. <interface>
  2569. <implementation>
  2570. this.$init=function(){
  2571. <initialization>
  2572. };
  2573. },
  2574. [<implementation uses1>,<uses2>, ...]);
  2575. *)
  2576. Var
  2577. OuterSrc , Src: TJSSourceElements;
  2578. RegModuleCall: TJSCallExpression;
  2579. ArgArray: TJSArguments;
  2580. UsesList: TFPList;
  2581. FunDef: TJSFuncDef;
  2582. FunBody: TJSFunctionBody;
  2583. FunDecl: TJSFunctionDeclarationStatement;
  2584. UsesSection: TPasSection;
  2585. ModuleName: String;
  2586. IntfContext: TInterfaceContext;
  2587. ImplVarSt: TJSVariableStatement;
  2588. VarDecl: TJSVarDeclaration;
  2589. ImplAssignSt: TJSSimpleAssignStatement;
  2590. ImplDecl: TJSElement;
  2591. begin
  2592. Result:=Nil;
  2593. OuterSrc:=TJSSourceElements(CreateElement(TJSSourceElements, El));
  2594. Result:=OuterSrc;
  2595. // create 'rtl.module(...)'
  2596. RegModuleCall:=CreateCallExpression(El);
  2597. AddToSourceElements(OuterSrc,RegModuleCall);
  2598. RegModuleCall.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],'module']);
  2599. ArgArray := RegModuleCall.Args;
  2600. RegModuleCall.Args:=ArgArray;
  2601. // add unitname parameter: unitname
  2602. ModuleName:=TransformModuleName(El,AContext);
  2603. ArgArray.Elements.AddElement.Expr:=CreateLiteralString(El,ModuleName);
  2604. // add interface-uses-section parameter: [<interface uses1>,<uses2>, ...]
  2605. UsesSection:=nil;
  2606. if (El is TPasProgram) then
  2607. UsesSection:=TPasProgram(El).ProgramSection
  2608. else if (El is TPasLibrary) then
  2609. UsesSection:=TPasLibrary(El).LibrarySection
  2610. else
  2611. UsesSection:=El.InterfaceSection;
  2612. ArgArray.Elements.AddElement.Expr:=CreateUsesList(UsesSection,AContext);
  2613. // add interface parameter: function(){}
  2614. FunDecl:=TJSFunctionDeclarationStatement.Create(0,0);
  2615. ArgArray.Elements.AddElement.Expr:=FunDecl;
  2616. FunDef:=TJSFuncDef.Create;
  2617. FunDecl.AFunction:=FunDef;
  2618. FunDef.Name:='';
  2619. FunBody:=TJSFunctionBody.Create(0,0);
  2620. FunDef.Body:=FunBody;
  2621. Src:=TJSSourceElements(CreateElement(TJSSourceElements, El));
  2622. FunBody.A:=Src;
  2623. if coUseStrict in Options then
  2624. AddToSourceElements(Src,CreateLiteralString(El,'use strict'));
  2625. IntfContext:=TInterfaceContext.Create(El,Src,AContext);
  2626. try
  2627. IntfContext.This:=El;
  2628. if (El is TPasProgram) then
  2629. begin // program
  2630. if Assigned(TPasProgram(El).ProgramSection) then
  2631. AddToSourceElements(Src,ConvertDeclarations(TPasProgram(El).ProgramSection,IntfContext));
  2632. CreateInitSection(El,Src,IntfContext);
  2633. end
  2634. else if El is TPasLibrary then
  2635. begin // library
  2636. if Assigned(TPasLibrary(El).LibrarySection) then
  2637. AddToSourceElements(Src,ConvertDeclarations(TPasLibrary(El).LibrarySection,IntfContext));
  2638. CreateInitSection(El,Src,IntfContext);
  2639. end
  2640. else
  2641. begin // unit
  2642. // add implementation object at top, so the interface elemwnts can add stuff
  2643. if (FBuiltInNames[pbivnImplementation]<>'') and Assigned(El.ImplementationSection) then
  2644. begin
  2645. // add 'var $impl = {};'
  2646. ImplVarSt:=TJSVariableStatement(CreateElement(TJSVariableStatement,El));
  2647. AddToSourceElements(Src,ImplVarSt);
  2648. VarDecl:=TJSVarDeclaration(CreateElement(TJSVarDeclaration,El));
  2649. ImplVarSt.A:=VarDecl;
  2650. VarDecl.Name:=FBuiltInNames[pbivnImplementation];
  2651. VarDecl.Init:=TJSEmptyBlockStatement(CreateElement(TJSEmptyBlockStatement,El.ImplementationSection));
  2652. // add 'this.$impl = $impl;'
  2653. ImplAssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  2654. AddToSourceElements(Src,ImplAssignSt);
  2655. ImplAssignSt.LHS:=CreateBuiltInIdentifierExpr('this.'+FBuiltInNames[pbivnImplementation]);
  2656. ImplAssignSt.Expr:=CreateBuiltInIdentifierExpr(FBuiltInNames[pbivnImplementation]);
  2657. end
  2658. else
  2659. begin
  2660. ImplVarSt:=nil;
  2661. ImplAssignSt:=nil;
  2662. end;
  2663. if Assigned(El.InterfaceSection) then
  2664. AddToSourceElements(Src,ConvertDeclarations(El.InterfaceSection,IntfContext));
  2665. if ImplVarSt<>nil then
  2666. begin
  2667. ImplDecl:=CreateImplementationSection(El,Src,IntfContext);
  2668. if ImplDecl=nil then
  2669. begin
  2670. RemoveFromSourceElements(Src,ImplVarSt);
  2671. RemoveFromSourceElements(Src,ImplAssignSt);
  2672. end;
  2673. end;
  2674. CreateInitSection(El,Src,IntfContext);
  2675. // add optional implementation uses list: [<implementation uses1>,<uses2>, ...]
  2676. if Assigned(El.ImplementationSection) then
  2677. begin
  2678. UsesList:=El.ImplementationSection.UsesList;
  2679. if (UsesList<>nil) and (UsesList.Count>0) then
  2680. ArgArray.Elements.AddElement.Expr:=CreateUsesList(El.ImplementationSection,AContext);
  2681. end;
  2682. end;
  2683. finally
  2684. IntfContext.Free;
  2685. end;
  2686. end;
  2687. function TPasToJSConverter.CreateElement(C: TJSElementClass; Src: TPasElement
  2688. ): TJSElement;
  2689. var
  2690. Line, Col: Integer;
  2691. begin
  2692. if Assigned(Src) then
  2693. begin
  2694. TPasResolver.UnmangleSourceLineNumber(Src.SourceLinenumber,Line,Col);
  2695. Result:=C.Create(Line,Col,Src.SourceFilename);
  2696. end
  2697. else
  2698. Result:=C.Create(0,0);
  2699. end;
  2700. function TPasToJSConverter.CreateFreeOrNewInstanceExpr(Ref: TResolvedReference;
  2701. AContext: TConvertContext): TJSCallExpression;
  2702. // create "$create("funcname");"
  2703. var
  2704. ok: Boolean;
  2705. C: TJSCallExpression;
  2706. Proc: TPasProcedure;
  2707. ProcScope: TPasProcedureScope;
  2708. ClassScope: TPasClassScope;
  2709. aClass: TPasElement;
  2710. ArgEx: TJSLiteral;
  2711. ArgElems: TJSArrayLiteralElements;
  2712. FunName: String;
  2713. begin
  2714. Result:=nil;
  2715. //writeln('TPasToJSConverter.CreateNewInstanceStatement Ref.Declaration=',GetObjName(Ref.Declaration));
  2716. Proc:=Ref.Declaration as TPasProcedure;
  2717. if Proc.Name='' then
  2718. RaiseInconsistency(20170125191914);
  2719. //writeln('TPasToJSConverter.CreateNewInstanceStatement Proc.Name=',Proc.Name);
  2720. ProcScope:=Proc.CustomData as TPasProcedureScope;
  2721. //writeln('TPasToJSConverter.CreateNewInstanceStatement ProcScope.Element=',GetObjName(ProcScope.Element),' ProcScope.ClassScope=',GetObjName(ProcScope.ClassScope),' ProcScope.DeclarationProc=',GetObjName(ProcScope.DeclarationProc),' ProcScope.ImplProc=',GetObjName(ProcScope.ImplProc),' ProcScope.CustomData=',GetObjName(ProcScope.CustomData));
  2722. ClassScope:=ProcScope.ClassScope;
  2723. aClass:=ClassScope.Element;
  2724. if aClass.Name='' then
  2725. RaiseInconsistency(20170125191923);
  2726. //writeln('TPasToJSConverter.CreateNewInstanceStatement aClass.Name=',aClass.Name);
  2727. C:=CreateCallExpression(Ref.Element);
  2728. ok:=false;
  2729. try
  2730. // add "$create()"
  2731. if rrfNewInstance in Ref.Flags then
  2732. FunName:=FBuiltInNames[pbifnClassInstanceNew]
  2733. else
  2734. FunName:=FBuiltInNames[pbifnClassInstanceFree];
  2735. FunName:=CreateReferencePath(Proc,AContext,rpkPathWithDot,false,Ref)+FunName;
  2736. C.Expr:=CreateBuiltInIdentifierExpr(FunName);
  2737. ArgElems:=C.Args.Elements;
  2738. // parameter: "funcname"
  2739. ArgEx := CreateLiteralString(Ref.Element,TransformVariableName(Proc,AContext));
  2740. ArgElems.AddElement.Expr:=ArgEx;
  2741. ok:=true;
  2742. finally
  2743. if not ok then
  2744. C.Free;
  2745. end;
  2746. Result:=C;
  2747. end;
  2748. function TPasToJSConverter.CreateFunction(El: TPasElement; WithBody: boolean
  2749. ): TJSFunctionDeclarationStatement;
  2750. var
  2751. FuncDef: TJSFuncDef;
  2752. FuncSt: TJSFunctionDeclarationStatement;
  2753. begin
  2754. FuncSt:=TJSFunctionDeclarationStatement(CreateElement(TJSFunctionDeclarationStatement,El));
  2755. Result:=FuncSt;
  2756. FuncDef:=TJSFuncDef.Create;
  2757. FuncSt.AFunction:=FuncDef;
  2758. if WithBody then
  2759. FuncDef.Body:=TJSFunctionBody(CreateElement(TJSFunctionBody,El));
  2760. end;
  2761. function TPasToJSConverter.ConvertUnaryExpression(El: TUnaryExpr;
  2762. AContext: TConvertContext): TJSElement;
  2763. procedure NotSupported;
  2764. begin
  2765. DoError(20170215134950,nUnaryOpcodeNotSupported,sUnaryOpcodeNotSupported,
  2766. [OpcodeStrings[El.OpCode]],El);
  2767. end;
  2768. Var
  2769. U : TJSUnaryExpression;
  2770. E : TJSElement;
  2771. ResolvedOp, ResolvedEl: TPasResolverResult;
  2772. BitwiseNot: Boolean;
  2773. begin
  2774. if AContext=nil then ;
  2775. Result:=Nil;
  2776. U:=nil;
  2777. Case El.OpCode of
  2778. eopAdd:
  2779. begin
  2780. E:=ConvertElement(El.Operand,AContext);
  2781. U:=TJSUnaryPlusExpression(CreateElement(TJSUnaryPlusExpression,El));
  2782. U.A:=E;
  2783. end;
  2784. eopSubtract:
  2785. begin
  2786. E:=ConvertElement(El.Operand,AContext);
  2787. U:=TJSUnaryMinusExpression(CreateElement(TJSUnaryMinusExpression,El));
  2788. U.A:=E;
  2789. end;
  2790. eopNot:
  2791. begin
  2792. E:=ConvertElement(El.Operand,AContext);
  2793. BitwiseNot:=true;
  2794. if AContext.Resolver<>nil then
  2795. begin
  2796. AContext.Resolver.ComputeElement(El.Operand,ResolvedOp,[]);
  2797. BitwiseNot:=ResolvedOp.BaseType in btAllInteger;
  2798. end;
  2799. if BitwiseNot then
  2800. U:=TJSUnaryInvExpression(CreateElement(TJSUnaryInvExpression,El))
  2801. else
  2802. U:=TJSUnaryNotExpression(CreateElement(TJSUnaryNotExpression,El));
  2803. U.A:=E;
  2804. end;
  2805. eopAddress:
  2806. begin
  2807. if AContext.Resolver=nil then
  2808. NotSupported;
  2809. AContext.Resolver.ComputeElement(El.Operand,ResolvedEl,[rcNoImplicitProc]);
  2810. {$IFDEF VerbosePas2JS}
  2811. writeln('TPasToJSConverter.ConvertUnaryExpression ',GetResolverResultDesc(ResolvedEl));
  2812. {$ENDIF}
  2813. if ResolvedEl.BaseType=btProc then
  2814. begin
  2815. if ResolvedEl.IdentEl is TPasProcedure then
  2816. begin
  2817. Result:=CreateCallback(El.Operand,ResolvedEl,AContext);
  2818. exit;
  2819. end;
  2820. end;
  2821. end;
  2822. end;
  2823. if U=nil then
  2824. NotSupported;
  2825. Result:=U;
  2826. end;
  2827. function TPasToJSConverter.GetExpressionValueType(El: TPasExpr;
  2828. AContext: TConvertContext): TJSType;
  2829. Function CombineValueType(A,B : TJSType) : TJSType;
  2830. begin
  2831. If (A=jstUNDEFINED) then
  2832. Result:=B
  2833. else if (B=jstUNDEFINED) then
  2834. Result:=A
  2835. else
  2836. Result:=A; // pick the first
  2837. end;
  2838. Var
  2839. A,B : TJSType;
  2840. begin
  2841. if (El is TBoolConstExpr) then
  2842. Result:=jstBoolean
  2843. else if (El is TPrimitiveExpr) then
  2844. begin
  2845. Case El.Kind of
  2846. pekIdent : Result:=GetPasIdentValueType(El.Name,AContext);
  2847. pekNumber : Result:=jstNumber;
  2848. pekString : Result:=jstString;
  2849. pekSet : Result:=jstUNDEFINED;
  2850. pekNil : Result:=jstNull;
  2851. pekBoolConst : Result:=jstBoolean;
  2852. pekRange : Result:=jstUNDEFINED;
  2853. pekFuncParams : Result:=jstUNDEFINED;
  2854. pekArrayParams : Result:=jstUNDEFINED;
  2855. pekListOfExp : Result:=jstUNDEFINED;
  2856. pekInherited : Result:=jstUNDEFINED;
  2857. pekSelf : Result:=jstObject;
  2858. end
  2859. end
  2860. else if (El is TUnaryExpr) then
  2861. Result:=GetExpressionValueType(TUnaryExpr(El).Operand,AContext)
  2862. else if (El is TBinaryExpr) then
  2863. begin
  2864. A:=GetExpressionValueType(TBinaryExpr(El).Left,AContext);
  2865. B:=GetExpressionValueType(TBinaryExpr(El).Right,AContext);
  2866. Result:=CombineValueType(A,B);
  2867. end
  2868. else
  2869. result:=jstUndefined
  2870. end;
  2871. function TPasToJSConverter.GetPasIdentValueType(AName: String;
  2872. AContext: TConvertContext): TJSType;
  2873. begin
  2874. if AContext=nil then ;
  2875. if AName='' then ;
  2876. Result:=jstUNDEFINED;
  2877. end;
  2878. function TPasToJSConverter.ComputeConstString(Expr: TPasExpr;
  2879. AContext: TConvertContext; NotEmpty: boolean): String;
  2880. var
  2881. Prim: TPrimitiveExpr;
  2882. begin
  2883. if AContext.Resolver<>nil then
  2884. Result:=AContext.Resolver.ComputeConstString(Expr,false,NotEmpty)
  2885. else
  2886. begin
  2887. // fall back:
  2888. Result:='';
  2889. if Expr is TPrimitiveExpr then
  2890. begin
  2891. Prim:=TPrimitiveExpr(Expr);
  2892. if Prim.Kind=pekString then
  2893. Result:=Prim.Value
  2894. else
  2895. RaiseNotSupported(Prim,AContext,20170215124733);
  2896. end
  2897. else
  2898. RaiseNotSupported(Expr,AContext,20170322121331);
  2899. end;
  2900. end;
  2901. function TPasToJSConverter.IsExternalClassConstructor(El: TPasElement): boolean;
  2902. var
  2903. P: TPasElement;
  2904. begin
  2905. if (El.ClassType=TPasConstructor)
  2906. and (pmExternal in TPasConstructor(El).Modifiers) then
  2907. begin
  2908. P:=El.Parent;
  2909. if (P<>nil) and (P.ClassType=TPasClassType) and TPasClassType(P).IsExternal then
  2910. exit(true);
  2911. end;
  2912. Result:=false;
  2913. end;
  2914. function TPasToJSConverter.ConvertBinaryExpression(El: TBinaryExpr;
  2915. AContext: TConvertContext): TJSElement;
  2916. Const
  2917. BinClasses : Array [TExprOpCode] of TJSBinaryClass = (
  2918. Nil, //eopEmpty,
  2919. TJSAdditiveExpressionPlus, // +
  2920. TJSAdditiveExpressionMinus, // -
  2921. TJSMultiplicativeExpressionMul, // *
  2922. TJSMultiplicativeExpressionDiv, // /
  2923. TJSMultiplicativeExpressionDiv, // div
  2924. TJSMultiplicativeExpressionMod, // mod
  2925. Nil, //eopPower
  2926. TJSURShiftExpression, // shr
  2927. TJSLShiftExpression, // shl
  2928. Nil, // Not
  2929. Nil, // And
  2930. Nil, // Or
  2931. Nil, // XOr
  2932. TJSEqualityExpressionEQ,
  2933. TJSEqualityExpressionNE,
  2934. TJSRelationalExpressionLT,
  2935. TJSRelationalExpressionGT,
  2936. TJSRelationalExpressionLE,
  2937. TJSRelationalExpressionGE,
  2938. Nil, // In
  2939. TJSRelationalExpressionInstanceOf, // is
  2940. Nil, // As
  2941. Nil, // Symmetrical diff
  2942. Nil, // Address,
  2943. Nil, // Deref
  2944. Nil // SubIndent,
  2945. );
  2946. Var
  2947. R : TJSBinary;
  2948. C : TJSBinaryClass;
  2949. A,B: TJSElement;
  2950. UseBitwiseOp: Boolean;
  2951. Call: TJSCallExpression;
  2952. LeftResolved, RightResolved: TPasResolverResult;
  2953. Flags: TPasResolverComputeFlags;
  2954. ModeSwitches: TModeSwitches;
  2955. begin
  2956. Result:=Nil;
  2957. case El.OpCode of
  2958. eopSubIdent:
  2959. begin
  2960. Result:=ConvertSubIdentExpression(El,AContext);
  2961. exit;
  2962. end;
  2963. eopNone:
  2964. if El.left is TInheritedExpr then
  2965. begin
  2966. Result:=ConvertInheritedExpression(TInheritedExpr(El.left),AContext);
  2967. exit;
  2968. end;
  2969. end;
  2970. if AContext.Access<>caRead then
  2971. DoError(20170209152633,nVariableIdentifierExpected,sVariableIdentifierExpected,[],El);
  2972. Call:=nil;
  2973. A:=ConvertElement(El.left,AContext);
  2974. B:=nil;
  2975. try
  2976. B:=ConvertElement(El.right,AContext);
  2977. if AContext.Resolver<>nil then
  2978. begin
  2979. ModeSwitches:=AContext.CurrentModeswitches;
  2980. // compute left
  2981. Flags:=[];
  2982. if El.OpCode in [eopEqual,eopNotEqual] then
  2983. if not (msDelphi in ModeSwitches) then
  2984. Flags:=[rcNoImplicitProcType];
  2985. AContext.Resolver.ComputeElement(El.left,LeftResolved,Flags);
  2986. // compute right
  2987. Flags:=[];
  2988. if (El.OpCode in [eopEqual,eopNotEqual])
  2989. and not (msDelphi in ModeSwitches) then
  2990. begin
  2991. if LeftResolved.BaseType=btNil then
  2992. Flags:=[rcNoImplicitProcType]
  2993. else if AContext.Resolver.IsProcedureType(LeftResolved,true) then
  2994. Flags:=[rcNoImplicitProcType]
  2995. else
  2996. Flags:=[];
  2997. end;
  2998. AContext.Resolver.ComputeElement(El.right,RightResolved,Flags);
  2999. Result:=ConvertBinaryExpressionRes(El,AContext,LeftResolved,RightResolved,A,B);
  3000. if Result<>nil then exit;
  3001. {$IFDEF VerbosePas2JS}
  3002. writeln('TPasToJSConverter.ConvertBinaryExpression Left=',GetResolverResultDesc(LeftResolved),' Right=',GetResolverResultDesc(RightResolved));
  3003. {$ENDIF}
  3004. end;
  3005. C:=BinClasses[El.OpCode];
  3006. if C=nil then
  3007. Case El.OpCode of
  3008. eopAs :
  3009. begin
  3010. // "A as B"
  3011. Call:=CreateCallExpression(El);
  3012. if (RightResolved.TypeEl is TPasClassType) and TPasClassType(RightResolved.TypeEl).IsExternal then
  3013. // B is external class -> "rtl.asExt(A,B)"
  3014. Call.Expr:=CreateBuiltInIdentifierExpr(FBuiltInNames[pbivnRTL]+'.'+FBuiltInNames[pbifnAsExt])
  3015. else
  3016. // otherwise -> "rtl.as(A,B)"
  3017. Call.Expr:=CreateBuiltInIdentifierExpr(FBuiltInNames[pbivnRTL]+'.'+FBuiltInNames[pbifnAs]);
  3018. Call.Args.Elements.AddElement.Expr:=A;
  3019. Call.Args.Elements.AddElement.Expr:=B;
  3020. Result:=Call;
  3021. exit;
  3022. end;
  3023. eopAnd,
  3024. eopOr,
  3025. eopXor:
  3026. begin
  3027. if AContext.Resolver<>nil then
  3028. UseBitwiseOp:=((LeftResolved.BaseType in btAllInteger)
  3029. or (RightResolved.BaseType in btAllInteger))
  3030. else
  3031. UseBitwiseOp:=(GetExpressionValueType(El.left,AContext)=jstNumber)
  3032. or (GetExpressionValueType(El.right,AContext)=jstNumber);
  3033. if UseBitwiseOp then
  3034. Case El.OpCode of
  3035. eopAnd : C:=TJSBitwiseAndExpression;
  3036. eopOr : C:=TJSBitwiseOrExpression;
  3037. eopXor : C:=TJSBitwiseXOrExpression;
  3038. end
  3039. else
  3040. Case El.OpCode of
  3041. eopAnd : C:=TJSLogicalAndExpression;
  3042. eopOr : C:=TJSLogicalOrExpression;
  3043. else
  3044. DoError(20161024191234,nBinaryOpcodeNotSupported,sBinaryOpcodeNotSupported,['logical XOR'],El);
  3045. end;
  3046. end;
  3047. else
  3048. if C=nil then
  3049. DoError(20161024191244,nBinaryOpcodeNotSupported,sBinaryOpcodeNotSupported,[OpcodeStrings[El.OpCode]],El);
  3050. end;
  3051. if (Result=Nil) and (C<>Nil) then
  3052. begin
  3053. R:=TJSBinary(CreateElement(C,El));
  3054. R.A:=A; A:=nil;
  3055. R.B:=B; B:=nil;
  3056. Result:=R;
  3057. if El.OpCode=eopDiv then
  3058. begin
  3059. // convert "a div b" to "Math.floor(a/b)"
  3060. Call:=CreateCallExpression(El);
  3061. Call.Args.Elements.AddElement.Expr:=R;
  3062. Call.Expr:=CreateBuiltInIdentifierExpr('Math.floor');
  3063. Result:=Call;
  3064. end;
  3065. end;
  3066. finally
  3067. if Result=nil then
  3068. begin
  3069. A.Free;
  3070. B.Free;
  3071. end;
  3072. end;
  3073. end;
  3074. function TPasToJSConverter.ConvertBinaryExpressionRes(El: TBinaryExpr;
  3075. AContext: TConvertContext; const LeftResolved,
  3076. RightResolved: TPasResolverResult; var A, B: TJSElement): TJSElement;
  3077. function CreateEqualCallback: TJSElement;
  3078. var
  3079. Call: TJSCallExpression;
  3080. NotEl: TJSUnaryNotExpression;
  3081. begin
  3082. // convert "proctypeA = proctypeB" to "rtl.eqCallback(proctypeA,proctypeB)"
  3083. Call:=CreateCallExpression(El);
  3084. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnProcType_Equal]]);
  3085. Call.Args.Elements.AddElement.Expr:=A;
  3086. A:=nil;
  3087. Call.Args.Elements.AddElement.Expr:=B;
  3088. B:=nil;
  3089. if El.OpCode=eopNotEqual then
  3090. begin
  3091. // convert "proctypeA <> proctypeB" to "!rtl.eqCallback(proctypeA,proctypeB)"
  3092. NotEl:=TJSUnaryNotExpression(CreateElement(TJSUnaryNotExpression,El));
  3093. NotEl.A:=Call;
  3094. Result:=NotEl;
  3095. end
  3096. else
  3097. Result:=Call;
  3098. end;
  3099. var
  3100. FunName: String;
  3101. Call: TJSCallExpression;
  3102. Bracket: TJSBracketMemberExpression;
  3103. DotExpr: TJSDotMemberExpression;
  3104. NotEl: TJSUnaryNotExpression;
  3105. begin
  3106. {$IFDEF VerbosePas2JS}
  3107. writeln('TPasToJSConverter.ConvertBinaryExpressionRes OpCode="',OpcodeStrings[El.OpCode],'" Left=',GetResolverResultDesc(LeftResolved),' Right=',GetResolverResultDesc(RightResolved));
  3108. {$ENDIF}
  3109. Result:=nil;
  3110. if LeftResolved.BaseType=btSet then
  3111. begin
  3112. // set operators -> rtl.operatorfunction(a,b)
  3113. case El.OpCode of
  3114. eopAdd: FunName:=FBuiltInNames[pbifnSet_Union];
  3115. eopSubtract: FunName:=FBuiltInNames[pbifnSet_Difference];
  3116. eopMultiply: FunName:=FBuiltInNames[pbifnSet_Intersect];
  3117. eopSymmetricaldifference: FunName:=FBuiltInNames[pbifnSet_SymDiffSet];
  3118. eopEqual: FunName:=FBuiltInNames[pbifnSet_Equal];
  3119. eopNotEqual: FunName:=FBuiltInNames[pbifnSet_NotEqual];
  3120. eopGreaterThanEqual: FunName:=FBuiltInNames[pbifnSet_GreaterEqual];
  3121. eopLessthanEqual: FunName:=FBuiltInNames[pbifnSet_LowerEqual];
  3122. else
  3123. DoError(20170209151300,nBinaryOpcodeNotSupported,sBinaryOpcodeNotSupported,[OpcodeStrings[El.OpCode]],El);
  3124. end;
  3125. Call:=CreateCallExpression(El);
  3126. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FunName]);
  3127. Call.Args.Elements.AddElement.Expr:=A;
  3128. A:=nil;
  3129. Call.Args.Elements.AddElement.Expr:=B;
  3130. B:=nil;
  3131. Result:=Call;
  3132. exit;
  3133. end
  3134. else if (RightResolved.BaseType=btSet) and (El.OpCode=eopIn) then
  3135. begin
  3136. // a in b -> b[a]
  3137. Bracket:=TJSBracketMemberExpression(CreateElement(TJSBracketMemberExpression,El));
  3138. Bracket.MExpr:=B;
  3139. B:=nil;
  3140. Bracket.Name:=A;
  3141. A:=nil;
  3142. Result:=Bracket;
  3143. exit;
  3144. end
  3145. else if (El.OpCode=eopIs) then
  3146. begin
  3147. // "A is B"
  3148. Call:=CreateCallExpression(El);
  3149. Result:=Call;
  3150. Call.Args.Elements.AddElement.Expr:=A; A:=nil;
  3151. if RightResolved.IdentEl is TPasClassOfType then
  3152. begin
  3153. // "A is class-of-type" -> "A is class"
  3154. FreeAndNil(B);
  3155. B:=CreateReferencePathExpr(TPasClassOfType(RightResolved.IdentEl).DestType,AContext);
  3156. end;
  3157. if (RightResolved.TypeEl is TPasClassType) and TPasClassType(RightResolved.TypeEl).IsExternal then
  3158. begin
  3159. // B is an external class -> "rtl.isExt(A,B)"
  3160. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnIsExt]]);
  3161. Call.Args.Elements.AddElement.Expr:=B; B:=nil;
  3162. end
  3163. else if LeftResolved.TypeEl is TPasClassOfType then
  3164. begin
  3165. // A is a TPasClassOfType -> "rtl.is(A,B)"
  3166. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnIs]]);
  3167. Call.Args.Elements.AddElement.Expr:=B; B:=nil;
  3168. end
  3169. else
  3170. begin
  3171. // use directly "B.isPrototypeOf(A)"
  3172. DotExpr:=TJSDotMemberExpression(CreateElement(TJSDotMemberExpression,El));
  3173. DotExpr.MExpr:=B; B:=nil;
  3174. DotExpr.Name:='isPrototypeOf';
  3175. Call.Expr:=DotExpr;
  3176. end;
  3177. exit;
  3178. end
  3179. else if (El.OpCode in [eopEqual,eopNotEqual]) then
  3180. begin
  3181. if AContext.Resolver.IsProcedureType(LeftResolved,true) then
  3182. begin
  3183. if RightResolved.BaseType=btNil then
  3184. else if AContext.Resolver.IsProcedureType(RightResolved,true)
  3185. or AContext.Resolver.IsJSBaseType(RightResolved,pbtJSValue,true) then
  3186. exit(CreateEqualCallback);
  3187. end
  3188. else if AContext.Resolver.IsProcedureType(RightResolved,true) then
  3189. begin
  3190. if LeftResolved.BaseType=btNil then
  3191. else if AContext.Resolver.IsJSBaseType(LeftResolved,pbtJSValue,true) then
  3192. exit(CreateEqualCallback);
  3193. end
  3194. else if LeftResolved.TypeEl is TPasRecordType then
  3195. begin
  3196. // convert "recordA = recordB" to "recordA.$equal(recordB)"
  3197. Call:=CreateCallExpression(El);
  3198. Call.Expr:=CreateDotExpression(El,A,CreateBuiltInIdentifierExpr(FBuiltInNames[pbifnRecordEqual]));
  3199. A:=nil;
  3200. Call.Args.Elements.AddElement.Expr:=B;
  3201. B:=nil;
  3202. if El.OpCode=eopNotEqual then
  3203. begin
  3204. // convert "recordA = recordB" to "!recordA.$equal(recordB)"
  3205. NotEl:=TJSUnaryNotExpression(CreateElement(TJSUnaryNotExpression,El));
  3206. NotEl.A:=Call;
  3207. Result:=NotEl;
  3208. end
  3209. else
  3210. Result:=Call;
  3211. exit;
  3212. end
  3213. else if LeftResolved.TypeEl is TPasArrayType then
  3214. begin
  3215. if RightResolved.BaseType=btNil then
  3216. begin
  3217. // convert "array = nil" to "rtl.length(array) > 0"
  3218. FreeAndNil(B);
  3219. Result:=CreateCmpArrayWithNil(El,A,El.OpCode);
  3220. A:=nil;
  3221. exit;
  3222. end;
  3223. end
  3224. else if RightResolved.TypeEl is TPasArrayType then
  3225. begin
  3226. if LeftResolved.BaseType=btNil then
  3227. begin
  3228. // convert "nil = array" to "0 < rtl.length(array)"
  3229. FreeAndNil(A);
  3230. Result:=CreateCmpArrayWithNil(El,B,El.OpCode);
  3231. B:=nil;
  3232. exit;
  3233. end;
  3234. end;
  3235. end;
  3236. end;
  3237. function TPasToJSConverter.ConvertSubIdentExpression(El: TBinaryExpr;
  3238. AContext: TConvertContext): TJSElement;
  3239. // connect El.left and El.right with a dot.
  3240. var
  3241. Left, Right: TJSElement;
  3242. DotContext: TDotContext;
  3243. OldAccess: TCtxAccess;
  3244. LeftResolved: TPasResolverResult;
  3245. RightRef: TResolvedReference;
  3246. ParamsExpr: TParamsExpr;
  3247. RightEl: TPasExpr;
  3248. begin
  3249. Result:=nil;
  3250. ParamsExpr:=nil;;
  3251. RightEl:=El.right;
  3252. while RightEl.ClassType=TParamsExpr do
  3253. begin
  3254. ParamsExpr:=TParamsExpr(RightEl);
  3255. RightEl:=ParamsExpr.Value;
  3256. end;
  3257. if (RightEl.ClassType=TPrimitiveExpr)
  3258. and (RightEl.CustomData is TResolvedReference) then
  3259. begin
  3260. RightRef:=TResolvedReference(RightEl.CustomData);
  3261. if IsExternalClassConstructor(RightRef.Declaration) then
  3262. begin
  3263. if ParamsExpr<>nil then
  3264. begin
  3265. // left side is done in ConvertFuncParams
  3266. Result:=ConvertParamsExpression(El.right as TParamsExpr,AContext);
  3267. end
  3268. else
  3269. Result:=ConvertExternalConstructor(El.left,RightRef,nil,AContext);
  3270. exit;
  3271. end;
  3272. end;
  3273. if AContext.Resolver<>nil then
  3274. begin
  3275. AContext.Resolver.ComputeElement(El.left,LeftResolved,[]);
  3276. if LeftResolved.BaseType=btModule then
  3277. begin
  3278. // e.g. System.ExitCode
  3279. // unit prefix is automatically created -> omit
  3280. Result:=ConvertElement(El.right,AContext);
  3281. exit;
  3282. end;
  3283. end;
  3284. // convert left side
  3285. OldAccess:=AContext.Access;
  3286. AContext.Access:=caRead;
  3287. Left:=ConvertElement(El.left,AContext);
  3288. if Left=nil then
  3289. RaiseInconsistency(20170201140821);
  3290. AContext.Access:=OldAccess;
  3291. // convert right side
  3292. DotContext:=TDotContext.Create(El,Left,AContext);
  3293. Right:=nil;
  3294. try
  3295. DotContext.LeftResolved:=LeftResolved;
  3296. Right:=ConvertElement(El.right,DotContext);
  3297. finally
  3298. DotContext.Free;
  3299. if Right=nil then
  3300. Left.Free;
  3301. end;
  3302. // connect via dot
  3303. Result:=CreateDotExpression(El,Left,Right);
  3304. end;
  3305. function TPasToJSConverter.CreateIdentifierExpr(AName: string; El: TPasElement;
  3306. AContext: TConvertContext): TJSPrimaryExpressionIdent;
  3307. Var
  3308. I : TJSPrimaryExpressionIdent;
  3309. begin
  3310. I:=TJSPrimaryExpressionIdent(CreateElement(TJSPrimaryExpressionIdent,El));
  3311. AName:=TransformVariableName(El,AName,AContext);
  3312. I.Name:=TJSString(AName);
  3313. Result:=I;
  3314. end;
  3315. function TPasToJSConverter.CreateDeclNameExpression(El: TPasElement;
  3316. const Name: string; AContext: TConvertContext): TJSPrimaryExpressionIdent;
  3317. var
  3318. CurName: String;
  3319. begin
  3320. CurName:=TransformVariableName(El,Name,AContext);
  3321. if (FBuiltInNames[pbivnImplementation]<>'') and (El.Parent.ClassType=TImplementationSection) then
  3322. CurName:=FBuiltInNames[pbivnImplementation]+'.'+CurName
  3323. else
  3324. CurName:='this.'+CurName;
  3325. Result:=TJSPrimaryExpressionIdent(CreateElement(TJSPrimaryExpressionIdent,El));
  3326. Result.Name:=TJSString(CurName);
  3327. end;
  3328. function TPasToJSConverter.ConvertPrimitiveExpression(El: TPrimitiveExpr;
  3329. AContext: TConvertContext): TJSElement;
  3330. Var
  3331. L : TJSLiteral;
  3332. Number : TJSNumber;
  3333. ConversionError : Integer;
  3334. i: Int64;
  3335. S: String;
  3336. begin
  3337. {$IFDEF VerbosePas2JS}
  3338. str(El.Kind,S);
  3339. writeln('TPasToJSConverter.ConvertPrimitiveExpression El=',GetObjName(El),' Context=',GetObjName(AContext),' El.Kind=',S);
  3340. {$ENDIF}
  3341. Result:=Nil;
  3342. case El.Kind of
  3343. pekString:
  3344. begin
  3345. if AContext.Resolver<>nil then
  3346. Result:=CreateLiteralJSString(El,
  3347. AContext.Resolver.ExtractPasStringLiteral(El,El.Value))
  3348. else
  3349. begin
  3350. S:=AnsiDequotedStr(El.Value,'''');
  3351. Result:=CreateLiteralString(El,S);
  3352. end;
  3353. //writeln('TPasToJSConverter.ConvertPrimitiveExpression Result="',TJSLiteral(Result).Value.AsString,'" ',GetObjName(AContext.Resolver));
  3354. end;
  3355. pekNumber:
  3356. begin
  3357. case El.Value[1] of
  3358. '0'..'9':
  3359. begin
  3360. Val(El.Value,Number,ConversionError);
  3361. if ConversionError<>0 then
  3362. DoError(20161024191248,nInvalidNumber,sInvalidNumber,[El.Value],El);
  3363. L:=CreateLiteralNumber(El,Number);
  3364. if El.Value[1] in ['0'..'9'] then
  3365. L.Value.CustomValue:=TJSString(El.Value);
  3366. end;
  3367. '$','&','%':
  3368. begin
  3369. i:=StrToInt64Def(El.Value,-1);
  3370. if i<0 then
  3371. DoError(20161024224442,nInvalidNumber,sInvalidNumber,[El.Value],El);
  3372. Number:=i;
  3373. if Number<>i then
  3374. // number was rounded -> we lost precision
  3375. DoError(20161024230812,nInvalidNumber,sInvalidNumber,[El.Value],El);
  3376. L:=CreateLiteralNumber(El,Number);
  3377. S:=copy(El.Value,2,length(El.Value));
  3378. case El.Value[1] of
  3379. '$': S:='0x'+S;
  3380. '&': if TargetProcessor=ProcessorECMAScript5 then
  3381. S:='0'+S
  3382. else
  3383. S:='0o'+S;
  3384. '%': if TargetProcessor=ProcessorECMAScript5 then
  3385. S:=''
  3386. else
  3387. S:='0b'+S;
  3388. end;
  3389. L.Value.CustomValue:=TJSString(S);
  3390. end;
  3391. else
  3392. DoError(20161024223232,nInvalidNumber,sInvalidNumber,[El.Value],El);
  3393. end;
  3394. Result:=L;
  3395. end;
  3396. pekIdent:
  3397. Result:=ConvertIdentifierExpr(El,AContext);
  3398. else
  3399. RaiseNotSupported(El,AContext,20161024222543);
  3400. end;
  3401. end;
  3402. function TPasToJSConverter.ConvertIdentifierExpr(El: TPrimitiveExpr;
  3403. AContext: TConvertContext): TJSElement;
  3404. var
  3405. Decl: TPasElement;
  3406. Name: String;
  3407. Ref: TResolvedReference;
  3408. Call: TJSCallExpression;
  3409. BuiltInProc: TResElDataBuiltInProc;
  3410. Prop: TPasProperty;
  3411. ImplicitCall: Boolean;
  3412. AssignContext: TAssignContext;
  3413. Arg: TPasArgument;
  3414. ParamContext: TParamContext;
  3415. ResolvedEl: TPasResolverResult;
  3416. ProcType: TPasProcedureType;
  3417. begin
  3418. Result:=nil;
  3419. if AContext=nil then ;
  3420. if El.Kind<>pekIdent then
  3421. RaiseInconsistency(20161024191255);
  3422. if El.CustomData is TResolvedReference then
  3423. begin
  3424. Ref:=TResolvedReference(El.CustomData);
  3425. Decl:=Ref.Declaration;
  3426. if IsExternalClassConstructor(Decl) then
  3427. begin
  3428. // create external object/function
  3429. Result:=ConvertExternalConstructor(nil,Ref,nil,AContext);
  3430. exit;
  3431. end;
  3432. if [rrfNewInstance,rrfFreeInstance]*Ref.Flags<>[] then
  3433. begin
  3434. // call constructor, destructor
  3435. Result:=CreateFreeOrNewInstanceExpr(Ref,AContext);
  3436. exit;
  3437. end;
  3438. Prop:=nil;
  3439. AssignContext:=nil;
  3440. ImplicitCall:=rrfImplicitCallWithoutParams in Ref.Flags;
  3441. if Decl.ClassType=TPasProperty then
  3442. begin
  3443. // Decl is a property -> redirect to getter/setter
  3444. Prop:=TPasProperty(Decl);
  3445. case AContext.Access of
  3446. caAssign:
  3447. begin
  3448. Decl:=AContext.Resolver.GetPasPropertySetter(Prop);
  3449. if Decl is TPasProcedure then
  3450. begin
  3451. AssignContext:=AContext.AccessContext as TAssignContext;
  3452. if AssignContext.Call<>nil then
  3453. RaiseNotSupported(El,AContext,20170206000310);
  3454. AssignContext.PropertyEl:=Prop;
  3455. AssignContext.Setter:=Decl;
  3456. // Setter
  3457. Call:=CreateCallExpression(El);
  3458. AssignContext.Call:=Call;
  3459. Call.Expr:=CreateReferencePathExpr(Decl,AContext,false,Ref);
  3460. Call.Args.Elements.AddElement.Expr:=AssignContext.RightSide;
  3461. AssignContext.RightSide:=nil;
  3462. Result:=Call;
  3463. exit;
  3464. end;
  3465. end;
  3466. caRead:
  3467. begin
  3468. Decl:=AContext.Resolver.GetPasPropertyGetter(Prop);
  3469. if (Decl is TPasFunction) and (Prop.Args.Count=0) then
  3470. ImplicitCall:=true;
  3471. end;
  3472. else
  3473. RaiseNotSupported(El,AContext,20170213212623);
  3474. end;
  3475. end
  3476. else if Decl.ClassType=TPasArgument then
  3477. begin
  3478. Arg:=TPasArgument(Decl);
  3479. if Arg.Access in [argVar,argOut] then
  3480. begin
  3481. // Arg is a reference object
  3482. case AContext.Access of
  3483. caRead:
  3484. begin
  3485. // create arg.get()
  3486. Call:=CreateCallExpression(El);
  3487. Call.Expr:=CreateDotExpression(El,
  3488. CreateIdentifierExpr(Arg.Name,Arg,AContext),
  3489. CreateBuiltInIdentifierExpr(TempRefObjGetterName));
  3490. Result:=Call;
  3491. exit;
  3492. end;
  3493. caAssign:
  3494. begin
  3495. // create arg.set(RHS)
  3496. AssignContext:=AContext.AccessContext as TAssignContext;
  3497. if AssignContext.Call<>nil then
  3498. RaiseNotSupported(El,AContext,20170214120606);
  3499. Call:=CreateCallExpression(El);
  3500. AssignContext.Call:=Call;
  3501. Call.Expr:=CreateDotExpression(El,
  3502. CreateIdentifierExpr(Arg.Name,Arg,AContext),
  3503. CreateBuiltInIdentifierExpr(TempRefObjSetterName));
  3504. Call.Args.Elements.AddElement.Expr:=AssignContext.RightSide;
  3505. AssignContext.RightSide:=nil;
  3506. Result:=Call;
  3507. exit;
  3508. end;
  3509. caByReference:
  3510. begin
  3511. // simply pass the reference
  3512. ParamContext:=AContext.AccessContext as TParamContext;
  3513. ParamContext.ReusingReference:=true;
  3514. Result:=CreateIdentifierExpr(Arg.Name,Arg,AContext);
  3515. exit;
  3516. end;
  3517. else
  3518. RaiseNotSupported(El,AContext,20170214120739);
  3519. end;
  3520. end;
  3521. end;
  3522. //writeln('TPasToJSConverter.ConvertPrimitiveExpression pekIdent TResolvedReference ',GetObjName(Ref.Declaration),' ',GetObjName(Ref.Declaration.CustomData));
  3523. if Decl.CustomData is TResElDataBuiltInProc then
  3524. begin
  3525. BuiltInProc:=TResElDataBuiltInProc(Decl.CustomData);
  3526. {$IFDEF VerbosePas2JS}
  3527. writeln('TPasToJSConverter.ConvertPrimitiveExpression ',Decl.Name,' ',ResolverBuiltInProcNames[BuiltInProc.BuiltIn]);
  3528. {$ENDIF}
  3529. case BuiltInProc.BuiltIn of
  3530. bfBreak: Result:=ConvertBuiltInBreak(El,AContext);
  3531. bfContinue: Result:=ConvertBuiltInContinue(El,AContext);
  3532. bfExit: Result:=ConvertBuiltInExit(El,AContext);
  3533. else
  3534. RaiseNotSupported(El,AContext,20161130164955,'built in proc '+ResolverBuiltInProcNames[BuiltInProc.BuiltIn]);
  3535. end;
  3536. if Result=nil then
  3537. RaiseInconsistency(20170214120048);
  3538. exit;
  3539. end;
  3540. {$IFDEF VerbosePas2JS}
  3541. writeln('TPasToJSConverter.ConvertIdentifierExpr ',GetObjName(El),' Decl=',GetObjName(Decl),' Decl.Parent=',GetObjName(Decl.Parent));
  3542. {$ENDIF}
  3543. if Decl is TPasModule then
  3544. Name:=FBuiltInNames[pbivnModules]+'.'+TransformModuleName(TPasModule(Decl),AContext)
  3545. else if (Decl is TPasFunctionType) and (CompareText(ResolverResultVar,El.Value)=0) then
  3546. Name:=ResolverResultVar
  3547. else if Decl.ClassType=TPasEnumValue then
  3548. begin
  3549. if UseEnumNumbers then
  3550. begin
  3551. Result:=CreateLiteralNumber(El,(Decl.Parent as TPasEnumType).Values.IndexOf(Decl));
  3552. exit;
  3553. end
  3554. else
  3555. begin
  3556. // enums always need the full path
  3557. Name:=CreateReferencePath(Decl,AContext,rpkPathAndName,true);
  3558. end;
  3559. end
  3560. else
  3561. Name:=CreateReferencePath(Decl,AContext,rpkPathAndName,false,Ref);
  3562. if Result=nil then
  3563. Result:=CreateBuiltInIdentifierExpr(Name);
  3564. if ImplicitCall then
  3565. begin
  3566. // create a call with default parameters
  3567. ProcType:=nil;
  3568. if Decl is TPasProcedure then
  3569. ProcType:=TPasProcedure(Decl).ProcType
  3570. else
  3571. begin
  3572. AContext.Resolver.ComputeElement(El,ResolvedEl,[rcNoImplicitProc]);
  3573. if ResolvedEl.TypeEl is TPasProcedureType then
  3574. ProcType:=TPasProcedureType(ResolvedEl.TypeEl)
  3575. else
  3576. RaiseNotSupported(El,AContext,20170217005025);
  3577. end;
  3578. Call:=nil;
  3579. try
  3580. CreateProcedureCall(Call,nil,ProcType,AContext);
  3581. Call.Expr:=Result;
  3582. Result:=Call;
  3583. finally
  3584. if Result<>Call then
  3585. Call.Free;
  3586. end;
  3587. end;
  3588. end
  3589. else if AContext.Resolver<>nil then
  3590. RaiseIdentifierNotFound(El.Value,El,20161024191306)
  3591. else
  3592. // simple mode
  3593. Result:=CreateIdentifierExpr(El.Value,El,AContext);
  3594. end;
  3595. function TPasToJSConverter.ConvertBoolConstExpression(El: TBoolConstExpr;
  3596. AContext: TConvertContext): TJSElement;
  3597. begin
  3598. if AContext=nil then ;
  3599. Result:=CreateLiteralBoolean(El,El.Value);
  3600. end;
  3601. function TPasToJSConverter.ConvertNilExpr(El: TNilExpr;
  3602. AContext: TConvertContext): TJSElement;
  3603. begin
  3604. if AContext=nil then ;
  3605. Result:=CreateLiteralNull(El);
  3606. end;
  3607. function TPasToJSConverter.ConvertInheritedExpression(El: TInheritedExpr;
  3608. AContext: TConvertContext): TJSElement;
  3609. function CreateAncestorCall(ParentEl: TPasElement; Apply: boolean;
  3610. AncestorProc: TPasProcedure; ParamsExpr: TParamsExpr): TJSElement;
  3611. var
  3612. FunName: String;
  3613. Call: TJSCallExpression;
  3614. ThisContext: TFunctionContext;
  3615. Proc: TPasProcedure;
  3616. ProcScope: TPasProcedureScope;
  3617. ClassScope, AncestorScope: TPasClassScope;
  3618. AncestorClass: TPasClassType;
  3619. begin
  3620. Result:=nil;
  3621. if (AncestorProc.Parent is TPasClassType)
  3622. and TPasClassType(AncestorProc.Parent).IsExternal then
  3623. begin
  3624. // ancestor is in an external class
  3625. // They could be overriden, without a Pascal declaration
  3626. // -> use the direct ancestor class of the current proc
  3627. ThisContext:=AContext.GetThisContext;
  3628. Proc:=ThisContext.PasElement as TPasProcedure;
  3629. ProcScope:=TPasProcedureScope(Proc.CustomData);
  3630. ClassScope:=ProcScope.ClassScope;
  3631. if ClassScope=nil then
  3632. RaiseInconsistency(20170323111252);
  3633. AncestorScope:=ClassScope.AncestorScope;
  3634. if AncestorScope=nil then
  3635. RaiseInconsistency(20170323111306);
  3636. AncestorClass:=AncestorScope.Element as TPasClassType;
  3637. FunName:=CreateReferencePath(AncestorClass,AContext,rpkPathAndName,true)
  3638. +'.'+TransformVariableName(AncestorProc,AContext);
  3639. end
  3640. else
  3641. FunName:=CreateReferencePath(AncestorProc,AContext,rpkPathAndName,true);
  3642. if Apply then
  3643. // create "ancestor.funcname.apply(this,arguments)"
  3644. FunName:=FunName+'.apply'
  3645. else
  3646. // create "ancestor.funcname.call(this,param1,param2,...)"
  3647. FunName:=FunName+'.call';
  3648. Call:=nil;
  3649. try
  3650. Call:=CreateCallExpression(ParentEl);
  3651. Call.Expr:=CreateBuiltInIdentifierExpr(FunName);
  3652. Call.Args.Elements.AddElement.Expr:=CreateBuiltInIdentifierExpr('this');
  3653. if Apply then
  3654. Call.Args.Elements.AddElement.Expr:=CreateBuiltInIdentifierExpr('arguments')
  3655. else
  3656. CreateProcedureCall(Call,ParamsExpr,AncestorProc.ProcType,AContext);
  3657. Result:=Call;
  3658. finally
  3659. if Result=nil then
  3660. Call.Free;
  3661. end;
  3662. end;
  3663. var
  3664. Right: TPasExpr;
  3665. Ref: TResolvedReference;
  3666. PrimExpr: TPrimitiveExpr;
  3667. AncestorProc: TPasProcedure;
  3668. ParamsExpr: TParamsExpr;
  3669. begin
  3670. Result:=nil;
  3671. if (El.Parent is TBinaryExpr) and (TBinaryExpr(El.Parent).OpCode=eopNone)
  3672. and (TBinaryExpr(El.Parent).left=El) then
  3673. begin
  3674. // "inherited <name>"
  3675. AncestorProc:=nil;
  3676. ParamsExpr:=nil;
  3677. Right:=TBinaryExpr(El.Parent).right;
  3678. if Right.ClassType=TPrimitiveExpr then
  3679. begin
  3680. PrimExpr:=TPrimitiveExpr(Right);
  3681. Ref:=PrimExpr.CustomData as TResolvedReference;
  3682. if rrfImplicitCallWithoutParams in Ref.Flags then
  3683. begin
  3684. // inherited <function>
  3685. // -> create "AncestorProc.call(this,defaultargs)"
  3686. AncestorProc:=Ref.Declaration as TPasProcedure;
  3687. end
  3688. else
  3689. begin
  3690. // inherited <varname>
  3691. // all variables have unique names -> simply access it
  3692. Result:=ConvertPrimitiveExpression(PrimExpr,AContext);
  3693. exit;
  3694. end;
  3695. end
  3696. else if Right.ClassType=TParamsExpr then
  3697. begin
  3698. ParamsExpr:=TParamsExpr(Right);
  3699. if ParamsExpr.Kind=pekFuncParams then
  3700. begin
  3701. if ParamsExpr.Value is TPrimitiveExpr then
  3702. begin
  3703. // inherited <function>(args)
  3704. // -> create "AncestorProc.call(this,args,defaultargs)"
  3705. PrimExpr:=TPrimitiveExpr(ParamsExpr.Value);
  3706. Ref:=PrimExpr.CustomData as TResolvedReference;
  3707. AncestorProc:=Ref.Declaration as TPasProcedure;
  3708. end;
  3709. end
  3710. else
  3711. begin
  3712. // inherited <varname>[]
  3713. // all variables have unique names -> simply access it
  3714. Result:=ConvertElement(Right,AContext);
  3715. exit;
  3716. end;
  3717. end;
  3718. if AncestorProc=nil then
  3719. begin
  3720. {$IFDEF VerbosePas2JS}
  3721. writeln('TPasToJSConverter.ConvertInheritedExpression Right=',GetObjName(Right));
  3722. {$ENDIF}
  3723. RaiseNotSupported(El,AContext,20170201190824);
  3724. end;
  3725. //writeln('TPasToJSConverter.ConvertInheritedExpression Func=',GetObjName(FuncContext.PasElement));
  3726. Result:=CreateAncestorCall(Right,false,AncestorProc,ParamsExpr);
  3727. end
  3728. else
  3729. begin
  3730. // "inherited;"
  3731. if El.CustomData=nil then
  3732. exit; // "inherited;" when there is no AncestorProc proc -> silently ignore
  3733. // create "AncestorProc.apply(this,arguments)"
  3734. Ref:=TResolvedReference(El.CustomData);
  3735. AncestorProc:=Ref.Declaration as TPasProcedure;
  3736. Result:=CreateAncestorCall(El,true,AncestorProc,nil);
  3737. end;
  3738. end;
  3739. function TPasToJSConverter.ConvertSelfExpression(El: TSelfExpr;
  3740. AContext: TConvertContext): TJSElement;
  3741. begin
  3742. if AContext=nil then ;
  3743. Result:=TJSPrimaryExpressionThis(CreateElement(TJSPrimaryExpressionThis,El));
  3744. end;
  3745. function TPasToJSConverter.ConvertParamsExpression(El: TParamsExpr;
  3746. AContext: TConvertContext): TJSElement;
  3747. begin
  3748. Result:=Nil;
  3749. {$IFDEF VerbosePas2JS}
  3750. writeln('TPasToJSConverter.ConvertParamsExpression ',GetObjName(El),' El.Kind=',ExprKindNames[El.Kind]);
  3751. {$ENDIF}
  3752. Case El.Kind of
  3753. pekFuncParams:
  3754. Result:=ConvertFuncParams(El,AContext);
  3755. pekArrayParams:
  3756. Result:=ConvertArrayParams(El,AContext);
  3757. pekSet:
  3758. Result:=ConvertSetLiteral(El,AContext);
  3759. else
  3760. RaiseNotSupported(El,AContext,20170209103235,ExprKindNames[El.Kind]);
  3761. end;
  3762. end;
  3763. function TPasToJSConverter.ConvertArrayParams(El: TParamsExpr;
  3764. AContext: TConvertContext): TJSElement;
  3765. var
  3766. ArgContext: TConvertContext;
  3767. function GetValueReference: TResolvedReference;
  3768. var
  3769. Value: TPasExpr;
  3770. begin
  3771. Result:=nil;
  3772. Value:=El.Value;
  3773. if (Value.ClassType=TPrimitiveExpr)
  3774. and (Value.CustomData is TResolvedReference) then
  3775. exit(TResolvedReference(Value.CustomData));
  3776. end;
  3777. procedure ConvertStringBracket;
  3778. var
  3779. Call: TJSCallExpression;
  3780. Param: TPasExpr;
  3781. Expr: TJSAdditiveExpressionMinus;
  3782. DotExpr: TJSDotMemberExpression;
  3783. AssignContext: TAssignContext;
  3784. Elements: TJSArrayLiteralElements;
  3785. AssignSt: TJSSimpleAssignStatement;
  3786. OldAccess: TCtxAccess;
  3787. begin
  3788. Param:=El.Params[0];
  3789. case AContext.Access of
  3790. caAssign:
  3791. begin
  3792. // s[index] := value -> s = rtl.setCharAt(s,index,value)
  3793. AssignContext:=AContext.AccessContext as TAssignContext;
  3794. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  3795. try
  3796. OldAccess:=AContext.Access;
  3797. AContext.Access:=caRead;
  3798. AssignSt.LHS:=ConvertElement(El.Value,AContext);
  3799. // rtl.setCharAt
  3800. Call:=CreateCallExpression(El);
  3801. AssignContext.Call:=Call;
  3802. AssignSt.Expr:=Call;
  3803. Elements:=Call.Args.Elements;
  3804. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnSetCharAt]]);
  3805. // first param s
  3806. Elements.AddElement.Expr:=ConvertElement(El.Value,AContext);
  3807. AContext.Access:=OldAccess;
  3808. // second param index
  3809. Elements.AddElement.Expr:=ConvertElement(Param,ArgContext);
  3810. // third param value
  3811. Elements.AddElement.Expr:=AssignContext.RightSide;
  3812. AssignContext.RightSide:=nil;
  3813. Result:=AssignSt
  3814. finally
  3815. if Result=nil then
  3816. AssignSt.Free;
  3817. end;
  3818. end;
  3819. caRead:
  3820. begin
  3821. Call:=CreateCallExpression(El);
  3822. Elements:=Call.Args.Elements;
  3823. try
  3824. // s[index] -> s.charAt(index-1)
  3825. // add string accessor
  3826. DotExpr:=TJSDotMemberExpression(CreateElement(TJSDotMemberExpression,El));
  3827. Call.Expr:=DotExpr;
  3828. DotExpr.MExpr:=ConvertElement(El.Value,AContext);
  3829. DotExpr.Name:='charAt';
  3830. // add parameter "index-1"
  3831. Expr:=TJSAdditiveExpressionMinus(CreateElement(TJSAdditiveExpressionMinus,Param));
  3832. Elements.AddElement.Expr:=Expr;
  3833. Expr.A:=ConvertElement(Param,ArgContext);
  3834. Expr.B:=CreateLiteralNumber(Param,1);
  3835. Result:=Call;
  3836. finally
  3837. if Result=nil then
  3838. Call.Free;
  3839. end;
  3840. end;
  3841. else
  3842. RaiseNotSupported(El,AContext,20170213213101);
  3843. end;
  3844. end;
  3845. procedure ConvertArray(ArrayEl: TPasArrayType);
  3846. var
  3847. B, Sub: TJSBracketMemberExpression;
  3848. i, ArgNo: Integer;
  3849. Arg: TJSElement;
  3850. OldAccess: TCtxAccess;
  3851. begin
  3852. B:=TJSBracketMemberExpression(CreateElement(TJSBracketMemberExpression,El));
  3853. try
  3854. // add read accessor
  3855. OldAccess:=AContext.Access;
  3856. AContext.Access:=caRead;
  3857. B.MExpr:=ConvertElement(El.Value,AContext);
  3858. AContext.Access:=OldAccess;
  3859. Result:=B;
  3860. ArgNo:=0;
  3861. repeat
  3862. // Note: dynamic array has length(ArrayEl.Ranges)=0
  3863. for i:=1 to Max(length(ArrayEl.Ranges),1) do
  3864. begin
  3865. // add parameter
  3866. ArgContext.Access:=caRead;
  3867. Arg:=ConvertElement(El.Params[ArgNo],ArgContext);
  3868. ArgContext.Access:=OldAccess;
  3869. if B.Name<>nil then
  3870. begin
  3871. Sub:=B;
  3872. B:=TJSBracketMemberExpression(CreateElement(TJSBracketMemberExpression,El));
  3873. B.MExpr:=Sub;
  3874. end;
  3875. B.Name:=Arg;
  3876. inc(ArgNo);
  3877. if ArgNo>length(El.Params) then
  3878. RaiseInconsistency(20170206180553);
  3879. end;
  3880. if ArgNo=length(El.Params) then
  3881. break;
  3882. // continue in sub array
  3883. ArrayEl:=AContext.Resolver.ResolveAliasType(ArrayEl.ElType) as TPasArrayType;
  3884. until false;
  3885. Result:=B;
  3886. finally
  3887. if Result=nil then
  3888. B.Free;
  3889. end;
  3890. end;
  3891. procedure ConvertJSObject;
  3892. var
  3893. B: TJSBracketMemberExpression;
  3894. OldAccess: TCtxAccess;
  3895. begin
  3896. B:=TJSBracketMemberExpression(CreateElement(TJSBracketMemberExpression,El));
  3897. try
  3898. // add read accessor
  3899. OldAccess:=AContext.Access;
  3900. AContext.Access:=caRead;
  3901. B.MExpr:=ConvertElement(El.Value,AContext);
  3902. AContext.Access:=OldAccess;
  3903. // add parameter
  3904. ArgContext.Access:=caRead;
  3905. B.Name:=ConvertElement(El.Params[0],ArgContext);
  3906. ArgContext.Access:=OldAccess;
  3907. Result:=B;
  3908. finally
  3909. if Result=nil then
  3910. B.Free;
  3911. end;
  3912. end;
  3913. function IsJSBracketAccessorAndConvert(Prop: TPasProperty;
  3914. AccessEl: TPasElement;
  3915. AContext: TConvertContext; ChompPropName: boolean): boolean;
  3916. // If El.Value contains property name set ChompPropName = true
  3917. var
  3918. Bracket: TJSBracketMemberExpression;
  3919. OldAccess: TCtxAccess;
  3920. PathEl: TPasExpr;
  3921. Ref: TResolvedReference;
  3922. Path: String;
  3923. begin
  3924. if not AContext.Resolver.IsExternalBracketAccessor(AccessEl) then
  3925. exit(false);
  3926. Result:=true;
  3927. // bracket accessor of external class
  3928. if Prop.Args.Count<>1 then
  3929. RaiseInconsistency(20170403003753);
  3930. // bracket accessor of external class -> create PathEl[param]
  3931. Bracket:=TJSBracketMemberExpression(CreateElement(TJSBracketMemberExpression,Prop));
  3932. try
  3933. PathEl:=El.Value;
  3934. if ChompPropName then
  3935. begin
  3936. if (PathEl is TPrimitiveExpr)
  3937. and (TPrimitiveExpr(PathEl).Kind=pekIdent)
  3938. and (PathEl.CustomData is TResolvedReference) then
  3939. begin
  3940. // propname without path, e.g. propname[param]
  3941. Ref:=TResolvedReference(PathEl.CustomData);
  3942. Path:=CreateReferencePath(Prop,AContext,rpkPath,false,Ref);
  3943. if Path<>'' then
  3944. Bracket.MExpr:=CreateBuiltInIdentifierExpr(Path);
  3945. PathEl:=nil;
  3946. end
  3947. else if (PathEl is TBinaryExpr)
  3948. and (TBinaryExpr(PathEl).OpCode=eopSubIdent)
  3949. and (TBinaryExpr(PathEl).right is TPrimitiveExpr)
  3950. and (TPrimitiveExpr(TBinaryExpr(PathEl).right).Kind=pekIdent) then
  3951. begin
  3952. // instance.propname[param] -> instance[param]
  3953. PathEl:=TBinaryExpr(PathEl).left;
  3954. end
  3955. else
  3956. RaiseNotSupported(El.Value,AContext,20170402225050);
  3957. end;
  3958. if (PathEl<>nil) and (Bracket.MExpr=nil) then
  3959. begin
  3960. OldAccess:=AContext.Access;
  3961. AContext.Access:=caRead;
  3962. Bracket.MExpr:=ConvertElement(PathEl,AContext);
  3963. AContext.Access:=OldAccess;
  3964. end;
  3965. OldAccess:=ArgContext.Access;
  3966. ArgContext.Access:=caRead;
  3967. Bracket.Name:=ConvertElement(El.Params[0],AContext);
  3968. ArgContext.Access:=OldAccess;
  3969. ConvertArrayParams:=Bracket;
  3970. Bracket:=nil;
  3971. finally
  3972. Bracket.Free;
  3973. end;
  3974. end;
  3975. procedure ConvertIndexProperty(Prop: TPasProperty; AContext: TConvertContext);
  3976. var
  3977. Call: TJSCallExpression;
  3978. i: Integer;
  3979. TargetArg: TPasArgument;
  3980. Elements: TJSArrayLiteralElements;
  3981. Arg: TJSElement;
  3982. AccessEl: TPasElement;
  3983. AssignContext: TAssignContext;
  3984. OldAccess: TCtxAccess;
  3985. begin
  3986. Result:=nil;
  3987. AssignContext:=nil;
  3988. Call:=CreateCallExpression(El);
  3989. try
  3990. case AContext.Access of
  3991. caAssign:
  3992. begin
  3993. AccessEl:=AContext.Resolver.GetPasPropertySetter(Prop);
  3994. if IsJSBracketAccessorAndConvert(Prop,AccessEl,AContext,true) then
  3995. exit;
  3996. AssignContext:=AContext.AccessContext as TAssignContext;
  3997. AssignContext.PropertyEl:=Prop;
  3998. AssignContext.Setter:=AccessEl;
  3999. AssignContext.Call:=Call;
  4000. end;
  4001. caRead:
  4002. begin
  4003. AccessEl:=AContext.Resolver.GetPasPropertyGetter(Prop);
  4004. if IsJSBracketAccessorAndConvert(Prop,AccessEl,AContext,true) then
  4005. exit;
  4006. end
  4007. else
  4008. RaiseNotSupported(El,AContext,20170213213317);
  4009. end;
  4010. Call.Expr:=CreateReferencePathExpr(AccessEl,AContext,false,GetValueReference);
  4011. Elements:=Call.Args.Elements;
  4012. OldAccess:=ArgContext.Access;
  4013. // add params
  4014. i:=0;
  4015. while i<Prop.Args.Count do
  4016. begin
  4017. TargetArg:=TPasArgument(Prop.Args[i]);
  4018. Arg:=CreateProcCallArg(El.Params[i],TargetArg,ArgContext);
  4019. Elements.AddElement.Expr:=Arg;
  4020. inc(i);
  4021. end;
  4022. // fill up default values
  4023. while i<Prop.Args.Count do
  4024. begin
  4025. TargetArg:=TPasArgument(Prop.Args[i]);
  4026. if TargetArg.ValueExpr=nil then
  4027. begin
  4028. {$IFDEF VerbosePas2JS}
  4029. writeln('TPasToJSConverter.ConvertArrayParams.ConvertIndexProperty missing default value: Prop=',Prop.Name,' i=',i);
  4030. {$ENDIF}
  4031. RaiseInconsistency(20170206185126);
  4032. end;
  4033. AContext.Access:=caRead;
  4034. Arg:=ConvertElement(TargetArg.ValueExpr,ArgContext);
  4035. Elements.AddElement.Expr:=Arg;
  4036. inc(i);
  4037. end;
  4038. // finally add as last parameter the value
  4039. if AssignContext<>nil then
  4040. begin
  4041. Elements.AddElement.Expr:=AssignContext.RightSide;
  4042. AssignContext.RightSide:=nil;
  4043. end;
  4044. ArgContext.Access:=OldAccess;
  4045. Result:=Call;
  4046. finally
  4047. if Result=nil then
  4048. begin
  4049. if (AssignContext<>nil) and (AssignContext.Call=Call) then
  4050. AssignContext.Call:=nil;
  4051. Call.Free;
  4052. end;
  4053. end;
  4054. end;
  4055. procedure ConvertDefaultProperty(const ResolvedEl: TPasResolverResult;
  4056. Prop: TPasProperty);
  4057. var
  4058. DotContext: TDotContext;
  4059. Left, Right: TJSElement;
  4060. OldAccess: TCtxAccess;
  4061. AccessEl, SetAccessEl: TPasElement;
  4062. begin
  4063. case AContext.Access of
  4064. caAssign:
  4065. begin
  4066. AccessEl:=AContext.Resolver.GetPasPropertySetter(Prop);
  4067. if IsJSBracketAccessorAndConvert(Prop,AccessEl,AContext,false) then
  4068. exit;
  4069. end;
  4070. caRead:
  4071. begin
  4072. AccessEl:=AContext.Resolver.GetPasPropertyGetter(Prop);
  4073. if IsJSBracketAccessorAndConvert(Prop,AccessEl,AContext,false) then
  4074. exit;
  4075. end;
  4076. caByReference:
  4077. begin
  4078. //ParamContext:=AContext.AccessContext as TParamContext;
  4079. AccessEl:=AContext.Resolver.GetPasPropertyGetter(Prop);
  4080. SetAccessEl:=AContext.Resolver.GetPasPropertySetter(Prop);
  4081. if AContext.Resolver.IsExternalBracketAccessor(AccessEl) then
  4082. begin
  4083. if AContext.Resolver.IsExternalBracketAccessor(SetAccessEl) then
  4084. begin
  4085. // read and write are brackets -> easy
  4086. if not IsJSBracketAccessorAndConvert(Prop,AccessEl,AContext,false) then
  4087. RaiseNotSupported(El,AContext,20170405090845);
  4088. exit;
  4089. end;
  4090. end;
  4091. RaiseNotSupported(El,AContext,20170403000550);
  4092. end;
  4093. else
  4094. RaiseNotSupported(El,AContext,20170402233834);
  4095. end;
  4096. DotContext:=nil;
  4097. Left:=nil;
  4098. Right:=nil;
  4099. try
  4100. OldAccess:=AContext.Access;
  4101. AContext.Access:=caRead;
  4102. Left:=ConvertElement(El.Value,AContext);
  4103. AContext.Access:=OldAccess;
  4104. DotContext:=TDotContext.Create(El.Value,Left,AContext);
  4105. DotContext.LeftResolved:=ResolvedEl;
  4106. ConvertIndexProperty(Prop,DotContext);
  4107. Right:=Result;
  4108. Result:=nil;
  4109. finally
  4110. DotContext.Free;
  4111. if Right=nil then
  4112. Left.Free;
  4113. end;
  4114. Result:=CreateDotExpression(El,Left,Right);
  4115. end;
  4116. Var
  4117. ResolvedEl: TPasResolverResult;
  4118. TypeEl: TPasType;
  4119. ClassScope: TPas2JSClassScope;
  4120. B: TJSBracketMemberExpression;
  4121. OldAccess: TCtxAccess;
  4122. aClass: TPasClassType;
  4123. begin
  4124. if El.Kind<>pekArrayParams then
  4125. RaiseInconsistency(20170209113713);
  4126. ArgContext:=AContext;
  4127. while ArgContext is TDotContext do
  4128. ArgContext:=ArgContext.Parent;
  4129. if AContext.Resolver=nil then
  4130. begin
  4131. // without Resolver
  4132. if Length(El.Params)<>1 then
  4133. RaiseNotSupported(El,AContext,20170207151325,'Cannot convert 2-dim arrays');
  4134. B:=TJSBracketMemberExpression(CreateElement(TJSBracketMemberExpression,El));
  4135. try
  4136. // add reference
  4137. OldAccess:=AContext.Access;
  4138. AContext.Access:=caRead;
  4139. B.MExpr:=ConvertElement(El.Value,AContext);
  4140. // add parameter
  4141. OldAccess:=ArgContext.Access;
  4142. ArgContext.Access:=caRead;
  4143. B.Name:=ConvertElement(El.Params[0],ArgContext);
  4144. ArgContext.Access:=OldAccess;
  4145. Result:=B;
  4146. finally
  4147. if Result=nil then
  4148. B.Free;
  4149. end;
  4150. exit;
  4151. end;
  4152. // has Resolver
  4153. AContext.Resolver.ComputeElement(El.Value,ResolvedEl,[]);
  4154. {$IFDEF VerbosePas2JS}
  4155. writeln('TPasToJSConverter.ConvertArrayParams Value=',GetResolverResultDesc(ResolvedEl));
  4156. {$ENDIF}
  4157. if ResolvedEl.BaseType in btAllStrings then
  4158. ConvertStringBracket
  4159. else if (ResolvedEl.IdentEl is TPasProperty)
  4160. and (TPasProperty(ResolvedEl.IdentEl).Args.Count>0) then
  4161. ConvertIndexProperty(TPasProperty(ResolvedEl.IdentEl),AContext)
  4162. else if ResolvedEl.BaseType=btContext then
  4163. begin
  4164. TypeEl:=ResolvedEl.TypeEl;
  4165. if TypeEl.ClassType=TPasClassType then
  4166. begin
  4167. aClass:=TPasClassType(TypeEl);
  4168. ClassScope:=TypeEl.CustomData as TPas2JSClassScope;
  4169. if ClassScope.DefaultProperty<>nil then
  4170. ConvertDefaultProperty(ResolvedEl,ClassScope.DefaultProperty)
  4171. else if AContext.Resolver.IsExternalClassName(aClass,'Array')
  4172. or AContext.Resolver.IsExternalClassName(aClass,'Object') then
  4173. ConvertJSObject
  4174. else
  4175. RaiseInconsistency(20170206180448);
  4176. end
  4177. else if TypeEl.ClassType=TPasClassOfType then
  4178. begin
  4179. ClassScope:=TPasClassOfType(TypeEl).DestType.CustomData as TPas2JSClassScope;
  4180. if ClassScope.DefaultProperty=nil then
  4181. RaiseInconsistency(20170206180503);
  4182. ConvertDefaultProperty(ResolvedEl,ClassScope.DefaultProperty);
  4183. end
  4184. else if TypeEl.ClassType=TPasArrayType then
  4185. ConvertArray(TPasArrayType(TypeEl))
  4186. else
  4187. RaiseNotSupported(El,AContext,20170206181220,GetResolverResultDesc(ResolvedEl));
  4188. end
  4189. else
  4190. RaiseNotSupported(El,AContext,20170206180222);
  4191. end;
  4192. function TPasToJSConverter.ConvertFuncParams(El: TParamsExpr;
  4193. AContext: TConvertContext): TJSElement;
  4194. var
  4195. Ref: TResolvedReference;
  4196. Decl, Left: TPasElement;
  4197. BuiltInProc: TResElDataBuiltInProc;
  4198. TargetProcType: TPasProcedureType;
  4199. Call: TJSCallExpression;
  4200. Elements: TJSArrayLiteralElements;
  4201. E: TJSArrayLiteral;
  4202. OldAccess: TCtxAccess;
  4203. DeclResolved, ParamResolved: TPasResolverResult;
  4204. Param: TPasExpr;
  4205. JSBaseType: TPas2jsBaseType;
  4206. C: TClass;
  4207. begin
  4208. Result:=nil;
  4209. if El.Kind<>pekFuncParams then
  4210. RaiseInconsistency(20170209113515);
  4211. //writeln('TPasToJSConverter.ConvertFuncParams START pekFuncParams ',GetObjName(El.CustomData),' ',GetObjName(El.Value.CustomData));
  4212. Call:=nil;
  4213. Elements:=nil;
  4214. TargetProcType:=nil;
  4215. if El.Value.CustomData is TResolvedReference then
  4216. begin
  4217. Ref:=TResolvedReference(El.Value.CustomData);
  4218. Decl:=Ref.Declaration;
  4219. if Decl is TPasType then
  4220. Decl:=AContext.Resolver.ResolveAliasType(TPasType(Decl));
  4221. //writeln('TPasToJSConverter.ConvertFuncParams pekFuncParams TResolvedReference ',GetObjName(Ref.Declaration),' ',GetObjName(Ref.Declaration.CustomData));
  4222. C:=Decl.ClassType;
  4223. if C=TPasUnresolvedSymbolRef then
  4224. begin
  4225. if Decl.CustomData is TResElDataBuiltInProc then
  4226. begin
  4227. BuiltInProc:=TResElDataBuiltInProc(Decl.CustomData);
  4228. {$IFDEF VerbosePas2JS}
  4229. writeln('TPasToJSConverter.ConvertFuncParams ',Decl.Name,' ',ResolverBuiltInProcNames[BuiltInProc.BuiltIn]);
  4230. {$ENDIF}
  4231. case BuiltInProc.BuiltIn of
  4232. bfLength: Result:=ConvertBuiltInLength(El,AContext);
  4233. bfSetLength: Result:=ConvertBuiltInSetLength(El,AContext);
  4234. bfInclude: Result:=ConvertBuiltInExcludeInclude(El,AContext,true);
  4235. bfExclude: Result:=ConvertBuiltInExcludeInclude(El,AContext,false);
  4236. bfExit: Result:=ConvertBuiltInExit(El,AContext);
  4237. bfInc,
  4238. bfDec: Result:=ConvertBuiltInIncDec(El,AContext);
  4239. bfAssigned: Result:=ConvertBuiltInAssigned(El,AContext);
  4240. bfChr: Result:=ConvertBuiltInChr(El,AContext);
  4241. bfOrd: Result:=ConvertBuiltInOrd(El,AContext);
  4242. bfLow: Result:=ConvertBuiltInLow(El,AContext);
  4243. bfHigh: Result:=ConvertBuiltInHigh(El,AContext);
  4244. bfPred: Result:=ConvertBuiltInPred(El,AContext);
  4245. bfSucc: Result:=ConvertBuiltInSucc(El,AContext);
  4246. bfStrProc: Result:=ConvertBuiltInStrProc(El,AContext);
  4247. bfStrFunc: Result:=ConvertBuiltInStrFunc(El,AContext);
  4248. bfConcatArray: Result:=ConvertBuiltInConcatArray(El,AContext);
  4249. bfCopyArray: Result:=ConvertBuiltInCopyArray(El,AContext);
  4250. bfInsertArray: Result:=ConvertBuiltInInsertArray(El,AContext);
  4251. bfDeleteArray: Result:=ConvertBuiltInDeleteArray(El,AContext);
  4252. else
  4253. RaiseNotSupported(El,AContext,20161130164955,'built in proc '+ResolverBuiltInProcNames[BuiltInProc.BuiltIn]);
  4254. end;
  4255. if Result=nil then
  4256. RaiseInconsistency(20170210121932);
  4257. exit;
  4258. end
  4259. else if Decl.CustomData is TResElDataBaseType then
  4260. begin
  4261. Result:=ConvertTypeCastToBaseType(El,AContext,TResElDataBaseType(Decl.CustomData));
  4262. exit;
  4263. end
  4264. else
  4265. RaiseNotSupported(El,AContext,20170325160624);
  4266. end
  4267. else if IsExternalClassConstructor(Decl) then
  4268. begin
  4269. // create external object/function
  4270. // -> check if there is complex left side, e.g. TExtA.Create(params)
  4271. Left:=El;
  4272. while (Left.Parent.ClassType=TParamsExpr) do
  4273. Left:=Left.Parent;
  4274. if (Left.Parent.ClassType=TBinaryExpr) and (TBinaryExpr(Left.Parent).right=Left) then
  4275. Left:=TBinaryExpr(Left.Parent).Left
  4276. else
  4277. Left:=nil;
  4278. Result:=ConvertExternalConstructor(Left,Ref,El,AContext);
  4279. exit;
  4280. end
  4281. else if C.InheritsFrom(TPasProcedure) then
  4282. TargetProcType:=TPasProcedure(Decl).ProcType
  4283. else if (C=TPasClassType)
  4284. or (C=TPasClassOfType)
  4285. or (C=TPasEnumType)
  4286. or (C=TPasArrayType) then
  4287. begin
  4288. // typecast
  4289. // default is to simply replace "aType(value)" with "value"
  4290. Param:=El.Params[0];
  4291. AContext.Resolver.ComputeElement(Param,ParamResolved,[]);
  4292. Result:=ConvertElement(Param,AContext);
  4293. if (ParamResolved.BaseType=btCustom)
  4294. and (ParamResolved.TypeEl.CustomData is TResElDataPas2JSBaseType) then
  4295. begin
  4296. JSBaseType:=TResElDataPas2JSBaseType(ParamResolved.TypeEl.CustomData).JSBaseType;
  4297. if JSBaseType=pbtJSValue then
  4298. begin
  4299. if (C=TPasClassType)
  4300. or (C=TPasClassOfType) then
  4301. begin
  4302. // TObject(jsvalue) -> rtl.getObject(jsvalue)
  4303. Call:=CreateCallExpression(El);
  4304. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnGetObject]]);
  4305. Call.Args.Elements.AddElement.Expr:=Result;
  4306. Result:=Call;
  4307. end;
  4308. end;
  4309. end;
  4310. exit;
  4311. end
  4312. else if C.InheritsFrom(TPasVariable) then
  4313. begin
  4314. AContext.Resolver.ComputeElement(Decl,DeclResolved,[rcType]);
  4315. if DeclResolved.TypeEl is TPasProcedureType then
  4316. TargetProcType:=TPasProcedureType(DeclResolved.TypeEl)
  4317. else
  4318. RaiseNotSupported(El,AContext,20170217115244);
  4319. end
  4320. else if (C=TPasArgument) then
  4321. begin
  4322. AContext.Resolver.ComputeElement(Decl,DeclResolved,[rcType]);
  4323. if DeclResolved.TypeEl is TPasProcedureType then
  4324. TargetProcType:=TPasProcedureType(DeclResolved.TypeEl)
  4325. else
  4326. RaiseNotSupported(El,AContext,20170328224020);
  4327. end
  4328. else if (C=TPasProcedureType)
  4329. or (C=TPasFunctionType) then
  4330. begin
  4331. TargetProcType:=TPasProcedureType(Decl);
  4332. end
  4333. else
  4334. begin
  4335. {$IFDEF VerbosePas2JS}
  4336. writeln('TPasToJSConverter.ConvertFuncParams El=',GetObjName(El),' Decl=',GetObjName(Decl));
  4337. {$ENDIF}
  4338. RaiseNotSupported(El,AContext,20170215114337);
  4339. end;
  4340. if [rrfNewInstance,rrfFreeInstance]*Ref.Flags<>[] then
  4341. // call constructor, destructor
  4342. Call:=CreateFreeOrNewInstanceExpr(Ref,AContext);
  4343. end;
  4344. if Call=nil then
  4345. begin
  4346. Call:=CreateCallExpression(El);
  4347. Elements:=Call.Args.Elements;
  4348. end;
  4349. OldAccess:=AContext.Access;
  4350. try
  4351. AContext.Access:=caRead;
  4352. if Call.Expr=nil then
  4353. Call.Expr:=ConvertElement(El.Value,AContext);
  4354. if Call.Args=nil then
  4355. begin
  4356. // append ()
  4357. Call.Args:=TJSArguments(CreateElement(TJSArguments,El));
  4358. Elements:=Call.Args.Elements;
  4359. end
  4360. else if Elements=nil then
  4361. begin
  4362. // insert array parameter [], e.g. this.TObject.$create("create",[])
  4363. Elements:=Call.Args.Elements;
  4364. E:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,El));
  4365. Elements.AddElement.Expr:=E;
  4366. Elements:=TJSArrayLiteral(E).Elements;
  4367. end;
  4368. CreateProcedureCallArgs(Elements,El,TargetProcType,AContext);
  4369. if Elements.Count=0 then
  4370. begin
  4371. Call.Args.Free;
  4372. Call.Args:=nil;
  4373. end;
  4374. Result:=Call;
  4375. finally
  4376. AContext.Access:=OldAccess;
  4377. if Result=nil then
  4378. Call.Free;
  4379. end;
  4380. end;
  4381. function TPasToJSConverter.ConvertExternalConstructor(Left: TPasElement;
  4382. Ref: TResolvedReference; ParamsExpr: TParamsExpr; AContext: TConvertContext
  4383. ): TJSElement;
  4384. var
  4385. Proc: TPasConstructor;
  4386. ExtName: String;
  4387. NewExpr: TJSNewMemberExpression;
  4388. Call: TJSCallExpression;
  4389. LeftResolved: TPasResolverResult;
  4390. OldAccess: TCtxAccess;
  4391. ExtNameEl: TJSElement;
  4392. WithData: TPas2JSWithExprScope;
  4393. begin
  4394. Result:=nil;
  4395. NewExpr:=nil;
  4396. Call:=nil;
  4397. ExtNameEl:=nil;
  4398. try
  4399. Proc:=Ref.Declaration as TPasConstructor;
  4400. ExtNameEl:=nil;
  4401. if Left<>nil then
  4402. begin
  4403. if AContext.Resolver<>nil then
  4404. begin
  4405. AContext.Resolver.ComputeElement(Left,LeftResolved,[]);
  4406. if LeftResolved.BaseType=btModule then
  4407. begin
  4408. // e.g. Unit.TExtA
  4409. // ExtName is global -> omit unit
  4410. Left:=nil;
  4411. end
  4412. else ;
  4413. end;
  4414. if Left<>nil then
  4415. begin
  4416. // convert left side
  4417. OldAccess:=AContext.Access;
  4418. AContext.Access:=caRead;
  4419. ExtNameEl:=ConvertElement(Left,AContext);
  4420. AContext.Access:=OldAccess;
  4421. end;
  4422. end;
  4423. if ExtNameEl=nil then
  4424. begin
  4425. if Ref.WithExprScope<>nil then
  4426. begin
  4427. // using local WITH var
  4428. WithData:=Ref.WithExprScope as TPas2JSWithExprScope;
  4429. ExtName:=WithData.WithVarName;
  4430. end
  4431. else
  4432. // use external class name
  4433. ExtName:=(Proc.Parent as TPasClassType).ExternalName;
  4434. ExtNameEl:=CreateBuiltInIdentifierExpr(ExtName);
  4435. end;
  4436. if CompareText(Proc.Name,'new')=0 then
  4437. begin
  4438. // create 'new ExtName(params)'
  4439. NewExpr:=TJSNewMemberExpression(CreateElement(TJSNewMemberExpression,Ref.Element));
  4440. NewExpr.MExpr:=ExtNameEl;
  4441. NewExpr.Args:=TJSArguments(CreateElement(TJSArguments,Ref.Element));
  4442. ExtNameEl:=nil;
  4443. if ParamsExpr<>nil then
  4444. CreateProcedureCallArgs(NewExpr.Args.Elements,ParamsExpr,Proc.ProcType,AContext);
  4445. Result:=NewExpr;
  4446. NewExpr:=nil;
  4447. end
  4448. else
  4449. RaiseInconsistency(20170323083214);
  4450. finally
  4451. ExtNameEl.Free;
  4452. NewExpr.Free;
  4453. Call.Free;
  4454. end;
  4455. end;
  4456. function TPasToJSConverter.ConvertTypeCastToBaseType(El: TParamsExpr;
  4457. AContext: TConvertContext; BaseTypeData: TResElDataBaseType): TJSElement;
  4458. var
  4459. bt: TResolverBaseType;
  4460. Param: TPasExpr;
  4461. ParamResolved: TPasResolverResult;
  4462. NotEqual: TJSEqualityExpressionNE;
  4463. CondExpr: TJSConditionalExpression;
  4464. JSBaseType: TPas2jsBaseType;
  4465. Call: TJSCallExpression;
  4466. NotExpr: TJSUnaryNotExpression;
  4467. AddExpr: TJSAdditiveExpressionPlus;
  4468. JSBaseTypeData: TResElDataPas2JSBaseType;
  4469. TypeEl: TPasType;
  4470. C: TClass;
  4471. function IsParamPas2JSBaseType: boolean;
  4472. var
  4473. TypeEl: TPasType;
  4474. begin
  4475. if ParamResolved.BaseType<>btCustom then exit(false);
  4476. TypeEl:=ParamResolved.TypeEl;
  4477. if TypeEl.ClassType<>TPasUnresolvedSymbolRef then exit(false);
  4478. if not (TypeEl.CustomData is TResElDataPas2JSBaseType) then exit(false);
  4479. Result:=true;
  4480. JSBaseTypeData:=TResElDataPas2JSBaseType(TypeEl.CustomData);
  4481. JSBaseType:=JSBaseTypeData.JSBaseType;
  4482. end;
  4483. begin
  4484. Result:=nil;
  4485. Param:=El.Params[0];
  4486. AContext.Resolver.ComputeElement(Param,ParamResolved,[]);
  4487. JSBaseTypeData:=nil;
  4488. JSBaseType:=pbtNone;
  4489. bt:=BaseTypeData.BaseType;
  4490. if bt in btAllInteger then
  4491. begin
  4492. if ParamResolved.BaseType in btAllInteger then
  4493. begin
  4494. // integer to integer -> value
  4495. Result:=ConvertElement(Param,AContext);
  4496. exit;
  4497. end
  4498. else if ParamResolved.BaseType in btAllBooleans then
  4499. begin
  4500. // boolean to integer -> value?1:0
  4501. Result:=ConvertElement(Param,AContext);
  4502. // Note: convert value first in case it raises an exception
  4503. CondExpr:=TJSConditionalExpression(CreateElement(TJSConditionalExpression,El));
  4504. CondExpr.A:=Result;
  4505. CondExpr.B:=CreateLiteralNumber(El,1);
  4506. CondExpr.C:=CreateLiteralNumber(El,0);
  4507. Result:=CondExpr;
  4508. exit;
  4509. end
  4510. else if IsParamPas2JSBaseType then
  4511. begin
  4512. if JSBaseType=pbtJSValue then
  4513. begin
  4514. // convert jsvalue to integer -> Math.floor(value)
  4515. Result:=ConvertElement(Param,AContext);
  4516. // Note: convert value first in case it raises an exception
  4517. Call:=CreateCallExpression(El);
  4518. Call.Expr:=CreateMemberExpression(['Math','floor']);
  4519. Call.Args.Elements.AddElement.Expr:=Result;
  4520. Result:=Call;
  4521. exit;
  4522. end;
  4523. end;
  4524. end
  4525. else if bt in btAllBooleans then
  4526. begin
  4527. if ParamResolved.BaseType in btAllBooleans then
  4528. begin
  4529. // boolean to boolean -> value
  4530. Result:=ConvertElement(Param,AContext);
  4531. exit;
  4532. end
  4533. else if ParamResolved.BaseType in btAllInteger then
  4534. begin
  4535. // integer to boolean -> value!=0
  4536. Result:=ConvertElement(Param,AContext);
  4537. // Note: convert value first in case it raises an exception
  4538. NotEqual:=TJSEqualityExpressionNE(CreateElement(TJSEqualityExpressionNE,El));
  4539. NotEqual.A:=Result;
  4540. NotEqual.B:=CreateLiteralNumber(El,0);
  4541. Result:=NotEqual;
  4542. exit;
  4543. end
  4544. else if IsParamPas2JSBaseType then
  4545. begin
  4546. if JSBaseType=pbtJSValue then
  4547. begin
  4548. // convert jsvalue to boolean -> !(value==false)
  4549. Result:=ConvertElement(Param,AContext);
  4550. // Note: convert value first in case it raises an exception
  4551. NotExpr:=TJSUnaryNotExpression(CreateElement(TJSUnaryNotExpression,El));
  4552. NotExpr.A:=TJSEqualityExpressionEQ(CreateElement(TJSEqualityExpressionEQ,El));
  4553. TJSEqualityExpressionEQ(NotExpr.A).A:=Result;
  4554. TJSEqualityExpressionEQ(NotExpr.A).B:=CreateLiteralBoolean(El,false);
  4555. Result:=NotExpr;
  4556. exit;
  4557. end;
  4558. end;
  4559. end
  4560. else if bt in btAllFloats then
  4561. begin
  4562. if ParamResolved.BaseType in (btAllFloats+btAllInteger) then
  4563. begin
  4564. // double to double -> value
  4565. Result:=ConvertElement(Param,AContext);
  4566. exit;
  4567. end
  4568. else if IsParamPas2JSBaseType then
  4569. begin
  4570. if JSBaseType=pbtJSValue then
  4571. begin
  4572. // convert jsvalue to double -> rtl.getNumber(value)
  4573. Result:=ConvertElement(Param,AContext);
  4574. // Note: convert value first in case it raises an exception
  4575. Call:=CreateCallExpression(El);
  4576. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnGetNumber]]);
  4577. Call.Args.Elements.AddElement.Expr:=Result;
  4578. Result:=Call;
  4579. exit;
  4580. end;
  4581. end;
  4582. end
  4583. else if bt in btAllStrings then
  4584. begin
  4585. if ParamResolved.BaseType in btAllStringAndChars then
  4586. begin
  4587. // string or char to string -> value
  4588. Result:=ConvertElement(Param,AContext);
  4589. exit;
  4590. end
  4591. else if IsParamPas2JSBaseType then
  4592. begin
  4593. if JSBaseType=pbtJSValue then
  4594. begin
  4595. // convert jsvalue to string -> ""+value
  4596. Result:=ConvertElement(Param,AContext);
  4597. // Note: convert value first in case it raises an exception
  4598. AddExpr:=TJSAdditiveExpressionPlus(CreateElement(TJSAdditiveExpressionPlus,El));
  4599. AddExpr.A:=CreateLiteralString(El,'');
  4600. AddExpr.B:=Result;
  4601. Result:=AddExpr;
  4602. exit;
  4603. end;
  4604. end;
  4605. end
  4606. else if bt=btChar then
  4607. begin
  4608. if ParamResolved.BaseType=btChar then
  4609. begin
  4610. // char to char
  4611. Result:=ConvertElement(Param,AContext);
  4612. exit;
  4613. end
  4614. else if IsParamPas2JSBaseType then
  4615. begin
  4616. if JSBaseType=pbtJSValue then
  4617. begin
  4618. // convert jsvalue to char -> rtl.getChar(value)
  4619. Result:=ConvertElement(Param,AContext);
  4620. // Note: convert value first in case it raises an exception
  4621. Call:=CreateCallExpression(El);
  4622. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnGetChar]]);
  4623. Call.Args.Elements.AddElement.Expr:=Result;
  4624. Result:=Call;
  4625. exit;
  4626. end;
  4627. end;
  4628. end
  4629. else if (bt=btCustom) and (BaseTypeData is TResElDataPas2JSBaseType) then
  4630. begin
  4631. JSBaseType:=TResElDataPas2JSBaseType(BaseTypeData).JSBaseType;
  4632. if JSBaseType=pbtJSValue then
  4633. begin
  4634. // type cast to jsvalue
  4635. Result:=ConvertElement(Param,AContext);
  4636. // Note: convert value first in case it raises an exception
  4637. if ParamResolved.BaseType=btContext then
  4638. begin
  4639. TypeEl:=AContext.Resolver.ResolveAliasType(ParamResolved.TypeEl);
  4640. C:=TypeEl.ClassType;
  4641. if C=TPasClassType then
  4642. begin
  4643. // TObject(vsvalue) -> rtl.getObject(vsvalue)
  4644. Call:=CreateCallExpression(El);
  4645. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnGetObject]]);
  4646. Call.Args.Elements.AddElement.Expr:=Result;
  4647. Result:=Call;
  4648. end;
  4649. end;
  4650. exit;
  4651. end;
  4652. end;
  4653. {$IFDEF VerbosePas2JS}
  4654. writeln('TPasToJSConverter.ConvertTypeCastToBaseType BaseTypeData=',BaseTypeNames[bt],' ParamResolved=',GetResolverResultDesc(ParamResolved));
  4655. {$ENDIF}
  4656. RaiseNotSupported(El,AContext,20170325161150);
  4657. end;
  4658. function TPasToJSConverter.ConvertSetLiteral(El: TParamsExpr;
  4659. AContext: TConvertContext): TJSElement;
  4660. var
  4661. Call: TJSCallExpression;
  4662. ArgContext: TConvertContext;
  4663. i: Integer;
  4664. Arg: TJSElement;
  4665. ArgEl: TPasExpr;
  4666. begin
  4667. if El.Kind<>pekSet then
  4668. RaiseInconsistency(20170209112737);
  4669. if AContext.Access<>caRead then
  4670. DoError(20170209112926,nCantWriteSetLiteral,sCantWriteSetLiteral,[],El);
  4671. if length(El.Params)=0 then
  4672. Result:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,El))
  4673. else
  4674. begin
  4675. Result:=nil;
  4676. ArgContext:=AContext;
  4677. while ArgContext is TDotContext do
  4678. ArgContext:=ArgContext.Parent;
  4679. Call:=CreateCallExpression(El);
  4680. try
  4681. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnSet_Create]]);
  4682. for i:=0 to length(El.Params)-1 do
  4683. begin
  4684. ArgEl:=El.Params[i];
  4685. {$IFDEF VerbosePas2JS}
  4686. writeln('TPasToJSConverter.ConvertSetLiteral ',i,' El.Params[i]=',GetObjName(ArgEl));
  4687. {$ENDIF}
  4688. if (ArgEl.ClassType=TBinaryExpr) and (TBinaryExpr(ArgEl).Kind=pekRange) then
  4689. begin
  4690. // range -> add three parameters: null,left,right
  4691. // ToDo: error if left>right
  4692. // add null
  4693. Call.Args.Elements.AddElement.Expr:=CreateLiteralNull(ArgEl);
  4694. // add left
  4695. Arg:=ConvertElement(TBinaryExpr(ArgEl).left,ArgContext);
  4696. Call.Args.Elements.AddElement.Expr:=Arg;
  4697. // add right
  4698. Arg:=ConvertElement(TBinaryExpr(ArgEl).right,ArgContext);
  4699. Call.Args.Elements.AddElement.Expr:=Arg;
  4700. end
  4701. else
  4702. begin
  4703. Arg:=ConvertElement(ArgEl,ArgContext);
  4704. Call.Args.Elements.AddElement.Expr:=Arg;
  4705. end;
  4706. end;
  4707. Result:=Call;
  4708. finally
  4709. if Result=nil then
  4710. Call.Free;
  4711. end;
  4712. end;
  4713. end;
  4714. function TPasToJSConverter.ConvertOpenArrayParam(ElType: TPasType;
  4715. El: TParamsExpr; AContext: TConvertContext): TJSElement;
  4716. var
  4717. ArrLit: TJSArrayLiteral;
  4718. i: Integer;
  4719. NestedElType: TPasType;
  4720. Param: TPasExpr;
  4721. JSParam: TJSElement;
  4722. begin
  4723. {$IFDEF VerbosePas2JS}
  4724. writeln('TPasToJSConverter.ConvertOpenArrayParam ',GetObjName(ElType));
  4725. {$ENDIF}
  4726. Result:=nil;
  4727. try
  4728. NestedElType:=nil;
  4729. if ElType is TPasArrayType then
  4730. NestedElType:=TPasArrayType(ElType).ElType;
  4731. ArrLit:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,El));
  4732. for i:=0 to length(El.Params)-1 do
  4733. begin
  4734. Param:=El.Params[i];
  4735. if (NestedElType<>nil)
  4736. and (Param is TParamsExpr) and (TParamsExpr(Param).Kind=pekSet) then
  4737. JSParam:=ConvertOpenArrayParam(NestedElType,TParamsExpr(Param),AContext)
  4738. else
  4739. JSParam:=ConvertElement(Param,AContext);
  4740. ArrLit.Elements.AddElement.Expr:=JSParam;
  4741. end;
  4742. Result:=ArrLit;
  4743. finally
  4744. if Result=nil then
  4745. ArrLit.Free;
  4746. end;
  4747. end;
  4748. function TPasToJSConverter.ConvertBuiltInLength(El: TParamsExpr;
  4749. AContext: TConvertContext): TJSElement;
  4750. var
  4751. Arg: TJSElement;
  4752. Param: TPasExpr;
  4753. ParamResolved, RangeResolved: TPasResolverResult;
  4754. Ranges: TPasExprArray;
  4755. Call: TJSCallExpression;
  4756. begin
  4757. Result:=nil;
  4758. Param:=El.Params[0];
  4759. AContext.Resolver.ComputeElement(Param,ParamResolved,[]);
  4760. if ParamResolved.BaseType=btContext then
  4761. begin
  4762. if ParamResolved.TypeEl is TPasArrayType then
  4763. begin
  4764. Ranges:=TPasArrayType(ParamResolved.TypeEl).Ranges;
  4765. if length(Ranges)>0 then
  4766. begin
  4767. // static array -> number literal
  4768. if length(Ranges)>1 then
  4769. RaiseNotSupported(El,AContext,20170223131042);
  4770. AContext.Resolver.ComputeElement(Ranges[0],RangeResolved,[rcConstant]);
  4771. if RangeResolved.BaseType=btContext then
  4772. begin
  4773. if RangeResolved.IdentEl is TPasEnumType then
  4774. begin
  4775. Result:=CreateLiteralNumber(El,TPasEnumType(RangeResolved.IdentEl).Values.Count);
  4776. exit;
  4777. end;
  4778. end
  4779. else if RangeResolved.BaseType=btBoolean then
  4780. begin
  4781. Result:=CreateLiteralNumber(El,2);
  4782. exit;
  4783. end;
  4784. end
  4785. else
  4786. begin
  4787. // dynamic array -> rtl.length(array)
  4788. Result:=ConvertElement(El.Params[0],AContext);
  4789. // Note: convert param first, it may raise an exception
  4790. Call:=CreateCallExpression(El);
  4791. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnArray_Length]]);
  4792. Call.Args.Elements.AddElement.Expr:=Result;
  4793. Result:=Call;
  4794. exit;
  4795. end;
  4796. end;
  4797. end;
  4798. // default: Param.length
  4799. Arg:=ConvertElement(Param,AContext);
  4800. Result:=CreateDotExpression(El,Arg,CreateBuiltInIdentifierExpr('length'));
  4801. end;
  4802. function TPasToJSConverter.ConvertBuiltInSetLength(El: TParamsExpr;
  4803. AContext: TConvertContext): TJSElement;
  4804. // convert "SetLength(a,Len)" to "a = rtl.arraySetLength(a,Len)"
  4805. var
  4806. Param0: TPasExpr;
  4807. ResolvedParam0: TPasResolverResult;
  4808. ArrayType: TPasArrayType;
  4809. Call: TJSCallExpression;
  4810. ValInit, Arg: TJSElement;
  4811. AssignSt: TJSSimpleAssignStatement;
  4812. AssignContext: TAssignContext;
  4813. ElType: TPasType;
  4814. begin
  4815. Result:=nil;
  4816. Param0:=El.Params[0];
  4817. if AContext.Access<>caRead then
  4818. RaiseInconsistency(20170213213621);
  4819. AContext.Resolver.ComputeElement(Param0,ResolvedParam0,[rcNoImplicitProc]);
  4820. {$IFDEF VerbosePasResolver}
  4821. writeln('TPasToJSConverter.ConvertBuiltInSetLength ',GetResolverResultDesc(ResolvedParam0));
  4822. {$ENDIF}
  4823. if ResolvedParam0.TypeEl is TPasArrayType then
  4824. begin
  4825. // SetLength(AnArray,newlength)
  4826. ArrayType:=TPasArrayType(ResolvedParam0.TypeEl);
  4827. {$IFDEF VerbosePasResolver}
  4828. writeln('TPasToJSConverter.ConvertBuiltInSetLength array');
  4829. {$ENDIF}
  4830. // -> AnArray = rtl.setArrayLength(AnArray,newlength,initvalue)
  4831. AssignContext:=TAssignContext.Create(El,nil,AContext);
  4832. try
  4833. AContext.Resolver.ComputeElement(Param0,AssignContext.LeftResolved,[rcNoImplicitProc]);
  4834. AssignContext.RightResolved:=ResolvedParam0;
  4835. // create right side
  4836. // rtl.setArrayLength()
  4837. Call:=CreateCallExpression(El);
  4838. AssignContext.RightSide:=Call;
  4839. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnArray_SetLength]]);
  4840. // 1st param: AnArray
  4841. Call.Args.Elements.AddElement.Expr:=ConvertElement(Param0,AContext);
  4842. // 2nd param: newlength
  4843. Call.Args.Elements.AddElement.Expr:=ConvertElement(El.Params[1],AContext);
  4844. // 3rd param: default value
  4845. ElType:=AContext.Resolver.ResolveAliasType(ArrayType.ElType);
  4846. if ElType.ClassType=TPasRecordType then
  4847. ValInit:=CreateReferencePathExpr(ElType,AContext)
  4848. else
  4849. ValInit:=CreateValInit(ElType,nil,Param0,AContext);
  4850. Call.Args.Elements.AddElement.Expr:=ValInit;
  4851. // create left side: array =
  4852. Result:=CreateAssignStatement(Param0,AssignContext);
  4853. finally
  4854. AssignContext.RightSide.Free;
  4855. AssignContext.Free;
  4856. end;
  4857. end
  4858. else if ResolvedParam0.BaseType=btString then
  4859. begin
  4860. // convert "SetLength(string,NewLen);" to "string.length == NewLen;"
  4861. {$IFDEF VerbosePasResolver}
  4862. writeln('TPasToJSConverter.ConvertBuiltInSetLength string');
  4863. {$ENDIF}
  4864. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  4865. try
  4866. Arg:=ConvertElement(Param0,AContext);
  4867. // left side: string.length
  4868. AssignSt.LHS:=CreateDotExpression(El,Arg,CreateBuiltInIdentifierExpr('length'));
  4869. // right side: newlength
  4870. AssignSt.Expr:=ConvertElement(El.Params[1],AContext);
  4871. Result:=AssignSt;
  4872. finally
  4873. if Result=nil then
  4874. AssignSt.Free;
  4875. end;
  4876. end
  4877. else
  4878. RaiseNotSupported(El.Value,AContext,20170130141026,'setlength '+GetResolverResultDesc(ResolvedParam0));
  4879. end;
  4880. function TPasToJSConverter.ConvertBuiltInExcludeInclude(El: TParamsExpr;
  4881. AContext: TConvertContext; IsInclude: boolean): TJSElement;
  4882. // convert "Include(aSet,Enum)" to "aSet=rtl.includeSet(aSet,Enum)"
  4883. var
  4884. Call: TJSCallExpression;
  4885. Param0: TPasExpr;
  4886. AssignContext: TAssignContext;
  4887. FunName: String;
  4888. begin
  4889. Result:=nil;
  4890. Param0:=El.Params[0];
  4891. AssignContext:=TAssignContext.Create(El,nil,AContext);
  4892. try
  4893. AContext.Resolver.ComputeElement(Param0,AssignContext.LeftResolved,[rcNoImplicitProc]);
  4894. AssignContext.RightResolved:=AssignContext.LeftResolved;
  4895. // create right side rtl.includeSet(aSet,Enum)
  4896. Call:=CreateCallExpression(El);
  4897. AssignContext.RightSide:=Call;
  4898. if IsInclude then
  4899. FunName:=FBuiltInNames[pbifnSet_Include]
  4900. else
  4901. FunName:=FBuiltInNames[pbifnSet_Exclude];
  4902. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FunName]);
  4903. Call.Args.Elements.AddElement.Expr:=ConvertElement(Param0,AContext);
  4904. Call.Args.Elements.AddElement.Expr:=ConvertElement(El.Params[1],AContext);
  4905. Result:=CreateAssignStatement(Param0,AssignContext);
  4906. finally
  4907. AssignContext.RightSide.Free;
  4908. AssignContext.Free;
  4909. end;
  4910. end;
  4911. function TPasToJSConverter.ConvertBuiltInContinue(El: TPasExpr;
  4912. AContext: TConvertContext): TJSElement;
  4913. begin
  4914. if AContext=nil then;
  4915. Result:=TJSContinueStatement(CreateElement(TJSContinueStatement,El));
  4916. end;
  4917. function TPasToJSConverter.ConvertBuiltInBreak(El: TPasExpr;
  4918. AContext: TConvertContext): TJSElement;
  4919. begin
  4920. if AContext=nil then;
  4921. Result:=TJSBreakStatement(CreateElement(TJSBreakStatement,El));
  4922. end;
  4923. function TPasToJSConverter.ConvertBuiltInExit(El: TPasExpr;
  4924. AContext: TConvertContext): TJSElement;
  4925. // convert "exit;" -> in a function: "return result;" in a procedure: "return;"
  4926. // convert "exit(param);" -> "return param;"
  4927. var
  4928. ProcEl: TPasElement;
  4929. begin
  4930. Result:=TJSReturnStatement(CreateElement(TJSReturnStatement,El));
  4931. if (El is TParamsExpr) and (length(TParamsExpr(El).Params)>0) then
  4932. begin
  4933. // with parameter. convert "exit(param);" -> "return param;"
  4934. TJSReturnStatement(Result).Expr:=ConvertExpression(TParamsExpr(El).Params[0],AContext);
  4935. end
  4936. else
  4937. begin
  4938. // without parameter.
  4939. ProcEl:=El.Parent;
  4940. while not (ProcEl is TPasProcedure) do ProcEl:=ProcEl.Parent;
  4941. if ProcEl is TPasFunction then
  4942. // in a function, "return result;"
  4943. TJSReturnStatement(Result).Expr:=CreateBuiltInIdentifierExpr(ResolverResultVar)
  4944. else
  4945. ; // in a procedure, "return;" which means "return undefined;"
  4946. end;
  4947. end;
  4948. function TPasToJSConverter.ConvertBuiltInIncDec(El: TParamsExpr;
  4949. AContext: TConvertContext): TJSElement;
  4950. // convert inc(a,b) to a+=b
  4951. // convert dec(a,b) to a-=b
  4952. var
  4953. AssignSt: TJSAssignStatement;
  4954. begin
  4955. if CompareText((El.Value as TPrimitiveExpr).Value,'inc')=0 then
  4956. AssignSt:=TJSAddEqAssignStatement(CreateElement(TJSAddEqAssignStatement,El))
  4957. else
  4958. AssignSt:=TJSSubEqAssignStatement(CreateElement(TJSSubEqAssignStatement,El));
  4959. Result:=AssignSt;
  4960. AssignSt.LHS:=ConvertExpression(El.Params[0],AContext);
  4961. if length(El.Params)=1 then
  4962. AssignSt.Expr:=CreateLiteralNumber(El,1)
  4963. else
  4964. AssignSt.Expr:=ConvertExpression(El.Params[1],AContext);
  4965. end;
  4966. function TPasToJSConverter.ConvertBuiltInAssigned(El: TParamsExpr;
  4967. AContext: TConvertContext): TJSElement;
  4968. var
  4969. NE: TJSEqualityExpressionNE;
  4970. Param: TPasExpr;
  4971. ParamResolved: TPasResolverResult;
  4972. C: TClass;
  4973. GT: TJSRelationalExpressionGT;
  4974. Call: TJSCallExpression;
  4975. begin
  4976. Result:=nil;
  4977. if AContext.Resolver=nil then
  4978. RaiseInconsistency(20170210105235);
  4979. Param:=El.Params[0];
  4980. AContext.Resolver.ComputeElement(Param,ParamResolved,[rcNoImplicitProcType]);
  4981. {$IFDEF VerbosePas2JS}
  4982. writeln('TPasToJSConverter.ConvertBuiltInAssigned ParamResolved=',GetResolverResultDesc(ParamResolved));
  4983. {$ENDIF}
  4984. if ParamResolved.BaseType=btContext then
  4985. begin
  4986. C:=ParamResolved.TypeEl.ClassType;
  4987. if (C=TPasClassType)
  4988. or (C=TPasClassOfType)
  4989. or C.InheritsFrom(TPasProcedureType) then
  4990. begin
  4991. // convert Assigned(value) -> value!=null
  4992. Result:=ConvertElement(Param,AContext);
  4993. // Note: convert Param first, it may raise an exception
  4994. NE:=TJSEqualityExpressionNE(CreateElement(TJSEqualityExpressionNE,El));
  4995. NE.A:=Result;
  4996. NE.B:=CreateLiteralNull(El);
  4997. Result:=NE;
  4998. end
  4999. else if C=TPasArrayType then
  5000. begin
  5001. // convert Assigned(value) -> rtl.length(value)>0
  5002. Result:=ConvertElement(Param,AContext);
  5003. // Note: convert Param first, it may raise an exception
  5004. GT:=TJSRelationalExpressionGT(CreateElement(TJSRelationalExpressionGT,El));
  5005. Call:=CreateCallExpression(El);
  5006. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnArray_Length]]);
  5007. Call.Args.Elements.AddElement.Expr:=Result;
  5008. GT.A:=Call;
  5009. GT.B:=CreateLiteralNumber(El,0);
  5010. Result:=GT;
  5011. end
  5012. else
  5013. RaiseNotSupported(El,AContext,20170328124606);
  5014. end;
  5015. end;
  5016. function TPasToJSConverter.ConvertBuiltInChr(El: TParamsExpr;
  5017. AContext: TConvertContext): TJSElement;
  5018. var
  5019. ParamResolved: TPasResolverResult;
  5020. Param: TPasExpr;
  5021. Call: TJSCallExpression;
  5022. begin
  5023. Result:=nil;
  5024. if AContext.Resolver=nil then
  5025. RaiseInconsistency(20170325185847);
  5026. Param:=El.Params[0];
  5027. AContext.Resolver.ComputeElement(Param,ParamResolved,[]);
  5028. if ParamResolved.BaseType in btAllInteger then
  5029. begin
  5030. // chr(integer) -> String.fromCharCode(integer)
  5031. Result:=ConvertElement(Param,AContext);
  5032. // Note: convert Param first, as it might raise an exception
  5033. Call:=CreateCallExpression(El);
  5034. Call.Expr:=CreateMemberExpression(['String','fromCharCode']);
  5035. Call.Args.Elements.AddElement.Expr:=Result;
  5036. Result:=Call;
  5037. exit;
  5038. end;
  5039. DoError(20170325185906,nExpectedXButFoundY,sExpectedXButFoundY,['integer',GetResolverResultDescription(ParamResolved)],Param);
  5040. end;
  5041. function TPasToJSConverter.ConvertBuiltInOrd(El: TParamsExpr;
  5042. AContext: TConvertContext): TJSElement;
  5043. var
  5044. ParamResolved: TPasResolverResult;
  5045. Param: TPasExpr;
  5046. Call: TJSCallExpression;
  5047. begin
  5048. Result:=nil;
  5049. if AContext.Resolver=nil then
  5050. RaiseInconsistency(20170210105235);
  5051. Param:=El.Params[0];
  5052. AContext.Resolver.ComputeElement(Param,ParamResolved,[]);
  5053. if ParamResolved.BaseType=btChar then
  5054. begin
  5055. // ord(aChar) -> aChar.charCodeAt()
  5056. Result:=ConvertElement(Param,AContext);
  5057. // Note: convert Param first, as it might raise an exception
  5058. Call:=CreateCallExpression(El);
  5059. Call.Expr:=CreateDotExpression(El,Result,CreateBuiltInIdentifierExpr('charCodeAt'));
  5060. Result:=Call;
  5061. exit;
  5062. end
  5063. else if ParamResolved.BaseType=btContext then
  5064. begin
  5065. if ParamResolved.TypeEl.ClassType=TPasEnumType then
  5066. begin
  5067. // ord(enum) -> enum
  5068. Result:=ConvertElement(Param,AContext);
  5069. exit;
  5070. end;
  5071. end;
  5072. DoError(20170210105339,nExpectedXButFoundY,sExpectedXButFoundY,['enum',GetResolverResultDescription(ParamResolved)],Param);
  5073. end;
  5074. function TPasToJSConverter.ConvertBuiltInLow(El: TParamsExpr;
  5075. AContext: TConvertContext): TJSElement;
  5076. // low(enumtype) -> first enumvalue
  5077. // low(set var) -> first enumvalue
  5078. // low(settype) -> first enumvalue
  5079. // low(array var) -> first index
  5080. procedure CreateEnumValue(TypeEl: TPasEnumType);
  5081. var
  5082. EnumValue: TPasEnumValue;
  5083. begin
  5084. EnumValue:=TPasEnumValue(TypeEl.Values[0]);
  5085. Result:=CreateReferencePathExpr(EnumValue,AContext);
  5086. end;
  5087. var
  5088. ResolvedEl, RangeResolved: TPasResolverResult;
  5089. Param: TPasExpr;
  5090. TypeEl: TPasType;
  5091. Ranges: TPasExprArray;
  5092. begin
  5093. Result:=nil;
  5094. if AContext.Resolver=nil then
  5095. RaiseInconsistency(20170210120659);
  5096. Param:=El.Params[0];
  5097. AContext.Resolver.ComputeElement(Param,ResolvedEl,[]);
  5098. case ResolvedEl.BaseType of
  5099. btContext:
  5100. begin
  5101. TypeEl:=ResolvedEl.TypeEl;
  5102. if TypeEl.ClassType=TPasEnumType then
  5103. begin
  5104. CreateEnumValue(TPasEnumType(TypeEl));
  5105. exit;
  5106. end
  5107. else if (TypeEl.ClassType=TPasSetType) then
  5108. begin
  5109. if TPasSetType(TypeEl).EnumType<>nil then
  5110. begin
  5111. TypeEl:=TPasSetType(TypeEl).EnumType;
  5112. CreateEnumValue(TPasEnumType(TypeEl));
  5113. exit;
  5114. end;
  5115. end
  5116. else if TypeEl.ClassType=TPasArrayType then
  5117. begin
  5118. Ranges:=TPasArrayType(TypeEl).Ranges;
  5119. if length(Ranges)=0 then
  5120. begin
  5121. Result:=CreateLiteralNumber(El,0);
  5122. exit;
  5123. end
  5124. else if length(Ranges)=1 then
  5125. begin
  5126. AContext.Resolver.ComputeElement(Ranges[0],RangeResolved,[rcConstant]);
  5127. if RangeResolved.BaseType=btContext then
  5128. begin
  5129. if RangeResolved.IdentEl is TPasEnumType then
  5130. begin
  5131. CreateEnumValue(TPasEnumType(RangeResolved.IdentEl));
  5132. exit;
  5133. end;
  5134. end
  5135. else if RangeResolved.BaseType=btBoolean then
  5136. begin
  5137. Result:=CreateLiteralBoolean(El,LowJSBoolean);
  5138. exit;
  5139. end;
  5140. end;
  5141. RaiseNotSupported(El,AContext,20170222231008);
  5142. end;
  5143. end;
  5144. btChar,
  5145. btWideChar:
  5146. begin
  5147. Result:=CreateLiteralJSString(El,#0);
  5148. exit;
  5149. end;
  5150. btBoolean:
  5151. begin
  5152. Result:=CreateLiteralBoolean(El,LowJSBoolean);
  5153. exit;
  5154. end;
  5155. btSet:
  5156. begin
  5157. TypeEl:=ResolvedEl.TypeEl;
  5158. if TypeEl.ClassType=TPasEnumType then
  5159. begin
  5160. CreateEnumValue(TPasEnumType(TypeEl));
  5161. exit;
  5162. end;
  5163. end;
  5164. end;
  5165. DoError(20170210110717,nExpectedXButFoundY,sExpectedXButFoundY,['enum or array',GetResolverResultDescription(ResolvedEl)],Param);
  5166. end;
  5167. function TPasToJSConverter.ConvertBuiltInHigh(El: TParamsExpr;
  5168. AContext: TConvertContext): TJSElement;
  5169. // high(enumtype) -> last enumvalue
  5170. // high(set var) -> last enumvalue
  5171. // high(settype) -> last enumvalue
  5172. // high(dynamic array) -> array.length-1
  5173. // high(static array) -> last index
  5174. procedure CreateEnumValue(TypeEl: TPasEnumType);
  5175. var
  5176. EnumValue: TPasEnumValue;
  5177. begin
  5178. EnumValue:=TPasEnumValue(TypeEl.Values[TypeEl.Values.Count-1]);
  5179. Result:=CreateReferencePathExpr(EnumValue,AContext);
  5180. end;
  5181. var
  5182. ResolvedEl, RangeResolved: TPasResolverResult;
  5183. Param, Range: TPasExpr;
  5184. TypeEl: TPasType;
  5185. MinusExpr: TJSAdditiveExpressionMinus;
  5186. Call: TJSCallExpression;
  5187. begin
  5188. Result:=nil;
  5189. if AContext.Resolver=nil then
  5190. RaiseInconsistency(20170210120653);
  5191. Param:=El.Params[0];
  5192. AContext.Resolver.ComputeElement(Param,ResolvedEl,[]);
  5193. case ResolvedEl.BaseType of
  5194. btContext:
  5195. begin
  5196. TypeEl:=ResolvedEl.TypeEl;
  5197. if TypeEl.ClassType=TPasEnumType then
  5198. begin
  5199. CreateEnumValue(TPasEnumType(TypeEl));
  5200. exit;
  5201. end
  5202. else if (TypeEl.ClassType=TPasSetType) then
  5203. begin
  5204. if TPasSetType(TypeEl).EnumType<>nil then
  5205. begin
  5206. TypeEl:=TPasSetType(TypeEl).EnumType;
  5207. CreateEnumValue(TPasEnumType(TypeEl));
  5208. exit;
  5209. end;
  5210. end
  5211. else if TypeEl.ClassType=TPasArrayType then
  5212. begin
  5213. if length(TPasArrayType(TypeEl).Ranges)=0 then
  5214. begin
  5215. // dynamic array -> rtl.length(Param)-1
  5216. Result:=ConvertElement(Param,AContext);
  5217. // Note: convert Param first, it may raise an exception
  5218. Call:=CreateCallExpression(El);
  5219. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnArray_Length]]);
  5220. Call.Args.Elements.AddElement.Expr:=Result;
  5221. MinusExpr:=TJSAdditiveExpressionMinus(CreateElement(TJSAdditiveExpressionMinus,El));
  5222. MinusExpr.A:=Call;
  5223. MinusExpr.B:=CreateLiteralNumber(El,1);
  5224. Result:=MinusExpr;
  5225. exit;
  5226. end
  5227. else if length(TPasArrayType(TypeEl).Ranges)=1 then
  5228. begin
  5229. // static array
  5230. Range:=TPasArrayType(TypeEl).Ranges[0];
  5231. AContext.Resolver.ComputeElement(Range,RangeResolved,[rcConstant]);
  5232. if RangeResolved.BaseType=btContext then
  5233. begin
  5234. if RangeResolved.IdentEl is TPasEnumType then
  5235. begin
  5236. CreateEnumValue(TPasEnumType(RangeResolved.IdentEl));
  5237. exit;
  5238. end;
  5239. end
  5240. else if RangeResolved.BaseType=btBoolean then
  5241. begin
  5242. Result:=CreateLiteralBoolean(Param,HighJSBoolean);
  5243. exit;
  5244. end;
  5245. end;
  5246. RaiseNotSupported(El,AContext,20170222231101);
  5247. end;
  5248. end;
  5249. btBoolean:
  5250. begin
  5251. Result:=CreateLiteralBoolean(Param,HighJSBoolean);
  5252. exit;
  5253. end;
  5254. btSet:
  5255. begin
  5256. TypeEl:=ResolvedEl.TypeEl;
  5257. if TypeEl.ClassType=TPasEnumType then
  5258. begin
  5259. CreateEnumValue(TPasEnumType(TypeEl));
  5260. exit;
  5261. end;
  5262. end;
  5263. end;
  5264. DoError(20170210114139,nExpectedXButFoundY,sExpectedXButFoundY,['enum or array',GetResolverResultDescription(ResolvedEl)],Param);
  5265. end;
  5266. function TPasToJSConverter.ConvertBuiltInPred(El: TParamsExpr;
  5267. AContext: TConvertContext): TJSElement;
  5268. // pred(enumvalue) -> enumvalue-1
  5269. var
  5270. ResolvedEl: TPasResolverResult;
  5271. Param: TPasExpr;
  5272. V: TJSElement;
  5273. Expr: TJSAdditiveExpressionMinus;
  5274. begin
  5275. Result:=nil;
  5276. if AContext.Resolver=nil then
  5277. RaiseInconsistency(20170210120648);
  5278. Param:=El.Params[0];
  5279. AContext.Resolver.ComputeElement(Param,ResolvedEl,[]);
  5280. if (ResolvedEl.BaseType=btContext)
  5281. and (ResolvedEl.TypeEl.ClassType=TPasEnumType) then
  5282. begin
  5283. V:=ConvertElement(Param,AContext);
  5284. Expr:=TJSAdditiveExpressionMinus(CreateElement(TJSAdditiveExpressionMinus,El));
  5285. Expr.A:=V;
  5286. Expr.B:=CreateLiteralNumber(El,1);
  5287. Result:=Expr;
  5288. exit;
  5289. end;
  5290. DoError(20170210120039,nExpectedXButFoundY,sExpectedXButFoundY,['enum',GetResolverResultDescription(ResolvedEl)],Param);
  5291. end;
  5292. function TPasToJSConverter.ConvertBuiltInSucc(El: TParamsExpr;
  5293. AContext: TConvertContext): TJSElement;
  5294. // succ(enumvalue) -> enumvalue+1
  5295. var
  5296. ResolvedEl: TPasResolverResult;
  5297. Param: TPasExpr;
  5298. V: TJSElement;
  5299. Expr: TJSAdditiveExpressionPlus;
  5300. begin
  5301. Result:=nil;
  5302. if AContext.Resolver=nil then
  5303. RaiseInconsistency(20170210120645);
  5304. Param:=El.Params[0];
  5305. AContext.Resolver.ComputeElement(Param,ResolvedEl,[]);
  5306. if (ResolvedEl.BaseType=btContext)
  5307. and (ResolvedEl.TypeEl.ClassType=TPasEnumType) then
  5308. begin
  5309. V:=ConvertElement(Param,AContext);
  5310. Expr:=TJSAdditiveExpressionPlus(CreateElement(TJSAdditiveExpressionPlus,El));
  5311. Expr.A:=V;
  5312. Expr.B:=CreateLiteralNumber(El,1);
  5313. Result:=Expr;
  5314. exit;
  5315. end;
  5316. DoError(20170210120626,nExpectedXButFoundY,sExpectedXButFoundY,['enum',GetResolverResultDescription(ResolvedEl)],Param);
  5317. end;
  5318. function TPasToJSConverter.ConvertBuiltInStrProc(El: TParamsExpr;
  5319. AContext: TConvertContext): TJSElement;
  5320. // convert 'str(value,aString)' to 'aString = <string>'
  5321. // for the conversion see ConvertBuiltInStrFunc
  5322. var
  5323. AssignContext: TAssignContext;
  5324. StrVar: TPasExpr;
  5325. begin
  5326. Result:=nil;
  5327. AssignContext:=TAssignContext.Create(El,nil,AContext);
  5328. try
  5329. StrVar:=El.Params[1];
  5330. AContext.Resolver.ComputeElement(StrVar,AssignContext.LeftResolved,[rcNoImplicitProc]);
  5331. // create right side
  5332. AssignContext.RightSide:=ConvertBuiltInStrParam(El.Params[0],AContext,false,true);
  5333. SetResolverValueExpr(AssignContext.RightResolved,btString,
  5334. AContext.Resolver.BaseTypes[btString],El,[rrfReadable]);
  5335. // create 'StrVar = rightside'
  5336. Result:=CreateAssignStatement(StrVar,AssignContext);
  5337. finally
  5338. AssignContext.RightSide.Free;
  5339. AssignContext.Free;
  5340. end;
  5341. end;
  5342. function TPasToJSConverter.ConvertBuiltInStrFunc(El: TParamsExpr;
  5343. AContext: TConvertContext): TJSElement;
  5344. // convert 'str(boolean)' to '""+boolean'
  5345. // convert 'str(integer)' to '""+integer'
  5346. // convert 'str(float)' to '""+float'
  5347. // convert 'str(float:width)' to rtl.spaceLeft('""+float,width)'
  5348. // convert 'str(float:width:precision)' to 'rtl.spaceLeft(float.toFixed(precision),width)'
  5349. var
  5350. i: Integer;
  5351. Param: TPasExpr;
  5352. Sum, Add: TJSElement;
  5353. AddEl: TJSAdditiveExpressionPlus;
  5354. begin
  5355. {$IFDEF VerbosePas2JS}
  5356. writeln('TPasToJSConverter.ConvertBuiltInStrFunc Count=',length(El.Params));
  5357. {$ENDIF}
  5358. Result:=nil;
  5359. Sum:=nil;
  5360. Add:=nil;
  5361. try
  5362. for i:=0 to length(El.Params)-1 do
  5363. begin
  5364. Param:=El.Params[i];
  5365. Add:=ConvertBuiltInStrParam(Param,AContext,true,i=0);
  5366. if Sum=nil then
  5367. Sum:=Add
  5368. else
  5369. begin
  5370. AddEl:=TJSAdditiveExpressionPlus(CreateElement(TJSAdditiveExpressionPlus,Param));
  5371. AddEl.A:=Sum;
  5372. AddEl.B:=Add;
  5373. Sum:=AddEl;
  5374. end;
  5375. Add:=nil;
  5376. end;
  5377. Result:=Sum;
  5378. finally
  5379. Add.Free;
  5380. if Result=nil then
  5381. Sum.Free;
  5382. end;
  5383. end;
  5384. function TPasToJSConverter.ConvertBuiltInStrParam(El: TPasExpr;
  5385. AContext: TConvertContext; IsStrFunc, IsFirst: boolean): TJSElement;
  5386. var
  5387. ResolvedEl: TPasResolverResult;
  5388. NeedStrLit: Boolean;
  5389. Add: TJSElement;
  5390. Call: TJSCallExpression;
  5391. PlusEl: TJSAdditiveExpressionPlus;
  5392. Bracket: TJSBracketMemberExpression;
  5393. procedure PrependStrLit;
  5394. begin
  5395. PlusEl:=TJSAdditiveExpressionPlus(CreateElement(TJSAdditiveExpressionPlus,El));
  5396. PlusEl.A:=CreateLiteralString(El,'');
  5397. PlusEl.B:=Add;
  5398. Add:=PlusEl;
  5399. end;
  5400. begin
  5401. Result:=nil;
  5402. AContext.Resolver.ComputeElement(El,ResolvedEl,[]);
  5403. Add:=nil;
  5404. Call:=nil;
  5405. Bracket:=nil;
  5406. try
  5407. NeedStrLit:=false;
  5408. if ResolvedEl.BaseType in (btAllBooleans+btAllInteger) then
  5409. begin
  5410. NeedStrLit:=true;
  5411. Add:=ConvertElement(El,AContext);
  5412. end
  5413. else if ResolvedEl.BaseType in btAllFloats then
  5414. begin
  5415. NeedStrLit:=true;
  5416. Add:=ConvertElement(El,AContext);
  5417. if El.format2<>nil then
  5418. begin
  5419. // precision -> rtl El.toFixed(precision);
  5420. NeedStrLit:=false;
  5421. Call:=CreateCallExpression(El);
  5422. Call.Expr:=CreateDotExpression(El,Add,CreateBuiltInIdentifierExpr('toFixed'));
  5423. Call.Args.Elements.AddElement.Expr:=ConvertElement(El.format2,AContext);
  5424. Add:=Call;
  5425. Call:=nil;
  5426. end;
  5427. end
  5428. else if IsStrFunc and (ResolvedEl.BaseType in btAllStringAndChars) then
  5429. Add:=ConvertElement(El,AContext)
  5430. else if ResolvedEl.BaseType=btContext then
  5431. begin
  5432. if ResolvedEl.TypeEl.ClassType=TPasEnumType then
  5433. begin
  5434. // create enumtype[enumvalue]
  5435. Bracket:=TJSBracketMemberExpression(CreateElement(TJSBracketMemberExpression,El));
  5436. Bracket.MExpr:=CreateReferencePathExpr(TPasEnumType(ResolvedEl.TypeEl),AContext);
  5437. Bracket.Name:=ConvertElement(El,AContext);
  5438. Add:=Bracket;
  5439. Bracket:=nil;
  5440. end
  5441. else
  5442. RaiseNotSupported(El,AContext,20170320123827);
  5443. end
  5444. else
  5445. RaiseNotSupported(El,AContext,20170320093001);
  5446. if El.format1<>nil then
  5447. begin
  5448. // width -> leading spaces
  5449. if NeedStrLit then
  5450. PrependStrLit;
  5451. // create 'rtl.spaceLeft(add,width)'
  5452. Call:=CreateCallExpression(El);
  5453. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnSpaceLeft]]);
  5454. Call.Args.Elements.AddElement.Expr:=Add;
  5455. Add:=nil;
  5456. Call.Args.Elements.AddElement.Expr:=ConvertElement(El.format1,AContext);
  5457. Add:=Call;
  5458. Call:=nil;
  5459. end
  5460. else if IsFirst and NeedStrLit then
  5461. PrependStrLit;
  5462. Result:=Add;
  5463. finally
  5464. Call.Free;
  5465. Bracket.Free;
  5466. if Result=nil then
  5467. Add.Free;
  5468. end;
  5469. end;
  5470. function TPasToJSConverter.ConvertBuiltInConcatArray(El: TParamsExpr;
  5471. AContext: TConvertContext): TJSElement;
  5472. // concat(array1, array2)
  5473. var
  5474. Param0Resolved, ElTypeResolved: TPasResolverResult;
  5475. Param0: TPasExpr;
  5476. ArrayType: TPasArrayType;
  5477. Call: TJSCallExpression;
  5478. i: Integer;
  5479. begin
  5480. if length(El.Params)<1 then
  5481. RaiseInconsistency(20170331000332);
  5482. if length(El.Params)=1 then
  5483. begin
  5484. // concat(array1) -> array1
  5485. {$IFDEF VerbosePas2JS}
  5486. writeln('TPasToJSConverter.ConvertBuiltInConcatArray Count=',length(El.Params));
  5487. {$ENDIF}
  5488. Result:=ConvertElement(El.Params[0],AContext);
  5489. end
  5490. else
  5491. begin
  5492. // concat(array1,array2,...)
  5493. Param0:=El.Params[0];
  5494. AContext.Resolver.ComputeElement(Param0,Param0Resolved,[]);
  5495. if Param0Resolved.BaseType<>btContext then
  5496. RaiseNotSupported(Param0,AContext,20170331000819);
  5497. if Param0Resolved.TypeEl.ClassType<>TPasArrayType then
  5498. RaiseNotSupported(Param0,AContext,20170331000846);
  5499. ArrayType:=TPasArrayType(Param0Resolved.TypeEl);
  5500. if length(ArrayType.Ranges)>0 then
  5501. RaiseNotSupported(Param0,AContext,20170331001021);
  5502. AContext.Resolver.ComputeElement(ArrayType.ElType,ElTypeResolved,[rcType]);
  5503. Call:=CreateCallExpression(El);
  5504. try
  5505. {$IFDEF VerbosePas2JS}
  5506. writeln('TPasToJSConverter.ConvertBuiltInConcatArray Count=',length(El.Params),' ElType=',GetResolverResultDesc(ElTypeResolved));
  5507. {$ENDIF}
  5508. if ElTypeResolved.BaseType=btContext then
  5509. begin
  5510. if ElTypeResolved.TypeEl.ClassType=TPasRecordType then
  5511. begin
  5512. // record: rtl.arrayConcat(RecordType,array1,array2,...)
  5513. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnArray_Concat]]);
  5514. Call.Args.Elements.AddElement.Expr:=CreateReferencePathExpr(
  5515. ElTypeResolved.TypeEl,AContext);
  5516. end;
  5517. end
  5518. else if ElTypeResolved.BaseType=btSet then
  5519. begin
  5520. // set: rtl.arrayConcat("refSet",array1,array2,...)
  5521. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnArray_Concat]]);
  5522. Call.Args.Elements.AddElement.Expr:=CreateLiteralString(El,FBuiltInNames[pbifnSet_Reference]);
  5523. end;
  5524. if Call.Expr=nil then
  5525. // default: array1.concat(array2,...)
  5526. Call.Expr:=CreateDotExpression(El,ConvertElement(Param0,AContext),
  5527. CreateBuiltInIdentifierExpr('concat'));
  5528. for i:=1 to length(El.Params)-1 do
  5529. Call.Args.Elements.AddElement.Expr:=ConvertElement(El.Params[i],AContext);
  5530. Result:=Call;
  5531. finally
  5532. if Result=nil then
  5533. Call.Free;
  5534. end;
  5535. end;
  5536. end;
  5537. function TPasToJSConverter.ConvertBuiltInCopyArray(El: TParamsExpr;
  5538. AContext: TConvertContext): TJSElement;
  5539. var
  5540. Param: TPasExpr;
  5541. ParamResolved, ElTypeResolved: TPasResolverResult;
  5542. C: TClass;
  5543. TypeParam: TJSElement;
  5544. Call: TJSCallExpression;
  5545. ArrayType: TPasArrayType;
  5546. begin
  5547. Result:=nil;
  5548. Call:=nil;
  5549. try
  5550. Param:=El.Params[0];
  5551. AContext.Resolver.ComputeElement(El,ParamResolved,[]);
  5552. if ParamResolved.BaseType<>btContext then
  5553. RaiseInconsistency(20170401003242);
  5554. if ParamResolved.TypeEl.ClassType<>TPasArrayType then
  5555. RaiseInconsistency(20170401003256);
  5556. ArrayType:=TPasArrayType(ParamResolved.TypeEl);
  5557. AContext.Resolver.ComputeElement(ArrayType.ElType,ElTypeResolved,[rcType]);
  5558. // rtl.arrayCopy(type,src,start,count)
  5559. TypeParam:=nil;
  5560. if ElTypeResolved.BaseType=btContext then
  5561. begin
  5562. C:=ElTypeResolved.TypeEl.ClassType;
  5563. if C=TPasRecordType then
  5564. TypeParam:=CreateReferencePathExpr(TPasRecordType(ElTypeResolved.TypeEl),AContext);
  5565. end
  5566. else if ElTypeResolved.BaseType=btSet then
  5567. TypeParam:=CreateLiteralString(El,FBuiltInNames[pbifnSet_Reference]);
  5568. if TypeParam=nil then
  5569. TypeParam:=CreateLiteralNumber(El,0);
  5570. Call:=CreateCallExpression(El);
  5571. // rtl.arrayCopy
  5572. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnArray_Copy]]);
  5573. // param: type
  5574. Call.Args.Elements.AddElement.Expr:=TypeParam;
  5575. // param: src
  5576. Call.Args.Elements.AddElement.Expr:=ConvertElement(Param,AContext);
  5577. // param: start
  5578. if length(El.Params)=1 then
  5579. Call.Args.Elements.AddElement.Expr:=CreateLiteralNumber(El,0)
  5580. else
  5581. Call.Args.Elements.AddElement.Expr:=ConvertElement(El.Params[1],AContext);
  5582. // param: count
  5583. if length(El.Params)>=3 then
  5584. Call.Args.Elements.AddElement.Expr:=ConvertElement(El.Params[2],AContext);
  5585. Result:=Call;
  5586. finally
  5587. if Result=nil then
  5588. Call.Free;
  5589. end;
  5590. if El=nil then ;
  5591. if AContext=nil then;
  5592. end;
  5593. function TPasToJSConverter.ConvertBuiltInInsertArray(El: TParamsExpr;
  5594. AContext: TConvertContext): TJSElement;
  5595. // procedure insert(item,var array,const position)
  5596. // -> array.splice(position,1,item);
  5597. var
  5598. ArrEl: TJSElement;
  5599. Call: TJSCallExpression;
  5600. begin
  5601. Result:=nil;
  5602. Call:=nil;
  5603. try
  5604. Call:=CreateCallExpression(El);
  5605. ArrEl:=ConvertElement(El.Params[1],AContext);
  5606. Call.Expr:=CreateDotExpression(El,ArrEl,CreateBuiltInIdentifierExpr('splice'));
  5607. Call.Args.Elements.AddElement.Expr:=ConvertElement(El.Params[2],AContext);
  5608. Call.Args.Elements.AddElement.Expr:=CreateLiteralNumber(El,1);
  5609. Call.Args.Elements.AddElement.Expr:=ConvertElement(El.Params[0],AContext);
  5610. Result:=Call;
  5611. finally
  5612. if Result=nil then
  5613. Call.Free;
  5614. end;
  5615. end;
  5616. function TPasToJSConverter.ConvertBuiltInDeleteArray(El: TParamsExpr;
  5617. AContext: TConvertContext): TJSElement;
  5618. // proc delete(var array,const start,count)
  5619. // -> array.splice(start,count)
  5620. var
  5621. ArrEl: TJSElement;
  5622. Call: TJSCallExpression;
  5623. begin
  5624. Result:=nil;
  5625. Call:=nil;
  5626. try
  5627. Call:=CreateCallExpression(El);
  5628. ArrEl:=ConvertElement(El.Params[0],AContext);
  5629. Call.Expr:=CreateDotExpression(El,ArrEl,CreateBuiltInIdentifierExpr('splice'));
  5630. Call.Args.Elements.AddElement.Expr:=ConvertElement(El.Params[1],AContext);
  5631. Call.Args.Elements.AddElement.Expr:=ConvertElement(El.Params[2],AContext);
  5632. Result:=Call;
  5633. finally
  5634. if Result=nil then
  5635. Call.Free;
  5636. end;
  5637. end;
  5638. function TPasToJSConverter.ConvertRecordValues(El: TRecordValues;
  5639. AContext: TConvertContext): TJSElement;
  5640. Var
  5641. R : TJSObjectLiteral;
  5642. I : Integer;
  5643. It : TRecordValuesItem;
  5644. rel : TJSObjectLiteralElement;
  5645. begin
  5646. R:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,El));
  5647. For I:=0 to Length(El.Fields)-1 do
  5648. begin
  5649. it:=El.Fields[i];
  5650. Rel:=R.Elements.AddElement;
  5651. Rel.Name:=TJSString(it.Name);
  5652. Rel.Expr:=ConvertElement(it.ValueExp,AContext);
  5653. end;
  5654. Result:=R;
  5655. end;
  5656. function TPasToJSConverter.ConvertArrayValues(El: TArrayValues;
  5657. AContext: TConvertContext): TJSElement;
  5658. Var
  5659. R : TJSArrayLiteral;
  5660. I : Integer;
  5661. rel : TJSArrayLiteralElement;
  5662. begin
  5663. R:=TJSArrayLiteral(CreateElement(TJSObjectLiteral,El));
  5664. For I:=0 to Length(El.Values)-1 do
  5665. begin
  5666. Rel:=R.Elements.AddElement;
  5667. Rel.ElementIndex:=i;
  5668. Rel.Expr:=ConvertElement(El.Values[i],AContext);
  5669. end;
  5670. Result:=R;
  5671. end;
  5672. function TPasToJSConverter.ConvertExpression(El: TPasExpr;
  5673. AContext: TConvertContext): TJSElement;
  5674. begin
  5675. {$IFDEF VerbosePas2JS}
  5676. writeln('TPasToJSConverter.ConvertExpression El=',GetObjName(El),' Context=',GetObjName(AContext));
  5677. {$ENDIF}
  5678. Result:=Nil;
  5679. if (El.ClassType=TUnaryExpr) then
  5680. Result:=ConvertUnaryExpression(TUnaryExpr(El),AContext)
  5681. else if (El.ClassType=TBinaryExpr) then
  5682. Result:=ConvertBinaryExpression(TBinaryExpr(El),AContext)
  5683. else if (El.ClassType=TPrimitiveExpr) then
  5684. Result:=ConvertPrimitiveExpression(TPrimitiveExpr(El),AContext)
  5685. else if (El.ClassType=TBoolConstExpr) then
  5686. Result:=ConvertBoolConstExpression(TBoolConstExpr(El),AContext)
  5687. else if (El.ClassType=TNilExpr) then
  5688. Result:=ConvertNilExpr(TNilExpr(El),AContext)
  5689. else if (El.ClassType=TInheritedExpr) then
  5690. Result:=ConvertInheritedExpression(TInheritedExpr(El),AContext)
  5691. else if (El.ClassType=TSelfExpr) then
  5692. Result:=ConvertSelfExpression(TSelfExpr(El),AContext)
  5693. else if (El.ClassType=TParamsExpr) then
  5694. Result:=ConvertParamsExpression(TParamsExpr(El),AContext)
  5695. else if (El.ClassType=TRecordValues) then
  5696. Result:=ConvertRecordValues(TRecordValues(El),AContext)
  5697. else
  5698. RaiseNotSupported(El,AContext,20161024191314);
  5699. end;
  5700. function TPasToJSConverter.CreateBuiltInIdentifierExpr(AName: string
  5701. ): TJSPrimaryExpressionIdent;
  5702. var
  5703. Ident: TJSPrimaryExpressionIdent;
  5704. begin
  5705. if AName='' then
  5706. RaiseInconsistency(20170402230134);
  5707. Ident:=TJSPrimaryExpressionIdent.Create(0,0);
  5708. // do not lowercase
  5709. Ident.Name:=TJSString(AName);
  5710. Result:=Ident;
  5711. end;
  5712. function TPasToJSConverter.CreateTypeDecl(El: TPasType;
  5713. AContext: TConvertContext): TJSElement;
  5714. var
  5715. ElClass: TClass;
  5716. begin
  5717. Result:=Nil;
  5718. ElClass:=El.ClassType;
  5719. if ElClass=TPasClassType then
  5720. Result := ConvertClassType(TPasClassType(El), AContext)
  5721. else if ElClass=TPasRecordType then
  5722. Result := ConvertRecordType(TPasRecordType(El), AContext)
  5723. else if ElClass=TPasEnumType then
  5724. Result := ConvertEnumType(TPasEnumType(El), AContext)
  5725. else if (ElClass=TPasSetType) then
  5726. begin
  5727. if TPasSetType(El).IsPacked then
  5728. DoError(20170222231613,nPasElementNotSupported,sPasElementNotSupported,
  5729. ['packed'],El);
  5730. end
  5731. else if (ElClass=TPasAliasType)
  5732. or (ElClass=TPasClassOfType) then
  5733. else if (ElClass=TPasProcedureType)
  5734. or (ElClass=TPasFunctionType) then
  5735. begin
  5736. if TPasProcedureType(El).IsNested then
  5737. DoError(20170222231636,nPasElementNotSupported,sPasElementNotSupported,
  5738. ['is nested'],El);
  5739. if TPasProcedureType(El).CallingConvention<>ccDefault then
  5740. DoError(20170222231532,nPasElementNotSupported,sPasElementNotSupported,
  5741. [cCallingConventions[TPasProcedureType(El).CallingConvention]],El);
  5742. end
  5743. else if (ElClass=TPasArrayType) then
  5744. begin
  5745. if TPasArrayType(El).PackMode<>pmNone then
  5746. DoError(20170222231648,nPasElementNotSupported,sPasElementNotSupported,
  5747. ['packed'],El);
  5748. end
  5749. else
  5750. begin
  5751. {$IFDEF VerbosePas2JS}
  5752. writeln('TPasToJSConverter.CreateTypeDecl El=',GetObjName(El));
  5753. {$ENDIF}
  5754. RaiseNotSupported(El,AContext,20170208144053);
  5755. end;
  5756. end;
  5757. function TPasToJSConverter.CreateVarDecl(El: TPasVariable;
  5758. AContext: TConvertContext): TJSElement;
  5759. Var
  5760. C : TJSElement;
  5761. V : TJSVariableStatement;
  5762. AssignSt: TJSSimpleAssignStatement;
  5763. Obj: TJSObjectLiteral;
  5764. ObjLit: TJSObjectLiteralElement;
  5765. begin
  5766. Result:=nil;
  5767. if vmExternal in El.VarModifiers then
  5768. begin
  5769. // external: do not add a declaration
  5770. exit;
  5771. end;
  5772. if AContext is TObjectContext then
  5773. begin
  5774. // create 'A: initvalue'
  5775. Obj:=TObjectContext(AContext).JSElement as TJSObjectLiteral;
  5776. ObjLit:=Obj.Elements.AddElement;
  5777. ObjLit.Name:=TJSString(TransformVariableName(El,AContext));
  5778. ObjLit.Expr:=CreateVarInit(El,AContext);
  5779. end
  5780. else if AContext.IsSingleton then
  5781. begin
  5782. // create 'this.A=initvalue'
  5783. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  5784. Result:=AssignSt;
  5785. AssignSt.LHS:=CreateDeclNameExpression(El,El.Name,AContext);
  5786. AssignSt.Expr:=CreateVarInit(El,AContext);
  5787. end
  5788. else
  5789. begin
  5790. // create 'var A=initvalue'
  5791. C:=ConvertVariable(El,AContext);
  5792. V:=TJSVariableStatement(CreateElement(TJSVariableStatement,El));
  5793. V.A:=C;
  5794. Result:=V;
  5795. end;
  5796. end;
  5797. function TPasToJSConverter.CreateSwitchStatement(El: TPasImplCaseOf;
  5798. AContext: TConvertContext): TJSElement;
  5799. var
  5800. SwitchEl: TJSSwitchStatement;
  5801. JSCaseEl: TJSCaseElement;
  5802. SubEl: TPasImplElement;
  5803. St: TPasImplCaseStatement;
  5804. ok: Boolean;
  5805. i, j: Integer;
  5806. BreakSt: TJSBreakStatement;
  5807. BodySt: TJSElement;
  5808. StList: TJSStatementList;
  5809. Expr: TPasExpr;
  5810. begin
  5811. Result:=nil;
  5812. SwitchEl:=TJSSwitchStatement(CreateElement(TJSSwitchStatement,El));
  5813. ok:=false;
  5814. try
  5815. SwitchEl.Cond:=ConvertExpression(El.CaseExpr,AContext);
  5816. for i:=0 to El.Elements.Count-1 do
  5817. begin
  5818. SubEl:=TPasImplElement(El.Elements[i]);
  5819. if not (SubEl is TPasImplCaseStatement) then
  5820. continue;
  5821. St:=TPasImplCaseStatement(SubEl);
  5822. JSCaseEl:=nil;
  5823. for j:=0 to St.Expressions.Count-1 do
  5824. begin
  5825. Expr:=TPasExpr(St.Expressions[j]);
  5826. JSCaseEl:=SwitchEl.Cases.AddCase;
  5827. JSCaseEl.Expr:=ConvertExpression(Expr,AContext);
  5828. end;
  5829. BodySt:=nil;
  5830. if St.Body<>nil then
  5831. BodySt:=ConvertElement(St.Body,AContext);
  5832. // add break
  5833. BreakSt:=TJSBreakStatement(CreateElement(TJSBreakStatement,St));
  5834. if BodySt=nil then
  5835. // no Pascal statement -> add only one 'break;'
  5836. BodySt:=BreakSt
  5837. else
  5838. begin
  5839. if (BodySt is TJSStatementList) then
  5840. begin
  5841. // list of statements -> append 'break;' to end
  5842. StList:=TJSStatementList(BodySt);
  5843. AddToStatementList(TJSStatementList(BodySt),StList,BreakSt,St);
  5844. end
  5845. else
  5846. begin
  5847. // single statement -> create list of old and 'break;'
  5848. StList:=TJSStatementList(CreateElement(TJSStatementList,St));
  5849. StList.A:=BodySt;
  5850. StList.B:=BreakSt;
  5851. BodySt:=StList;
  5852. end;
  5853. end;
  5854. JSCaseEl.Body:=BodySt;
  5855. end;
  5856. if El.ElseBranch<>nil then
  5857. begin
  5858. JSCaseEl:=SwitchEl.Cases.AddCase;
  5859. JSCaseEl.Body:=ConvertImplBlockElements(El.ElseBranch,AContext,false);
  5860. SwitchEl.TheDefault:=JSCaseEl;
  5861. end;
  5862. ok:=true;
  5863. finally
  5864. if not ok then
  5865. SwitchEl.Free;
  5866. end;
  5867. Result:=SwitchEl;
  5868. end;
  5869. function TPasToJSConverter.ConvertDeclarations(El: TPasDeclarations;
  5870. AContext: TConvertContext): TJSElement;
  5871. Var
  5872. E : TJSElement;
  5873. SLFirst, SLLast: TJSStatementList;
  5874. P: TPasElement;
  5875. IsProcBody, IsFunction, IsAssembler: boolean;
  5876. I : Integer;
  5877. PasProc: TPasProcedure;
  5878. ProcScope: TPasProcedureScope;
  5879. ProcBody: TPasImplBlock;
  5880. Procedure Add(NewEl: TJSElement);
  5881. begin
  5882. if AContext is TObjectContext then
  5883. begin
  5884. // NewEl is already added
  5885. end
  5886. else
  5887. begin
  5888. AddToStatementList(SLFirst,SLLast,NewEl,El);
  5889. ConvertDeclarations:=SLFirst;
  5890. end;
  5891. end;
  5892. Procedure AddFunctionResultInit;
  5893. var
  5894. VarSt: TJSVariableStatement;
  5895. AssignSt: TJSSimpleAssignStatement;
  5896. PasFun: TPasFunction;
  5897. FunType: TPasFunctionType;
  5898. ResultEl: TPasResultElement;
  5899. begin
  5900. PasFun:=El.Parent as TPasFunction;
  5901. FunType:=PasFun.FuncType;
  5902. ResultEl:=FunType.ResultEl;
  5903. // add 'var result=initvalue'
  5904. VarSt:=TJSVariableStatement(CreateElement(TJSVariableStatement,El));
  5905. Add(VarSt);
  5906. Result:=SLFirst;
  5907. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  5908. VarSt.A:=AssignSt;
  5909. AssignSt.LHS:=CreateBuiltInIdentifierExpr(ResolverResultVar);
  5910. AssignSt.Expr:=CreateValInit(ResultEl.ResultType,nil,El,aContext);
  5911. end;
  5912. Procedure AddFunctionResultReturn;
  5913. var
  5914. RetSt: TJSReturnStatement;
  5915. begin
  5916. RetSt:=TJSReturnStatement(CreateElement(TJSReturnStatement,El));
  5917. RetSt.Expr:=CreateBuiltInIdentifierExpr(ResolverResultVar);
  5918. Add(RetSt);
  5919. end;
  5920. begin
  5921. Result:=nil;
  5922. {
  5923. TPasDeclarations = class(TPasElement)
  5924. TPasSection = class(TPasDeclarations)
  5925. TInterfaceSection = class(TPasSection)
  5926. TImplementationSection = class(TPasSection)
  5927. TProgramSection = class(TImplementationSection)
  5928. TLibrarySection = class(TImplementationSection)
  5929. TProcedureBody = class(TPasDeclarations)
  5930. }
  5931. SLFirst:=nil;
  5932. SLLast:=nil;
  5933. IsProcBody:=(El is TProcedureBody) and (TProcedureBody(El).Body<>nil);
  5934. IsFunction:=IsProcBody and (El.Parent is TPasFunction);
  5935. IsAssembler:=IsProcBody and (TProcedureBody(El).Body is TPasImplAsmStatement);
  5936. if IsFunction and not IsAssembler then
  5937. AddFunctionResultInit;
  5938. For I:=0 to El.Declarations.Count-1 do
  5939. begin
  5940. P:=TPasElement(El.Declarations[i]);
  5941. //writeln('TPasToJSConverter.ConvertDeclarations El[',i,']=',GetObjName(P));
  5942. if not IsElementUsed(P) then continue;
  5943. E:=Nil;
  5944. if P.ClassType=TPasConst then
  5945. E:=ConvertConst(TPasConst(P),aContext) // can be nil
  5946. else if P.ClassType=TPasVariable then
  5947. E:=CreateVarDecl(TPasVariable(P),aContext) // can be nil
  5948. else if P is TPasType then
  5949. E:=CreateTypeDecl(TPasType(P),aContext) // can be nil
  5950. else if P is TPasProcedure then
  5951. begin
  5952. PasProc:=TPasProcedure(P);
  5953. if PasProc.IsForward then continue; // JavaScript does not need the forward
  5954. ProcScope:=TPasProcedureScope(PasProc.CustomData);
  5955. if (ProcScope.DeclarationProc<>nil)
  5956. and (not ProcScope.DeclarationProc.IsForward) then
  5957. continue; // this proc was already converted in interface or class
  5958. if ProcScope.DeclarationProc<>nil then
  5959. PasProc:=ProcScope.DeclarationProc;
  5960. E:=ConvertProcedure(PasProc,aContext);
  5961. end
  5962. else
  5963. RaiseNotSupported(P as TPasElement,AContext,20161024191434);
  5964. Add(E);
  5965. end;
  5966. if IsProcBody then
  5967. begin
  5968. ProcBody:=TProcedureBody(El).Body;
  5969. if (ProcBody.Elements.Count>0) or IsAssembler then
  5970. begin
  5971. E:=ConvertElement(TProcedureBody(El).Body,aContext);
  5972. Add(E);
  5973. end;
  5974. end;
  5975. if IsFunction and not IsAssembler then
  5976. AddFunctionResultReturn;
  5977. end;
  5978. function TPasToJSConverter.ConvertClassType(El: TPasClassType;
  5979. AContext: TConvertContext): TJSElement;
  5980. (*
  5981. type
  5982. TMyClass = class(Ancestor)
  5983. i: longint;
  5984. end;
  5985. rtl.createClass(this,"TMyClass",Ancestor,function(){
  5986. this.i = 0;
  5987. });
  5988. *)
  5989. type
  5990. TMemberFunc = (mfInit, mfFinalize);
  5991. const
  5992. MemberFuncName: array[TMemberFunc] of string = (
  5993. '$init',
  5994. '$final'
  5995. );
  5996. var
  5997. IsTObject, AncestorIsExternal: boolean;
  5998. function IsMemberNeeded(aMember: TPasElement): boolean;
  5999. begin
  6000. if IsElementUsed(aMember) then exit(true);
  6001. if IsTObject then
  6002. begin
  6003. if aMember is TPasProcedure then
  6004. begin
  6005. if (CompareText(aMember.Name,'AfterConstruction')=0)
  6006. or (CompareText(aMember.Name,'BeforeDestruction')=0) then
  6007. exit(true);
  6008. end;
  6009. end;
  6010. Result:=false;
  6011. end;
  6012. procedure AddCallAncestorMemberFunction(ClassContext: TConvertContext;
  6013. Ancestor: TPasType; Src: TJSSourceElements; Kind: TMemberFunc);
  6014. var
  6015. Call: TJSCallExpression;
  6016. AncestorPath: String;
  6017. begin
  6018. if (Ancestor=nil) or AncestorIsExternal then
  6019. exit;
  6020. Call:=CreateCallExpression(El);
  6021. AncestorPath:=CreateReferencePath(Ancestor,ClassContext,rpkPathAndName);
  6022. Call.Expr:=CreateBuiltInIdentifierExpr(AncestorPath+'.'+MemberFuncName[Kind]+'.call');
  6023. Call.Args.Elements.AddElement.Expr:=CreateBuiltInIdentifierExpr('this');
  6024. AddToSourceElements(Src,Call);
  6025. end;
  6026. procedure AddInstanceMemberFunction(Src: TJSSourceElements;
  6027. ClassContext: TConvertContext; Ancestor: TPasType; Kind: TMemberFunc);
  6028. // add instance initialization function:
  6029. // this.$init = function(){
  6030. // ancestor.$init();
  6031. // ... init variables ...
  6032. // }
  6033. // or add instance finalization function:
  6034. // this.$final = function(){
  6035. // ... clear references ...
  6036. // ancestor.$final();
  6037. // }
  6038. var
  6039. FuncVD: TJSVarDeclaration;
  6040. New_Src: TJSSourceElements;
  6041. New_FuncContext: TFunctionContext;
  6042. I: Integer;
  6043. P: TPasElement;
  6044. NewEl: TJSElement;
  6045. Func: TJSFunctionDeclarationStatement;
  6046. VarType: TPasType;
  6047. AssignSt: TJSSimpleAssignStatement;
  6048. begin
  6049. // add instance members
  6050. New_Src:=TJSSourceElements(CreateElement(TJSSourceElements, El));
  6051. New_FuncContext:=TFunctionContext.Create(El,New_Src,ClassContext);
  6052. try
  6053. New_FuncContext.This:=El;
  6054. New_FuncContext.IsSingleton:=true;
  6055. // add class members
  6056. For I:=0 to El.Members.Count-1 do
  6057. begin
  6058. P:=TPasElement(El.Members[i]);
  6059. if not IsMemberNeeded(P) then continue;
  6060. NewEl:=nil;
  6061. if (P.ClassType=TPasVariable)
  6062. and (ClassVarModifiersType*TPasVariable(P).VarModifiers=[]) then
  6063. begin
  6064. if Kind=mfInit then
  6065. // mfInit: init var
  6066. NewEl:=CreateVarDecl(TPasVariable(P),New_FuncContext) // can be nil
  6067. else
  6068. begin
  6069. // mfFinalize: clear reference
  6070. if vmExternal in TPasVariable(P).VarModifiers then continue;
  6071. VarType:=ClassContext.Resolver.ResolveAliasType(TPasVariable(P).VarType);
  6072. if (VarType.ClassType=TPasRecordType)
  6073. or (VarType.ClassType=TPasClassType)
  6074. or (VarType.ClassType=TPasClassOfType)
  6075. or (VarType.ClassType=TPasSetType)
  6076. or (VarType.ClassType=TPasProcedureType)
  6077. or (VarType.ClassType=TPasFunctionType)
  6078. or (VarType.ClassType=TPasArrayType) then
  6079. begin
  6080. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  6081. NewEl:=AssignSt;
  6082. AssignSt.LHS:=CreateDeclNameExpression(P,P.Name,New_FuncContext);
  6083. AssignSt.Expr:=CreateLiteralUndefined(El);
  6084. end;
  6085. end;
  6086. end;
  6087. if NewEl=nil then continue;
  6088. if (Kind=mfInit) and (New_Src.Statements.Count=0) then
  6089. // add call ancestor.$init.call(this)
  6090. AddCallAncestorMemberFunction(ClassContext,Ancestor,New_Src,Kind);
  6091. AddToSourceElements(New_Src,NewEl);
  6092. end;
  6093. if (Kind=mfFinalize) and (New_Src.Statements.Count>0) then
  6094. // call ancestor.$final.call(this)
  6095. AddCallAncestorMemberFunction(ClassContext,Ancestor,New_Src,Kind);
  6096. if (Ancestor<>nil) and (not AncestorIsExternal)
  6097. and (New_Src.Statements.Count=0) then
  6098. exit; // descendent does not need $init/$final
  6099. FuncVD:=TJSVarDeclaration(CreateElement(TJSVarDeclaration,El));
  6100. AddToSourceElements(Src,FuncVD);
  6101. FuncVD.Name:='this.'+MemberFuncName[Kind];
  6102. Func:=CreateFunction(El);
  6103. FuncVD.Init:=Func;
  6104. Func.AFunction.Body.A:=New_Src;
  6105. New_Src:=nil;
  6106. finally
  6107. New_Src.Free;
  6108. New_FuncContext.Free;
  6109. end;
  6110. end;
  6111. var
  6112. Call: TJSCallExpression;
  6113. FunDecl: TJSFunctionDeclarationStatement;
  6114. FunDef: TJSFuncDef;
  6115. Src: TJSSourceElements;
  6116. ArgEx: TJSLiteral;
  6117. FuncContext: TFunctionContext;
  6118. i: Integer;
  6119. NewEl: TJSElement;
  6120. P: TPasElement;
  6121. Scope: TPas2JSClassScope;
  6122. Ancestor: TPasType;
  6123. AncestorPath: String;
  6124. C: TClass;
  6125. begin
  6126. Result:=nil;
  6127. if El.IsForward then
  6128. exit(nil);
  6129. if El.IsExternal then exit;
  6130. if El.CustomData is TPas2JSClassScope then
  6131. Scope:=TPas2JSClassScope(El.CustomData)
  6132. else
  6133. Scope:=nil;
  6134. IsTObject:=CompareText(El.Name,'TObject')=0;
  6135. if (Scope<>nil) and (Scope.AncestorScope<>nil) then
  6136. Ancestor:=Scope.AncestorScope.Element as TPasType
  6137. else
  6138. Ancestor:=El.AncestorType;
  6139. // create call 'rtl.createClass('
  6140. Call:=CreateCallExpression(El);
  6141. try
  6142. AncestorIsExternal:=(Ancestor is TPasClassType) and TPasClassType(Ancestor).IsExternal;
  6143. if AncestorIsExternal then
  6144. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnCreateClassExt]])
  6145. else
  6146. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnCreateClass]]);
  6147. // add parameter: owner. 'this' for top level class.
  6148. Call.Args.Elements.AddElement.Expr:=CreateBuiltInIdentifierExpr('this');
  6149. // add parameter: string constant '"classname"'
  6150. ArgEx := CreateLiteralString(El,TransformVariableName(El,AContext));
  6151. Call.Args.Elements.AddElement.Expr:=ArgEx;
  6152. // add parameter: ancestor
  6153. if Ancestor=nil then
  6154. AncestorPath:='null'
  6155. else if AncestorIsExternal then
  6156. AncestorPath:=TPasClassType(Ancestor).ExternalName
  6157. else
  6158. AncestorPath:=CreateReferencePath(Ancestor,AContext,rpkPathAndName);
  6159. Call.Args.Elements.AddElement.Expr:=CreateBuiltInIdentifierExpr(AncestorPath);
  6160. if AncestorIsExternal then
  6161. begin
  6162. // add the name of the NewInstance function
  6163. if Scope.NewInstanceFunction<>nil then
  6164. Call.Args.Elements.AddElement.Expr:=CreateLiteralString(
  6165. Scope.NewInstanceFunction,Scope.NewInstanceFunction.Name)
  6166. else
  6167. Call.Args.Elements.AddElement.Expr:=CreateLiteralString(El,'');
  6168. end;
  6169. // add parameter: class initialize function 'function(){...}'
  6170. FunDecl:=TJSFunctionDeclarationStatement.Create(0,0);
  6171. Call.Args.Elements.AddElement.Expr:=FunDecl;
  6172. FunDef:=TJSFuncDef.Create;
  6173. FunDecl.AFunction:=FunDef;
  6174. FunDef.Name:='';
  6175. FunDef.Body:=TJSFunctionBody.Create(0,0);
  6176. Src:=TJSSourceElements(CreateElement(TJSSourceElements, El));
  6177. FunDef.Body.A:=Src;
  6178. // add members
  6179. FuncContext:=TFunctionContext.Create(El,Src,AContext);
  6180. try
  6181. FuncContext.IsSingleton:=true;
  6182. FuncContext.This:=El;
  6183. // add class members: types and class vars
  6184. For i:=0 to El.Members.Count-1 do
  6185. begin
  6186. P:=TPasElement(El.Members[i]);
  6187. //writeln('TPasToJSConverter.ConvertClassType class El[',i,']=',GetObjName(P));
  6188. if not IsMemberNeeded(P) then continue;
  6189. C:=P.ClassType;
  6190. NewEl:=nil;
  6191. if C=TPasVariable then
  6192. begin
  6193. if ClassVarModifiersType*TPasVariable(P).VarModifiers<>[] then
  6194. begin
  6195. NewEl:=CreateVarDecl(TPasVariable(P),FuncContext); // can be nil
  6196. if NewEl=nil then continue;
  6197. end
  6198. else
  6199. continue;
  6200. end
  6201. else if C=TPasConst then
  6202. NewEl:=ConvertConst(TPasConst(P),aContext)
  6203. else if C=TPasProperty then
  6204. begin
  6205. NewEl:=ConvertProperty(TPasProperty(P),AContext);
  6206. if NewEl=nil then continue;
  6207. end
  6208. else if C.InheritsFrom(TPasType) then
  6209. NewEl:=CreateTypeDecl(TPasType(P),aContext)
  6210. else if C.InheritsFrom(TPasProcedure) then
  6211. continue
  6212. else
  6213. RaiseNotSupported(P,FuncContext,20161221233338);
  6214. if NewEl=nil then
  6215. RaiseNotSupported(P,FuncContext,20170204223922);
  6216. AddToSourceElements(Src,NewEl);
  6217. end;
  6218. // instance initialization function
  6219. AddInstanceMemberFunction(Src,FuncContext,Ancestor,mfInit);
  6220. // instance finalization function
  6221. AddInstanceMemberFunction(Src,FuncContext,Ancestor,mfFinalize);
  6222. // add methods
  6223. For i:=0 to El.Members.Count-1 do
  6224. begin
  6225. P:=TPasElement(El.Members[i]);
  6226. //writeln('TPasToJSConverter.ConvertClassType class El[',i,']=',GetObjName(P));
  6227. if not IsMemberNeeded(P) then continue;
  6228. if P is TPasProcedure then
  6229. NewEl:=ConvertProcedure(TPasProcedure(P),aContext)
  6230. else
  6231. continue;
  6232. if NewEl=nil then
  6233. continue; // e.g. abstract or external proc
  6234. AddToSourceElements(Src,NewEl);
  6235. end;
  6236. finally
  6237. FuncContext.Free;
  6238. end;
  6239. Result:=Call;
  6240. finally
  6241. if Result<>Call then
  6242. Call.Free;
  6243. end;
  6244. end;
  6245. function TPasToJSConverter.ConvertClassExternalType(El: TPasClassType;
  6246. AContext: TConvertContext): TJSElement;
  6247. function IsMemberNeeded(aMember: TPasElement): boolean;
  6248. begin
  6249. Result:=IsElementUsed(aMember);
  6250. end;
  6251. var
  6252. i: Integer;
  6253. P: TPasElement;
  6254. C: TClass;
  6255. Proc: TPasProcedure;
  6256. begin
  6257. Result:=nil;
  6258. if El.IsForward then exit;
  6259. // add class members: types and class vars
  6260. For i:=0 to El.Members.Count-1 do
  6261. begin
  6262. P:=TPasElement(El.Members[i]);
  6263. //writeln('TPasToJSConverter.ConvertClassExternalType class El[',i,']=',GetObjName(P));
  6264. if not IsMemberNeeded(P) then continue;
  6265. C:=P.ClassType;
  6266. if (C=TPasVariable) or (C=TPasConst) then
  6267. begin
  6268. if not (vmExternal in TPasVariable(P).VarModifiers) then
  6269. DoError(20170321150737,nMissingExternalName,sMissingExternalName,[],P);
  6270. end
  6271. else if C=TPasProperty then
  6272. // is replaced with Getter/Setter -> nothing to do here
  6273. else if C.InheritsFrom(TPasProcedure) then
  6274. begin
  6275. Proc:=TPasProcedure(P);
  6276. if Proc.IsExternal then
  6277. // external, nothing to do here
  6278. else
  6279. DoError(20170321152209,nMissingExternalName,sMissingExternalName,[],P);
  6280. end
  6281. else
  6282. RaiseNotSupported(P,AContext,20170321151727);
  6283. end;
  6284. end;
  6285. function TPasToJSConverter.ConvertEnumType(El: TPasEnumType;
  6286. AContext: TConvertContext): TJSElement;
  6287. // TMyEnum = (red, green)
  6288. // convert to
  6289. // this.TMyEnum = {
  6290. // "0":"red",
  6291. // "red":0,
  6292. // "0":"green",
  6293. // "green":0,
  6294. // }
  6295. var
  6296. ObjectContect: TObjectContext;
  6297. i: Integer;
  6298. EnumValue: TPasEnumValue;
  6299. ParentObj, Obj: TJSObjectLiteral;
  6300. ObjLit: TJSObjectLiteralElement;
  6301. AssignSt: TJSSimpleAssignStatement;
  6302. JSName: TJSString;
  6303. begin
  6304. Result:=nil;
  6305. for i:=0 to El.Values.Count-1 do
  6306. begin
  6307. EnumValue:=TPasEnumValue(El.Values[i]);
  6308. if EnumValue.Value<>nil then
  6309. RaiseNotSupported(EnumValue.Value,AContext,20170208145221,'enum constant');
  6310. end;
  6311. ObjectContect:=nil;
  6312. try
  6313. Obj:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,El));
  6314. if AContext is TObjectContext then
  6315. begin
  6316. // add 'TypeName: function(){}'
  6317. ParentObj:=TObjectContext(AContext).JSElement as TJSObjectLiteral;
  6318. ObjLit:=ParentObj.Elements.AddElement;
  6319. ObjLit.Name:=TJSString(TransformVariableName(El,AContext));
  6320. ObjLit.Expr:=Obj;
  6321. Result:=Obj;
  6322. end
  6323. else
  6324. begin
  6325. // add 'this.TypeName = function(){}'
  6326. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  6327. AssignSt.LHS:=CreateDeclNameExpression(El,El.Name,AContext);
  6328. AssignSt.Expr:=Obj;
  6329. Result:=AssignSt;
  6330. end;
  6331. ObjectContect:=TObjectContext.Create(El,Obj,AContext);
  6332. for i:=0 to El.Values.Count-1 do
  6333. begin
  6334. EnumValue:=TPasEnumValue(El.Values[i]);
  6335. JSName:=TJSString(TransformVariableName(EnumValue,AContext));
  6336. // add "0":"value"
  6337. ObjLit:=Obj.Elements.AddElement;
  6338. ObjLit.Name:=TJSString(IntToStr(i));
  6339. ObjLit.Expr:=CreateLiteralJSString(El,JSName);
  6340. // add value:0
  6341. ObjLit:=Obj.Elements.AddElement;
  6342. ObjLit.Name:=JSName;
  6343. ObjLit.Expr:=CreateLiteralNumber(El,i);
  6344. end;
  6345. finally
  6346. ObjectContect.Free;
  6347. end;
  6348. end;
  6349. procedure TPasToJSConverter.ForLoop_OnProcBodyElement(El: TPasElement;
  6350. arg: pointer);
  6351. // Called by ConvertForStatement on each element of the current proc body
  6352. // Check each element that lies behind the loop if it is reads the LoopVar
  6353. var
  6354. Data: PForLoopFindData absolute arg;
  6355. begin
  6356. if El.HasParent(Data^.ForLoop) then
  6357. Data^.FoundLoop:=true
  6358. else if Data^.FoundLoop and (not Data^.LoopVarWrite) and (not Data^.LoopVarRead) then
  6359. begin
  6360. // El comes after loop and LoopVar was not yet accessed
  6361. if (El.CustomData is TResolvedReference)
  6362. and (TResolvedReference(El.CustomData).Declaration=Data^.LoopVar) then
  6363. begin
  6364. // El refers the LoopVar
  6365. // ToDo: check write only access
  6366. Data^.LoopVarRead:=true;
  6367. end;
  6368. end;
  6369. end;
  6370. procedure TPasToJSConverter.TryExcept_OnElement(El: TPasElement; arg: pointer);
  6371. var
  6372. Data: PTryExceptFindData absolute arg;
  6373. begin
  6374. if (El is TPasImplRaise) and (TPasImplRaise(El).ExceptObject=nil) then
  6375. Data^.HasRaiseWithoutObject:=true;
  6376. end;
  6377. procedure TPasToJSConverter.SetUseEnumNumbers(const AValue: boolean);
  6378. begin
  6379. if AValue then
  6380. Include(FOptions,coEnumNumbers)
  6381. else
  6382. Exclude(FOptions,coEnumNumbers);
  6383. end;
  6384. procedure TPasToJSConverter.SetUseLowerCase(const AValue: boolean);
  6385. begin
  6386. if AValue then
  6387. Include(FOptions,coLowerCase)
  6388. else
  6389. Exclude(FOptions,coLowerCase);
  6390. end;
  6391. procedure TPasToJSConverter.SetUseSwitchStatement(const AValue: boolean);
  6392. begin
  6393. if AValue then
  6394. Include(FOptions,coSwitchStatement)
  6395. else
  6396. Exclude(FOptions,coSwitchStatement);
  6397. end;
  6398. constructor TPasToJSConverter.Create;
  6399. var
  6400. n: TPas2JSBuiltInName;
  6401. begin
  6402. FOptions:=[coLowerCase];
  6403. for n in TPas2JSBuiltInName do
  6404. FBuiltInNames[n]:=Pas2JSBuiltInNames[n];
  6405. end;
  6406. destructor TPasToJSConverter.Destroy;
  6407. begin
  6408. inherited Destroy;
  6409. end;
  6410. function TPasToJSConverter.ConvertProcedure(El: TPasProcedure;
  6411. AContext: TConvertContext): TJSElement;
  6412. Var
  6413. FS : TJSFunctionDeclarationStatement;
  6414. FD : TJSFuncDef;
  6415. n:Integer;
  6416. AssignSt: TJSSimpleAssignStatement;
  6417. FuncContext: TFunctionContext;
  6418. ProcScope: TPasProcedureScope;
  6419. Arg: TPasArgument;
  6420. ImplProc: TPasProcedure;
  6421. begin
  6422. Result:=nil;
  6423. if El.IsAbstract then exit;
  6424. if El.IsExternal then exit;
  6425. ProcScope:=TPasProcedureScope(El.CustomData);
  6426. if ProcScope.DeclarationProc<>nil then
  6427. exit;
  6428. {$IFDEF VerbosePas2JS}
  6429. writeln('TPasToJSConverter.ConvertProcedure "',El.Name,'" ',El.Parent.ClassName);
  6430. {$ENDIF}
  6431. ImplProc:=El;
  6432. if ProcScope.ImplProc<>nil then
  6433. ImplProc:=ProcScope.ImplProc;
  6434. AssignSt:=nil;
  6435. if AContext.IsSingleton then
  6436. begin
  6437. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  6438. Result:=AssignSt;
  6439. AssignSt.LHS:=CreateDeclNameExpression(El,El.Name,AContext);
  6440. end;
  6441. FS:=CreateFunction(El,ImplProc.Body<>nil);
  6442. FD:=FS.AFunction;
  6443. if AssignSt<>nil then
  6444. AssignSt.Expr:=FS
  6445. else
  6446. begin
  6447. // local/nested function
  6448. Result:=FS;
  6449. FD.Name:=TJSString(TransformVariableName(El,AContext));
  6450. end;
  6451. for n := 0 to El.ProcType.Args.Count - 1 do
  6452. begin
  6453. Arg:=TPasArgument(El.ProcType.Args[n]);
  6454. FD.Params.Add(TransformVariableName(Arg,AContext));
  6455. end;
  6456. if ImplProc.Body<>nil then
  6457. begin
  6458. FuncContext:=TFunctionContext.Create(ImplProc,FD.Body,AContext);
  6459. try
  6460. if ProcScope.ClassScope<>nil then
  6461. FuncContext.This:=ProcScope.ClassScope.Element
  6462. else
  6463. FuncContext.This:=AContext.GetThis;
  6464. FD.Body.A:=ConvertDeclarations(ImplProc.Body,FuncContext);
  6465. finally
  6466. FuncContext.Free;
  6467. end;
  6468. end;
  6469. {
  6470. TPasProcedureBase = class(TPasElement)
  6471. TPasOverloadedProc = class(TPasProcedureBase)
  6472. TPasProcedure = class(TPasProcedureBase)
  6473. TPasFunction = class(TPasProcedure)
  6474. TPasOperator = class(TPasProcedure)
  6475. TPasConstructor = class(TPasProcedure)
  6476. TPasDestructor = class(TPasProcedure)
  6477. TPasClassProcedure = class(TPasProcedure)
  6478. TPasClassFunction = class(TPasProcedure)
  6479. }
  6480. end;
  6481. function TPasToJSConverter.ConvertBeginEndStatement(El: TPasImplBeginBlock;
  6482. AContext: TConvertContext; NilIfEmpty: boolean): TJSElement;
  6483. begin
  6484. Result:=ConvertImplBlockElements(El,AContext,NilIfEmpty);
  6485. end;
  6486. function TPasToJSConverter.ConvertImplBlockElements(El: TPasImplBlock;
  6487. AContext: TConvertContext; NilIfEmpty: boolean): TJSElement;
  6488. var
  6489. First, Last: TJSStatementList;
  6490. I : Integer;
  6491. PasImpl: TPasImplElement;
  6492. JSImpl : TJSElement;
  6493. begin
  6494. if Not (Assigned(El.Elements) and (El.Elements.Count>0)) then
  6495. begin
  6496. if NilIfEmpty then
  6497. Result:=nil
  6498. else
  6499. Result:=TJSEmptyBlockStatement(CreateElement(TJSEmptyBlockStatement,El));
  6500. end
  6501. else
  6502. begin
  6503. First:=nil;
  6504. Result:=First;
  6505. Last:=First;
  6506. //writeln('TPasToJSConverter.ConvertImplBlockElements START El.Elements.Count=',El.Elements.Count);
  6507. For I:=0 to El.Elements.Count-1 do
  6508. begin
  6509. PasImpl:=TPasImplElement(El.Elements[i]);
  6510. JSImpl:=ConvertElement(PasImpl,AContext);
  6511. if JSImpl=nil then
  6512. continue; // e.g. "inherited;" when there is no ancestor proc
  6513. //writeln('TPasToJSConverter.ConvertImplBlockElements ',i,' ',JSImpl.ClassName);
  6514. AddToStatementList(First,Last,JSImpl,PasImpl);
  6515. Result:=First;
  6516. end;
  6517. end;
  6518. end;
  6519. function TPasToJSConverter.ConvertInitializationSection(
  6520. El: TInitializationSection; AContext: TConvertContext): TJSElement;
  6521. var
  6522. FDS: TJSFunctionDeclarationStatement;
  6523. FunName: String;
  6524. IsMain, ok: Boolean;
  6525. AssignSt: TJSSimpleAssignStatement;
  6526. FuncContext: TFunctionContext;
  6527. Body: TJSFunctionBody;
  6528. begin
  6529. // create: 'this.$init=function(){}'
  6530. IsMain:=(El.Parent<>nil) and (El.Parent is TPasProgram);
  6531. if IsMain then
  6532. FunName:=FBuiltInNames[pbifnProgramMain]
  6533. else
  6534. FunName:=FBuiltInNames[pbifnUnitInit];
  6535. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  6536. Result:=AssignSt;
  6537. FuncContext:=nil;
  6538. ok:=false;
  6539. try
  6540. AssignSt.LHS:=CreateMemberExpression(['this',FunName]);
  6541. FDS:=CreateFunction(El,El.Elements.Count>0);
  6542. AssignSt.Expr:=FDS;
  6543. if El.Elements.Count>0 then
  6544. begin
  6545. Body:=FDS.AFunction.Body;
  6546. FuncContext:=TFunctionContext.Create(El,Body,AContext);
  6547. FuncContext.This:=AContext.GetThis;
  6548. Body.A:=ConvertImplBlockElements(El,FuncContext,false);
  6549. end;
  6550. ok:=true;
  6551. finally
  6552. FuncContext.Free;
  6553. if not ok then FreeAndNil(Result);
  6554. end;
  6555. end;
  6556. function TPasToJSConverter.ConvertFinalizationSection(El: TFinalizationSection;
  6557. AContext: TConvertContext): TJSElement;
  6558. begin
  6559. Result:=nil;
  6560. RaiseNotSupported(El,AContext,20161024192519);
  6561. end;
  6562. function TPasToJSConverter.ConvertTryStatement(El: TPasImplTry;
  6563. AContext: TConvertContext): TJSElement;
  6564. function NeedExceptObject: boolean;
  6565. var
  6566. Data: TTryExceptFindData;
  6567. begin
  6568. Result:=false;
  6569. if El.FinallyExcept.Elements.Count=0 then exit;
  6570. if TPasElement(El.FinallyExcept.Elements[0]) is TPasImplExceptOn then
  6571. exit(true);
  6572. Data:=Default(TTryExceptFindData);
  6573. El.FinallyExcept.ForEachCall(@TryExcept_OnElement,@Data);
  6574. Result:=Data.HasRaiseWithoutObject;
  6575. end;
  6576. Var
  6577. T : TJSTryStatement;
  6578. ExceptBlock: TPasImplTryHandler;
  6579. i: Integer;
  6580. ExceptOn: TPasImplExceptOn;
  6581. IfSt, Last: TJSIfStatement;
  6582. begin
  6583. Result:=nil;
  6584. T:=nil;
  6585. try
  6586. if El.FinallyExcept is TPasImplTryFinally then
  6587. begin
  6588. T:=TJSTryFinallyStatement(CreateElement(TJSTryFinallyStatement,El));
  6589. T.Block:=ConvertImplBlockElements(El,AContext,true);
  6590. T.BFinally:=ConvertImplBlockElements(El.FinallyExcept,AContext,true);
  6591. end
  6592. else
  6593. begin
  6594. T:=TJSTryCatchStatement(CreateElement(TJSTryCatchStatement,El));
  6595. T.Block:=ConvertImplBlockElements(El,AContext,true);
  6596. if NeedExceptObject then
  6597. T.Ident:=TJSString(FBuiltInNames[pbivnExceptObject]);
  6598. //T.BCatch:=ConvertElement(El.FinallyExcept,AContext);
  6599. ExceptBlock:=El.FinallyExcept;
  6600. if (ExceptBlock.Elements.Count>0)
  6601. and (TPasImplElement(ExceptBlock.Elements[0]) is TPasImplExceptOn) then
  6602. begin
  6603. Last:=nil;
  6604. for i:=0 to ExceptBlock.Elements.Count-1 do
  6605. begin
  6606. ExceptOn:=TObject(ExceptBlock.Elements[i]) as TPasImplExceptOn;
  6607. IfSt:=ConvertExceptOn(ExceptOn,AContext) as TJSIfStatement;
  6608. if Last=nil then
  6609. T.BCatch:=IfSt
  6610. else
  6611. Last.BFalse:=IfSt;
  6612. Last:=IfSt;
  6613. end;
  6614. if El.ElseBranch<>nil then
  6615. Last.BFalse:=ConvertImplBlockElements(El.ElseBranch,AContext,true)
  6616. else
  6617. begin
  6618. // default else: throw exceptobject
  6619. Last.BFalse:=TJSThrowStatement(CreateElement(TJSThrowStatement,El));
  6620. TJSThrowStatement(Last.BFalse).A:=
  6621. CreateBuiltInIdentifierExpr(FBuiltInNames[pbivnExceptObject]);
  6622. end;
  6623. end
  6624. else
  6625. begin
  6626. if El.ElseBranch<>nil then
  6627. RaiseNotSupported(El.ElseBranch,AContext,20170205003014);
  6628. T.BCatch:=ConvertImplBlockElements(ExceptBlock,AContext,true);
  6629. end;
  6630. end;
  6631. Result:=T;
  6632. finally
  6633. if Result=nil then
  6634. T.Free;
  6635. end;
  6636. end;
  6637. function TPasToJSConverter.ConvertCaseOfStatement(El: TPasImplCaseOf;
  6638. AContext: TConvertContext): TJSElement;
  6639. var
  6640. SubEl: TPasImplElement;
  6641. St: TPasImplCaseStatement;
  6642. ok: Boolean;
  6643. i, j: Integer;
  6644. JSExpr: TJSElement;
  6645. StList: TJSStatementList;
  6646. Expr: TPasExpr;
  6647. IfSt, LastIfSt: TJSIfStatement;
  6648. TmpVarName: String;
  6649. VarDecl: TJSVarDeclaration;
  6650. VarSt: TJSVariableStatement;
  6651. JSOrExpr: TJSLogicalOrExpression;
  6652. JSAndExpr: TJSLogicalAndExpression;
  6653. JSLEExpr: TJSRelationalExpressionLE;
  6654. JSGEExpr: TJSRelationalExpressionGE;
  6655. JSEQExpr: TJSEqualityExpressionEQ;
  6656. begin
  6657. Result:=nil;
  6658. if UseSwitchStatement then
  6659. begin
  6660. // convert to switch statement
  6661. // switch does not support ranges -> check
  6662. ok:=true;
  6663. for i:=0 to El.Elements.Count-1 do
  6664. begin
  6665. SubEl:=TPasImplElement(El.Elements[i]);
  6666. if not (SubEl is TPasImplCaseStatement) then
  6667. continue;
  6668. St:=TPasImplCaseStatement(SubEl);
  6669. for j:=0 to St.Expressions.Count-1 do
  6670. begin
  6671. Expr:=TPasExpr(St.Expressions[j]);
  6672. if (Expr is TBinaryExpr) and (TBinaryExpr(Expr).Kind=pekRange) then
  6673. begin
  6674. ok:=false;
  6675. break;
  6676. end;
  6677. end;
  6678. if not ok then break;
  6679. end;
  6680. if ok then
  6681. begin
  6682. Result:=CreateSwitchStatement(El,AContext);
  6683. exit;
  6684. end;
  6685. end;
  6686. // convert to if statements
  6687. StList:=TJSStatementList(CreateElement(TJSStatementList,El));
  6688. ok:=false;
  6689. try
  6690. // create var $tmp=CaseExpr;
  6691. TmpVarName:=AContext.CreateLocalIdentifier('$tmp');
  6692. VarSt:=TJSVariableStatement(CreateElement(TJSVariableStatement,El.CaseExpr));
  6693. StList.A:=VarSt;
  6694. VarDecl:=TJSVarDeclaration(CreateElement(TJSVarDeclaration,El.CaseExpr));
  6695. VarSt.A:=VarDecl;
  6696. VarDecl.Name:=TmpVarName;
  6697. VarDecl.Init:=ConvertExpression(El.CaseExpr,AContext);
  6698. LastIfSt:=nil;
  6699. for i:=0 to El.Elements.Count-1 do
  6700. begin
  6701. SubEl:=TPasImplElement(El.Elements[i]);
  6702. if SubEl is TPasImplCaseStatement then
  6703. begin
  6704. St:=TPasImplCaseStatement(SubEl);
  6705. // create for example "if (tmp==expr) || ((tmp>=expr) && (tmp<=expr)){}"
  6706. IfSt:=TJSIfStatement(CreateElement(TJSIfStatement,SubEl));
  6707. if LastIfSt=nil then
  6708. StList.B:=IfSt
  6709. else
  6710. LastIfSt.BFalse:=IfSt;
  6711. LastIfSt:=IfSt;
  6712. for j:=0 to St.Expressions.Count-1 do
  6713. begin
  6714. Expr:=TPasExpr(St.Expressions[j]);
  6715. if (Expr is TBinaryExpr) and (TBinaryExpr(Expr).Kind=pekRange) then
  6716. begin
  6717. // range -> create "(tmp>=left) && (tmp<=right)"
  6718. // create "() && ()"
  6719. JSAndExpr:=TJSLogicalAndExpression(CreateElement(TJSLogicalAndExpression,Expr));
  6720. JSExpr:=JSAndExpr;
  6721. // create "tmp>=left"
  6722. JSGEExpr:=TJSRelationalExpressionGE(CreateElement(TJSRelationalExpressionGE,Expr));
  6723. JSAndExpr.A:=JSGEExpr;
  6724. JSGEExpr.A:=CreateIdentifierExpr(TmpVarName,El.CaseExpr,AContext);
  6725. JSGEExpr.B:=ConvertExpression(TBinaryExpr(Expr).left,AContext);
  6726. // create "tmp<=right"
  6727. JSLEExpr:=TJSRelationalExpressionLE(CreateElement(TJSRelationalExpressionLE,Expr));
  6728. JSAndExpr.B:=JSLEExpr;
  6729. JSLEExpr.A:=CreateIdentifierExpr(TmpVarName,El.CaseExpr,AContext);
  6730. JSLEExpr.B:=ConvertExpression(TBinaryExpr(Expr).right,AContext);
  6731. end
  6732. else
  6733. begin
  6734. // value -> create (tmp==Expr)
  6735. JSEQExpr:=TJSEqualityExpressionEQ(CreateElement(TJSEqualityExpressionEQ,Expr));
  6736. JSExpr:=JSEQExpr;
  6737. JSEQExpr.A:=CreateIdentifierExpr(TmpVarName,El.CaseExpr,AContext);
  6738. JSEQExpr.B:=ConvertExpression(Expr,AContext);
  6739. end;
  6740. if IfSt.Cond=nil then
  6741. // first expression
  6742. IfSt.Cond:=JSExpr
  6743. else
  6744. begin
  6745. // multi expression -> append with OR
  6746. JSOrExpr:=TJSLogicalOrExpression(CreateElement(TJSLogicalOrExpression,St));
  6747. JSOrExpr.A:=IfSt.Cond;
  6748. JSOrExpr.B:=JSExpr;
  6749. IfSt.Cond:=JSOrExpr;
  6750. end;
  6751. end;
  6752. // convert statement
  6753. if St.Body<>nil then
  6754. IfSt.BTrue:=ConvertElement(St.Body,AContext)
  6755. else
  6756. IfSt.BTrue:=TJSEmptyStatement(CreateElement(TJSEmptyStatement,St));
  6757. end
  6758. else if SubEl is TPasImplCaseElse then
  6759. begin
  6760. // Pascal 'else' or 'otherwise' -> create JS "else{}"
  6761. if LastIfSt=nil then
  6762. RaiseNotSupported(SubEl,AContext,20161128120802,'case-of needs at least one case');
  6763. LastIfSt.BFalse:=ConvertImplBlockElements(El.ElseBranch,AContext,true);
  6764. end
  6765. else
  6766. RaiseNotSupported(SubEl,AContext,20161128113055);
  6767. end;
  6768. ok:=true;
  6769. finally
  6770. if not ok then
  6771. StList.Free;
  6772. end;
  6773. Result:=StList;
  6774. end;
  6775. function TPasToJSConverter.ConvertAsmStatement(El: TPasImplAsmStatement;
  6776. AContext: TConvertContext): TJSElement;
  6777. var
  6778. s: String;
  6779. L: TJSLiteral;
  6780. begin
  6781. if AContext=nil then ;
  6782. s:=Trim(El.Tokens.Text);
  6783. if (s<>'') and (s[length(s)]=';') then
  6784. Delete(s,length(s),1);
  6785. if s='' then
  6786. Result:=TJSEmptyStatement(CreateElement(TJSEmptyStatement,El))
  6787. else begin
  6788. L:=TJSLiteral(CreateElement(TJSLiteral,El));
  6789. L.Value.CustomValue:=TJSString(s);
  6790. Result:=L;
  6791. end;
  6792. end;
  6793. function TPasToJSConverter.CreateImplementationSection(El: TPasModule;
  6794. Src: TJSSourceElements; AContext: TConvertContext): TJSElement;
  6795. var
  6796. Section: TImplementationSection;
  6797. begin
  6798. Result:=nil;
  6799. if not Assigned(El.ImplementationSection) then
  6800. exit;
  6801. Section:=El.ImplementationSection;
  6802. // add implementation section
  6803. // merge interface and implementation
  6804. Result:=ConvertDeclarations(Section,AContext);
  6805. AddToSourceElements(Src,Result);
  6806. end;
  6807. procedure TPasToJSConverter.CreateInitSection(El: TPasModule;
  6808. Src: TJSSourceElements; AContext: TConvertContext);
  6809. begin
  6810. // add initialization section
  6811. if Assigned(El.InitializationSection) then
  6812. AddToSourceElements(Src,ConvertInitializationSection(El.InitializationSection,AContext));
  6813. // finalization: not supported
  6814. if Assigned(El.FinalizationSection) then
  6815. raise Exception.Create('TPasToJSConverter.ConvertInitializationSection: finalization section is not supported');
  6816. end;
  6817. function TPasToJSConverter.CreateDotExpression(aParent: TPasElement; Left,
  6818. Right: TJSElement): TJSElement;
  6819. var
  6820. Dot: TJSDotMemberExpression;
  6821. RightParent: TJSElement;
  6822. ok: Boolean;
  6823. begin
  6824. Result:=nil;
  6825. if Left=nil then
  6826. RaiseInconsistency(20170201140827);
  6827. if Right=nil then
  6828. RaiseInconsistency(20170211192018);
  6829. ok:=false;
  6830. try
  6831. // create a TJSDotMemberExpression of Left and the left-most identifier of Right
  6832. // Left becomes the new left-most element of Right.
  6833. Result:=Right;
  6834. RightParent:=nil;
  6835. repeat
  6836. if (Right.ClassType=TJSCallExpression) then
  6837. begin
  6838. RightParent:=Right;
  6839. Right:=TJSCallExpression(Right).Expr;
  6840. if Right=nil then
  6841. begin
  6842. // left-most is nil -> insert Left
  6843. TJSCallExpression(RightParent).Expr:=Left;
  6844. ok:=true;
  6845. exit;
  6846. end;
  6847. end
  6848. else if (Right.ClassType=TJSBracketMemberExpression) then
  6849. begin
  6850. RightParent:=Right;
  6851. Right:=TJSBracketMemberExpression(Right).MExpr;
  6852. if Right=nil then
  6853. begin
  6854. // left-most is nil -> insert Left
  6855. TJSBracketMemberExpression(RightParent).MExpr:=Left;
  6856. ok:=true;
  6857. exit;
  6858. end;
  6859. end
  6860. else if (Right.ClassType=TJSDotMemberExpression) then
  6861. begin
  6862. RightParent:=Right;
  6863. Right:=TJSDotMemberExpression(Right).MExpr;
  6864. if Right=nil then
  6865. begin
  6866. // left-most is nil -> insert Left
  6867. TJSDotMemberExpression(RightParent).MExpr:=Left;
  6868. ok:=true;
  6869. exit;
  6870. end;
  6871. end
  6872. else if (Right.ClassType=TJSPrimaryExpressionIdent) then
  6873. begin
  6874. // left-most identifier found
  6875. // -> replace it
  6876. Dot := TJSDotMemberExpression(CreateElement(TJSDotMemberExpression, aParent));
  6877. if Result=Right then
  6878. Result:=Dot
  6879. else if RightParent is TJSBracketMemberExpression then
  6880. TJSBracketMemberExpression(RightParent).MExpr:=Dot
  6881. else if RightParent is TJSCallExpression then
  6882. TJSCallExpression(RightParent).Expr:=Dot
  6883. else if RightParent is TJSDotMemberExpression then
  6884. TJSDotMemberExpression(RightParent).MExpr:=Dot
  6885. else
  6886. begin
  6887. Dot.Free;
  6888. {$IFDEF VerbosePas2JS}
  6889. writeln('TPasToJSConverter.CreateDotExpression Right=',GetObjName(Right),' RightParent=',GetObjName(RightParent),' Result=',GetObjName(Result));
  6890. {$ENDIF}
  6891. RaiseInconsistency(20170129141307);
  6892. end;
  6893. Dot.MExpr := Left;
  6894. Dot.Name := TJSPrimaryExpressionIdent(Right).Name;
  6895. FreeAndNil(Right);
  6896. break;
  6897. end
  6898. else
  6899. begin
  6900. {$IFDEF VerbosePas2JS}
  6901. writeln('CreateDotExpression Right=',Right.ClassName);
  6902. {$ENDIF}
  6903. DoError(20161024191240,nMemberExprMustBeIdentifier,sMemberExprMustBeIdentifier,[],aParent);
  6904. end;
  6905. until false;
  6906. ok:=true;
  6907. finally
  6908. if not ok then
  6909. begin
  6910. Left.Free;
  6911. FreeAndNil(Result);
  6912. end;
  6913. end;
  6914. end;
  6915. function TPasToJSConverter.CreateReferencedSet(El: TPasElement; SetExpr: TJSElement
  6916. ): TJSElement;
  6917. var
  6918. Call: TJSCallExpression;
  6919. begin
  6920. Call:=CreateCallExpression(El);
  6921. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnSet_Reference]]);
  6922. Call.Args.Elements.AddElement.Expr:=SetExpr;
  6923. Result:=Call;
  6924. end;
  6925. function TPasToJSConverter.CreateCloneRecord(El: TPasElement;
  6926. ResolvedEl: TPasResolverResult; RecordExpr: TJSElement;
  6927. AContext: TConvertContext): TJSElement;
  6928. // create "new RecordType(RecordExpr)
  6929. var
  6930. NewExpr: TJSNewMemberExpression;
  6931. begin
  6932. if not (ResolvedEl.TypeEl is TPasRecordType) then
  6933. RaiseInconsistency(20170212155956);
  6934. NewExpr:=TJSNewMemberExpression(CreateElement(TJSNewMemberExpression,El));
  6935. NewExpr.MExpr:=CreateReferencePathExpr(ResolvedEl.TypeEl,AContext);
  6936. NewExpr.Args:=TJSArguments(CreateElement(TJSArguments,El));
  6937. NewExpr.Args.Elements.AddElement.Expr:=RecordExpr;
  6938. Result:=NewExpr;
  6939. end;
  6940. function TPasToJSConverter.CreateCallback(El: TPasElement;
  6941. ResolvedEl: TPasResolverResult; AContext: TConvertContext): TJSElement;
  6942. var
  6943. Call: TJSCallExpression;
  6944. Scope: TJSElement;
  6945. DotExpr: TJSDotMemberExpression;
  6946. Prim: TJSPrimaryExpressionIdent;
  6947. aName: String;
  6948. DotPos: SizeInt;
  6949. FunName: String;
  6950. begin
  6951. // create "rtl.createCallback(scope,func)"
  6952. Result:=nil;
  6953. if not (ResolvedEl.IdentEl is TPasProcedure) then
  6954. RaiseInconsistency(20170215140756);
  6955. Call:=nil;
  6956. Scope:=nil;
  6957. try
  6958. Call:=CreateCallExpression(El);
  6959. // "rtl.createCallback"
  6960. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnProcType_Create]]);
  6961. // add parameters
  6962. Scope:=ConvertElement(El,AContext);
  6963. {$IFDEF VerbosePas2JS}
  6964. writeln('TPasToJSConverter.CreateCallback ',GetObjName(Scope));
  6965. {$ENDIF}
  6966. FunName:='';
  6967. // the last element of Scope is the proc, chomp that off
  6968. if Scope.ClassType=TJSDotMemberExpression then
  6969. begin
  6970. // chomp dot member -> rtl.createCallback(scope,"FunName")
  6971. DotExpr:=TJSDotMemberExpression(Scope);
  6972. FunName:=String(DotExpr.Name);
  6973. DotPos:=PosLast('.',FunName);
  6974. if DotPos>0 then
  6975. begin
  6976. // e.g. path dot $class.funname
  6977. // keep DotExpr, chomp funname
  6978. DotExpr.Name:=TJSString(LeftStr(FunName,DotPos-1));
  6979. FunName:=copy(FunName,DotPos+1);
  6980. if not IsValidJSIdentifier(DotExpr.Name) then
  6981. begin
  6982. {$IFDEF VerbosePas2JS}
  6983. writeln('TPasToJSConverter.CreateCallback ',GetObjName(Scope),' DotExpr.Name="',DotExpr.Name,'"');
  6984. {$ENDIF}
  6985. DoError(20170215161802,nInvalidFunctionReference,sInvalidFunctionReference,[],El);
  6986. end;
  6987. end
  6988. else
  6989. begin
  6990. // e.g. path dot funname
  6991. // delete DotExpr
  6992. Scope:=DotExpr.MExpr;
  6993. DotExpr.MExpr:=nil;
  6994. FreeAndNil(DotExpr);
  6995. end;
  6996. if not IsValidJSIdentifier(TJSString(FunName)) then
  6997. begin
  6998. {$IFDEF VerbosePas2JS}
  6999. writeln('TPasToJSConverter.CreateCallback ',GetObjName(Scope),' FunName="',FunName,'"');
  7000. {$ENDIF}
  7001. DoError(20170215161802,nInvalidFunctionReference,sInvalidFunctionReference,[],El);
  7002. end;
  7003. Call.Args.Elements.AddElement.Expr:=Scope;
  7004. // add function name as parameter
  7005. Call.Args.Elements.AddElement.Expr:=CreateLiteralString(El,FunName);
  7006. end
  7007. else if Scope.ClassType=TJSPrimaryExpressionIdent then
  7008. begin
  7009. Prim:=TJSPrimaryExpressionIdent(Scope);
  7010. aName:=String(Prim.Name);
  7011. DotPos:=PosLast('.',aName);
  7012. if DotPos>0 then
  7013. begin
  7014. // chomp dotted identifier -> rtl.createCallback(scope,"FunName")
  7015. FunName:=copy(aName,DotPos+1);
  7016. Prim.Name:=TJSString(LeftStr(aName,DotPos-1));
  7017. Call.Args.Elements.AddElement.Expr:=Prim;
  7018. // add function name as parameter
  7019. Call.Args.Elements.AddElement.Expr:=CreateLiteralString(El,FunName);
  7020. end
  7021. else
  7022. begin
  7023. // nested proc -> rtl.createCallback(this,FunName)
  7024. FunName:=aName;
  7025. Prim.Name:='this';
  7026. Call.Args.Elements.AddElement.Expr:=Prim;
  7027. // add function as parameter
  7028. Call.Args.Elements.AddElement.Expr:=CreateBuiltInIdentifierExpr(FunName);
  7029. end;
  7030. end
  7031. else
  7032. begin
  7033. {$IFDEF VerbosePas2JS}
  7034. writeln('TPasToJSConverter.CreateCallback invalid Scope=',GetObjName(Scope));
  7035. {$ENDIF}
  7036. RaiseNotSupported(El,AContext,20170215161210);
  7037. end;
  7038. Result:=Call;
  7039. finally
  7040. if Result=nil then
  7041. begin
  7042. Scope.Free;
  7043. Call.Free;
  7044. end;
  7045. end;
  7046. end;
  7047. function TPasToJSConverter.CreateAssignStatement(LeftEl: TPasElement;
  7048. AssignContext: TAssignContext): TJSElement;
  7049. var
  7050. LHS: TJSElement;
  7051. AssignSt: TJSSimpleAssignStatement;
  7052. begin
  7053. Result:=nil;
  7054. LHS:=ConvertElement(LeftEl,AssignContext);
  7055. if AssignContext.Call<>nil then
  7056. begin
  7057. // has a setter -> right side was already added as parameter
  7058. if AssignContext.RightSide<>nil then
  7059. begin
  7060. LHS.Free;
  7061. RaiseInconsistency(20170207215447);
  7062. end;
  7063. Result:=LHS;
  7064. end
  7065. else
  7066. begin
  7067. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,AssignContext.PasElement));
  7068. AssignSt.LHS:=LHS;
  7069. AssignSt.Expr:=AssignContext.RightSide;
  7070. AssignContext.RightSide:=nil;
  7071. Result:=AssignSt;
  7072. end;
  7073. end;
  7074. function TPasToJSConverter.ConvertImplBlock(El: TPasImplBlock;
  7075. AContext: TConvertContext): TJSElement;
  7076. begin
  7077. Result:=Nil;
  7078. if (El is TPasImplStatement) then
  7079. Result:=ConvertStatement(TPasImplStatement(El),AContext)
  7080. else if (El.ClassType=TPasImplIfElse) then
  7081. Result:=ConvertIfStatement(TPasImplIfElse(El),AContext)
  7082. else if (El.ClassType=TPasImplRepeatUntil) then
  7083. Result:=ConvertRepeatStatement(TPasImplRepeatUntil(El),AContext)
  7084. else if (El.ClassType=TPasImplBeginBlock) then
  7085. Result:=ConvertBeginEndStatement(TPasImplBeginBlock(El),AContext,true)
  7086. else if (El.ClassType=TInitializationSection) then
  7087. Result:=ConvertInitializationSection(TInitializationSection(El),AContext)
  7088. else if (El.ClassType=TFinalizationSection) then
  7089. Result:=ConvertFinalizationSection(TFinalizationSection(El),AContext)
  7090. else if (El.ClassType=TPasImplTry) then
  7091. Result:=ConvertTryStatement(TPasImplTry(El),AContext)
  7092. else if (El.ClassType=TPasImplCaseOf) then
  7093. Result:=ConvertCaseOfStatement(TPasImplCaseOf(El),AContext)
  7094. else
  7095. RaiseNotSupported(El,AContext,20161024192156);
  7096. (*
  7097. TPasImplBlock = class(TPasImplElement)
  7098. TPasImplCaseOf = class(TPasImplBlock)
  7099. TPasImplStatement = class(TPasImplBlock)
  7100. TPasImplCaseElse = class(TPasImplBlock)
  7101. TPasImplTry = class(TPasImplBlock)
  7102. TPasImplTryHandler = class(TPasImplBlock)
  7103. TPasImplTryFinally = class(TPasImplTryHandler)
  7104. TPasImplTryExcept = class(TPasImplTryHandler)
  7105. TPasImplTryExceptElse = class(TPasImplTryHandler)
  7106. *)
  7107. end;
  7108. function TPasToJSConverter.ConvertPackage(El: TPasPackage;
  7109. AContext: TConvertContext): TJSElement;
  7110. begin
  7111. RaiseNotSupported(El,AContext,20161024192555);
  7112. Result:=Nil;
  7113. // ToDo TPasPackage = class(TPasElement)
  7114. end;
  7115. function TPasToJSConverter.ConvertResString(El: TPasResString;
  7116. AContext: TConvertContext): TJSElement;
  7117. begin
  7118. RaiseNotSupported(El,AContext,20161024192604);
  7119. Result:=Nil;
  7120. // ToDo: TPasResString
  7121. end;
  7122. function TPasToJSConverter.ConvertVariable(El: TPasVariable;
  7123. AContext: TConvertContext): TJSElement;
  7124. Var
  7125. V : TJSVarDeclaration;
  7126. vm: TVariableModifier;
  7127. begin
  7128. for vm in TVariableModifier do
  7129. if (vm in El.VarModifiers) and (not (vm in [vmClass,vmExternal])) then
  7130. RaiseNotSupported(El,AContext,20170208141622,'modifier '+VariableModifierNames[vm]);
  7131. if El.LibraryName<>nil then
  7132. RaiseNotSupported(El,AContext,20170208141844,'library name');
  7133. if El.AbsoluteLocation<>'' then
  7134. RaiseNotSupported(El,AContext,20170208141926,'absolute');
  7135. V:=TJSVarDeclaration(CreateElement(TJSVarDeclaration,El));
  7136. V.Name:=TransformVariableName(El,AContext);
  7137. V.Init:=CreateVarInit(El,AContext);
  7138. Result:=V;
  7139. end;
  7140. function TPasToJSConverter.ConvertProperty(El: TPasProperty;
  7141. AContext: TConvertContext): TJSElement;
  7142. begin
  7143. Result:=Nil;
  7144. if El.IndexExpr<>nil then
  7145. RaiseNotSupported(El.IndexExpr,AContext,20170215103010,'property index expression');
  7146. if El.ImplementsFunc<>nil then
  7147. RaiseNotSupported(El.ImplementsFunc,AContext,20170215102923,'property implements function');
  7148. if El.DispIDExpr<>nil then
  7149. RaiseNotSupported(El.DispIDExpr,AContext,20170215103029,'property dispid expression');
  7150. if El.DefaultExpr<>nil then
  7151. RaiseNotSupported(El.DefaultExpr,AContext,20170215103129,'property default modifier');
  7152. if El.StoredAccessor<>nil then
  7153. RaiseNotSupported(El.StoredAccessor,AContext,20170215121145,'property stored accessor');
  7154. if El.StoredAccessorName<>'' then
  7155. RaiseNotSupported(El,AContext,20170215121248,'property stored accessor');
  7156. // does not need any declaration. Access is redirected to getter/setter.
  7157. end;
  7158. function TPasToJSConverter.ConvertExportSymbol(El: TPasExportSymbol;
  7159. AContext: TConvertContext): TJSElement;
  7160. begin
  7161. RaiseNotSupported(El,AContext,20161024192650);
  7162. Result:=Nil;
  7163. // ToDo: TPasExportSymbol
  7164. end;
  7165. function TPasToJSConverter.ConvertLabels(El: TPasLabels;
  7166. AContext: TConvertContext): TJSElement;
  7167. begin
  7168. RaiseNotSupported(El,AContext,20161024192701);
  7169. Result:=Nil;
  7170. // ToDo: TPasLabels = class(TPasImplElement)
  7171. end;
  7172. function TPasToJSConverter.ConvertRaiseStatement(El: TPasImplRaise;
  7173. AContext: TConvertContext): TJSElement;
  7174. Var
  7175. E : TJSElement;
  7176. T : TJSThrowStatement;
  7177. begin
  7178. if El.ExceptObject<>Nil then
  7179. E:=ConvertElement(El.ExceptObject,AContext)
  7180. else
  7181. E:=CreateBuiltInIdentifierExpr(FBuiltInNames[pbivnExceptObject]);
  7182. T:=TJSThrowStatement(CreateElement(TJSThrowStatement,El));
  7183. T.A:=E;
  7184. Result:=T;
  7185. end;
  7186. function TPasToJSConverter.ConvertAssignStatement(El: TPasImplAssign;
  7187. AContext: TConvertContext): TJSElement;
  7188. Var
  7189. LHS: TJSElement;
  7190. T: TJSAssignStatement;
  7191. AssignContext: TAssignContext;
  7192. Flags: TPasResolverComputeFlags;
  7193. LeftIsProcType: Boolean;
  7194. begin
  7195. Result:=nil;
  7196. LHS:=nil;
  7197. AssignContext:=TAssignContext.Create(El,nil,AContext);
  7198. try
  7199. if AContext.Resolver<>nil then
  7200. begin
  7201. AContext.Resolver.ComputeElement(El.left,AssignContext.LeftResolved,[rcNoImplicitProc]);
  7202. Flags:=[];
  7203. LeftIsProcType:=AContext.Resolver.IsProcedureType(AssignContext.LeftResolved,true);
  7204. if LeftIsProcType then
  7205. begin
  7206. if msDelphi in AContext.CurrentModeswitches then
  7207. Include(Flags,rcNoImplicitProc)
  7208. else
  7209. Include(Flags,rcNoImplicitProcType);
  7210. end;
  7211. AContext.Resolver.ComputeElement(El.right,AssignContext.RightResolved,Flags);
  7212. {$IFDEF VerbosePas2JS}
  7213. writeln('TPasToJSConverter.ConvertAssignStatement Left={',GetResolverResultDesc(AssignContext.LeftResolved),'} Right={',GetResolverResultDesc(AssignContext.RightResolved),'}');
  7214. {$ENDIF}
  7215. if LeftIsProcType and (msDelphi in AContext.CurrentModeswitches)
  7216. and (AssignContext.RightResolved.BaseType=btProc) then
  7217. begin
  7218. // Delphi allows assigning a proc without @: proctype:=proc
  7219. AssignContext.RightSide:=CreateCallback(El.right,AssignContext.RightResolved,AContext);
  7220. end
  7221. else if AssignContext.RightResolved.BaseType=btNil then
  7222. begin
  7223. if AContext.Resolver.IsArrayType(AssignContext.LeftResolved) then
  7224. begin
  7225. // array:=nil -> array:=[]
  7226. AssignContext.RightSide:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,El.right));
  7227. end;
  7228. end;
  7229. end;
  7230. if AssignContext.RightSide=nil then
  7231. AssignContext.RightSide:=ConvertElement(El.right,AContext);
  7232. if (AssignContext.RightResolved.BaseType=btSet)
  7233. and (AssignContext.RightResolved.IdentEl<>nil) then
  7234. begin
  7235. // right side is a set variable -> create reference
  7236. {$IFDEF VerbosePas2JS}
  7237. //writeln('TPasToJSConverter.ConvertAssignStatement SET variable Right={',GetResolverResultDesc(AssignContext.RightResolved),'} AssignContext.RightResolved.IdentEl=',GetObjName(AssignContext.RightResolved.IdentEl));
  7238. {$ENDIF}
  7239. // create rtl.refSet(right)
  7240. AssignContext.RightSide:=CreateReferencedSet(El.right,AssignContext.RightSide);
  7241. end
  7242. else if AssignContext.RightResolved.BaseType=btContext then
  7243. begin
  7244. if AssignContext.RightResolved.TypeEl.ClassType=TPasRecordType then
  7245. begin
  7246. // right side is a record -> clone
  7247. {$IFDEF VerbosePas2JS}
  7248. writeln('TPasToJSConverter.ConvertAssignStatement RECORD variable Right={',GetResolverResultDesc(AssignContext.RightResolved),'} AssignContext.RightResolved.IdentEl=',GetObjName(AssignContext.RightResolved.IdentEl));
  7249. {$ENDIF}
  7250. // create "new RightRecordType(RightRecord)"
  7251. AssignContext.RightSide:=CreateCloneRecord(El.right,
  7252. AssignContext.RightResolved,AssignContext.RightSide,AContext);
  7253. end;
  7254. end;
  7255. LHS:=ConvertElement(El.left,AssignContext);
  7256. if AssignContext.Call<>nil then
  7257. begin
  7258. // left side is a Setter -> RightSide was already inserted as parameter
  7259. if AssignContext.RightSide<>nil then
  7260. RaiseInconsistency(20170207215544);
  7261. Result:=LHS;
  7262. end
  7263. else
  7264. begin
  7265. // left side is a variable -> create normal assign statement
  7266. case El.Kind of
  7267. akDefault: T:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  7268. akAdd: T:=TJSAddEqAssignStatement(CreateElement(TJSAddEqAssignStatement,El));
  7269. akMinus: T:=TJSSubEqAssignStatement(CreateElement(TJSSubEqAssignStatement,El));
  7270. akMul: T:=TJSMulEqAssignStatement(CreateElement(TJSMulEqAssignStatement,El));
  7271. akDivision: T:=TJSDivEqAssignStatement(CreateElement(TJSDivEqAssignStatement,El));
  7272. else RaiseNotSupported(El,AContext,20161107221807);
  7273. end;
  7274. T.Expr:=AssignContext.RightSide;
  7275. AssignContext.RightSide:=nil;
  7276. T.LHS:=LHS;
  7277. Result:=T;
  7278. end;
  7279. finally
  7280. if Result=nil then
  7281. LHS.Free;
  7282. AssignContext.RightSide.Free;
  7283. AssignContext.Free;
  7284. end;
  7285. end;
  7286. function TPasToJSConverter.ConvertCommand(El: TPasImplCommand;
  7287. AContext: TConvertContext): TJSElement;
  7288. begin
  7289. RaiseNotSupported(El,AContext,20161024192705);
  7290. Result:=Nil;
  7291. // ToDo: TPasImplCommand = class(TPasImplElement)
  7292. end;
  7293. function TPasToJSConverter.ConvertIfStatement(El: TPasImplIfElse;
  7294. AContext: TConvertContext): TJSElement;
  7295. Var
  7296. C,BThen,BElse : TJSElement;
  7297. T : TJSIfStatement;
  7298. ok: Boolean;
  7299. begin
  7300. if AContext=nil then ;
  7301. C:=Nil;
  7302. BThen:=Nil;
  7303. BElse:=Nil;
  7304. ok:=false;
  7305. try
  7306. C:=ConvertElement(El.ConditionExpr,AContext);
  7307. if Assigned(El.IfBranch) then
  7308. BThen:=ConvertElement(El.IfBranch,AContext);
  7309. if Assigned(El.ElseBranch) then
  7310. BElse:=ConvertElement(El.ElseBranch,AContext);
  7311. ok:=true;
  7312. finally
  7313. if not ok then
  7314. begin
  7315. FreeAndNil(C);
  7316. FreeAndNil(BThen);
  7317. FreeAndNil(BElse);
  7318. end;
  7319. end;
  7320. T:=TJSIfStatement(CreateElement(TJSIfStatement,El));
  7321. T.Cond:=C;
  7322. T.BTrue:=BThen;
  7323. T.BFalse:=BElse;
  7324. Result:=T;
  7325. end;
  7326. function TPasToJSConverter.ConvertWhileStatement(El: TPasImplWhileDo;
  7327. AContext: TConvertContext): TJSElement;
  7328. Var
  7329. C : TJSElement;
  7330. B : TJSElement;
  7331. W : TJSWhileStatement;
  7332. ok: Boolean;
  7333. begin
  7334. Result:=Nil;
  7335. C:=Nil;
  7336. B:=Nil;
  7337. ok:=false;
  7338. try
  7339. C:=ConvertElement(EL.ConditionExpr,AContext);
  7340. if Assigned(EL.Body) then
  7341. B:=ConvertElement(EL.Body,AContext)
  7342. else
  7343. B:=TJSEmptyBlockStatement(CreateElement(TJSEmptyBlockStatement,El));
  7344. ok:=true;
  7345. finally
  7346. if not ok then
  7347. begin
  7348. FreeAndNil(B);
  7349. FreeAndNil(C);
  7350. end;
  7351. end;
  7352. W:=TJSWhileStatement(CreateElement(TJSWhileStatement,El));
  7353. W.Cond:=C;
  7354. W.Body:=B;
  7355. Result:=W;
  7356. end;
  7357. function TPasToJSConverter.ConvertRepeatStatement(El: TPasImplRepeatUntil;
  7358. AContext: TConvertContext): TJSElement;
  7359. Var
  7360. C : TJSElement;
  7361. N : TJSUnaryNotExpression;
  7362. W : TJSDoWhileStatement;
  7363. B : TJSElement;
  7364. ok: Boolean;
  7365. begin
  7366. Result:=Nil;
  7367. C:=Nil;
  7368. B:=Nil;
  7369. ok:=false;
  7370. try
  7371. C:=ConvertElement(EL.ConditionExpr,AContext);
  7372. N:=TJSUnaryNotExpression(CreateElement(TJSUnaryNotExpression,EL.ConditionExpr));
  7373. N.A:=C;
  7374. B:=ConvertImplBlockElements(El,AContext,false);
  7375. ok:=true;
  7376. finally
  7377. if not ok then
  7378. begin
  7379. FreeAndNil(B);
  7380. FreeAndNil(C);
  7381. end;
  7382. end;
  7383. W:=TJSDoWhileStatement(CreateElement(TJSDoWhileStatement,El));
  7384. W.Cond:=N;
  7385. W.Body:=B;
  7386. Result:=W;
  7387. end;
  7388. function TPasToJSConverter.ConvertForStatement(El: TPasImplForLoop;
  7389. AContext: TConvertContext): TJSElement;
  7390. // Creates the following code:
  7391. // var $loopend=<EndExpr>;
  7392. // for(LoopVar=<StartExpr>; LoopVar<=$loopend; LoopVar++){}
  7393. // if(LoopVar>$loopend)LoopVar--; // this line is only added if LoopVar is read later
  7394. //
  7395. // The StartExpr must be executed exactly once at beginning.
  7396. // The EndExpr must be executed exactly once at beginning.
  7397. // LoopVar can be a varname or programname.varname
  7398. Var
  7399. ForSt : TJSForStatement;
  7400. List, ListEnd: TJSStatementList;
  7401. SimpleAss : TJSSimpleAssignStatement;
  7402. VarDecl : TJSVarDeclaration;
  7403. Incr, Decr : TJSUNaryExpression;
  7404. BinExp : TJSBinaryExpression;
  7405. VarStat: TJSVariableStatement;
  7406. IfSt: TJSIfStatement;
  7407. GTExpr: TJSRelationalExpression;
  7408. CurLoopEndVarName: String;
  7409. FuncContext: TConvertContext;
  7410. ResolvedVar: TPasResolverResult;
  7411. function NeedDecrAfterLoop: boolean;
  7412. var
  7413. ResolvedVar: TPasResolverResult;
  7414. aParent: TPasElement;
  7415. ProcBody: TProcedureBody;
  7416. FindData: TForLoopFindData;
  7417. begin
  7418. Result:=true;
  7419. if AContext.Resolver=nil then exit(false);
  7420. AContext.Resolver.ComputeElement(El.VariableName,ResolvedVar,[rcNoImplicitProc]);
  7421. if ResolvedVar.IdentEl=nil then
  7422. exit;
  7423. if ResolvedVar.IdentEl.Parent is TProcedureBody then
  7424. begin
  7425. // loopvar is a local var
  7426. ProcBody:=TProcedureBody(ResolvedVar.IdentEl.Parent);
  7427. aParent:=El;
  7428. while true do
  7429. begin
  7430. aParent:=aParent.Parent;
  7431. if aParent=nil then exit;
  7432. if aParent is TProcedureBody then
  7433. begin
  7434. if aParent<>ProcBody then exit;
  7435. break;
  7436. end;
  7437. end;
  7438. // loopvar is a local var of the same function as where the loop is
  7439. // -> check if it is read after the loop
  7440. FindData:=Default(TForLoopFindData);
  7441. FindData.ForLoop:=El;
  7442. FindData.LoopVar:=ResolvedVar.IdentEl;
  7443. ProcBody.Body.ForEachCall(@ForLoop_OnProcBodyElement,@FindData);
  7444. if not FindData.LoopVarRead then
  7445. exit(false);
  7446. end;
  7447. end;
  7448. begin
  7449. Result:=Nil;
  7450. BinExp:=Nil;
  7451. if AContext.Access<>caRead then
  7452. RaiseInconsistency(20170213213740);
  7453. // get function context
  7454. FuncContext:=AContext;
  7455. while (FuncContext.Parent<>nil) and (not (FuncContext is TFunctionContext)) do
  7456. FuncContext:=FuncContext.Parent;
  7457. // create unique loopend var name
  7458. CurLoopEndVarName:=FuncContext.CreateLocalIdentifier(FBuiltInNames[pbivnLoopEnd]);
  7459. // loopvar:=
  7460. // for (statementlist...
  7461. List:=TJSStatementList(CreateElement(TJSStatementList,El));
  7462. ListEnd:=List;
  7463. try
  7464. // add "var $loopend=<EndExpr>"
  7465. VarStat:=TJSVariableStatement(CreateElement(TJSVariableStatement,El));
  7466. List.A:=VarStat;
  7467. VarDecl:=TJSVarDeclaration(CreateElement(TJSVarDeclaration,El));
  7468. VarStat.A:=VarDecl;
  7469. VarDecl.Name:=CurLoopEndVarName;
  7470. VarDecl.Init:=ConvertElement(El.EndExpr,AContext);
  7471. // add "for()"
  7472. ForSt:=TJSForStatement(CreateElement(TJSForStatement,El));
  7473. List.B:=ForSt;
  7474. // add "LoopVar=<StartExpr>;"
  7475. SimpleAss:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El.StartExpr));
  7476. ForSt.Init:=SimpleAss;
  7477. if AContext.Resolver<>nil then
  7478. begin
  7479. AContext.Resolver.ComputeElement(El.VariableName,ResolvedVar,[rcNoImplicitProc]);
  7480. if not (ResolvedVar.IdentEl is TPasVariable) then
  7481. DoError(20170213214404,nExpectedXButFoundY,sExpectedXButFoundY,['var',GetResolverResultDescription(ResolvedVar)],El);
  7482. end;
  7483. SimpleAss.LHS:=ConvertElement(El.VariableName,AContext);
  7484. SimpleAss.Expr:=ConvertElement(El.StartExpr,AContext);
  7485. // add "LoopVar<=$loopend"
  7486. if El.Down then
  7487. BinExp:=TJSRelationalExpressionGE(CreateElement(TJSRelationalExpressionGE,El.EndExpr))
  7488. else
  7489. BinExp:=TJSRelationalExpressionLE(CreateElement(TJSRelationalExpressionLE,El.EndExpr));
  7490. ForSt.Cond:=BinExp;
  7491. BinExp.A:=ConvertElement(El.VariableName,AContext);
  7492. BinExp.B:=CreateIdentifierExpr(CurLoopEndVarName,El.EndExpr,AContext);
  7493. // add "LoopVar++"
  7494. if El.Down then
  7495. Incr:=TJSUnaryPostMinusMinusExpression(CreateElement(TJSUnaryPostMinusMinusExpression,El))
  7496. else
  7497. Incr:=TJSUnaryPostPlusPlusExpression(CreateElement(TJSUnaryPostPlusPlusExpression,El));
  7498. ForSt.Incr:=Incr;
  7499. Incr.A:=ConvertElement(El.VariableName,AContext);
  7500. // add body
  7501. if El.Body<>nil then
  7502. ForSt.Body:=ConvertElement(El.Body,AContext);
  7503. if NeedDecrAfterLoop then
  7504. begin
  7505. // add "if(LoopVar>$loopend)LoopVar--;"
  7506. // add "if()"
  7507. IfSt:=TJSIfStatement(CreateElement(TJSIfStatement,El));
  7508. AddToStatementList(List,ListEnd,IfSt,El);
  7509. // add "LoopVar>$loopend"
  7510. if El.Down then
  7511. GTExpr:=TJSRelationalExpressionLT(CreateElement(TJSRelationalExpressionLT,El))
  7512. else
  7513. GTExpr:=TJSRelationalExpressionGT(CreateElement(TJSRelationalExpressionGT,El));
  7514. IfSt.Cond:=GTExpr;
  7515. GTExpr.A:=ConvertElement(El.VariableName,AContext);
  7516. GTExpr.B:=CreateIdentifierExpr(CurLoopEndVarName,El.EndExpr,AContext);
  7517. // add "LoopVar--"
  7518. if El.Down then
  7519. Decr:=TJSUnaryPostPlusPlusExpression(CreateElement(TJSUnaryPostPlusPlusExpression,El))
  7520. else
  7521. Decr:=TJSUnaryPostMinusMinusExpression(CreateElement(TJSUnaryPostMinusMinusExpression,El));
  7522. IfSt.BTrue:=Decr;
  7523. Decr.A:=ConvertElement(El.VariableName,AContext);
  7524. end;
  7525. Result:=List;
  7526. finally
  7527. if Result=nil then
  7528. List.Free;
  7529. end;
  7530. end;
  7531. function TPasToJSConverter.ConvertSimpleStatement(El: TPasImplSimple;
  7532. AContext: TConvertContext): TJSElement;
  7533. Var
  7534. E : TJSElement;
  7535. begin
  7536. E:=ConvertElement(EL.Expr,AContext);
  7537. if E=nil then
  7538. exit(nil); // e.g. "inherited;" without ancestor proc
  7539. Result:=TJSExpressionStatement(CreateElement(TJSExpressionStatement,El));
  7540. TJSExpressionStatement(Result).A:=E;
  7541. end;
  7542. function TPasToJSConverter.ConvertWithStatement(El: TPasImplWithDo;
  7543. AContext: TConvertContext): TJSElement;
  7544. Var
  7545. B,E , Expr: TJSElement;
  7546. W,W2 : TJSWithStatement;
  7547. I : Integer;
  7548. ok: Boolean;
  7549. PasExpr: TPasElement;
  7550. V: TJSVariableStatement;
  7551. VarDecl: TJSVarDeclaration;
  7552. FuncContext: TFunctionContext;
  7553. FirstSt, LastSt: TJSStatementList;
  7554. WithScope: TPasWithScope;
  7555. WithExprScope: TPas2JSWithExprScope;
  7556. begin
  7557. Result:=nil;
  7558. if AContext.Resolver<>nil then
  7559. begin
  7560. // with Resolver:
  7561. // Insert for each expression a local var. Example:
  7562. // with aPoint do X:=3;
  7563. // convert to
  7564. // var $with1 = aPoint;
  7565. // $with1.X = 3;
  7566. FuncContext:=TFunctionContext(AContext.GetContextOfType(TFunctionContext));
  7567. if FuncContext=nil then
  7568. RaiseInconsistency(20170212003759);
  7569. FirstSt:=nil;
  7570. LastSt:=nil;
  7571. try
  7572. WithScope:=El.CustomData as TPasWithScope;
  7573. for i:=0 to El.Expressions.Count-1 do
  7574. begin
  7575. PasExpr:=TPasElement(El.Expressions[i]);
  7576. Expr:=ConvertElement(PasExpr,AContext);
  7577. // create unique local var name
  7578. WithExprScope:=WithScope.ExpressionScopes[i] as TPas2JSWithExprScope;
  7579. WithExprScope.WithVarName:=FuncContext.CreateLocalIdentifier(FBuiltInNames[pbivnWith]);
  7580. // create local "var $with1 = expr;"
  7581. V:=TJSVariableStatement(CreateElement(TJSVariableStatement,PasExpr));
  7582. VarDecl:=TJSVarDeclaration(CreateElement(TJSVarDeclaration,PasExpr));
  7583. V.A:=VarDecl;
  7584. VarDecl.Name:=WithExprScope.WithVarName;
  7585. VarDecl.Init:=Expr;
  7586. AddToStatementList(FirstSt,LastSt,V,PasExpr);
  7587. end;
  7588. if Assigned(El.Body) then
  7589. begin
  7590. B:=ConvertElement(El.Body,AContext);
  7591. AddToStatementList(FirstSt,LastSt,B,El.Body);
  7592. end;
  7593. Result:=FirstSt;
  7594. finally
  7595. if Result=nil then
  7596. FreeAndNil(FirstSt);
  7597. end;
  7598. end
  7599. else
  7600. begin
  7601. // without Resolver use as fallback the JavaScript with(){}
  7602. W:=Nil;
  7603. if Assigned(El.Body) then
  7604. B:=ConvertElement(El.Body,AContext)
  7605. else
  7606. B:=TJSEmptyBlockStatement(CreateElement(TJSEmptyBlockStatement,El));
  7607. ok:=false;
  7608. try
  7609. For I:=0 to El.Expressions.Count-1 do
  7610. begin
  7611. E:=ConvertElement(TPasElement(El.Expressions[i]),AContext);
  7612. W2:=TJSWithStatement(CreateElement(TJSWithStatement,TPasElement(El.Expressions[i])));
  7613. if Not Assigned(Result) then // result is the first
  7614. Result:=W2;
  7615. if Assigned(W) then // Chain
  7616. W.B:=W2;
  7617. W:=W2; // W is the last
  7618. W.A:=E;
  7619. end;
  7620. ok:=true;
  7621. finally
  7622. if not ok then
  7623. begin
  7624. FreeAndNil(E);
  7625. FreeAndNil(Result);
  7626. end;
  7627. end;
  7628. W.B:=B;
  7629. end;
  7630. end;
  7631. function TPasToJSConverter.IsElementUsed(El: TPasElement): boolean;
  7632. begin
  7633. if Assigned(OnIsElementUsed) then
  7634. Result:=OnIsElementUsed(Self,El)
  7635. else
  7636. Result:=true;
  7637. end;
  7638. procedure TPasToJSConverter.RaiseInconsistency(Id: int64);
  7639. begin
  7640. raise Exception.Create('TPasToJSConverter.RaiseInconsistency['+IntToStr(Id)+']: you found a bug');
  7641. end;
  7642. function TPasToJSConverter.CreateUnary(Members: array of string; E: TJSElement): TJSUnary;
  7643. var
  7644. unary: TJSUnary;
  7645. asi: TJSSimpleAssignStatement;
  7646. begin
  7647. unary := TJSUnary.Create(0, 0, '');
  7648. asi := TJSSimpleAssignStatement.Create(0, 0, '');
  7649. unary.A := asi;
  7650. asi.Expr := E;
  7651. asi.LHS := CreateMemberExpression(Members);
  7652. Result := unary;
  7653. end;
  7654. function TPasToJSConverter.CreateMemberExpression(Members: array of string): TJSDotMemberExpression;
  7655. var
  7656. pex: TJSPrimaryExpressionIdent;
  7657. MExpr: TJSDotMemberExpression;
  7658. LastMExpr: TJSDotMemberExpression;
  7659. k: integer;
  7660. begin
  7661. if Length(Members) < 2 then
  7662. DoError(20161024192715,'internal error: member expression with less than two members');
  7663. LastMExpr := nil;
  7664. for k:=High(Members) downto Low(Members)+1 do
  7665. begin
  7666. MExpr := TJSDotMemberExpression.Create(0, 0, '');
  7667. MExpr.Name := TJSString(Members[k]);
  7668. if LastMExpr=nil then
  7669. Result := MExpr
  7670. else
  7671. LastMExpr.MExpr := MExpr;
  7672. LastMExpr := MExpr;
  7673. end;
  7674. pex := TJSPrimaryExpressionIdent.Create(0, 0, '');
  7675. pex.Name := TJSString(Members[Low(Members)]);
  7676. LastMExpr.MExpr := pex;
  7677. end;
  7678. function TPasToJSConverter.CreateCallExpression(El: TPasElement
  7679. ): TJSCallExpression;
  7680. begin
  7681. Result:=TJSCallExpression(CreateElement(TJSCallExpression,El));
  7682. Result.Args:=TJSArguments(CreateElement(TJSArguments,El));
  7683. end;
  7684. function TPasToJSConverter.CreateUsesList(UsesSection: TPasSection;
  7685. AContext: TConvertContext): TJSArrayLiteral;
  7686. var
  7687. ArgArray: TJSArrayLiteral;
  7688. k: Integer;
  7689. El: TPasElement;
  7690. anUnitName: String;
  7691. ArgEx: TJSLiteral;
  7692. UsesList: TFPList;
  7693. begin
  7694. UsesList:=UsesSection.UsesList;
  7695. ArgArray:=TJSArrayLiteral.Create(0,0);
  7696. if UsesList<>nil then
  7697. for k:=0 to UsesList.Count-1 do
  7698. begin
  7699. El:=TPasElement(UsesList[k]);
  7700. if not (El is TPasModule) then continue;
  7701. if (not IsElementUsed(El)) and (CompareText('system',El.Name)<>0) then
  7702. continue;
  7703. anUnitName := TransformVariableName(TPasModule(El),AContext);
  7704. ArgEx := CreateLiteralString(UsesSection,anUnitName);
  7705. ArgArray.Elements.AddElement.Expr := ArgEx;
  7706. end;
  7707. Result:=ArgArray;
  7708. end;
  7709. procedure TPasToJSConverter.AddToStatementList(var First,
  7710. Last: TJSStatementList; Add: TJSElement; Src: TPasElement);
  7711. var
  7712. SL2: TJSStatementList;
  7713. begin
  7714. if not Assigned(Add) then exit;
  7715. if Add is TJSStatementList then
  7716. begin
  7717. // add list
  7718. if TJSStatementList(Add).A=nil then
  7719. begin
  7720. // empty list -> skip
  7721. if TJSStatementList(Add).B<>nil then
  7722. raise Exception.Create('internal error: AddToStatementList add list A=nil, B<>nil, B='+TJSStatementList(Add).B.ClassName);
  7723. FreeAndNil(Add);
  7724. end
  7725. else if Last=nil then
  7726. begin
  7727. // our list is not yet started -> simply take the extra list
  7728. Last:=TJSStatementList(Add);
  7729. First:=Last;
  7730. end
  7731. else
  7732. begin
  7733. // merge lists (append)
  7734. if Last.B<>nil then
  7735. begin
  7736. // add a nil to the end of chain
  7737. SL2:=TJSStatementList(CreateElement(TJSStatementList,Src));
  7738. SL2.A:=Last.B;
  7739. Last.B:=SL2;
  7740. Last:=SL2;
  7741. // Last.B is now nil
  7742. end;
  7743. Last.B:=Add;
  7744. while Last.B is TJSStatementList do
  7745. Last:=TJSStatementList(Last.B);
  7746. end;
  7747. end
  7748. else
  7749. begin
  7750. if Last=nil then
  7751. begin
  7752. // start list
  7753. Last:=TJSStatementList(CreateElement(TJSStatementList,Src));
  7754. First:=Last;
  7755. Last.A:=Add;
  7756. end
  7757. else if Last.B=nil then
  7758. // second element
  7759. Last.B:=Add
  7760. else
  7761. begin
  7762. // add to chain
  7763. while Last.B is TJSStatementList do
  7764. Last:=TJSStatementList(Last.B);
  7765. SL2:=TJSStatementList(CreateElement(TJSStatementList,Src));
  7766. SL2.A:=Last.B;
  7767. Last.B:=SL2;
  7768. Last:=SL2;
  7769. Last.B:=Add;
  7770. end;
  7771. end;
  7772. end;
  7773. function TPasToJSConverter.CreateValInit(PasType: TPasType; Expr: TPasElement;
  7774. El: TPasElement; AContext: TConvertContext): TJSElement;
  7775. var
  7776. T: TPasType;
  7777. Lit: TJSLiteral;
  7778. bt: TResolverBaseType;
  7779. JSBaseType: TPas2jsBaseType;
  7780. begin
  7781. T:=PasType;
  7782. if AContext.Resolver<>nil then
  7783. T:=AContext.Resolver.ResolveAliasType(T);
  7784. if (T is TPasArrayType) then
  7785. Result:=CreateArrayInit(TPasArrayType(T),Expr,El,AContext)
  7786. else if T is TPasRecordType then
  7787. Result:=CreateRecordInit(TPasRecordType(T),Expr,El,AContext)
  7788. else if Assigned(Expr) then
  7789. Result:=ConvertElement(Expr,AContext)
  7790. else if T is TPasSetType then
  7791. Result:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,El))
  7792. else
  7793. begin
  7794. // always init with a default value to create a typed variable (faster and more readable)
  7795. Lit:=TJSLiteral(CreateElement(TJSLiteral,El));
  7796. Result:=Lit;
  7797. if T=nil then
  7798. Lit.Value.IsUndefined:=true
  7799. else if (T.ClassType=TPasPointerType)
  7800. or (T.ClassType=TPasClassType)
  7801. or (T.ClassType=TPasClassOfType)
  7802. or (T.ClassType=TPasProcedureType)
  7803. or (T.ClassType=TPasFunctionType) then
  7804. Lit.Value.IsNull:=true
  7805. else if T.ClassType=TPasStringType then
  7806. Lit.Value.AsString:=''
  7807. else if T.ClassType=TPasEnumType then
  7808. Lit.Value.AsNumber:=0
  7809. else if T.ClassType=TPasUnresolvedSymbolRef then
  7810. begin
  7811. if T.CustomData is TResElDataBaseType then
  7812. begin
  7813. bt:=TResElDataBaseType(T.CustomData).BaseType;
  7814. if bt in btAllInteger then
  7815. Lit.Value.AsNumber:=0
  7816. else if bt in btAllFloats then
  7817. Lit.Value.CustomValue:='0.0'
  7818. else if bt in btAllStringAndChars then
  7819. Lit.Value.AsString:=''
  7820. else if bt in btAllBooleans then
  7821. Lit.Value.AsBoolean:=false
  7822. else if bt in [btNil,btPointer,btProc] then
  7823. Lit.Value.IsNull:=true
  7824. else if (bt=btCustom) and (T.CustomData is TResElDataPas2JSBaseType) then
  7825. begin
  7826. JSBaseType:=TResElDataPas2JSBaseType(T.CustomData).JSBaseType;
  7827. if JSBaseType=pbtJSValue then
  7828. Lit.Value.IsUndefined:=true;
  7829. end
  7830. else
  7831. begin
  7832. {$IFDEF VerbosePas2JS}
  7833. writeln('TPasToJSConverter.CreateVarInit unknown PasType T=',GetObjName(T),' basetype=',BaseTypeNames[bt]);
  7834. {$ENDIF}
  7835. RaiseNotSupported(PasType,AContext,20170208162121);
  7836. end;
  7837. end
  7838. else if (CompareText(T.Name,'longint')=0)
  7839. or (CompareText(T.Name,'int64')=0)
  7840. or (CompareText(T.Name,'real')=0)
  7841. or (CompareText(T.Name,'double')=0)
  7842. or (CompareText(T.Name,'single')=0) then
  7843. Lit.Value.AsNumber:=0.0
  7844. else if (CompareText(T.Name,'boolean')=0) then
  7845. Lit.Value.AsBoolean:=false
  7846. else if (CompareText(T.Name,'string')=0)
  7847. or (CompareText(T.Name,'char')=0)
  7848. then
  7849. Lit.Value.AsString:=''
  7850. else
  7851. begin
  7852. Lit.Value.IsUndefined:=true;
  7853. {$IFDEF VerbosePas2JS}
  7854. writeln('TPasToJSConverter.CreateVarInit unknown PasType class=',T.ClassName,' name=',T.Name);
  7855. {$ENDIF}
  7856. end;
  7857. end
  7858. else
  7859. begin
  7860. {$IFDEF VerbosePas2JS}
  7861. writeln('TPasToJSConverter.CreateValInit unknown PasType ',GetObjName(T));
  7862. {$ENDIF}
  7863. RaiseNotSupported(PasType,AContext,20170208161506);
  7864. end;
  7865. end;
  7866. end;
  7867. function TPasToJSConverter.CreateVarInit(El: TPasVariable;
  7868. AContext: TConvertContext): TJSElement;
  7869. begin
  7870. Result:=CreateValInit(El.VarType,El.Expr,El,AContext);
  7871. end;
  7872. function TPasToJSConverter.CreateLiteralNumber(El: TPasElement;
  7873. const n: TJSNumber): TJSLiteral;
  7874. begin
  7875. Result:=TJSLiteral(CreateElement(TJSLiteral,El));
  7876. Result.Value.AsNumber:=n;
  7877. end;
  7878. function TPasToJSConverter.CreateLiteralString(El: TPasElement; const s: string
  7879. ): TJSLiteral;
  7880. begin
  7881. Result:=TJSLiteral(CreateElement(TJSLiteral,El));
  7882. Result.Value.AsString:=TJSString(s);
  7883. end;
  7884. function TPasToJSConverter.CreateLiteralJSString(El: TPasElement;
  7885. const s: TJSString): TJSLiteral;
  7886. begin
  7887. Result:=TJSLiteral(CreateElement(TJSLiteral,El));
  7888. Result.Value.AsString:=s;
  7889. end;
  7890. function TPasToJSConverter.CreateLiteralBoolean(El: TPasElement; b: boolean
  7891. ): TJSLiteral;
  7892. begin
  7893. Result:=TJSLiteral(CreateElement(TJSLiteral,El));
  7894. Result.Value.AsBoolean:=b;
  7895. end;
  7896. function TPasToJSConverter.CreateLiteralNull(El: TPasElement): TJSLiteral;
  7897. begin
  7898. Result:=TJSLiteral(CreateElement(TJSLiteral,El));
  7899. Result.Value.IsNull:=true;
  7900. end;
  7901. function TPasToJSConverter.CreateLiteralUndefined(El: TPasElement): TJSLiteral;
  7902. begin
  7903. Result:=TJSLiteral(CreateElement(TJSLiteral,El));
  7904. Result.Value.IsUndefined:=true;
  7905. end;
  7906. function TPasToJSConverter.CreateRecordInit(aRecord: TPasRecordType;
  7907. Expr: TPasElement; El: TPasElement; AContext: TConvertContext): TJSElement;
  7908. // new recordtype()
  7909. var
  7910. NewMemE: TJSNewMemberExpression;
  7911. begin
  7912. if Expr<>nil then
  7913. RaiseNotSupported(Expr,AContext,20161024192747);
  7914. NewMemE:=TJSNewMemberExpression(CreateElement(TJSNewMemberExpression,El));
  7915. Result:=NewMemE;
  7916. NewMemE.MExpr:=CreateReferencePathExpr(aRecord,AContext);
  7917. end;
  7918. function TPasToJSConverter.CreateArrayInit(ArrayType: TPasArrayType;
  7919. Expr: TPasElement; El: TPasElement; AContext: TConvertContext): TJSElement;
  7920. var
  7921. Call: TJSCallExpression;
  7922. DimArray, ArrLit: TJSArrayLiteral;
  7923. i, DimSize: Integer;
  7924. RangeResolved, ElTypeResolved, ExprResolved: TPasResolverResult;
  7925. Range: TPasExpr;
  7926. Lit: TJSLiteral;
  7927. CurArrayType: TPasArrayType;
  7928. DefaultValue: TJSElement;
  7929. ArrayValues: TPasExprArray;
  7930. begin
  7931. if Assigned(Expr) then
  7932. begin
  7933. // init array with constant(s)
  7934. if AContext.Resolver=nil then
  7935. DoError(20161024192739,nInitializedArraysNotSupported,sInitializedArraysNotSupported,[],ArrayType);
  7936. ArrLit:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,El));
  7937. try
  7938. AContext.Resolver.ComputeElement(Expr,ExprResolved,[rcConstant]);
  7939. if (ExprResolved.BaseType=btArray)
  7940. and (ExprResolved.ExprEl is TArrayValues) then
  7941. begin
  7942. ArrayValues:=TArrayValues(ExprResolved.ExprEl).Values;
  7943. for i:=0 to length(ArrayValues)-1 do
  7944. ArrLit.Elements.AddElement.Expr:=ConvertElement(ArrayValues[i],AContext);
  7945. end
  7946. else
  7947. RaiseNotSupported(Expr,AContext,20170223133034);
  7948. Result:=ArrLit;
  7949. finally
  7950. if Result=nil then
  7951. ArrLit.Free;
  7952. end;
  7953. end
  7954. else if length(ArrayType.Ranges)=0 then
  7955. begin
  7956. // empty dynamic array: []
  7957. Result:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,El));
  7958. end
  7959. else
  7960. begin
  7961. // static array
  7962. // create "rtl.arrayNewMultiDim([dim1,dim2,...],defaultvalue)"
  7963. if AContext.Resolver=nil then
  7964. RaiseNotSupported(El,AContext,20170223113050,'');
  7965. Result:=nil;
  7966. try
  7967. Call:=CreateCallExpression(El);
  7968. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnArray_NewMultiDim]]);
  7969. // add parameter [dim1,dim2,...]
  7970. DimArray:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,El));
  7971. Call.Args.Elements.AddElement.Expr:=DimArray;
  7972. CurArrayType:=ArrayType;
  7973. while true do
  7974. begin
  7975. for i:=0 to length(CurArrayType.Ranges)-1 do
  7976. begin
  7977. Range:=CurArrayType.Ranges[i];
  7978. // compute size of this dimension
  7979. AContext.Resolver.ComputeElement(Range,RangeResolved,[rcConstant]);
  7980. DimSize:=AContext.Resolver.GetRangeLength(RangeResolved);
  7981. if DimSize=0 then
  7982. RaiseNotSupported(Range,AContext,20170223113318);
  7983. Lit:=CreateLiteralNumber(El,DimSize);
  7984. DimArray.Elements.AddElement.Expr:=Lit;
  7985. end;
  7986. AContext.Resolver.ComputeElement(CurArrayType.ElType,ElTypeResolved,[rcType]);
  7987. if (ElTypeResolved.TypeEl is TPasArrayType) then
  7988. begin
  7989. CurArrayType:=TPasArrayType(ElTypeResolved.TypeEl);
  7990. if length(CurArrayType.Ranges)>0 then
  7991. begin
  7992. // nested static array
  7993. continue;
  7994. end;
  7995. end;
  7996. break;
  7997. end;
  7998. // add parameter defaultvalue
  7999. DefaultValue:=CreateValInit(ElTypeResolved.TypeEl,nil,El,AContext);
  8000. Call.Args.Elements.AddElement.Expr:=DefaultValue;
  8001. Result:=Call;
  8002. finally
  8003. if Result=nil then
  8004. Call.Free;
  8005. end;
  8006. end;
  8007. end;
  8008. function TPasToJSConverter.CreateCmpArrayWithNil(El: TPasElement;
  8009. JSArray: TJSElement; OpCode: TExprOpCode): TJSElement;
  8010. var
  8011. Call: TJSCallExpression;
  8012. BinExpr: TJSBinaryExpression;
  8013. begin
  8014. if not (OpCode in [eopEqual,eopNotEqual]) then
  8015. RaiseInconsistency(20170401184819);
  8016. Call:=CreateCallExpression(El);
  8017. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnArray_Length]]);
  8018. Call.Args.Elements.AddElement.Expr:=JSArray;
  8019. if OpCode=eopEqual then
  8020. BinExpr:=TJSEqualityExpressionEQ(CreateElement(TJSEqualityExpressionEQ,El))
  8021. else
  8022. BinExpr:=TJSRelationalExpressionGT(CreateElement(TJSRelationalExpressionGT,El));
  8023. BinExpr.A:=Call;
  8024. BinExpr.B:=CreateLiteralNumber(El,0);
  8025. Result:=BinExpr;
  8026. end;
  8027. function TPasToJSConverter.CreateReferencePath(El: TPasElement;
  8028. AContext: TConvertContext; Kind: TRefPathKind; Full: boolean;
  8029. Ref: TResolvedReference): string;
  8030. { Notes:
  8031. - local var, argument or result variable, even higher lvl does not need a reference path
  8032. local vars are also argument, result var, result variable
  8033. - 'this':
  8034. - in interface function (even nested) 'this' is the interface,
  8035. - in implementation function (even nested) 'this' is the implementation,
  8036. - in initialization 'this' is interface
  8037. - in method body 'this' is the instance
  8038. - in class method body 'this' is the class
  8039. - with context uses the local $withnnn var
  8040. otherwise use absolute path
  8041. }
  8042. function GetReferenceEl: TPasElement;
  8043. begin
  8044. if Ref<>nil then
  8045. Result:=Ref.Element
  8046. else
  8047. Result:=El;
  8048. end;
  8049. function IsLocalVar: boolean;
  8050. begin
  8051. Result:=false;
  8052. if El.ClassType=TPasArgument then
  8053. exit(true);
  8054. if El.ClassType=TPasResultElement then
  8055. exit(true);
  8056. if AContext.Resolver=nil then
  8057. exit(true);
  8058. if El.Parent=nil then
  8059. RaiseNotSupported(El,AContext,20170203121306,GetObjName(El));
  8060. if El.Parent.ClassType=TPasImplExceptOn then
  8061. exit(true);
  8062. if not (El.Parent is TProcedureBody) then exit;
  8063. Result:=true;
  8064. end;
  8065. procedure Prepend(var aPath: string; Prefix: string);
  8066. begin
  8067. if aPath<>'' then
  8068. aPath:='.'+aPath;
  8069. aPath:=Prefix+aPath;
  8070. end;
  8071. function IsClassFunction(Proc: TPasElement): boolean;
  8072. var
  8073. C: TClass;
  8074. begin
  8075. if Proc=nil then exit(false);
  8076. C:=Proc.ClassType;
  8077. Result:=(C=TPasClassFunction) or (C=TPasClassProcedure)
  8078. or (C=TPasClassConstructor) or (C=TPasClassDestructor);
  8079. end;
  8080. procedure Append_GetClass(Member: TPasElement);
  8081. begin
  8082. if (Member.Parent as TPasClassType).IsExternal then
  8083. exit;
  8084. if Result<>'' then
  8085. Result:=Result+'.'+FBuiltInNames[pbivnPtrClass]
  8086. else
  8087. Result:=FBuiltInNames[pbivnPtrClass];
  8088. end;
  8089. var
  8090. FoundModule: TPasModule;
  8091. This, ParentEl: TPasElement;
  8092. Dot: TDotContext;
  8093. ThisContext: TFunctionContext;
  8094. WithData: TPas2JSWithExprScope;
  8095. ProcScope: TPasProcedureScope;
  8096. begin
  8097. Result:='';
  8098. //writeln('TPasToJSConverter.CreateReferencePath START El=',GetObjName(El),' Parent=',GetObjName(El.Parent),' Context=',GetObjName(AContext));
  8099. if AContext is TDotContext then
  8100. begin
  8101. Dot:=TDotContext(AContext);
  8102. if Dot.Resolver<>nil then
  8103. begin
  8104. if El is TPasVariable then
  8105. begin
  8106. //writeln('TPasToJSConverter.CreateReferencePath Left=',GetResolverResultDesc(Dot.LeftResolved),' Right=class var ',GetObjName(El));
  8107. if (ClassVarModifiersType*TPasVariable(El).VarModifiers<>[])
  8108. and (Dot.Access=caAssign)
  8109. and Dot.Resolver.ResolvedElIsClassInstance(Dot.LeftResolved) then
  8110. begin
  8111. // writing a class var
  8112. Append_GetClass(El);
  8113. end;
  8114. end
  8115. else if IsClassFunction(El) then
  8116. begin
  8117. if Dot.Resolver.ResolvedElIsClassInstance(Dot.LeftResolved) then
  8118. // accessing a class method from an object, 'this' must be the class
  8119. Append_GetClass(El);
  8120. end;
  8121. end;
  8122. end
  8123. else if (Ref<>nil) and (Ref.WithExprScope<>nil) then
  8124. begin
  8125. // using local WITH var
  8126. WithData:=Ref.WithExprScope as TPas2JSWithExprScope;
  8127. Prepend(Result,WithData.WithVarName);
  8128. end
  8129. else if IsLocalVar then
  8130. begin
  8131. // El is local var -> does not need path
  8132. end
  8133. else if (El is TPasProcedure) and (TPasProcedure(El).LibrarySymbolName<>nil)
  8134. and not (El.Parent is TPasClassType) then
  8135. begin
  8136. // an external function -> use the literal
  8137. if Kind=rpkPathAndName then
  8138. Result:=ComputeConstString(TPasProcedure(El).LibrarySymbolName,AContext,true)
  8139. else
  8140. Result:='';
  8141. exit;
  8142. end
  8143. else if (El is TPasVariable) and (TPasVariable(El).ExportName<>nil)
  8144. and not (El.Parent is TPasClassType) then
  8145. begin
  8146. // an external var -> use the literal
  8147. if Kind=rpkPathAndName then
  8148. Result:=ComputeConstString(TPasVariable(El).ExportName,AContext,true)
  8149. else
  8150. Result:='';
  8151. exit;
  8152. end
  8153. else if (El is TPasClassType) and TPasClassType(El).IsExternal then
  8154. begin
  8155. Result:=TPasClassType(El).ExternalName;
  8156. exit;
  8157. end
  8158. else
  8159. begin
  8160. // need full path
  8161. if El.Parent=nil then
  8162. RaiseNotSupported(El,AContext,20170201172141,GetObjName(El));
  8163. if (El.CustomData is TPasProcedureScope) then
  8164. begin
  8165. ProcScope:=TPasProcedureScope(El.CustomData);
  8166. if ProcScope.DeclarationProc<>nil then
  8167. El:=ProcScope.DeclarationProc;
  8168. end;
  8169. ThisContext:=AContext.GetThisContext;
  8170. if ThisContext<>nil then
  8171. This:=ThisContext.GetThis
  8172. else
  8173. This:=nil;
  8174. ParentEl:=El.Parent;
  8175. while ParentEl<>nil do
  8176. begin
  8177. if (ParentEl.CustomData is TPasProcedureScope) then
  8178. begin
  8179. ProcScope:=TPasProcedureScope(ParentEl.CustomData);
  8180. if ProcScope.DeclarationProc<>nil then
  8181. ParentEl:=ProcScope.DeclarationProc;
  8182. end;
  8183. if ParentEl.ClassType=TImplementationSection then
  8184. begin
  8185. // element is in an implementation section
  8186. if ParentEl=This then
  8187. Prepend(Result,'this')
  8188. else
  8189. begin
  8190. FoundModule:=El.GetModule;
  8191. if FoundModule=nil then
  8192. RaiseInconsistency(20161024192755);
  8193. if AContext.GetRootModule=FoundModule then
  8194. // in same unit -> use '$impl'
  8195. Prepend(Result,FBuiltInNames[pbivnImplementation])
  8196. else
  8197. // in other unit -> use pas.unitname.$impl
  8198. Prepend(Result,FBuiltInNames[pbivnModules]
  8199. +'.'+TransformModuleName(FoundModule,AContext)
  8200. +'.'+FBuiltInNames[pbivnImplementation]);
  8201. end;
  8202. break;
  8203. end
  8204. else if ParentEl is TPasModule then
  8205. begin
  8206. // element is in an unit interface or program/library section
  8207. if ParentEl=This then
  8208. Prepend(Result,'this')
  8209. else
  8210. Prepend(Result,FBuiltInNames[pbivnModules]
  8211. +'.'+TransformModuleName(TPasModule(ParentEl),AContext));
  8212. break;
  8213. end
  8214. else if (ParentEl.ClassType=TPasClassType)
  8215. or (ParentEl.ClassType=TPasRecordType) then
  8216. begin
  8217. // element is a class or record
  8218. if Full then
  8219. Prepend(Result,ParentEl.Name)
  8220. else
  8221. begin
  8222. // Pascal and JS have similar scoping rules, so we can use 'this'.
  8223. Result:='this';
  8224. if (ThisContext<>nil) and (not IsClassFunction(ThisContext.PasElement)) then
  8225. begin
  8226. // 'this' is an class instance
  8227. if El is TPasVariable then
  8228. begin
  8229. //writeln('TPasToJSConverter.CreateReferencePath class var ',GetObjName(El),' This=',GetObjName(This));
  8230. if (ClassVarModifiersType*TPasVariable(El).VarModifiers<>[])
  8231. and (AContext.Access=caAssign) then
  8232. begin
  8233. Append_GetClass(El); // writing a class var
  8234. end;
  8235. end
  8236. else if IsClassFunction(El) then
  8237. Append_GetClass(El); // accessing a class function
  8238. end;
  8239. break;
  8240. end;
  8241. end
  8242. else if ParentEl.ClassType=TPasEnumType then
  8243. Prepend(Result,ParentEl.Name);
  8244. ParentEl:=ParentEl.Parent;
  8245. end;
  8246. end;
  8247. if (Result<>'') and (Kind in [rpkPathWithDot,rpkPathAndName]) then
  8248. Result:=Result+'.';
  8249. if Kind=rpkPathAndName then
  8250. Result:=Result+TransformVariableName(El,AContext);
  8251. end;
  8252. function TPasToJSConverter.CreateReferencePathExpr(El: TPasElement;
  8253. AContext: TConvertContext; Full: boolean; Ref: TResolvedReference
  8254. ): TJSPrimaryExpressionIdent;
  8255. var
  8256. Name: String;
  8257. begin
  8258. {$IFDEF VerbosePas2JS}
  8259. writeln('TPasToJSConverter.CreateReferencePathExpr El="',GetObjName(El),'" El.Parent=',GetObjName(El.Parent));
  8260. {$ENDIF}
  8261. Name:=CreateReferencePath(El,AContext,rpkPathAndName,Full,Ref);
  8262. Result:=CreateBuiltInIdentifierExpr(Name);
  8263. end;
  8264. procedure TPasToJSConverter.CreateProcedureCall(var Call: TJSCallExpression;
  8265. Args: TParamsExpr; TargetProc: TPasProcedureType; AContext: TConvertContext);
  8266. // create a call, adding call by reference and default values
  8267. begin
  8268. if Call=nil then
  8269. Call:=TJSCallExpression(CreateElement(TJSCallExpression,Args));
  8270. if ((Args=nil) or (length(Args.Params)=0))
  8271. and ((TargetProc=nil) or (TargetProc.Args.Count=0)) then
  8272. exit;
  8273. if Call.Args=nil then
  8274. Call.Args:=TJSArguments(CreateElement(TJSArguments,Args));
  8275. CreateProcedureCallArgs(Call.Args.Elements,Args,TargetProc,AContext);
  8276. end;
  8277. procedure TPasToJSConverter.CreateProcedureCallArgs(
  8278. Elements: TJSArrayLiteralElements; Args: TParamsExpr;
  8279. TargetProc: TPasProcedureType; AContext: TConvertContext);
  8280. // Add call arguments. Handle call by reference and default values
  8281. var
  8282. ArgContext: TConvertContext;
  8283. i: Integer;
  8284. Arg: TJSElement;
  8285. TargetArgs: TFPList;
  8286. TargetArg: TPasArgument;
  8287. OldAccess: TCtxAccess;
  8288. begin
  8289. // get context
  8290. ArgContext:=AContext;
  8291. while ArgContext is TDotContext do
  8292. ArgContext:=ArgContext.Parent;
  8293. i:=0;
  8294. OldAccess:=ArgContext.Access;
  8295. if TargetProc<>nil then
  8296. TargetArgs:=TargetProc.Args
  8297. else
  8298. TargetArgs:=nil;
  8299. // add params
  8300. if Args<>nil then
  8301. while i<length(Args.Params) do
  8302. begin
  8303. if (TargetArgs<>nil) and (i<TargetArgs.Count) then
  8304. TargetArg:=TPasArgument(TargetArgs[i])
  8305. else
  8306. TargetArg:=nil;
  8307. Arg:=CreateProcCallArg(Args.Params[i],TargetArg,ArgContext);
  8308. Elements.AddElement.Expr:=Arg;
  8309. inc(i);
  8310. end;
  8311. // fill up default values
  8312. if TargetProc<>nil then
  8313. begin
  8314. while i<TargetArgs.Count do
  8315. begin
  8316. TargetArg:=TPasArgument(TargetArgs[i]);
  8317. if TargetArg.ValueExpr=nil then
  8318. begin
  8319. {$IFDEF VerbosePas2JS}
  8320. writeln('TPasToJSConverter.CreateProcedureCallArgs missing default value: TargetProc=',TargetProc.Name,' i=',i);
  8321. {$ENDIF}
  8322. RaiseNotSupported(Args,AContext,20170201193601);
  8323. end;
  8324. AContext.Access:=caRead;
  8325. Arg:=ConvertElement(TargetArg.ValueExpr,ArgContext);
  8326. Elements.AddElement.Expr:=Arg;
  8327. inc(i);
  8328. end;
  8329. end;
  8330. ArgContext.Access:=OldAccess;
  8331. end;
  8332. function TPasToJSConverter.CreateProcCallArg(El: TPasExpr;
  8333. TargetArg: TPasArgument; AContext: TConvertContext): TJSElement;
  8334. var
  8335. ExprResolved, ArgResolved: TPasResolverResult;
  8336. ExprFlags: TPasResolverComputeFlags;
  8337. NeedVar: Boolean;
  8338. begin
  8339. Result:=nil;
  8340. if TargetArg=nil then
  8341. begin
  8342. // simple conversion
  8343. AContext.Access:=caRead;
  8344. Result:=ConvertElement(El,AContext);
  8345. exit;
  8346. end;
  8347. if not (TargetArg.Access in [argDefault,argVar,argOut,argConst]) then
  8348. DoError(20170213220927,nPasElementNotSupported,sPasElementNotSupported,
  8349. [AccessNames[TargetArg.Access]],El);
  8350. NeedVar:=TargetArg.Access in [argVar,argOut];
  8351. AContext.Resolver.ComputeElement(TargetArg,ArgResolved,[]);
  8352. ExprFlags:=[];
  8353. if NeedVar then
  8354. Include(ExprFlags,rcNoImplicitProc)
  8355. else if AContext.Resolver.IsProcedureType(ArgResolved,true) then
  8356. Include(ExprFlags,rcNoImplicitProcType);
  8357. if (ArgResolved.TypeEl is TPasArrayType)
  8358. and (El is TParamsExpr) and (TParamsExpr(El).Kind=pekSet) then
  8359. begin
  8360. // passing a set to an open array
  8361. if NeedVar then
  8362. RaiseNotSupported(El,AContext,20170326213042);
  8363. Result:=ConvertOpenArrayParam(AContext.Resolver.ResolveAliasType(ArgResolved.TypeEl),
  8364. TParamsExpr(El),AContext);
  8365. exit;
  8366. end;
  8367. AContext.Resolver.ComputeElement(El,ExprResolved,ExprFlags);
  8368. // consider TargetArg access
  8369. if NeedVar then
  8370. Result:=CreateProcCallArgRef(El,ExprResolved,TargetArg,AContext)
  8371. else
  8372. begin
  8373. // pass as default, const or constref
  8374. AContext.Access:=caRead;
  8375. if (ExprResolved.BaseType=btNil) and (ArgResolved.TypeEl is TPasArrayType) then
  8376. begin
  8377. // arrays must never be null -> pass []
  8378. Result:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,El));
  8379. exit;
  8380. end;
  8381. Result:=ConvertElement(El,AContext);
  8382. if TargetArg.Access=argDefault then
  8383. begin
  8384. if (ExprResolved.BaseType=btSet) and (ExprResolved.IdentEl<>nil) then
  8385. begin
  8386. // right side is a set variable -> create reference
  8387. {$IFDEF VerbosePas2JS}
  8388. writeln('TPasToJSConverter.CreateProcedureCallArg create reference of SET variable Right={',GetResolverResultDesc(ExprResolved),'} AssignContext.RightResolved.IdentEl=',GetObjName(ExprResolved.IdentEl));
  8389. {$ENDIF}
  8390. // create rtl.refSet(right)
  8391. Result:=CreateReferencedSet(El,Result);
  8392. exit;
  8393. end
  8394. else if ExprResolved.BaseType=btContext then
  8395. begin
  8396. if ExprResolved.TypeEl.ClassType=TPasRecordType then
  8397. begin
  8398. // right side is a record -> clone
  8399. {$IFDEF VerbosePas2JS}
  8400. writeln('TPasToJSConverter.CreateProcedureCallArg clone RECORD variable Right={',GetResolverResultDesc(ExprResolved),'} AssignContext.RightResolved.IdentEl=',GetObjName(ExprResolved.IdentEl));
  8401. {$ENDIF}
  8402. // create "new RightRecordType(RightRecord)"
  8403. Result:=CreateCloneRecord(El,ExprResolved,Result,AContext);
  8404. exit;
  8405. end;
  8406. end;
  8407. end;
  8408. end;
  8409. end;
  8410. function TPasToJSConverter.CreateProcCallArgRef(El: TPasExpr;
  8411. ResolvedEl: TPasResolverResult; TargetArg: TPasArgument;
  8412. AContext: TConvertContext): TJSElement;
  8413. const
  8414. GetPathName = 'p';
  8415. SetPathName = 's';
  8416. ParamName = 'a';
  8417. var
  8418. Obj: TJSObjectLiteral;
  8419. procedure AddVar(const aName: string; var Expr: TJSElement);
  8420. var
  8421. ObjLit: TJSObjectLiteralElement;
  8422. begin
  8423. if Expr=nil then exit;
  8424. ObjLit:=Obj.Elements.AddElement;
  8425. ObjLit.Name:=TJSString(aName);
  8426. ObjLit.Expr:=Expr;
  8427. Expr:=nil;
  8428. end;
  8429. var
  8430. ParamContext: TParamContext;
  8431. FullGetter, GetPathExpr, SetPathExpr, GetExpr, SetExpr, ParamExpr: TJSElement;
  8432. AssignSt: TJSSimpleAssignStatement;
  8433. ObjLit: TJSObjectLiteralElement;
  8434. FuncSt: TJSFunctionDeclarationStatement;
  8435. RetSt: TJSReturnStatement;
  8436. GetDotPos, SetDotPos: Integer;
  8437. GetPath, SetPath: String;
  8438. BracketExpr: TJSBracketMemberExpression;
  8439. DotExpr: TJSDotMemberExpression;
  8440. begin
  8441. // pass reference -> create a temporary JS object with a FullGetter and setter
  8442. Obj:=nil;
  8443. FullGetter:=nil;
  8444. ParamContext:=TParamContext.Create(El,nil,AContext);
  8445. GetPathExpr:=nil;
  8446. SetPathExpr:=nil;
  8447. GetExpr:=nil;
  8448. SetExpr:=nil;
  8449. try
  8450. // create FullGetter and setter
  8451. ParamContext.Access:=caByReference;
  8452. ParamContext.Arg:=TargetArg;
  8453. ParamContext.Expr:=El;
  8454. ParamContext.ResolvedExpr:=ResolvedEl;
  8455. FullGetter:=ConvertElement(El,ParamContext);
  8456. // FullGetter is now a full JS expression to retrieve the value.
  8457. if ParamContext.ReusingReference then
  8458. begin
  8459. // result is already a reference
  8460. Result:=FullGetter;
  8461. exit;
  8462. end;
  8463. // if ParamContext.Getter is set then
  8464. // ParamContext.Getter is the last part of the FullGetter
  8465. // FullSetter is created from FullGetter by replacing the Getter with the Setter
  8466. {$IFDEF VerbosePas2JS}
  8467. writeln('TPasToJSConverter.CreateProcedureCallArg VAR FullGetter=',GetObjName(FullGetter),' Getter=',GetObjName(ParamContext.Getter),' Setter=',GetObjName(ParamContext.Setter));
  8468. {$ENDIF}
  8469. if (ParamContext.Getter=nil)<>(ParamContext.Setter=nil) then
  8470. begin
  8471. {$IFDEF VerbosePas2JS}
  8472. writeln('TPasToJSConverter.CreateProcedureCallArg FullGetter=',GetObjName(FullGetter),' Getter=',GetObjName(ParamContext.Getter),' Setter=',GetObjName(ParamContext.Setter));
  8473. {$ENDIF}
  8474. RaiseInconsistency(20170213222941);
  8475. end;
  8476. // create "{p:Result,get:function(){return this.p.Getter},set:function(v){this.p.Setter(v);}}"
  8477. Obj:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,El));
  8478. if FullGetter.ClassType=TJSPrimaryExpressionIdent then
  8479. begin
  8480. // create "{get:function(){return FullGetter;},set:function(v){FullGetter=v;}}"
  8481. if (ParamContext.Getter<>nil) and (ParamContext.Getter<>FullGetter) then
  8482. RaiseInconsistency(20170213224339);
  8483. GetPath:=String(TJSPrimaryExpressionIdent(FullGetter).Name);
  8484. GetDotPos:=PosLast('.',GetPath);
  8485. if GetDotPos>0 then
  8486. begin
  8487. // e.g. path1.path2.readvar
  8488. // create
  8489. // GetPathExpr: path1.path2
  8490. // GetExpr: this.p.readvar
  8491. // Will create "{p:GetPathExpr, get:function(){return GetExpr;},
  8492. // set:function(v){GetExpr = v;}}"
  8493. GetPathExpr:=CreateBuiltInIdentifierExpr(LeftStr(GetPath,GetDotPos-1));
  8494. GetExpr:=CreateDotExpression(El,CreateBuiltInIdentifierExpr('this.'+GetPathName),
  8495. CreateBuiltInIdentifierExpr(copy(GetPath,GetDotPos+1)));
  8496. if ParamContext.Setter=nil then
  8497. SetExpr:=CreateDotExpression(El,CreateBuiltInIdentifierExpr('this.'+GetPathName),
  8498. CreateBuiltInIdentifierExpr(copy(GetPath,GetDotPos+1)));
  8499. end
  8500. else
  8501. begin
  8502. // local var
  8503. GetExpr:=FullGetter;
  8504. FullGetter:=nil;
  8505. if ParamContext.Setter=nil then
  8506. SetExpr:=CreateBuiltInIdentifierExpr(GetPath);
  8507. end;
  8508. if ParamContext.Setter<>nil then
  8509. begin
  8510. // custom Setter
  8511. SetExpr:=ParamContext.Setter;
  8512. ParamContext.Setter:=nil;
  8513. if SetExpr.ClassType=TJSPrimaryExpressionIdent then
  8514. begin
  8515. SetPath:=String(TJSPrimaryExpressionIdent(SetExpr).Name);
  8516. SetDotPos:=PosLast('.',SetPath);
  8517. FreeAndNil(SetExpr);
  8518. if LeftStr(GetPath,GetDotPos)=LeftStr(SetPath,SetDotPos) then
  8519. begin
  8520. // use GetPathExpr for setter
  8521. SetExpr:=CreateDotExpression(El,CreateBuiltInIdentifierExpr('this.'+GetPathName),
  8522. CreateBuiltInIdentifierExpr(copy(SetPath,GetDotPos+1)));
  8523. end
  8524. else
  8525. begin
  8526. // setter needs its own SetPathExpr
  8527. SetPathExpr:=CreateBuiltInIdentifierExpr(LeftStr(SetPath,SetDotPos-1));
  8528. SetExpr:=CreateDotExpression(El,CreateBuiltInIdentifierExpr('this.'+SetPathName),
  8529. CreateBuiltInIdentifierExpr(copy(SetPath,GetDotPos+1)));
  8530. end;
  8531. end;
  8532. end;
  8533. end
  8534. else if FullGetter.ClassType=TJSDotMemberExpression then
  8535. begin
  8536. if ParamContext.Setter<>nil then
  8537. RaiseNotSupported(El,AContext,20170214231900);
  8538. // convert this.r.i to
  8539. // {p:this.r,
  8540. // get:function{return this.p.i;},
  8541. // set:function(v){this.p.i=v;}
  8542. // }
  8543. // GetPathExpr: this.r
  8544. // GetExpr: this.p.i
  8545. // SetExpr: this.p.i
  8546. DotExpr:=TJSDotMemberExpression(FullGetter);
  8547. GetPathExpr:=DotExpr.MExpr;
  8548. DotExpr.MExpr:=CreateBuiltInIdentifierExpr('this.'+GetPathName);
  8549. GetExpr:=DotExpr;
  8550. FullGetter:=nil;
  8551. SetExpr:=CreateDotExpression(El,
  8552. CreateBuiltInIdentifierExpr('this.'+GetPathName),
  8553. CreateBuiltInIdentifierExpr(String(DotExpr.Name)));
  8554. end
  8555. else if FullGetter.ClassType=TJSBracketMemberExpression then
  8556. begin
  8557. if ParamContext.Setter<>nil then
  8558. RaiseNotSupported(El,AContext,20170214215150);
  8559. // convert this.arr[value] to
  8560. // {a:value,
  8561. // p:this.arr,
  8562. // get:function{return this.p[this.a];},
  8563. // set:function(v){this.p[this.a]=v;}
  8564. // }
  8565. BracketExpr:=TJSBracketMemberExpression(FullGetter);
  8566. ParamExpr:=BracketExpr.Name;
  8567. // create "a:value"
  8568. BracketExpr.Name:=CreateBuiltInIdentifierExpr('this.'+ParamName);
  8569. AddVar(ParamName,ParamExpr);
  8570. // create GetPathExpr "this.arr"
  8571. GetPathExpr:=BracketExpr.MExpr;
  8572. BracketExpr.MExpr:=CreateBuiltInIdentifierExpr('this.'+GetPathName);
  8573. // GetExpr "this.p[this.a]"
  8574. GetExpr:=BracketExpr;
  8575. FullGetter:=nil;
  8576. // SetExpr "this.p[this.a]"
  8577. BracketExpr:=TJSBracketMemberExpression(CreateElement(TJSBracketMemberExpression,El));
  8578. SetExpr:=BracketExpr;
  8579. BracketExpr.MExpr:=CreateBuiltInIdentifierExpr('this.'+GetPathName);
  8580. BracketExpr.Name:=CreateBuiltInIdentifierExpr('this.'+ParamName);
  8581. end
  8582. else
  8583. begin
  8584. {$IFDEF VerbosePas2JS}
  8585. writeln('TPasToJSConverter.CreateProcedureCallArg FullGetter=',GetObjName(FullGetter),' Getter=',GetObjName(ParamContext.Getter),' Setter=',GetObjName(ParamContext.Setter));
  8586. {$ENDIF}
  8587. RaiseNotSupported(El,AContext,20170213230336);
  8588. end;
  8589. if (SetExpr.ClassType=TJSPrimaryExpressionIdent)
  8590. or (SetExpr.ClassType=TJSDotMemberExpression)
  8591. or (SetExpr.ClassType=TJSBracketMemberExpression) then
  8592. begin
  8593. // create SetExpr = v;
  8594. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  8595. AssignSt.LHS:=SetExpr;
  8596. AssignSt.Expr:=CreateBuiltInIdentifierExpr(TempRefObjSetterArgName);
  8597. SetExpr:=AssignSt;
  8598. end
  8599. else if (SetExpr.ClassType=TJSCallExpression) then
  8600. // has already the form Func(v)
  8601. else
  8602. RaiseInconsistency(20170213225940);
  8603. // add p:GetPathExpr
  8604. AddVar(GetPathName,GetPathExpr);
  8605. // add get:function(){ return GetExpr; }
  8606. ObjLit:=Obj.Elements.AddElement;
  8607. ObjLit.Name:=TempRefObjGetterName;
  8608. FuncSt:=CreateFunction(El);
  8609. ObjLit.Expr:=FuncSt;
  8610. RetSt:=TJSReturnStatement(CreateElement(TJSReturnStatement,El));
  8611. FuncSt.AFunction.Body.A:=RetSt;
  8612. RetSt.Expr:=GetExpr;
  8613. GetExpr:=nil;
  8614. // add s:GetPathExpr
  8615. AddVar(SetPathName,SetPathExpr);
  8616. // add set:function(v){ SetExpr }
  8617. ObjLit:=Obj.Elements.AddElement;
  8618. ObjLit.Name:=TempRefObjSetterName;
  8619. FuncSt:=CreateFunction(El);
  8620. ObjLit.Expr:=FuncSt;
  8621. FuncSt.AFunction.Params.Add(TempRefObjSetterArgName);
  8622. FuncSt.AFunction.Body.A:=SetExpr;
  8623. SetExpr:=nil;
  8624. Result:=Obj;
  8625. finally
  8626. if Result=nil then
  8627. begin
  8628. GetPathExpr.Free;
  8629. SetPathExpr.Free;
  8630. GetExpr.Free;
  8631. SetExpr.Free;
  8632. Obj.Free;
  8633. ParamContext.Setter.Free;
  8634. FullGetter.Free;
  8635. end;
  8636. ParamContext.Free;
  8637. end;
  8638. end;
  8639. function TPasToJSConverter.ConvertExceptOn(El: TPasImplExceptOn;
  8640. AContext: TConvertContext): TJSElement;
  8641. // convert "on T do ;" to "if(T.isPrototypeOf(exceptObject)){}"
  8642. // convert "on E:T do ;" to "if(T.isPrototypeOf(exceptObject)){ var E=exceptObject; }"
  8643. Var
  8644. IfSt : TJSIfStatement;
  8645. ListFirst , ListLast: TJSStatementList;
  8646. DotExpr: TJSDotMemberExpression;
  8647. Call: TJSCallExpression;
  8648. V: TJSVariableStatement;
  8649. VarDecl: TJSVarDeclaration;
  8650. begin
  8651. Result:=nil;
  8652. // create "if()"
  8653. IfSt:=TJSIfStatement(CreateElement(TJSIfStatement,El));
  8654. try
  8655. // create "T.isPrototypeOf"
  8656. DotExpr:=TJSDotMemberExpression(CreateElement(TJSDotMemberExpression,El));
  8657. DotExpr.MExpr:=CreateReferencePathExpr(El.TypeEl,AContext);
  8658. DotExpr.Name:='isPrototypeOf';
  8659. // create "T.isPrototypeOf(exceptObject)"
  8660. Call:=CreateCallExpression(El);
  8661. Call.Expr:=DotExpr;
  8662. Call.Args.Elements.AddElement.Expr:=CreateBuiltInIdentifierExpr(FBuiltInNames[pbivnExceptObject]);
  8663. IfSt.Cond:=Call;
  8664. if El.VarEl<>nil then
  8665. begin
  8666. // add "var E=exceptObject;"
  8667. ListFirst:=TJSStatementList(CreateElement(TJSStatementList,El.Body));
  8668. ListLast:=ListFirst;
  8669. IfSt.BTrue:=ListFirst;
  8670. V:=TJSVariableStatement(CreateElement(TJSVariableStatement,El));
  8671. ListFirst.A:=V;
  8672. VarDecl:=TJSVarDeclaration(CreateElement(TJSVarDeclaration,El));
  8673. V.A:=VarDecl;
  8674. VarDecl.Name:=TransformVariableName(El,El.VariableName,AContext);
  8675. VarDecl.Init:=CreateBuiltInIdentifierExpr(FBuiltInNames[pbivnExceptObject]);
  8676. // add statements
  8677. AddToStatementList(ListFirst,ListLast,ConvertElement(El.Body,AContext),El);
  8678. end
  8679. else if El.Body<>nil then
  8680. // add statements
  8681. IfSt.BTrue:=ConvertElement(El.Body,AContext);
  8682. Result:=IfSt;
  8683. finally
  8684. if Result=nil then
  8685. IfSt.Free;
  8686. end;
  8687. end;
  8688. function TPasToJSConverter.ConvertStatement(El: TPasImplStatement;
  8689. AContext: TConvertContext): TJSElement;
  8690. begin
  8691. Result:=Nil;
  8692. if (El is TPasImplRaise) then
  8693. Result:=ConvertRaiseStatement(TPasImplRaise(El),AContext)
  8694. else if (El is TPasImplAssign) then
  8695. Result:=ConvertAssignStatement(TPasImplAssign(El),AContext)
  8696. else if (El is TPasImplWhileDo) then
  8697. Result:=ConvertWhileStatement(TPasImplWhileDo(El),AContext)
  8698. else if (El is TPasImplSimple) then
  8699. Result:=ConvertSimpleStatement(TPasImplSimple(El),AContext)
  8700. else if (El is TPasImplWithDo) then
  8701. Result:=ConvertWithStatement(TPasImplWithDo(El),AContext)
  8702. else if (El is TPasImplExceptOn) then
  8703. Result:=ConvertExceptOn(TPasImplExceptOn(El),AContext)
  8704. else if (El is TPasImplForLoop) then
  8705. Result:=ConvertForStatement(TPasImplForLoop(El),AContext)
  8706. else if (El is TPasImplAsmStatement) then
  8707. Result:=ConvertAsmStatement(TPasImplAsmStatement(El),AContext)
  8708. else
  8709. RaiseNotSupported(El,AContext,20161024192759);
  8710. {
  8711. TPasImplCaseStatement = class(TPasImplStatement)
  8712. }
  8713. end;
  8714. function TPasToJSConverter.ConvertCommands(El: TPasImplCommands;
  8715. AContext: TConvertContext): TJSElement;
  8716. begin
  8717. RaiseNotSupported(El,AContext,20161024192806);
  8718. Result:=Nil;
  8719. // ToDo: TPasImplCommands = class(TPasImplElement)
  8720. end;
  8721. function TPasToJSConverter.ConvertConst(El: TPasConst; AContext: TConvertContext
  8722. ): TJSElement;
  8723. // Important: returns nil if const was added to higher context
  8724. Var
  8725. AssignSt: TJSSimpleAssignStatement;
  8726. Obj: TJSObjectLiteral;
  8727. ObjLit: TJSObjectLiteralElement;
  8728. ConstContext: TFunctionContext;
  8729. C: TJSElement;
  8730. V: TJSVariableStatement;
  8731. Src: TJSSourceElements;
  8732. begin
  8733. Result:=nil;
  8734. if not AContext.IsSingleton then
  8735. begin
  8736. // local const are stored in interface/implementation
  8737. ConstContext:=AContext.GetSingletonFunc;
  8738. if not (ConstContext.JSElement is TJSSourceElements) then
  8739. begin
  8740. {$IFDEF VerbosePas2JS}
  8741. writeln('TPasToJSConverter.CreateConstDecl ConstContext=',GetObjName(ConstContext),' JSElement=',GetObjName(ConstContext.JSElement));
  8742. {$ENDIF}
  8743. RaiseNotSupported(El,AContext,20170220153216);
  8744. end;
  8745. Src:=TJSSourceElements(ConstContext.JSElement);
  8746. C:=ConvertVariable(El,AContext);
  8747. V:=TJSVariableStatement(CreateElement(TJSVariableStatement,El));
  8748. V.A:=C;
  8749. AddToSourceElements(Src,V);
  8750. end
  8751. else if AContext is TObjectContext then
  8752. begin
  8753. // create 'A: initvalue'
  8754. Obj:=TObjectContext(AContext).JSElement as TJSObjectLiteral;
  8755. ObjLit:=Obj.Elements.AddElement;
  8756. ObjLit.Name:=TJSString(TransformVariableName(El,AContext));
  8757. ObjLit.Expr:=CreateVarInit(El,AContext);
  8758. end
  8759. else
  8760. begin
  8761. // create 'this.A=initvalue'
  8762. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  8763. Result:=AssignSt;
  8764. AssignSt.LHS:=CreateDeclNameExpression(El,El.Name,AContext);
  8765. AssignSt.Expr:=CreateVarInit(El,AContext);
  8766. end;
  8767. end;
  8768. function TPasToJSConverter.ConvertLabelMark(El: TPasImplLabelMark;
  8769. AContext: TConvertContext): TJSElement;
  8770. begin
  8771. RaiseNotSupported(El,AContext,20161024192857);
  8772. Result:=Nil;
  8773. // ToDo: TPasImplLabelMark = class(TPasImplLabelMark) then
  8774. end;
  8775. function TPasToJSConverter.ConvertElement(El: TPasElement;
  8776. AContext: TConvertContext): TJSElement;
  8777. var
  8778. C: TClass;
  8779. begin
  8780. {$IFDEF VerbosePas2JS}
  8781. writeln('TPasToJSConverter.ConvertElement El=',GetObjName(El),' Context=',GetObjName(AContext));
  8782. {$ENDIF}
  8783. if El=nil then
  8784. begin
  8785. Result:=nil;
  8786. RaiseInconsistency(20161024190203);
  8787. end;
  8788. C:=El.ClassType;
  8789. If (C=TPasPackage) then
  8790. Result:=ConvertPackage(TPasPackage(El),AContext)
  8791. else if (C=TPasResString) then
  8792. Result:=ConvertResString(TPasResString(El),AContext)
  8793. else if (C=TPasConst) then
  8794. Result:=ConvertConst(TPasConst(El),AContext)
  8795. else if (C=TPasProperty) then
  8796. Result:=ConvertProperty(TPasProperty(El),AContext)
  8797. else if (C=TPasVariable) then
  8798. Result:=ConvertVariable(TPasVariable(El),AContext)
  8799. else if (C=TPasExportSymbol) then
  8800. Result:=ConvertExportSymbol(TPasExportSymbol(El),AContext)
  8801. else if (C=TPasLabels) then
  8802. Result:=ConvertLabels(TPasLabels(El),AContext)
  8803. else if (C=TPasImplCommand) then
  8804. Result:=ConvertCommand(TPasImplCommand(El),AContext)
  8805. else if (C=TPasImplCommands) then
  8806. Result:=ConvertCommands(TPasImplCommands(El),AContext)
  8807. else if (C=TPasImplLabelMark) then
  8808. Result:=ConvertLabelMark(TPasImplLabelMark(El),AContext)
  8809. else if C.InheritsFrom(TPasExpr) then
  8810. Result:=ConvertExpression(TPasExpr(El),AContext)
  8811. else if C.InheritsFrom(TPasDeclarations) then
  8812. Result:=ConvertDeclarations(TPasDeclarations(El),AContext)
  8813. else if C.InheritsFrom(TPasProcedure) then
  8814. Result:=ConvertProcedure(TPasProcedure(El),AContext)
  8815. else if C.InheritsFrom(TPasImplBlock) then
  8816. Result:=ConvertImplBlock(TPasImplBlock(El),AContext)
  8817. else if C.InheritsFrom(TPasModule) then
  8818. Result:=ConvertModule(TPasModule(El),AContext)
  8819. else
  8820. begin
  8821. Result:=nil;
  8822. RaiseNotSupported(El, AContext, 20161024190449);
  8823. end;
  8824. {$IFDEF VerbosePas2JS}
  8825. writeln('TPasToJSConverter.ConvertElement END ',GetObjName(El));
  8826. {$ENDIF}
  8827. end;
  8828. function TPasToJSConverter.ConvertRecordType(El: TPasRecordType;
  8829. AContext: TConvertContext): TJSElement;
  8830. (*
  8831. type
  8832. TMyRecord = record
  8833. i: longint;
  8834. s: string;
  8835. d: double;
  8836. r: TOtherRecord;
  8837. end;
  8838. this.TMyRecord=function(s) {
  8839. if (s){
  8840. this.i = s.i;
  8841. this.s = s.s;
  8842. this.d = s.d;
  8843. this.r = new this.TOtherRecord(s.r);
  8844. } else {
  8845. this.i = 0;
  8846. this.s = "";
  8847. this.d = 0.0;
  8848. this.r = new this.TOtherRecord();
  8849. };
  8850. this.$equal = function(b){
  8851. return (this.i == b.i) && (this.s == b.s) && (this.d == b.d)
  8852. && (this.r.$equal(b.r))
  8853. };
  8854. };
  8855. *)
  8856. const
  8857. SrcParamName = 's';
  8858. EqualParamName = 'b';
  8859. procedure AddCloneStatements(IfSt: TJSIfStatement;
  8860. FuncContext: TFunctionContext);
  8861. var
  8862. i: Integer;
  8863. PasVar: TPasVariable;
  8864. VarAssignSt: TJSSimpleAssignStatement;
  8865. First, Last: TJSStatementList;
  8866. VarDotExpr: TJSDotMemberExpression;
  8867. PasVarType: TPasType;
  8868. ResolvedPasVar: TPasResolverResult;
  8869. begin
  8870. // init members with s
  8871. First:=nil;
  8872. Last:=nil;
  8873. for i:=0 to El.Members.Count-1 do
  8874. begin
  8875. PasVar:=TPasVariable(El.Members[i]);
  8876. if not IsElementUsed(PasVar) then continue;
  8877. // create 'this.A = s.A;'
  8878. VarAssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,PasVar));
  8879. AddToStatementList(First,Last,VarAssignSt,PasVar);
  8880. if i=0 then IfSt.BTrue:=First;
  8881. VarAssignSt.LHS:=CreateDeclNameExpression(PasVar,PasVar.Name,FuncContext);
  8882. VarDotExpr:=TJSDotMemberExpression(CreateElement(TJSDotMemberExpression,PasVar));
  8883. VarAssignSt.Expr:=VarDotExpr;
  8884. VarDotExpr.MExpr:=CreateBuiltInIdentifierExpr(SrcParamName);
  8885. VarDotExpr.Name:=TJSString(TransformVariableName(PasVar,FuncContext));
  8886. if (AContext.Resolver<>nil) then
  8887. begin
  8888. PasVarType:=AContext.Resolver.ResolveAliasType(PasVar.VarType);
  8889. if PasVarType.ClassType=TPasRecordType then
  8890. begin
  8891. SetResolverIdentifier(ResolvedPasVar,btContext,PasVar,PasVarType,[rrfReadable,rrfWritable]);
  8892. VarAssignSt.Expr:=CreateCloneRecord(PasVar,ResolvedPasVar,VarDotExpr,FuncContext);
  8893. continue;
  8894. end
  8895. else if PasVarType.ClassType=TPasSetType then
  8896. begin
  8897. VarAssignSt.Expr:=CreateReferencedSet(PasVar,VarDotExpr);
  8898. continue;
  8899. end
  8900. end;
  8901. end;
  8902. end;
  8903. procedure AddInitDefaultStatements(IfSt: TJSIfStatement;
  8904. FuncContext: TFunctionContext);
  8905. var
  8906. i: Integer;
  8907. PasVar: TPasVariable;
  8908. JSVar: TJSElement;
  8909. First, Last: TJSStatementList;
  8910. begin
  8911. // the "else" part:
  8912. // when there is no s parameter, init members with default value
  8913. First:=nil;
  8914. Last:=nil;
  8915. for i:=0 to El.Members.Count-1 do
  8916. begin
  8917. PasVar:=TPasVariable(El.Members[i]);
  8918. if not IsElementUsed(PasVar) then continue;
  8919. JSVar:=CreateVarDecl(PasVar,FuncContext);
  8920. AddToStatementList(First,Last,JSVar,PasVar);
  8921. if IfSt.BFalse=nil then
  8922. IfSt.BFalse:=First;
  8923. end;
  8924. end;
  8925. procedure Add_AndExpr_ToReturnSt(RetSt: TJSReturnStatement;
  8926. PasVar: TPasVariable; var LastAndExpr: TJSLogicalAndExpression;
  8927. Expr: TJSElement);
  8928. var
  8929. AndExpr: TJSLogicalAndExpression;
  8930. begin
  8931. if RetSt.Expr=nil then
  8932. RetSt.Expr:=Expr
  8933. else
  8934. begin
  8935. AndExpr:=TJSLogicalAndExpression(CreateElement(TJSLogicalAndExpression,PasVar));
  8936. if LastAndExpr=nil then
  8937. begin
  8938. AndExpr.A:=RetSt.Expr;
  8939. RetSt.Expr:=AndExpr;
  8940. end
  8941. else
  8942. begin
  8943. AndExpr.A:=LastAndExpr.B;
  8944. LastAndExpr.B:=AndExpr;
  8945. end;
  8946. AndExpr.B:=Expr;
  8947. LastAndExpr:=AndExpr;
  8948. end;
  8949. end;
  8950. procedure AddEqualFunction(var BodyFirst, BodyLast: TJSStatementList;
  8951. FuncContext: TFunctionContext);
  8952. // add equal function:
  8953. // this.$equal = function(b){
  8954. // return (this.member1 == b.member1);
  8955. // };
  8956. var
  8957. AssignSt: TJSSimpleAssignStatement;
  8958. FD: TJSFuncDef;
  8959. RetSt: TJSReturnStatement;
  8960. i: Integer;
  8961. PasVar: TPasVariable;
  8962. FDS: TJSFunctionDeclarationStatement;
  8963. EqExpr: TJSEqualityExpressionEQ;
  8964. LastAndExpr: TJSLogicalAndExpression;
  8965. VarType: TPasType;
  8966. Call: TJSCallExpression;
  8967. VarName: String;
  8968. begin
  8969. // add "this.$equal ="
  8970. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  8971. AssignSt.LHS:=CreateMemberExpression(['this',FBuiltInNames[pbifnRecordEqual]]);
  8972. AddToStatementList(BodyFirst,BodyLast,AssignSt,El);
  8973. // add "function(b){"
  8974. FDS:=CreateFunction(El);
  8975. AssignSt.Expr:=FDS;
  8976. FD:=FDS.AFunction;
  8977. FD.Params.Add(EqualParamName);
  8978. FD.Body:=TJSFunctionBody(CreateElement(TJSFunctionBody,El));
  8979. // add "return "
  8980. RetSt:=TJSReturnStatement(CreateElement(TJSReturnStatement,El));
  8981. FD.Body.A:=RetSt;
  8982. LastAndExpr:=nil;
  8983. for i:=0 to El.Members.Count-1 do
  8984. begin
  8985. PasVar:=TPasVariable(El.Members[i]);
  8986. if not IsElementUsed(PasVar) then continue;
  8987. // "this.member = b.member;"
  8988. VarType:=PasVar.VarType;
  8989. if FuncContext.Resolver<>nil then
  8990. VarType:=FuncContext.Resolver.ResolveAliasType(VarType);
  8991. VarName:=TransformVariableName(PasVar,FuncContext);
  8992. if VarType.ClassType=TPasRecordType then
  8993. begin
  8994. // record
  8995. // add "this.member.$equal(b.member)"
  8996. Call:=CreateCallExpression(PasVar);
  8997. Add_AndExpr_ToReturnSt(RetSt,PasVar,LastAndExpr,Call);
  8998. Call.Expr:=CreateMemberExpression(['this',VarName,FBuiltInNames[pbifnRecordEqual]]);
  8999. Call.Args.Elements.AddElement.Expr:=CreateMemberExpression([EqualParamName,VarName]);
  9000. end
  9001. else if VarType.ClassType=TPasSetType then
  9002. begin
  9003. // set
  9004. // add "rtl.eqSet(this.member,b.member)"
  9005. Call:=CreateCallExpression(PasVar);
  9006. Add_AndExpr_ToReturnSt(RetSt,PasVar,LastAndExpr,Call);
  9007. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnSet_Equal]]);
  9008. Call.Args.Elements.AddElement.Expr:=CreateMemberExpression(['this',VarName]);
  9009. Call.Args.Elements.AddElement.Expr:=CreateMemberExpression([EqualParamName,VarName]);
  9010. end
  9011. else if VarType is TPasProcedureType then
  9012. begin
  9013. // proc type
  9014. // add "rtl.eqCallback(this.member,b.member)"
  9015. Call:=CreateCallExpression(PasVar);
  9016. Add_AndExpr_ToReturnSt(RetSt,PasVar,LastAndExpr,Call);
  9017. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnProcType_Equal]]);
  9018. Call.Args.Elements.AddElement.Expr:=CreateMemberExpression(['this',VarName]);
  9019. Call.Args.Elements.AddElement.Expr:=CreateMemberExpression([EqualParamName,VarName]);
  9020. end
  9021. else
  9022. begin
  9023. // default: use simple equal "=="
  9024. EqExpr:=TJSEqualityExpressionEQ(CreateElement(TJSEqualityExpressionEQ,PasVar));
  9025. Add_AndExpr_ToReturnSt(RetSt,PasVar,LastAndExpr,EqExpr);
  9026. EqExpr.A:=CreateMemberExpression(['this',VarName]);
  9027. EqExpr.B:=CreateMemberExpression([EqualParamName,VarName]);
  9028. end;
  9029. end;
  9030. end;
  9031. var
  9032. AssignSt: TJSSimpleAssignStatement;
  9033. FDS: TJSFunctionDeclarationStatement;
  9034. FD: TJSFuncDef;
  9035. BodyFirst, BodyLast: TJSStatementList;
  9036. FuncContext: TFunctionContext;
  9037. Obj: TJSObjectLiteral;
  9038. ObjLit: TJSObjectLiteralElement;
  9039. IfSt: TJSIfStatement;
  9040. begin
  9041. Result:=nil;
  9042. FuncContext:=nil;
  9043. AssignSt:=nil;
  9044. try
  9045. FDS:=CreateFunction(El);
  9046. if AContext is TObjectContext then
  9047. begin
  9048. // add 'TypeName: function(){}'
  9049. Obj:=TObjectContext(AContext).JSElement as TJSObjectLiteral;
  9050. ObjLit:=Obj.Elements.AddElement;
  9051. ObjLit.Name:=TJSString(TransformVariableName(El,AContext));
  9052. ObjLit.Expr:=FDS;
  9053. end
  9054. else
  9055. begin
  9056. // add 'this.TypeName = function(){}'
  9057. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  9058. AssignSt.LHS:=CreateDeclNameExpression(El,El.Name,AContext);
  9059. AssignSt.Expr:=FDS;
  9060. end;
  9061. FD:=FDS.AFunction;
  9062. // add param s
  9063. FD.Params.Add(SrcParamName);
  9064. // create function body
  9065. FuncContext:=TFunctionContext.Create(El,FD.Body,AContext);
  9066. FuncContext.This:=El;
  9067. FuncContext.IsSingleton:=true;
  9068. if El.Members.Count>0 then
  9069. begin
  9070. BodyFirst:=nil;
  9071. BodyLast:=nil;
  9072. // add if(s)
  9073. IfSt:=TJSIfStatement(CreateElement(TJSIfStatement,El));
  9074. AddToStatementList(BodyFirst,BodyLast,IfSt,El);
  9075. FD.Body.A:=BodyFirst;
  9076. IfSt.Cond:=CreateBuiltInIdentifierExpr(SrcParamName);
  9077. // add clone statements
  9078. AddCloneStatements(IfSt,FuncContext);
  9079. // add init default statements
  9080. AddInitDefaultStatements(IfSt,FuncContext);
  9081. // add equal function
  9082. AddEqualFunction(BodyFirst,BodyLast,FuncContext);
  9083. end;
  9084. Result:=AssignSt;
  9085. finally
  9086. FuncContext.Free;
  9087. if Result=nil then AssignSt.Free;
  9088. end;
  9089. end;
  9090. procedure TPasToJSConverter.DoError(Id: int64; const Msg: String);
  9091. var
  9092. E: EPas2JS;
  9093. begin
  9094. E:=EPas2JS.Create(Msg);
  9095. E.Id:=Id;
  9096. E.MsgType:=mtError;
  9097. Raise E;
  9098. end;
  9099. procedure TPasToJSConverter.DoError(Id: int64; const Msg: String;
  9100. const Args: array of const);
  9101. var
  9102. E: EPas2JS;
  9103. begin
  9104. E:=EPas2JS.CreateFmt(Msg,Args);
  9105. E.Id:=Id;
  9106. E.MsgType:=mtError;
  9107. Raise E;
  9108. end;
  9109. procedure TPasToJSConverter.DoError(Id: int64; MsgNumber: integer;
  9110. const MsgPattern: string; const Args: array of const; El: TPasElement);
  9111. var
  9112. E: EPas2JS;
  9113. begin
  9114. E:=EPas2JS.CreateFmt(MsgPattern,Args);
  9115. {$IFDEF VerbosePas2JS}
  9116. writeln('TPasToJSConverter.DoError ',id,' ',El.FullName,':',El.ClassName,' Msg="',E.Message,'"');
  9117. {$ENDIF}
  9118. E.PasElement:=El;
  9119. E.MsgNumber:=MsgNumber;
  9120. E.Id:=Id;
  9121. E.MsgType:=mtError;
  9122. CreateMsgArgs(E.Args,Args);
  9123. raise E;
  9124. end;
  9125. procedure TPasToJSConverter.RaiseNotSupported(El: TPasElement;
  9126. AContext: TConvertContext; Id: int64; const Msg: string);
  9127. var
  9128. E: EPas2JS;
  9129. begin
  9130. {$IFDEF VerbosePas2JS}
  9131. writeln('TPasToJSConverter.RaiseNotSupported ',id,' ',El.FullName,':',El.ClassName,' Msg="',Msg,'"');
  9132. {$ENDIF}
  9133. if AContext=nil then ;
  9134. E:=EPas2JS.CreateFmt(sPasElementNotSupported,[GetObjName(El)]);
  9135. if Msg<>'' then
  9136. E.Message:=E.Message+': '+Msg;
  9137. E.PasElement:=El;
  9138. E.MsgNumber:=nPasElementNotSupported;
  9139. SetLength(E.Args,1);
  9140. E.Args[0]:=El.ClassName;
  9141. E.Id:=Id;
  9142. E.MsgType:=mtError;
  9143. raise E;
  9144. end;
  9145. procedure TPasToJSConverter.RaiseIdentifierNotFound(Identifier: string;
  9146. El: TPasElement; Id: int64);
  9147. var
  9148. E: EPas2JS;
  9149. begin
  9150. E:=EPas2JS.CreateFmt(sIdentifierNotFound,[Identifier]);
  9151. E.PasElement:=El;
  9152. E.MsgNumber:=nIdentifierNotFound;
  9153. SetLength(E.Args,1);
  9154. E.Args[0]:=Identifier;
  9155. E.Id:=Id;
  9156. E.MsgType:=mtError;
  9157. raise E;
  9158. end;
  9159. function TPasToJSConverter.TransformVariableName(El: TPasElement;
  9160. const AName: String; AContext: TConvertContext): String;
  9161. var
  9162. i: Integer;
  9163. c: Char;
  9164. begin
  9165. if AContext=nil then ;
  9166. if Pos('.',AName)>0 then
  9167. RaiseInconsistency(20170203164711);
  9168. if UseLowerCase then
  9169. Result:=LowerCase(AName)
  9170. else
  9171. Result:=AName;
  9172. if not IsPreservedWord(Result) then
  9173. exit;
  9174. for i:=1 to length(Result) do
  9175. begin
  9176. c:=Result[i];
  9177. case c of
  9178. 'a'..'z','A'..'Z':
  9179. begin
  9180. Result[i]:=chr(ord(c) xor 32);
  9181. if not IsPreservedWord(Result) then
  9182. exit;
  9183. end;
  9184. end;
  9185. end;
  9186. RaiseNotSupported(El,AContext,20170203131832);
  9187. end;
  9188. function TPasToJSConverter.TransformVariableName(El: TPasElement;
  9189. AContext: TConvertContext): String;
  9190. begin
  9191. if (El is TPasProcedure) and (TPasProcedure(El).LibrarySymbolName<>nil) then
  9192. Result:=ComputeConstString(TPasProcedure(El).LibrarySymbolName,AContext,true)
  9193. else if (El is TPasVariable) and (TPasVariable(El).ExportName<>nil) then
  9194. Result:=ComputeConstString(TPasVariable(El).ExportName,AContext,true)
  9195. else
  9196. Result:=TransformVariableName(El,El.Name,AContext);
  9197. end;
  9198. function TPasToJSConverter.TransformModuleName(El: TPasModule;
  9199. AContext: TConvertContext): String;
  9200. begin
  9201. if El is TPasProgram then
  9202. Result:='program'
  9203. else
  9204. Result:=TransformVariableName(El,AContext);
  9205. end;
  9206. function TPasToJSConverter.IsPreservedWord(const aName: string): boolean;
  9207. var
  9208. l, r, m, cmp: Integer;
  9209. begin
  9210. Result:=true;
  9211. if aName=FBuiltInNames[pbivnModules] then exit;
  9212. if aName=FBuiltInNames[pbivnRTL] then exit;
  9213. // search default list
  9214. l:=low(JSReservedWords);
  9215. r:=high(JSReservedWords);
  9216. while l<=r do
  9217. begin
  9218. m:=(l+r) div 2;
  9219. cmp:=CompareStr(aName,JSReservedWords[m]);
  9220. //writeln('TPasToJSConverter.IsPreservedWord Name="',aName,'" l=',l,' r=',r,' m=',m,' JSReservedWords[m]=',JSReservedWords[m],' cmp=',cmp);
  9221. if cmp>0 then
  9222. l:=m+1
  9223. else if cmp<0 then
  9224. r:=m-1
  9225. else
  9226. exit;
  9227. end;
  9228. // search user list
  9229. l:=0;
  9230. r:=length(FPreservedWords)-1;
  9231. while l<=r do
  9232. begin
  9233. m:=(l+r) div 2;
  9234. cmp:=CompareStr(aName,FPreservedWords[m]);
  9235. //writeln('TPasToJSConverter.IsPreservedWord Name="',aName,'" l=',l,' r=',r,' m=',m,' FReservedWords[m]=',FReservedWords[m],' cmp=',cmp);
  9236. if cmp>0 then
  9237. l:=m+1
  9238. else if cmp<0 then
  9239. r:=m-1
  9240. else
  9241. exit;
  9242. end;
  9243. Result:=false;
  9244. end;
  9245. function TPasToJSConverter.ConvertPasElement(El: TPasElement;
  9246. Resolver: TPas2JSResolver): TJSElement;
  9247. var
  9248. aContext: TRootContext;
  9249. begin
  9250. aContext:=TRootContext.Create(El,nil,nil);
  9251. try
  9252. aContext.Resolver:=Resolver;
  9253. if (El.ClassType=TPasImplBeginBlock) then
  9254. Result:=ConvertBeginEndStatement(TPasImplBeginBlock(El),AContext,false)
  9255. else
  9256. Result:=ConvertElement(El,aContext);
  9257. finally
  9258. FreeAndNil(aContext);
  9259. end;
  9260. end;
  9261. var
  9262. i: integer;
  9263. initialization
  9264. for i:=low(JSReservedWords) to High(JSReservedWords)-1 do
  9265. if CompareStr(JSReservedWords[i],JSReservedWords[i+1])>=0 then
  9266. raise Exception.Create('20170203135442 '+JSReservedWords[i]+' >= '+JSReservedWords[i+1]);
  9267. end.