fppas2js.pp 932 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871987298739874987598769877987898799880988198829883988498859886988798889889989098919892989398949895989698979898989999009901990299039904990599069907990899099910991199129913991499159916991799189919992099219922992399249925992699279928992999309931993299339934993599369937993899399940994199429943994499459946994799489949995099519952995399549955995699579958995999609961996299639964996599669967996899699970997199729973997499759976997799789979998099819982998399849985998699879988998999909991999299939994999599969997999899991000010001100021000310004100051000610007100081000910010100111001210013100141001510016100171001810019100201002110022100231002410025100261002710028100291003010031100321003310034100351003610037100381003910040100411004210043100441004510046100471004810049100501005110052100531005410055100561005710058100591006010061100621006310064100651006610067100681006910070100711007210073100741007510076100771007810079100801008110082100831008410085100861008710088100891009010091100921009310094100951009610097100981009910100101011010210103101041010510106101071010810109101101011110112101131011410115101161011710118101191012010121101221012310124101251012610127101281012910130101311013210133101341013510136101371013810139101401014110142101431014410145101461014710148101491015010151101521015310154101551015610157101581015910160101611016210163101641016510166101671016810169101701017110172101731017410175101761017710178101791018010181101821018310184101851018610187101881018910190101911019210193101941019510196101971019810199102001020110202102031020410205102061020710208102091021010211102121021310214102151021610217102181021910220102211022210223102241022510226102271022810229102301023110232102331023410235102361023710238102391024010241102421024310244102451024610247102481024910250102511025210253102541025510256102571025810259102601026110262102631026410265102661026710268102691027010271102721027310274102751027610277102781027910280102811028210283102841028510286102871028810289102901029110292102931029410295102961029710298102991030010301103021030310304103051030610307103081030910310103111031210313103141031510316103171031810319103201032110322103231032410325103261032710328103291033010331103321033310334103351033610337103381033910340103411034210343103441034510346103471034810349103501035110352103531035410355103561035710358103591036010361103621036310364103651036610367103681036910370103711037210373103741037510376103771037810379103801038110382103831038410385103861038710388103891039010391103921039310394103951039610397103981039910400104011040210403104041040510406104071040810409104101041110412104131041410415104161041710418104191042010421104221042310424104251042610427104281042910430104311043210433104341043510436104371043810439104401044110442104431044410445104461044710448104491045010451104521045310454104551045610457104581045910460104611046210463104641046510466104671046810469104701047110472104731047410475104761047710478104791048010481104821048310484104851048610487104881048910490104911049210493104941049510496104971049810499105001050110502105031050410505105061050710508105091051010511105121051310514105151051610517105181051910520105211052210523105241052510526105271052810529105301053110532105331053410535105361053710538105391054010541105421054310544105451054610547105481054910550105511055210553105541055510556105571055810559105601056110562105631056410565105661056710568105691057010571105721057310574105751057610577105781057910580105811058210583105841058510586105871058810589105901059110592105931059410595105961059710598105991060010601106021060310604106051060610607106081060910610106111061210613106141061510616106171061810619106201062110622106231062410625106261062710628106291063010631106321063310634106351063610637106381063910640106411064210643106441064510646106471064810649106501065110652106531065410655106561065710658106591066010661106621066310664106651066610667106681066910670106711067210673106741067510676106771067810679106801068110682106831068410685106861068710688106891069010691106921069310694106951069610697106981069910700107011070210703107041070510706107071070810709107101071110712107131071410715107161071710718107191072010721107221072310724107251072610727107281072910730107311073210733107341073510736107371073810739107401074110742107431074410745107461074710748107491075010751107521075310754107551075610757107581075910760107611076210763107641076510766107671076810769107701077110772107731077410775107761077710778107791078010781107821078310784107851078610787107881078910790107911079210793107941079510796107971079810799108001080110802108031080410805108061080710808108091081010811108121081310814108151081610817108181081910820108211082210823108241082510826108271082810829108301083110832108331083410835108361083710838108391084010841108421084310844108451084610847108481084910850108511085210853108541085510856108571085810859108601086110862108631086410865108661086710868108691087010871108721087310874108751087610877108781087910880108811088210883108841088510886108871088810889108901089110892108931089410895108961089710898108991090010901109021090310904109051090610907109081090910910109111091210913109141091510916109171091810919109201092110922109231092410925109261092710928109291093010931109321093310934109351093610937109381093910940109411094210943109441094510946109471094810949109501095110952109531095410955109561095710958109591096010961109621096310964109651096610967109681096910970109711097210973109741097510976109771097810979109801098110982109831098410985109861098710988109891099010991109921099310994109951099610997109981099911000110011100211003110041100511006110071100811009110101101111012110131101411015110161101711018110191102011021110221102311024110251102611027110281102911030110311103211033110341103511036110371103811039110401104111042110431104411045110461104711048110491105011051110521105311054110551105611057110581105911060110611106211063110641106511066110671106811069110701107111072110731107411075110761107711078110791108011081110821108311084110851108611087110881108911090110911109211093110941109511096110971109811099111001110111102111031110411105111061110711108111091111011111111121111311114111151111611117111181111911120111211112211123111241112511126111271112811129111301113111132111331113411135111361113711138111391114011141111421114311144111451114611147111481114911150111511115211153111541115511156111571115811159111601116111162111631116411165111661116711168111691117011171111721117311174111751117611177111781117911180111811118211183111841118511186111871118811189111901119111192111931119411195111961119711198111991120011201112021120311204112051120611207112081120911210112111121211213112141121511216112171121811219112201122111222112231122411225112261122711228112291123011231112321123311234112351123611237112381123911240112411124211243112441124511246112471124811249112501125111252112531125411255112561125711258112591126011261112621126311264112651126611267112681126911270112711127211273112741127511276112771127811279112801128111282112831128411285112861128711288112891129011291112921129311294112951129611297112981129911300113011130211303113041130511306113071130811309113101131111312113131131411315113161131711318113191132011321113221132311324113251132611327113281132911330113311133211333113341133511336113371133811339113401134111342113431134411345113461134711348113491135011351113521135311354113551135611357113581135911360113611136211363113641136511366113671136811369113701137111372113731137411375113761137711378113791138011381113821138311384113851138611387113881138911390113911139211393113941139511396113971139811399114001140111402114031140411405114061140711408114091141011411114121141311414114151141611417114181141911420114211142211423114241142511426114271142811429114301143111432114331143411435114361143711438114391144011441114421144311444114451144611447114481144911450114511145211453114541145511456114571145811459114601146111462114631146411465114661146711468114691147011471114721147311474114751147611477114781147911480114811148211483114841148511486114871148811489114901149111492114931149411495114961149711498114991150011501115021150311504115051150611507115081150911510115111151211513115141151511516115171151811519115201152111522115231152411525115261152711528115291153011531115321153311534115351153611537115381153911540115411154211543115441154511546115471154811549115501155111552115531155411555115561155711558115591156011561115621156311564115651156611567115681156911570115711157211573115741157511576115771157811579115801158111582115831158411585115861158711588115891159011591115921159311594115951159611597115981159911600116011160211603116041160511606116071160811609116101161111612116131161411615116161161711618116191162011621116221162311624116251162611627116281162911630116311163211633116341163511636116371163811639116401164111642116431164411645116461164711648116491165011651116521165311654116551165611657116581165911660116611166211663116641166511666116671166811669116701167111672116731167411675116761167711678116791168011681116821168311684116851168611687116881168911690116911169211693116941169511696116971169811699117001170111702117031170411705117061170711708117091171011711117121171311714117151171611717117181171911720117211172211723117241172511726117271172811729117301173111732117331173411735117361173711738117391174011741117421174311744117451174611747117481174911750117511175211753117541175511756117571175811759117601176111762117631176411765117661176711768117691177011771117721177311774117751177611777117781177911780117811178211783117841178511786117871178811789117901179111792117931179411795117961179711798117991180011801118021180311804118051180611807118081180911810118111181211813118141181511816118171181811819118201182111822118231182411825118261182711828118291183011831118321183311834118351183611837118381183911840118411184211843118441184511846118471184811849118501185111852118531185411855118561185711858118591186011861118621186311864118651186611867118681186911870118711187211873118741187511876118771187811879118801188111882118831188411885118861188711888118891189011891118921189311894118951189611897118981189911900119011190211903119041190511906119071190811909119101191111912119131191411915119161191711918119191192011921119221192311924119251192611927119281192911930119311193211933119341193511936119371193811939119401194111942119431194411945119461194711948119491195011951119521195311954119551195611957119581195911960119611196211963119641196511966119671196811969119701197111972119731197411975119761197711978119791198011981119821198311984119851198611987119881198911990119911199211993119941199511996119971199811999120001200112002120031200412005120061200712008120091201012011120121201312014120151201612017120181201912020120211202212023120241202512026120271202812029120301203112032120331203412035120361203712038120391204012041120421204312044120451204612047120481204912050120511205212053120541205512056120571205812059120601206112062120631206412065120661206712068120691207012071120721207312074120751207612077120781207912080120811208212083120841208512086120871208812089120901209112092120931209412095120961209712098120991210012101121021210312104121051210612107121081210912110121111211212113121141211512116121171211812119121201212112122121231212412125121261212712128121291213012131121321213312134121351213612137121381213912140121411214212143121441214512146121471214812149121501215112152121531215412155121561215712158121591216012161121621216312164121651216612167121681216912170121711217212173121741217512176121771217812179121801218112182121831218412185121861218712188121891219012191121921219312194121951219612197121981219912200122011220212203122041220512206122071220812209122101221112212122131221412215122161221712218122191222012221122221222312224122251222612227122281222912230122311223212233122341223512236122371223812239122401224112242122431224412245122461224712248122491225012251122521225312254122551225612257122581225912260122611226212263122641226512266122671226812269122701227112272122731227412275122761227712278122791228012281122821228312284122851228612287122881228912290122911229212293122941229512296122971229812299123001230112302123031230412305123061230712308123091231012311123121231312314123151231612317123181231912320123211232212323123241232512326123271232812329123301233112332123331233412335123361233712338123391234012341123421234312344123451234612347123481234912350123511235212353123541235512356123571235812359123601236112362123631236412365123661236712368123691237012371123721237312374123751237612377123781237912380123811238212383123841238512386123871238812389123901239112392123931239412395123961239712398123991240012401124021240312404124051240612407124081240912410124111241212413124141241512416124171241812419124201242112422124231242412425124261242712428124291243012431124321243312434124351243612437124381243912440124411244212443124441244512446124471244812449124501245112452124531245412455124561245712458124591246012461124621246312464124651246612467124681246912470124711247212473124741247512476124771247812479124801248112482124831248412485124861248712488124891249012491124921249312494124951249612497124981249912500125011250212503125041250512506125071250812509125101251112512125131251412515125161251712518125191252012521125221252312524125251252612527125281252912530125311253212533125341253512536125371253812539125401254112542125431254412545125461254712548125491255012551125521255312554125551255612557125581255912560125611256212563125641256512566125671256812569125701257112572125731257412575125761257712578125791258012581125821258312584125851258612587125881258912590125911259212593125941259512596125971259812599126001260112602126031260412605126061260712608126091261012611126121261312614126151261612617126181261912620126211262212623126241262512626126271262812629126301263112632126331263412635126361263712638126391264012641126421264312644126451264612647126481264912650126511265212653126541265512656126571265812659126601266112662126631266412665126661266712668126691267012671126721267312674126751267612677126781267912680126811268212683126841268512686126871268812689126901269112692126931269412695126961269712698126991270012701127021270312704127051270612707127081270912710127111271212713127141271512716127171271812719127201272112722127231272412725127261272712728127291273012731127321273312734127351273612737127381273912740127411274212743127441274512746127471274812749127501275112752127531275412755127561275712758127591276012761127621276312764127651276612767127681276912770127711277212773127741277512776127771277812779127801278112782127831278412785127861278712788127891279012791127921279312794127951279612797127981279912800128011280212803128041280512806128071280812809128101281112812128131281412815128161281712818128191282012821128221282312824128251282612827128281282912830128311283212833128341283512836128371283812839128401284112842128431284412845128461284712848128491285012851128521285312854128551285612857128581285912860128611286212863128641286512866128671286812869128701287112872128731287412875128761287712878128791288012881128821288312884128851288612887128881288912890128911289212893128941289512896128971289812899129001290112902129031290412905129061290712908129091291012911129121291312914129151291612917129181291912920129211292212923129241292512926129271292812929129301293112932129331293412935129361293712938129391294012941129421294312944129451294612947129481294912950129511295212953129541295512956129571295812959129601296112962129631296412965129661296712968129691297012971129721297312974129751297612977129781297912980129811298212983129841298512986129871298812989129901299112992129931299412995129961299712998129991300013001130021300313004130051300613007130081300913010130111301213013130141301513016130171301813019130201302113022130231302413025130261302713028130291303013031130321303313034130351303613037130381303913040130411304213043130441304513046130471304813049130501305113052130531305413055130561305713058130591306013061130621306313064130651306613067130681306913070130711307213073130741307513076130771307813079130801308113082130831308413085130861308713088130891309013091130921309313094130951309613097130981309913100131011310213103131041310513106131071310813109131101311113112131131311413115131161311713118131191312013121131221312313124131251312613127131281312913130131311313213133131341313513136131371313813139131401314113142131431314413145131461314713148131491315013151131521315313154131551315613157131581315913160131611316213163131641316513166131671316813169131701317113172131731317413175131761317713178131791318013181131821318313184131851318613187131881318913190131911319213193131941319513196131971319813199132001320113202132031320413205132061320713208132091321013211132121321313214132151321613217132181321913220132211322213223132241322513226132271322813229132301323113232132331323413235132361323713238132391324013241132421324313244132451324613247132481324913250132511325213253132541325513256132571325813259132601326113262132631326413265132661326713268132691327013271132721327313274132751327613277132781327913280132811328213283132841328513286132871328813289132901329113292132931329413295132961329713298132991330013301133021330313304133051330613307133081330913310133111331213313133141331513316133171331813319133201332113322133231332413325133261332713328133291333013331133321333313334133351333613337133381333913340133411334213343133441334513346133471334813349133501335113352133531335413355133561335713358133591336013361133621336313364133651336613367133681336913370133711337213373133741337513376133771337813379133801338113382133831338413385133861338713388133891339013391133921339313394133951339613397133981339913400134011340213403134041340513406134071340813409134101341113412134131341413415134161341713418134191342013421134221342313424134251342613427134281342913430134311343213433134341343513436134371343813439134401344113442134431344413445134461344713448134491345013451134521345313454134551345613457134581345913460134611346213463134641346513466134671346813469134701347113472134731347413475134761347713478134791348013481134821348313484134851348613487134881348913490134911349213493134941349513496134971349813499135001350113502135031350413505135061350713508135091351013511135121351313514135151351613517135181351913520135211352213523135241352513526135271352813529135301353113532135331353413535135361353713538135391354013541135421354313544135451354613547135481354913550135511355213553135541355513556135571355813559135601356113562135631356413565135661356713568135691357013571135721357313574135751357613577135781357913580135811358213583135841358513586135871358813589135901359113592135931359413595135961359713598135991360013601136021360313604136051360613607136081360913610136111361213613136141361513616136171361813619136201362113622136231362413625136261362713628136291363013631136321363313634136351363613637136381363913640136411364213643136441364513646136471364813649136501365113652136531365413655136561365713658136591366013661136621366313664136651366613667136681366913670136711367213673136741367513676136771367813679136801368113682136831368413685136861368713688136891369013691136921369313694136951369613697136981369913700137011370213703137041370513706137071370813709137101371113712137131371413715137161371713718137191372013721137221372313724137251372613727137281372913730137311373213733137341373513736137371373813739137401374113742137431374413745137461374713748137491375013751137521375313754137551375613757137581375913760137611376213763137641376513766137671376813769137701377113772137731377413775137761377713778137791378013781137821378313784137851378613787137881378913790137911379213793137941379513796137971379813799138001380113802138031380413805138061380713808138091381013811138121381313814138151381613817138181381913820138211382213823138241382513826138271382813829138301383113832138331383413835138361383713838138391384013841138421384313844138451384613847138481384913850138511385213853138541385513856138571385813859138601386113862138631386413865138661386713868138691387013871138721387313874138751387613877138781387913880138811388213883138841388513886138871388813889138901389113892138931389413895138961389713898138991390013901139021390313904139051390613907139081390913910139111391213913139141391513916139171391813919139201392113922139231392413925139261392713928139291393013931139321393313934139351393613937139381393913940139411394213943139441394513946139471394813949139501395113952139531395413955139561395713958139591396013961139621396313964139651396613967139681396913970139711397213973139741397513976139771397813979139801398113982139831398413985139861398713988139891399013991139921399313994139951399613997139981399914000140011400214003140041400514006140071400814009140101401114012140131401414015140161401714018140191402014021140221402314024140251402614027140281402914030140311403214033140341403514036140371403814039140401404114042140431404414045140461404714048140491405014051140521405314054140551405614057140581405914060140611406214063140641406514066140671406814069140701407114072140731407414075140761407714078140791408014081140821408314084140851408614087140881408914090140911409214093140941409514096140971409814099141001410114102141031410414105141061410714108141091411014111141121411314114141151411614117141181411914120141211412214123141241412514126141271412814129141301413114132141331413414135141361413714138141391414014141141421414314144141451414614147141481414914150141511415214153141541415514156141571415814159141601416114162141631416414165141661416714168141691417014171141721417314174141751417614177141781417914180141811418214183141841418514186141871418814189141901419114192141931419414195141961419714198141991420014201142021420314204142051420614207142081420914210142111421214213142141421514216142171421814219142201422114222142231422414225142261422714228142291423014231142321423314234142351423614237142381423914240142411424214243142441424514246142471424814249142501425114252142531425414255142561425714258142591426014261142621426314264142651426614267142681426914270142711427214273142741427514276142771427814279142801428114282142831428414285142861428714288142891429014291142921429314294142951429614297142981429914300143011430214303143041430514306143071430814309143101431114312143131431414315143161431714318143191432014321143221432314324143251432614327143281432914330143311433214333143341433514336143371433814339143401434114342143431434414345143461434714348143491435014351143521435314354143551435614357143581435914360143611436214363143641436514366143671436814369143701437114372143731437414375143761437714378143791438014381143821438314384143851438614387143881438914390143911439214393143941439514396143971439814399144001440114402144031440414405144061440714408144091441014411144121441314414144151441614417144181441914420144211442214423144241442514426144271442814429144301443114432144331443414435144361443714438144391444014441144421444314444144451444614447144481444914450144511445214453144541445514456144571445814459144601446114462144631446414465144661446714468144691447014471144721447314474144751447614477144781447914480144811448214483144841448514486144871448814489144901449114492144931449414495144961449714498144991450014501145021450314504145051450614507145081450914510145111451214513145141451514516145171451814519145201452114522145231452414525145261452714528145291453014531145321453314534145351453614537145381453914540145411454214543145441454514546145471454814549145501455114552145531455414555145561455714558145591456014561145621456314564145651456614567145681456914570145711457214573145741457514576145771457814579145801458114582145831458414585145861458714588145891459014591145921459314594145951459614597145981459914600146011460214603146041460514606146071460814609146101461114612146131461414615146161461714618146191462014621146221462314624146251462614627146281462914630146311463214633146341463514636146371463814639146401464114642146431464414645146461464714648146491465014651146521465314654146551465614657146581465914660146611466214663146641466514666146671466814669146701467114672146731467414675146761467714678146791468014681146821468314684146851468614687146881468914690146911469214693146941469514696146971469814699147001470114702147031470414705147061470714708147091471014711147121471314714147151471614717147181471914720147211472214723147241472514726147271472814729147301473114732147331473414735147361473714738147391474014741147421474314744147451474614747147481474914750147511475214753147541475514756147571475814759147601476114762147631476414765147661476714768147691477014771147721477314774147751477614777147781477914780147811478214783147841478514786147871478814789147901479114792147931479414795147961479714798147991480014801148021480314804148051480614807148081480914810148111481214813148141481514816148171481814819148201482114822148231482414825148261482714828148291483014831148321483314834148351483614837148381483914840148411484214843148441484514846148471484814849148501485114852148531485414855148561485714858148591486014861148621486314864148651486614867148681486914870148711487214873148741487514876148771487814879148801488114882148831488414885148861488714888148891489014891148921489314894148951489614897148981489914900149011490214903149041490514906149071490814909149101491114912149131491414915149161491714918149191492014921149221492314924149251492614927149281492914930149311493214933149341493514936149371493814939149401494114942149431494414945149461494714948149491495014951149521495314954149551495614957149581495914960149611496214963149641496514966149671496814969149701497114972149731497414975149761497714978149791498014981149821498314984149851498614987149881498914990149911499214993149941499514996149971499814999150001500115002150031500415005150061500715008150091501015011150121501315014150151501615017150181501915020150211502215023150241502515026150271502815029150301503115032150331503415035150361503715038150391504015041150421504315044150451504615047150481504915050150511505215053150541505515056150571505815059150601506115062150631506415065150661506715068150691507015071150721507315074150751507615077150781507915080150811508215083150841508515086150871508815089150901509115092150931509415095150961509715098150991510015101151021510315104151051510615107151081510915110151111511215113151141511515116151171511815119151201512115122151231512415125151261512715128151291513015131151321513315134151351513615137151381513915140151411514215143151441514515146151471514815149151501515115152151531515415155151561515715158151591516015161151621516315164151651516615167151681516915170151711517215173151741517515176151771517815179151801518115182151831518415185151861518715188151891519015191151921519315194151951519615197151981519915200152011520215203152041520515206152071520815209152101521115212152131521415215152161521715218152191522015221152221522315224152251522615227152281522915230152311523215233152341523515236152371523815239152401524115242152431524415245152461524715248152491525015251152521525315254152551525615257152581525915260152611526215263152641526515266152671526815269152701527115272152731527415275152761527715278152791528015281152821528315284152851528615287152881528915290152911529215293152941529515296152971529815299153001530115302153031530415305153061530715308153091531015311153121531315314153151531615317153181531915320153211532215323153241532515326153271532815329153301533115332153331533415335153361533715338153391534015341153421534315344153451534615347153481534915350153511535215353153541535515356153571535815359153601536115362153631536415365153661536715368153691537015371153721537315374153751537615377153781537915380153811538215383153841538515386153871538815389153901539115392153931539415395153961539715398153991540015401154021540315404154051540615407154081540915410154111541215413154141541515416154171541815419154201542115422154231542415425154261542715428154291543015431154321543315434154351543615437154381543915440154411544215443154441544515446154471544815449154501545115452154531545415455154561545715458154591546015461154621546315464154651546615467154681546915470154711547215473154741547515476154771547815479154801548115482154831548415485154861548715488154891549015491154921549315494154951549615497154981549915500155011550215503155041550515506155071550815509155101551115512155131551415515155161551715518155191552015521155221552315524155251552615527155281552915530155311553215533155341553515536155371553815539155401554115542155431554415545155461554715548155491555015551155521555315554155551555615557155581555915560155611556215563155641556515566155671556815569155701557115572155731557415575155761557715578155791558015581155821558315584155851558615587155881558915590155911559215593155941559515596155971559815599156001560115602156031560415605156061560715608156091561015611156121561315614156151561615617156181561915620156211562215623156241562515626156271562815629156301563115632156331563415635156361563715638156391564015641156421564315644156451564615647156481564915650156511565215653156541565515656156571565815659156601566115662156631566415665156661566715668156691567015671156721567315674156751567615677156781567915680156811568215683156841568515686156871568815689156901569115692156931569415695156961569715698156991570015701157021570315704157051570615707157081570915710157111571215713157141571515716157171571815719157201572115722157231572415725157261572715728157291573015731157321573315734157351573615737157381573915740157411574215743157441574515746157471574815749157501575115752157531575415755157561575715758157591576015761157621576315764157651576615767157681576915770157711577215773157741577515776157771577815779157801578115782157831578415785157861578715788157891579015791157921579315794157951579615797157981579915800158011580215803158041580515806158071580815809158101581115812158131581415815158161581715818158191582015821158221582315824158251582615827158281582915830158311583215833158341583515836158371583815839158401584115842158431584415845158461584715848158491585015851158521585315854158551585615857158581585915860158611586215863158641586515866158671586815869158701587115872158731587415875158761587715878158791588015881158821588315884158851588615887158881588915890158911589215893158941589515896158971589815899159001590115902159031590415905159061590715908159091591015911159121591315914159151591615917159181591915920159211592215923159241592515926159271592815929159301593115932159331593415935159361593715938159391594015941159421594315944159451594615947159481594915950159511595215953159541595515956159571595815959159601596115962159631596415965159661596715968159691597015971159721597315974159751597615977159781597915980159811598215983159841598515986159871598815989159901599115992159931599415995159961599715998159991600016001160021600316004160051600616007160081600916010160111601216013160141601516016160171601816019160201602116022160231602416025160261602716028160291603016031160321603316034160351603616037160381603916040160411604216043160441604516046160471604816049160501605116052160531605416055160561605716058160591606016061160621606316064160651606616067160681606916070160711607216073160741607516076160771607816079160801608116082160831608416085160861608716088160891609016091160921609316094160951609616097160981609916100161011610216103161041610516106161071610816109161101611116112161131611416115161161611716118161191612016121161221612316124161251612616127161281612916130161311613216133161341613516136161371613816139161401614116142161431614416145161461614716148161491615016151161521615316154161551615616157161581615916160161611616216163161641616516166161671616816169161701617116172161731617416175161761617716178161791618016181161821618316184161851618616187161881618916190161911619216193161941619516196161971619816199162001620116202162031620416205162061620716208162091621016211162121621316214162151621616217162181621916220162211622216223162241622516226162271622816229162301623116232162331623416235162361623716238162391624016241162421624316244162451624616247162481624916250162511625216253162541625516256162571625816259162601626116262162631626416265162661626716268162691627016271162721627316274162751627616277162781627916280162811628216283162841628516286162871628816289162901629116292162931629416295162961629716298162991630016301163021630316304163051630616307163081630916310163111631216313163141631516316163171631816319163201632116322163231632416325163261632716328163291633016331163321633316334163351633616337163381633916340163411634216343163441634516346163471634816349163501635116352163531635416355163561635716358163591636016361163621636316364163651636616367163681636916370163711637216373163741637516376163771637816379163801638116382163831638416385163861638716388163891639016391163921639316394163951639616397163981639916400164011640216403164041640516406164071640816409164101641116412164131641416415164161641716418164191642016421164221642316424164251642616427164281642916430164311643216433164341643516436164371643816439164401644116442164431644416445164461644716448164491645016451164521645316454164551645616457164581645916460164611646216463164641646516466164671646816469164701647116472164731647416475164761647716478164791648016481164821648316484164851648616487164881648916490164911649216493164941649516496164971649816499165001650116502165031650416505165061650716508165091651016511165121651316514165151651616517165181651916520165211652216523165241652516526165271652816529165301653116532165331653416535165361653716538165391654016541165421654316544165451654616547165481654916550165511655216553165541655516556165571655816559165601656116562165631656416565165661656716568165691657016571165721657316574165751657616577165781657916580165811658216583165841658516586165871658816589165901659116592165931659416595165961659716598165991660016601166021660316604166051660616607166081660916610166111661216613166141661516616166171661816619166201662116622166231662416625166261662716628166291663016631166321663316634166351663616637166381663916640166411664216643166441664516646166471664816649166501665116652166531665416655166561665716658166591666016661166621666316664166651666616667166681666916670166711667216673166741667516676166771667816679166801668116682166831668416685166861668716688166891669016691166921669316694166951669616697166981669916700167011670216703167041670516706167071670816709167101671116712167131671416715167161671716718167191672016721167221672316724167251672616727167281672916730167311673216733167341673516736167371673816739167401674116742167431674416745167461674716748167491675016751167521675316754167551675616757167581675916760167611676216763167641676516766167671676816769167701677116772167731677416775167761677716778167791678016781167821678316784167851678616787167881678916790167911679216793167941679516796167971679816799168001680116802168031680416805168061680716808168091681016811168121681316814168151681616817168181681916820168211682216823168241682516826168271682816829168301683116832168331683416835168361683716838168391684016841168421684316844168451684616847168481684916850168511685216853168541685516856168571685816859168601686116862168631686416865168661686716868168691687016871168721687316874168751687616877168781687916880168811688216883168841688516886168871688816889168901689116892168931689416895168961689716898168991690016901169021690316904169051690616907169081690916910169111691216913169141691516916169171691816919169201692116922169231692416925169261692716928169291693016931169321693316934169351693616937169381693916940169411694216943169441694516946169471694816949169501695116952169531695416955169561695716958169591696016961169621696316964169651696616967169681696916970169711697216973169741697516976169771697816979169801698116982169831698416985169861698716988169891699016991169921699316994169951699616997169981699917000170011700217003170041700517006170071700817009170101701117012170131701417015170161701717018170191702017021170221702317024170251702617027170281702917030170311703217033170341703517036170371703817039170401704117042170431704417045170461704717048170491705017051170521705317054170551705617057170581705917060170611706217063170641706517066170671706817069170701707117072170731707417075170761707717078170791708017081170821708317084170851708617087170881708917090170911709217093170941709517096170971709817099171001710117102171031710417105171061710717108171091711017111171121711317114171151711617117171181711917120171211712217123171241712517126171271712817129171301713117132171331713417135171361713717138171391714017141171421714317144171451714617147171481714917150171511715217153171541715517156171571715817159171601716117162171631716417165171661716717168171691717017171171721717317174171751717617177171781717917180171811718217183171841718517186171871718817189171901719117192171931719417195171961719717198171991720017201172021720317204172051720617207172081720917210172111721217213172141721517216172171721817219172201722117222172231722417225172261722717228172291723017231172321723317234172351723617237172381723917240172411724217243172441724517246172471724817249172501725117252172531725417255172561725717258172591726017261172621726317264172651726617267172681726917270172711727217273172741727517276172771727817279172801728117282172831728417285172861728717288172891729017291172921729317294172951729617297172981729917300173011730217303173041730517306173071730817309173101731117312173131731417315173161731717318173191732017321173221732317324173251732617327173281732917330173311733217333173341733517336173371733817339173401734117342173431734417345173461734717348173491735017351173521735317354173551735617357173581735917360173611736217363173641736517366173671736817369173701737117372173731737417375173761737717378173791738017381173821738317384173851738617387173881738917390173911739217393173941739517396173971739817399174001740117402174031740417405174061740717408174091741017411174121741317414174151741617417174181741917420174211742217423174241742517426174271742817429174301743117432174331743417435174361743717438174391744017441174421744317444174451744617447174481744917450174511745217453174541745517456174571745817459174601746117462174631746417465174661746717468174691747017471174721747317474174751747617477174781747917480174811748217483174841748517486174871748817489174901749117492174931749417495174961749717498174991750017501175021750317504175051750617507175081750917510175111751217513175141751517516175171751817519175201752117522175231752417525175261752717528175291753017531175321753317534175351753617537175381753917540175411754217543175441754517546175471754817549175501755117552175531755417555175561755717558175591756017561175621756317564175651756617567175681756917570175711757217573175741757517576175771757817579175801758117582175831758417585175861758717588175891759017591175921759317594175951759617597175981759917600176011760217603176041760517606176071760817609176101761117612176131761417615176161761717618176191762017621176221762317624176251762617627176281762917630176311763217633176341763517636176371763817639176401764117642176431764417645176461764717648176491765017651176521765317654176551765617657176581765917660176611766217663176641766517666176671766817669176701767117672176731767417675176761767717678176791768017681176821768317684176851768617687176881768917690176911769217693176941769517696176971769817699177001770117702177031770417705177061770717708177091771017711177121771317714177151771617717177181771917720177211772217723177241772517726177271772817729177301773117732177331773417735177361773717738177391774017741177421774317744177451774617747177481774917750177511775217753177541775517756177571775817759177601776117762177631776417765177661776717768177691777017771177721777317774177751777617777177781777917780177811778217783177841778517786177871778817789177901779117792177931779417795177961779717798177991780017801178021780317804178051780617807178081780917810178111781217813178141781517816178171781817819178201782117822178231782417825178261782717828178291783017831178321783317834178351783617837178381783917840178411784217843178441784517846178471784817849178501785117852178531785417855178561785717858178591786017861178621786317864178651786617867178681786917870178711787217873178741787517876178771787817879178801788117882178831788417885178861788717888178891789017891178921789317894178951789617897178981789917900179011790217903179041790517906179071790817909179101791117912179131791417915179161791717918179191792017921179221792317924179251792617927179281792917930179311793217933179341793517936179371793817939179401794117942179431794417945179461794717948179491795017951179521795317954179551795617957179581795917960179611796217963179641796517966179671796817969179701797117972179731797417975179761797717978179791798017981179821798317984179851798617987179881798917990179911799217993179941799517996179971799817999180001800118002180031800418005180061800718008180091801018011180121801318014180151801618017180181801918020180211802218023180241802518026180271802818029180301803118032180331803418035180361803718038180391804018041180421804318044180451804618047180481804918050180511805218053180541805518056180571805818059180601806118062180631806418065180661806718068180691807018071180721807318074180751807618077180781807918080180811808218083180841808518086180871808818089180901809118092180931809418095180961809718098180991810018101181021810318104181051810618107181081810918110181111811218113181141811518116181171811818119181201812118122181231812418125181261812718128181291813018131181321813318134181351813618137181381813918140181411814218143181441814518146181471814818149181501815118152181531815418155181561815718158181591816018161181621816318164181651816618167181681816918170181711817218173181741817518176181771817818179181801818118182181831818418185181861818718188181891819018191181921819318194181951819618197181981819918200182011820218203182041820518206182071820818209182101821118212182131821418215182161821718218182191822018221182221822318224182251822618227182281822918230182311823218233182341823518236182371823818239182401824118242182431824418245182461824718248182491825018251182521825318254182551825618257182581825918260182611826218263182641826518266182671826818269182701827118272182731827418275182761827718278182791828018281182821828318284182851828618287182881828918290182911829218293182941829518296182971829818299183001830118302183031830418305183061830718308183091831018311183121831318314183151831618317183181831918320183211832218323183241832518326183271832818329183301833118332183331833418335183361833718338183391834018341183421834318344183451834618347183481834918350183511835218353183541835518356183571835818359183601836118362183631836418365183661836718368183691837018371183721837318374183751837618377183781837918380183811838218383183841838518386183871838818389183901839118392183931839418395183961839718398183991840018401184021840318404184051840618407184081840918410184111841218413184141841518416184171841818419184201842118422184231842418425184261842718428184291843018431184321843318434184351843618437184381843918440184411844218443184441844518446184471844818449184501845118452184531845418455184561845718458184591846018461184621846318464184651846618467184681846918470184711847218473184741847518476184771847818479184801848118482184831848418485184861848718488184891849018491184921849318494184951849618497184981849918500185011850218503185041850518506185071850818509185101851118512185131851418515185161851718518185191852018521185221852318524185251852618527185281852918530185311853218533185341853518536185371853818539185401854118542185431854418545185461854718548185491855018551185521855318554185551855618557185581855918560185611856218563185641856518566185671856818569185701857118572185731857418575185761857718578185791858018581185821858318584185851858618587185881858918590185911859218593185941859518596185971859818599186001860118602186031860418605186061860718608186091861018611186121861318614186151861618617186181861918620186211862218623186241862518626186271862818629186301863118632186331863418635186361863718638186391864018641186421864318644186451864618647186481864918650186511865218653186541865518656186571865818659186601866118662186631866418665186661866718668186691867018671186721867318674186751867618677186781867918680186811868218683186841868518686186871868818689186901869118692186931869418695186961869718698186991870018701187021870318704187051870618707187081870918710187111871218713187141871518716187171871818719187201872118722187231872418725187261872718728187291873018731187321873318734187351873618737187381873918740187411874218743187441874518746187471874818749187501875118752187531875418755187561875718758187591876018761187621876318764187651876618767187681876918770187711877218773187741877518776187771877818779187801878118782187831878418785187861878718788187891879018791187921879318794187951879618797187981879918800188011880218803188041880518806188071880818809188101881118812188131881418815188161881718818188191882018821188221882318824188251882618827188281882918830188311883218833188341883518836188371883818839188401884118842188431884418845188461884718848188491885018851188521885318854188551885618857188581885918860188611886218863188641886518866188671886818869188701887118872188731887418875188761887718878188791888018881188821888318884188851888618887188881888918890188911889218893188941889518896188971889818899189001890118902189031890418905189061890718908189091891018911189121891318914189151891618917189181891918920189211892218923189241892518926189271892818929189301893118932189331893418935189361893718938189391894018941189421894318944189451894618947189481894918950189511895218953189541895518956189571895818959189601896118962189631896418965189661896718968189691897018971189721897318974189751897618977189781897918980189811898218983189841898518986189871898818989189901899118992189931899418995189961899718998189991900019001190021900319004190051900619007190081900919010190111901219013190141901519016190171901819019190201902119022190231902419025190261902719028190291903019031190321903319034190351903619037190381903919040190411904219043190441904519046190471904819049190501905119052190531905419055190561905719058190591906019061190621906319064190651906619067190681906919070190711907219073190741907519076190771907819079190801908119082190831908419085190861908719088190891909019091190921909319094190951909619097190981909919100191011910219103191041910519106191071910819109191101911119112191131911419115191161911719118191191912019121191221912319124191251912619127191281912919130191311913219133191341913519136191371913819139191401914119142191431914419145191461914719148191491915019151191521915319154191551915619157191581915919160191611916219163191641916519166191671916819169191701917119172191731917419175191761917719178191791918019181191821918319184191851918619187191881918919190191911919219193191941919519196191971919819199192001920119202192031920419205192061920719208192091921019211192121921319214192151921619217192181921919220192211922219223192241922519226192271922819229192301923119232192331923419235192361923719238192391924019241192421924319244192451924619247192481924919250192511925219253192541925519256192571925819259192601926119262192631926419265192661926719268192691927019271192721927319274192751927619277192781927919280192811928219283192841928519286192871928819289192901929119292192931929419295192961929719298192991930019301193021930319304193051930619307193081930919310193111931219313193141931519316193171931819319193201932119322193231932419325193261932719328193291933019331193321933319334193351933619337193381933919340193411934219343193441934519346193471934819349193501935119352193531935419355193561935719358193591936019361193621936319364193651936619367193681936919370193711937219373193741937519376193771937819379193801938119382193831938419385193861938719388193891939019391193921939319394193951939619397193981939919400194011940219403194041940519406194071940819409194101941119412194131941419415194161941719418194191942019421194221942319424194251942619427194281942919430194311943219433194341943519436194371943819439194401944119442194431944419445194461944719448194491945019451194521945319454194551945619457194581945919460194611946219463194641946519466194671946819469194701947119472194731947419475194761947719478194791948019481194821948319484194851948619487194881948919490194911949219493194941949519496194971949819499195001950119502195031950419505195061950719508195091951019511195121951319514195151951619517195181951919520195211952219523195241952519526195271952819529195301953119532195331953419535195361953719538195391954019541195421954319544195451954619547195481954919550195511955219553195541955519556195571955819559195601956119562195631956419565195661956719568195691957019571195721957319574195751957619577195781957919580195811958219583195841958519586195871958819589195901959119592195931959419595195961959719598195991960019601196021960319604196051960619607196081960919610196111961219613196141961519616196171961819619196201962119622196231962419625196261962719628196291963019631196321963319634196351963619637196381963919640196411964219643196441964519646196471964819649196501965119652196531965419655196561965719658196591966019661196621966319664196651966619667196681966919670196711967219673196741967519676196771967819679196801968119682196831968419685196861968719688196891969019691196921969319694196951969619697196981969919700197011970219703197041970519706197071970819709197101971119712197131971419715197161971719718197191972019721197221972319724197251972619727197281972919730197311973219733197341973519736197371973819739197401974119742197431974419745197461974719748197491975019751197521975319754197551975619757197581975919760197611976219763197641976519766197671976819769197701977119772197731977419775197761977719778197791978019781197821978319784197851978619787197881978919790197911979219793197941979519796197971979819799198001980119802198031980419805198061980719808198091981019811198121981319814198151981619817198181981919820198211982219823198241982519826198271982819829198301983119832198331983419835198361983719838198391984019841198421984319844198451984619847198481984919850198511985219853198541985519856198571985819859198601986119862198631986419865198661986719868198691987019871198721987319874198751987619877198781987919880198811988219883198841988519886198871988819889198901989119892198931989419895198961989719898198991990019901199021990319904199051990619907199081990919910199111991219913199141991519916199171991819919199201992119922199231992419925199261992719928199291993019931199321993319934199351993619937199381993919940199411994219943199441994519946199471994819949199501995119952199531995419955199561995719958199591996019961199621996319964199651996619967199681996919970199711997219973199741997519976199771997819979199801998119982199831998419985199861998719988199891999019991199921999319994199951999619997199981999920000200012000220003200042000520006200072000820009200102001120012200132001420015200162001720018200192002020021200222002320024200252002620027200282002920030200312003220033200342003520036200372003820039200402004120042200432004420045200462004720048200492005020051200522005320054200552005620057200582005920060200612006220063200642006520066200672006820069200702007120072200732007420075200762007720078200792008020081200822008320084200852008620087200882008920090200912009220093200942009520096200972009820099201002010120102201032010420105201062010720108201092011020111201122011320114201152011620117201182011920120201212012220123201242012520126201272012820129201302013120132201332013420135201362013720138201392014020141201422014320144201452014620147201482014920150201512015220153201542015520156201572015820159201602016120162201632016420165201662016720168201692017020171201722017320174201752017620177201782017920180201812018220183201842018520186201872018820189201902019120192201932019420195201962019720198201992020020201202022020320204202052020620207202082020920210202112021220213202142021520216202172021820219202202022120222202232022420225202262022720228202292023020231202322023320234202352023620237202382023920240202412024220243202442024520246202472024820249202502025120252202532025420255202562025720258202592026020261202622026320264202652026620267202682026920270202712027220273202742027520276202772027820279202802028120282202832028420285202862028720288202892029020291202922029320294202952029620297202982029920300203012030220303203042030520306203072030820309203102031120312203132031420315203162031720318203192032020321203222032320324203252032620327203282032920330203312033220333203342033520336203372033820339203402034120342203432034420345203462034720348203492035020351203522035320354203552035620357203582035920360203612036220363203642036520366203672036820369203702037120372203732037420375203762037720378203792038020381203822038320384203852038620387203882038920390203912039220393203942039520396203972039820399204002040120402204032040420405204062040720408204092041020411204122041320414204152041620417204182041920420204212042220423204242042520426204272042820429204302043120432204332043420435204362043720438204392044020441204422044320444204452044620447204482044920450204512045220453204542045520456204572045820459204602046120462204632046420465204662046720468204692047020471204722047320474204752047620477204782047920480204812048220483204842048520486204872048820489204902049120492204932049420495204962049720498204992050020501205022050320504205052050620507205082050920510205112051220513205142051520516205172051820519205202052120522205232052420525205262052720528205292053020531205322053320534205352053620537205382053920540205412054220543205442054520546205472054820549205502055120552205532055420555205562055720558205592056020561205622056320564205652056620567205682056920570205712057220573205742057520576205772057820579205802058120582205832058420585205862058720588205892059020591205922059320594205952059620597205982059920600206012060220603206042060520606206072060820609206102061120612206132061420615206162061720618206192062020621206222062320624206252062620627206282062920630206312063220633206342063520636206372063820639206402064120642206432064420645206462064720648206492065020651206522065320654206552065620657206582065920660206612066220663206642066520666206672066820669206702067120672206732067420675206762067720678206792068020681206822068320684206852068620687206882068920690206912069220693206942069520696206972069820699207002070120702207032070420705207062070720708207092071020711207122071320714207152071620717207182071920720207212072220723207242072520726207272072820729207302073120732207332073420735207362073720738207392074020741207422074320744207452074620747207482074920750207512075220753207542075520756207572075820759207602076120762207632076420765207662076720768207692077020771207722077320774207752077620777207782077920780207812078220783207842078520786207872078820789207902079120792207932079420795207962079720798207992080020801208022080320804208052080620807208082080920810208112081220813208142081520816208172081820819208202082120822208232082420825208262082720828208292083020831208322083320834208352083620837208382083920840208412084220843208442084520846208472084820849208502085120852208532085420855208562085720858208592086020861208622086320864208652086620867208682086920870208712087220873208742087520876208772087820879208802088120882208832088420885208862088720888208892089020891208922089320894208952089620897208982089920900209012090220903209042090520906209072090820909209102091120912209132091420915209162091720918209192092020921209222092320924209252092620927209282092920930209312093220933209342093520936209372093820939209402094120942209432094420945209462094720948209492095020951209522095320954209552095620957209582095920960209612096220963209642096520966209672096820969209702097120972209732097420975209762097720978209792098020981209822098320984209852098620987209882098920990209912099220993209942099520996209972099820999210002100121002210032100421005210062100721008210092101021011210122101321014210152101621017210182101921020210212102221023210242102521026210272102821029210302103121032210332103421035210362103721038210392104021041210422104321044210452104621047210482104921050210512105221053210542105521056210572105821059210602106121062210632106421065210662106721068210692107021071210722107321074210752107621077210782107921080210812108221083210842108521086210872108821089210902109121092210932109421095210962109721098210992110021101211022110321104211052110621107211082110921110211112111221113211142111521116211172111821119211202112121122211232112421125211262112721128211292113021131211322113321134211352113621137211382113921140211412114221143211442114521146211472114821149211502115121152211532115421155211562115721158211592116021161211622116321164211652116621167211682116921170211712117221173211742117521176211772117821179211802118121182211832118421185211862118721188211892119021191211922119321194211952119621197211982119921200212012120221203212042120521206212072120821209212102121121212212132121421215212162121721218212192122021221212222122321224212252122621227212282122921230212312123221233212342123521236212372123821239212402124121242212432124421245212462124721248212492125021251212522125321254212552125621257212582125921260212612126221263212642126521266212672126821269212702127121272212732127421275212762127721278212792128021281212822128321284212852128621287212882128921290212912129221293212942129521296212972129821299213002130121302213032130421305213062130721308213092131021311213122131321314213152131621317213182131921320213212132221323213242132521326213272132821329213302133121332213332133421335213362133721338213392134021341213422134321344213452134621347213482134921350213512135221353213542135521356213572135821359213602136121362213632136421365213662136721368213692137021371213722137321374213752137621377213782137921380213812138221383213842138521386213872138821389213902139121392213932139421395213962139721398213992140021401214022140321404214052140621407214082140921410214112141221413214142141521416214172141821419214202142121422214232142421425214262142721428214292143021431214322143321434214352143621437214382143921440214412144221443214442144521446214472144821449214502145121452214532145421455214562145721458214592146021461214622146321464214652146621467214682146921470214712147221473214742147521476214772147821479214802148121482214832148421485214862148721488214892149021491214922149321494214952149621497214982149921500215012150221503215042150521506215072150821509215102151121512215132151421515215162151721518215192152021521215222152321524215252152621527215282152921530215312153221533215342153521536215372153821539215402154121542215432154421545215462154721548215492155021551215522155321554215552155621557215582155921560215612156221563215642156521566215672156821569215702157121572215732157421575215762157721578215792158021581215822158321584215852158621587215882158921590215912159221593215942159521596215972159821599216002160121602216032160421605216062160721608216092161021611216122161321614216152161621617216182161921620216212162221623216242162521626216272162821629216302163121632216332163421635216362163721638216392164021641216422164321644216452164621647216482164921650216512165221653216542165521656216572165821659216602166121662216632166421665216662166721668216692167021671216722167321674216752167621677216782167921680216812168221683216842168521686216872168821689216902169121692216932169421695216962169721698216992170021701217022170321704217052170621707217082170921710217112171221713217142171521716217172171821719217202172121722217232172421725217262172721728217292173021731217322173321734217352173621737217382173921740217412174221743217442174521746217472174821749217502175121752217532175421755217562175721758217592176021761217622176321764217652176621767217682176921770217712177221773217742177521776217772177821779217802178121782217832178421785217862178721788217892179021791217922179321794217952179621797217982179921800218012180221803218042180521806218072180821809218102181121812218132181421815218162181721818218192182021821218222182321824218252182621827218282182921830218312183221833218342183521836218372183821839218402184121842218432184421845218462184721848218492185021851218522185321854218552185621857218582185921860218612186221863218642186521866218672186821869218702187121872218732187421875218762187721878218792188021881218822188321884218852188621887218882188921890218912189221893218942189521896218972189821899219002190121902219032190421905219062190721908219092191021911219122191321914219152191621917219182191921920219212192221923219242192521926219272192821929219302193121932219332193421935219362193721938219392194021941219422194321944219452194621947219482194921950219512195221953219542195521956219572195821959219602196121962219632196421965219662196721968219692197021971219722197321974219752197621977219782197921980219812198221983219842198521986219872198821989219902199121992219932199421995219962199721998219992200022001220022200322004220052200622007220082200922010220112201222013220142201522016220172201822019220202202122022220232202422025220262202722028220292203022031220322203322034220352203622037220382203922040220412204222043220442204522046220472204822049220502205122052220532205422055220562205722058220592206022061220622206322064220652206622067220682206922070220712207222073220742207522076220772207822079220802208122082220832208422085220862208722088220892209022091220922209322094220952209622097220982209922100221012210222103221042210522106221072210822109221102211122112221132211422115221162211722118221192212022121221222212322124221252212622127221282212922130221312213222133221342213522136221372213822139221402214122142221432214422145221462214722148221492215022151221522215322154221552215622157221582215922160221612216222163221642216522166221672216822169221702217122172221732217422175221762217722178221792218022181221822218322184221852218622187221882218922190221912219222193221942219522196221972219822199222002220122202222032220422205222062220722208222092221022211222122221322214222152221622217222182221922220222212222222223222242222522226222272222822229222302223122232222332223422235222362223722238222392224022241222422224322244222452224622247222482224922250222512225222253222542225522256222572225822259222602226122262222632226422265222662226722268222692227022271222722227322274222752227622277222782227922280222812228222283222842228522286222872228822289222902229122292222932229422295222962229722298222992230022301223022230322304223052230622307223082230922310223112231222313223142231522316223172231822319223202232122322223232232422325223262232722328223292233022331223322233322334223352233622337223382233922340223412234222343223442234522346223472234822349223502235122352223532235422355223562235722358223592236022361223622236322364223652236622367223682236922370223712237222373223742237522376223772237822379223802238122382223832238422385223862238722388223892239022391223922239322394223952239622397223982239922400224012240222403224042240522406224072240822409224102241122412224132241422415224162241722418224192242022421224222242322424224252242622427224282242922430224312243222433224342243522436224372243822439224402244122442224432244422445224462244722448224492245022451224522245322454224552245622457224582245922460224612246222463224642246522466224672246822469224702247122472224732247422475224762247722478224792248022481224822248322484224852248622487224882248922490224912249222493224942249522496224972249822499225002250122502225032250422505225062250722508225092251022511225122251322514225152251622517225182251922520225212252222523225242252522526225272252822529225302253122532225332253422535225362253722538225392254022541225422254322544225452254622547225482254922550225512255222553225542255522556225572255822559225602256122562225632256422565225662256722568225692257022571225722257322574225752257622577225782257922580225812258222583225842258522586225872258822589225902259122592225932259422595225962259722598225992260022601226022260322604226052260622607226082260922610226112261222613226142261522616226172261822619226202262122622226232262422625226262262722628226292263022631226322263322634226352263622637226382263922640226412264222643226442264522646226472264822649226502265122652226532265422655226562265722658226592266022661226622266322664226652266622667226682266922670226712267222673226742267522676226772267822679226802268122682226832268422685226862268722688226892269022691226922269322694226952269622697226982269922700227012270222703227042270522706227072270822709227102271122712227132271422715227162271722718227192272022721227222272322724227252272622727227282272922730227312273222733227342273522736227372273822739227402274122742227432274422745227462274722748227492275022751227522275322754227552275622757227582275922760227612276222763227642276522766227672276822769227702277122772227732277422775227762277722778227792278022781227822278322784227852278622787227882278922790227912279222793227942279522796227972279822799228002280122802228032280422805228062280722808228092281022811228122281322814228152281622817228182281922820228212282222823228242282522826228272282822829228302283122832228332283422835228362283722838228392284022841228422284322844228452284622847228482284922850228512285222853228542285522856228572285822859228602286122862228632286422865228662286722868228692287022871228722287322874228752287622877228782287922880228812288222883228842288522886228872288822889228902289122892228932289422895228962289722898228992290022901229022290322904229052290622907229082290922910229112291222913229142291522916229172291822919229202292122922229232292422925229262292722928229292293022931229322293322934229352293622937229382293922940229412294222943229442294522946229472294822949229502295122952229532295422955229562295722958229592296022961229622296322964229652296622967229682296922970229712297222973229742297522976229772297822979229802298122982229832298422985229862298722988229892299022991229922299322994229952299622997229982299923000230012300223003230042300523006230072300823009230102301123012230132301423015230162301723018230192302023021230222302323024230252302623027230282302923030230312303223033230342303523036230372303823039230402304123042230432304423045230462304723048230492305023051230522305323054230552305623057230582305923060230612306223063230642306523066230672306823069230702307123072230732307423075230762307723078230792308023081230822308323084230852308623087230882308923090230912309223093230942309523096230972309823099231002310123102231032310423105231062310723108231092311023111231122311323114231152311623117231182311923120231212312223123231242312523126231272312823129231302313123132231332313423135231362313723138231392314023141231422314323144231452314623147231482314923150231512315223153231542315523156231572315823159231602316123162231632316423165231662316723168231692317023171231722317323174231752317623177231782317923180231812318223183231842318523186231872318823189231902319123192231932319423195231962319723198231992320023201232022320323204232052320623207232082320923210232112321223213232142321523216232172321823219232202322123222232232322423225232262322723228232292323023231232322323323234232352323623237232382323923240232412324223243232442324523246232472324823249232502325123252232532325423255232562325723258232592326023261232622326323264232652326623267232682326923270232712327223273232742327523276232772327823279232802328123282232832328423285232862328723288232892329023291232922329323294232952329623297232982329923300233012330223303233042330523306233072330823309233102331123312233132331423315233162331723318233192332023321233222332323324233252332623327233282332923330233312333223333233342333523336233372333823339233402334123342233432334423345233462334723348233492335023351233522335323354233552335623357233582335923360233612336223363233642336523366233672336823369233702337123372233732337423375233762337723378233792338023381233822338323384233852338623387233882338923390233912339223393233942339523396233972339823399234002340123402234032340423405234062340723408234092341023411234122341323414234152341623417234182341923420234212342223423234242342523426234272342823429234302343123432234332343423435234362343723438234392344023441234422344323444234452344623447234482344923450234512345223453234542345523456234572345823459234602346123462234632346423465234662346723468234692347023471234722347323474234752347623477234782347923480234812348223483234842348523486234872348823489234902349123492234932349423495234962349723498234992350023501235022350323504235052350623507235082350923510235112351223513235142351523516235172351823519235202352123522235232352423525235262352723528235292353023531235322353323534235352353623537235382353923540235412354223543235442354523546235472354823549235502355123552235532355423555235562355723558235592356023561235622356323564235652356623567235682356923570235712357223573235742357523576235772357823579235802358123582235832358423585235862358723588235892359023591235922359323594235952359623597235982359923600236012360223603236042360523606236072360823609236102361123612236132361423615236162361723618236192362023621236222362323624236252362623627236282362923630236312363223633236342363523636236372363823639236402364123642236432364423645236462364723648236492365023651236522365323654236552365623657236582365923660236612366223663236642366523666236672366823669236702367123672236732367423675236762367723678236792368023681236822368323684236852368623687236882368923690236912369223693236942369523696236972369823699237002370123702237032370423705237062370723708237092371023711237122371323714237152371623717237182371923720237212372223723237242372523726237272372823729237302373123732237332373423735237362373723738237392374023741237422374323744237452374623747237482374923750237512375223753237542375523756237572375823759237602376123762237632376423765237662376723768237692377023771237722377323774237752377623777237782377923780237812378223783237842378523786237872378823789237902379123792237932379423795237962379723798237992380023801238022380323804238052380623807238082380923810238112381223813238142381523816238172381823819238202382123822238232382423825238262382723828238292383023831238322383323834238352383623837238382383923840238412384223843238442384523846238472384823849238502385123852238532385423855238562385723858238592386023861238622386323864238652386623867238682386923870238712387223873238742387523876238772387823879238802388123882238832388423885238862388723888238892389023891238922389323894238952389623897238982389923900239012390223903239042390523906239072390823909239102391123912239132391423915239162391723918239192392023921239222392323924239252392623927239282392923930239312393223933239342393523936239372393823939239402394123942239432394423945239462394723948239492395023951239522395323954239552395623957239582395923960239612396223963239642396523966239672396823969239702397123972239732397423975239762397723978239792398023981239822398323984239852398623987239882398923990239912399223993239942399523996239972399823999240002400124002240032400424005240062400724008240092401024011240122401324014240152401624017240182401924020240212402224023240242402524026240272402824029240302403124032240332403424035240362403724038240392404024041240422404324044240452404624047240482404924050240512405224053240542405524056240572405824059240602406124062240632406424065240662406724068240692407024071240722407324074240752407624077240782407924080240812408224083240842408524086240872408824089240902409124092240932409424095240962409724098240992410024101241022410324104241052410624107241082410924110241112411224113241142411524116241172411824119241202412124122241232412424125241262412724128241292413024131241322413324134241352413624137241382413924140241412414224143241442414524146241472414824149241502415124152241532415424155241562415724158241592416024161241622416324164241652416624167241682416924170241712417224173241742417524176241772417824179241802418124182241832418424185241862418724188241892419024191241922419324194241952419624197241982419924200242012420224203242042420524206242072420824209242102421124212242132421424215242162421724218242192422024221242222422324224242252422624227242282422924230242312423224233242342423524236242372423824239242402424124242242432424424245242462424724248242492425024251242522425324254242552425624257242582425924260242612426224263242642426524266242672426824269242702427124272242732427424275242762427724278242792428024281242822428324284242852428624287242882428924290242912429224293242942429524296242972429824299243002430124302243032430424305243062430724308243092431024311243122431324314243152431624317243182431924320243212432224323243242432524326243272432824329243302433124332243332433424335243362433724338243392434024341243422434324344243452434624347243482434924350243512435224353243542435524356243572435824359243602436124362243632436424365243662436724368243692437024371243722437324374243752437624377243782437924380243812438224383243842438524386243872438824389243902439124392243932439424395243962439724398243992440024401244022440324404244052440624407244082440924410244112441224413244142441524416244172441824419244202442124422244232442424425244262442724428244292443024431244322443324434244352443624437244382443924440244412444224443244442444524446244472444824449244502445124452244532445424455244562445724458244592446024461244622446324464244652446624467244682446924470244712447224473244742447524476244772447824479244802448124482244832448424485244862448724488244892449024491244922449324494244952449624497244982449924500245012450224503245042450524506245072450824509245102451124512245132451424515245162451724518245192452024521245222452324524245252452624527245282452924530245312453224533245342453524536245372453824539245402454124542245432454424545245462454724548245492455024551245522455324554245552455624557245582455924560245612456224563245642456524566245672456824569245702457124572245732457424575245762457724578245792458024581245822458324584245852458624587245882458924590245912459224593245942459524596245972459824599246002460124602246032460424605246062460724608246092461024611246122461324614246152461624617246182461924620246212462224623246242462524626246272462824629246302463124632246332463424635246362463724638246392464024641246422464324644246452464624647246482464924650246512465224653246542465524656246572465824659246602466124662246632466424665246662466724668246692467024671246722467324674246752467624677246782467924680246812468224683246842468524686246872468824689246902469124692246932469424695246962469724698246992470024701247022470324704247052470624707247082470924710247112471224713247142471524716247172471824719247202472124722247232472424725247262472724728247292473024731247322473324734247352473624737247382473924740247412474224743247442474524746247472474824749247502475124752247532475424755247562475724758247592476024761247622476324764247652476624767247682476924770247712477224773247742477524776247772477824779247802478124782247832478424785247862478724788247892479024791247922479324794247952479624797247982479924800248012480224803248042480524806248072480824809248102481124812248132481424815248162481724818248192482024821248222482324824248252482624827248282482924830248312483224833248342483524836248372483824839248402484124842248432484424845248462484724848248492485024851248522485324854248552485624857248582485924860248612486224863248642486524866248672486824869248702487124872248732487424875248762487724878248792488024881248822488324884248852488624887248882488924890248912489224893248942489524896248972489824899249002490124902249032490424905249062490724908249092491024911249122491324914249152491624917249182491924920249212492224923249242492524926249272492824929249302493124932249332493424935249362493724938249392494024941249422494324944249452494624947249482494924950249512495224953249542495524956249572495824959249602496124962249632496424965249662496724968249692497024971249722497324974249752497624977249782497924980249812498224983249842498524986249872498824989249902499124992249932499424995249962499724998249992500025001250022500325004250052500625007250082500925010250112501225013250142501525016250172501825019250202502125022250232502425025250262502725028250292503025031250322503325034250352503625037250382503925040250412504225043250442504525046250472504825049250502505125052250532505425055250562505725058250592506025061250622506325064250652506625067250682506925070250712507225073250742507525076250772507825079250802508125082250832508425085250862508725088250892509025091250922509325094250952509625097250982509925100251012510225103251042510525106251072510825109251102511125112251132511425115251162511725118251192512025121251222512325124251252512625127251282512925130251312513225133251342513525136251372513825139251402514125142251432514425145251462514725148251492515025151251522515325154251552515625157251582515925160251612516225163251642516525166251672516825169251702517125172251732517425175251762517725178251792518025181251822518325184251852518625187251882518925190251912519225193251942519525196251972519825199252002520125202252032520425205252062520725208252092521025211252122521325214252152521625217252182521925220252212522225223252242522525226252272522825229252302523125232252332523425235252362523725238252392524025241252422524325244252452524625247252482524925250252512525225253252542525525256252572525825259252602526125262252632526425265252662526725268252692527025271252722527325274252752527625277252782527925280252812528225283252842528525286252872528825289252902529125292252932529425295252962529725298252992530025301253022530325304253052530625307253082530925310253112531225313253142531525316253172531825319253202532125322253232532425325253262532725328253292533025331253322533325334253352533625337253382533925340253412534225343253442534525346253472534825349253502535125352253532535425355253562535725358253592536025361253622536325364253652536625367253682536925370253712537225373253742537525376253772537825379253802538125382253832538425385253862538725388253892539025391253922539325394253952539625397253982539925400254012540225403254042540525406254072540825409254102541125412254132541425415254162541725418254192542025421254222542325424254252542625427254282542925430254312543225433254342543525436254372543825439254402544125442254432544425445254462544725448254492545025451254522545325454254552545625457254582545925460254612546225463254642546525466254672546825469254702547125472254732547425475254762547725478254792548025481254822548325484254852548625487254882548925490254912549225493254942549525496254972549825499255002550125502255032550425505255062550725508255092551025511255122551325514255152551625517255182551925520255212552225523255242552525526255272552825529255302553125532255332553425535255362553725538255392554025541255422554325544255452554625547255482554925550255512555225553255542555525556255572555825559255602556125562255632556425565255662556725568255692557025571255722557325574255752557625577255782557925580255812558225583255842558525586255872558825589255902559125592255932559425595255962559725598255992560025601256022560325604256052560625607256082560925610256112561225613256142561525616256172561825619256202562125622256232562425625256262562725628256292563025631256322563325634256352563625637256382563925640256412564225643256442564525646256472564825649256502565125652256532565425655256562565725658256592566025661256622566325664256652566625667256682566925670256712567225673256742567525676256772567825679256802568125682256832568425685256862568725688256892569025691256922569325694256952569625697256982569925700257012570225703257042570525706257072570825709257102571125712257132571425715257162571725718257192572025721257222572325724257252572625727257282572925730257312573225733257342573525736257372573825739257402574125742257432574425745257462574725748257492575025751257522575325754257552575625757257582575925760257612576225763257642576525766257672576825769257702577125772257732577425775257762577725778257792578025781257822578325784257852578625787257882578925790257912579225793257942579525796257972579825799258002580125802258032580425805258062580725808258092581025811258122581325814258152581625817258182581925820258212582225823258242582525826258272582825829258302583125832258332583425835258362583725838258392584025841258422584325844258452584625847258482584925850258512585225853258542585525856258572585825859258602586125862258632586425865258662586725868258692587025871258722587325874258752587625877258782587925880258812588225883258842588525886258872588825889258902589125892258932589425895258962589725898258992590025901259022590325904259052590625907259082590925910259112591225913259142591525916259172591825919259202592125922259232592425925259262592725928259292593025931259322593325934259352593625937259382593925940259412594225943259442594525946259472594825949259502595125952259532595425955259562595725958259592596025961259622596325964259652596625967259682596925970259712597225973259742597525976259772597825979259802598125982259832598425985259862598725988259892599025991259922599325994259952599625997259982599926000260012600226003260042600526006260072600826009260102601126012260132601426015260162601726018260192602026021260222602326024260252602626027260282602926030260312603226033260342603526036260372603826039260402604126042260432604426045260462604726048260492605026051260522605326054260552605626057260582605926060260612606226063260642606526066260672606826069260702607126072260732607426075260762607726078260792608026081260822608326084260852608626087260882608926090260912609226093260942609526096260972609826099261002610126102261032610426105261062610726108261092611026111261122611326114261152611626117261182611926120261212612226123261242612526126261272612826129261302613126132261332613426135261362613726138261392614026141261422614326144261452614626147261482614926150261512615226153261542615526156261572615826159261602616126162261632616426165261662616726168261692617026171261722617326174261752617626177261782617926180261812618226183261842618526186261872618826189261902619126192261932619426195261962619726198261992620026201262022620326204262052620626207262082620926210262112621226213262142621526216262172621826219262202622126222262232622426225262262622726228262292623026231262322623326234262352623626237262382623926240262412624226243262442624526246262472624826249262502625126252262532625426255262562625726258262592626026261262622626326264262652626626267262682626926270262712627226273262742627526276262772627826279262802628126282262832628426285262862628726288262892629026291262922629326294262952629626297262982629926300263012630226303263042630526306263072630826309263102631126312263132631426315263162631726318263192632026321263222632326324263252632626327263282632926330263312633226333263342633526336263372633826339263402634126342263432634426345263462634726348263492635026351263522635326354263552635626357263582635926360263612636226363263642636526366263672636826369263702637126372263732637426375263762637726378263792638026381263822638326384263852638626387263882638926390263912639226393263942639526396263972639826399264002640126402264032640426405264062640726408264092641026411264122641326414264152641626417264182641926420264212642226423264242642526426264272642826429264302643126432264332643426435264362643726438264392644026441264422644326444264452644626447264482644926450264512645226453264542645526456264572645826459264602646126462264632646426465264662646726468264692647026471264722647326474264752647626477264782647926480264812648226483264842648526486264872648826489264902649126492264932649426495264962649726498264992650026501265022650326504265052650626507265082650926510265112651226513265142651526516265172651826519265202652126522265232652426525265262652726528265292653026531265322653326534265352653626537265382653926540265412654226543265442654526546265472654826549265502655126552265532655426555265562655726558265592656026561265622656326564265652656626567265682656926570265712657226573265742657526576265772657826579265802658126582265832658426585265862658726588265892659026591265922659326594265952659626597265982659926600266012660226603266042660526606266072660826609266102661126612266132661426615266162661726618266192662026621266222662326624266252662626627266282662926630266312663226633266342663526636266372663826639266402664126642266432664426645266462664726648266492665026651266522665326654266552665626657266582665926660266612666226663266642666526666266672666826669266702667126672266732667426675266762667726678266792668026681266822668326684266852668626687266882668926690266912669226693266942669526696266972669826699267002670126702267032670426705267062670726708267092671026711267122671326714267152671626717267182671926720267212672226723267242672526726267272672826729267302673126732267332673426735267362673726738267392674026741267422674326744267452674626747267482674926750267512675226753267542675526756267572675826759267602676126762267632676426765267662676726768267692677026771267722677326774267752677626777267782677926780267812678226783267842678526786267872678826789267902679126792267932679426795267962679726798267992680026801268022680326804268052680626807268082680926810268112681226813268142681526816268172681826819268202682126822268232682426825268262682726828268292683026831268322683326834268352683626837268382683926840268412684226843268442684526846268472684826849268502685126852268532685426855268562685726858268592686026861268622686326864268652686626867268682686926870268712687226873268742687526876268772687826879268802688126882268832688426885268862688726888268892689026891268922689326894268952689626897268982689926900269012690226903269042690526906269072690826909269102691126912269132691426915269162691726918269192692026921269222692326924269252692626927269282692926930269312693226933269342693526936269372693826939269402694126942269432694426945269462694726948269492695026951269522695326954269552695626957269582695926960269612696226963269642696526966269672696826969269702697126972269732697426975269762697726978269792698026981269822698326984269852698626987269882698926990269912699226993269942699526996269972699826999270002700127002270032700427005270062700727008270092701027011270122701327014270152701627017270182701927020270212702227023270242702527026270272702827029270302703127032270332703427035270362703727038270392704027041270422704327044270452704627047270482704927050270512705227053270542705527056270572705827059270602706127062270632706427065270662706727068270692707027071270722707327074270752707627077270782707927080270812708227083270842708527086270872708827089270902709127092270932709427095270962709727098270992710027101271022710327104271052710627107271082710927110271112711227113271142711527116271172711827119271202712127122271232712427125271262712727128271292713027131271322713327134271352713627137271382713927140271412714227143271442714527146271472714827149271502715127152271532715427155271562715727158271592716027161271622716327164271652716627167271682716927170271712717227173271742717527176271772717827179271802718127182271832718427185271862718727188271892719027191271922719327194271952719627197271982719927200272012720227203272042720527206272072720827209272102721127212272132721427215272162721727218272192722027221272222722327224272252722627227272282722927230272312723227233272342723527236272372723827239272402724127242272432724427245272462724727248272492725027251272522725327254272552725627257272582725927260272612726227263272642726527266272672726827269272702727127272272732727427275272762727727278272792728027281272822728327284272852728627287272882728927290272912729227293272942729527296272972729827299273002730127302273032730427305273062730727308273092731027311273122731327314273152731627317273182731927320273212732227323273242732527326273272732827329273302733127332273332733427335273362733727338273392734027341273422734327344273452734627347273482734927350273512735227353273542735527356273572735827359273602736127362273632736427365273662736727368273692737027371273722737327374273752737627377273782737927380273812738227383273842738527386273872738827389273902739127392273932739427395273962739727398273992740027401274022740327404274052740627407274082740927410274112741227413274142741527416274172741827419274202742127422274232742427425274262742727428274292743027431274322743327434274352743627437274382743927440274412744227443274442744527446274472744827449274502745127452274532745427455274562745727458274592746027461274622746327464274652746627467274682746927470274712747227473274742747527476274772747827479274802748127482274832748427485274862748727488274892749027491274922749327494274952749627497274982749927500275012750227503275042750527506275072750827509275102751127512275132751427515275162751727518275192752027521275222752327524275252752627527275282752927530275312753227533275342753527536275372753827539275402754127542275432754427545275462754727548275492755027551275522755327554275552755627557275582755927560275612756227563275642756527566275672756827569275702757127572275732757427575275762757727578275792758027581275822758327584275852758627587275882758927590275912759227593275942759527596275972759827599276002760127602276032760427605276062760727608276092761027611276122761327614276152761627617276182761927620276212762227623276242762527626276272762827629276302763127632276332763427635276362763727638276392764027641276422764327644276452764627647276482764927650276512765227653276542765527656276572765827659276602766127662276632766427665276662766727668276692767027671276722767327674276752767627677276782767927680276812768227683276842768527686276872768827689276902769127692276932769427695276962769727698276992770027701277022770327704277052770627707277082770927710277112771227713277142771527716277172771827719277202772127722277232772427725277262772727728277292773027731277322773327734277352773627737277382773927740277412774227743277442774527746277472774827749277502775127752277532775427755277562775727758277592776027761277622776327764277652776627767277682776927770277712777227773277742777527776277772777827779277802778127782277832778427785277862778727788277892779027791277922779327794277952779627797277982779927800278012780227803278042780527806278072780827809278102781127812278132781427815278162781727818278192782027821278222782327824278252782627827278282782927830278312783227833278342783527836278372783827839278402784127842278432784427845278462784727848278492785027851278522785327854278552785627857278582785927860278612786227863278642786527866278672786827869278702787127872278732787427875278762787727878278792788027881278822788327884278852788627887278882788927890278912789227893278942789527896278972789827899279002790127902279032790427905279062790727908279092791027911279122791327914279152791627917279182791927920279212792227923279242792527926279272792827929279302793127932279332793427935279362793727938279392794027941279422794327944279452794627947279482794927950279512795227953279542795527956279572795827959279602796127962279632796427965279662796727968279692797027971279722797327974279752797627977279782797927980279812798227983279842798527986279872798827989279902799127992279932799427995279962799727998279992800028001280022800328004280052800628007280082800928010280112801228013280142801528016280172801828019280202802128022280232802428025280262802728028280292803028031280322803328034280352803628037280382803928040280412804228043280442804528046280472804828049280502805128052280532805428055280562805728058280592806028061280622806328064280652806628067280682806928070280712807228073280742807528076280772807828079280802808128082280832808428085280862808728088280892809028091280922809328094280952809628097280982809928100281012810228103281042810528106281072810828109281102811128112281132811428115281162811728118281192812028121281222812328124281252812628127281282812928130281312813228133281342813528136281372813828139281402814128142281432814428145281462814728148281492815028151281522815328154281552815628157281582815928160281612816228163281642816528166281672816828169281702817128172281732817428175281762817728178281792818028181281822818328184281852818628187281882818928190281912819228193281942819528196281972819828199282002820128202282032820428205282062820728208282092821028211282122821328214282152821628217282182821928220282212822228223282242822528226282272822828229282302823128232282332823428235282362823728238282392824028241282422824328244282452824628247282482824928250282512825228253282542825528256282572825828259282602826128262282632826428265282662826728268282692827028271282722827328274282752827628277282782827928280282812828228283282842828528286282872828828289282902829128292282932829428295282962829728298282992830028301283022830328304283052830628307283082830928310283112831228313283142831528316283172831828319283202832128322283232832428325283262832728328283292833028331283322833328334283352833628337283382833928340283412834228343283442834528346283472834828349283502835128352283532835428355283562835728358283592836028361283622836328364283652836628367283682836928370283712837228373283742837528376283772837828379283802838128382283832838428385283862838728388283892839028391283922839328394283952839628397283982839928400284012840228403284042840528406284072840828409284102841128412284132841428415284162841728418284192842028421284222842328424284252842628427284282842928430284312843228433284342843528436284372843828439284402844128442284432844428445284462844728448284492845028451284522845328454284552845628457284582845928460284612846228463284642846528466284672846828469284702847128472284732847428475284762847728478284792848028481284822848328484284852848628487284882848928490284912849228493284942849528496284972849828499285002850128502285032850428505285062850728508285092851028511285122851328514285152851628517285182851928520285212852228523285242852528526285272852828529285302853128532285332853428535285362853728538285392854028541285422854328544285452854628547285482854928550285512855228553285542855528556285572855828559285602856128562285632856428565285662856728568285692857028571285722857328574285752857628577285782857928580285812858228583285842858528586285872858828589285902859128592285932859428595285962859728598285992860028601286022860328604286052860628607286082860928610286112861228613286142861528616286172861828619286202862128622286232862428625286262862728628286292863028631286322863328634286352863628637286382863928640286412864228643286442864528646286472864828649286502865128652286532865428655286562865728658286592866028661286622866328664286652866628667286682866928670286712867228673286742867528676286772867828679286802868128682286832868428685286862868728688286892869028691286922869328694286952869628697286982869928700287012870228703287042870528706287072870828709287102871128712287132871428715287162871728718287192872028721287222872328724287252872628727287282872928730287312873228733287342873528736287372873828739287402874128742287432874428745287462874728748287492875028751287522875328754287552875628757287582875928760287612876228763287642876528766287672876828769287702877128772287732877428775287762877728778287792878028781287822878328784287852878628787287882878928790287912879228793287942879528796287972879828799288002880128802288032880428805288062880728808288092881028811288122881328814
  1. { **********************************************************************
  2. This file is part of the Free Component Library (FCL)
  3. Copyright (c) 2025 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. - option to disable "use strict"
  20. - interface vars
  21. - only double, no other float type
  22. - only string, no other string type
  23. - modifier public to protect from removing by optimizer
  24. - implementation vars
  25. - external vars
  26. - initialization section
  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. - choose overloads based on type and precision
  40. - fail overload on multiple with loss of precision or one used default param
  41. - FuncName:=, auto rename lower lvl Result variables
  42. - var modifier 'absolute' for local vars
  43. - assign statements
  44. - char
  45. - literals
  46. - ord(AnsiChar) -> char.charCodeAt()
  47. - chr(integer) -> String.fromCharCode(integer)
  48. - string
  49. - literals
  50. - setlength(s,newlen) -> s = rtl.strSetLength(s,newlen)
  51. - read and write char aString[]
  52. - allow only String, no ShortString, AnsiString, UnicodeString,...
  53. - allow type casting string to external class name 'String'
  54. - for int/enum do, for char do, for bool do
  55. - repeat..until
  56. - while..do
  57. - try..finally
  58. - try..except, try..except on else
  59. - raise, raise E
  60. - asm..end
  61. - assembler; asm..end;
  62. - break
  63. - continue
  64. - procedure str, function str
  65. - type alias
  66. - inc/dec to += -=
  67. - case-of
  68. - convert "a div b" to "Math.floor(a / b)"
  69. - and, or, xor, not: logical and bitwise
  70. - typecast boolean to integer and back with unary plus: +bool and int!=0
  71. - rename name conflicts with js identifiers: apply, bind, call, prototype, ...
  72. - record
  73. - types and vars
  74. - assign, copy members, not record reference, needed by ^record
  75. - assign record member
  76. - clone set member
  77. - clone static array member
  78. - clone when passing as argument
  79. - equal, not equal
  80. - const
  81. - array of record-const
  82. - skip clone record of new record
  83. - use rtl.recNewT to create a record type
  84. - use TRec.$new to instantiate records, using Object.create to instantiate
  85. - record field external name
  86. - advanced records:
  87. - public, private, strict private
  88. - class var
  89. - const member
  90. - sub types
  91. - functions
  92. - properties
  93. - class properties
  94. - default property
  95. - rtti
  96. - constructor
  97. - assign: copy values, do not create new JS object, needed by ^record
  98. - classes
  99. - declare using createClass
  100. - constructor
  101. - destructor
  102. - vars, init on create, clear references on destroy
  103. - class vars
  104. - ancestor
  105. - virtual, override, abstract
  106. - "is" operator
  107. - "as" operator
  108. - call inherited
  109. - "inherited;",
  110. - "inherited funcname(params);"
  111. - in nested proc
  112. - call class method
  113. - read/write class var
  114. - property
  115. - param list
  116. - property of type array
  117. - class property
  118. - accessors non static
  119. - Assigned()
  120. - default property
  121. - type casts
  122. - overloads, reintroduce append $1, $2, ...
  123. - reintroduced variables
  124. - external vars and methods
  125. - const
  126. - bracket accessor, getter/setter has external name '[]'
  127. - TObject.Free sets variable to nil
  128. - property stored and index modifier
  129. - option verify method calls -CR, bsObjectChecks
  130. - dynamic arrays
  131. - arrays can be null
  132. - init as "arr = []" so typeof works
  133. - SetLength(arr,dim1,...) becomes arr = rtl.arraySetLength(arr,defaultvalue,dim1,dim2,...)
  134. - length(), low(), high(), assigned(), concat()
  135. - assign nil -> [] so typeof works
  136. - read, write element arr[index]
  137. - multi dimensional [index1,index2] -> [index1][index2]
  138. - array of record
  139. - equal, unequal nil -> rtl.length(array)==0 or >0
  140. - when passing nil to an array argument, pass []
  141. - allow type casting array to external class name 'Array'
  142. - type cast array to array of same dimensions and compatible element type
  143. - function copy(array,start=0,count=max): array
  144. - procedure insert(item,var array,const position)
  145. - procedure delete(var array,const start,count)
  146. - const c: dynarray = (a,b,...)
  147. - mode delphi: var B: TBytes = [1,2,3]; // square bracket initialization
  148. - a:=[];
  149. - a:=[1,2,3]; // assignation using constant array
  150. - a:=[[],[]] // nested constant array
  151. - string like operations: modeswitch arrayoperators a:=A+[4,5];
  152. - Insert(Arr,MultiDimArr,0-based-pos);
  153. - a := Concat([1,2,3],[4,5,6]);
  154. - copy, concat for static arrays, creating dynamic arrays
  155. - static arrays
  156. - range: enumtype, boolean, int, char, custom int
  157. - init as arr = rtl.arraySetLength(null,value,dim1,dim2,...)
  158. - init with expression
  159. - length(1-dim array)
  160. - low(1-dim array), high(1-dim array)
  161. - "=" operator for records with static array fields
  162. - of record
  163. - open arrays
  164. - as dynamic arrays
  165. - enums
  166. - type with values and names
  167. - option to write numbers instead of variables
  168. - ord(), low(), high(), pred(), succ(), str(), writestr()
  169. - type cast alias to enumtype
  170. - type cast number to enumtype, enumtype to number
  171. - const aliasname = enumvalue
  172. - sets
  173. - set of enum
  174. - include, exclude, clone when referenced
  175. - assign := set state referenced
  176. - constant set: enums, enum vars, ranges
  177. - set operators +, -, *, ><, =, <>, >=, <=
  178. - in-operator
  179. - low(), high()
  180. - when passing as argument set state referenced
  181. - set of (enum,enum2) - anonymous enumtype
  182. - set of char, boolean, integer range, char range, enum range
  183. - with-do using local var
  184. - with record do i:=v;
  185. - with classinstance do begin create; i:=v; f(); i:=a[]; end;
  186. - pass by reference
  187. - pass local var to a var/out parameter
  188. - pass variable to a var/out parameter
  189. - pass reference to a var/out parameter
  190. - pass array element to a var/out parameter
  191. - procedure types
  192. - implemented as immutable wrapper function
  193. - assign := nil, proctype (not clone), @function, @method
  194. - call explicit and implicit
  195. - compare equal and notequal with nil, proctype, address, function
  196. - assigned(proctype)
  197. - pass as argument
  198. - methods
  199. - mode delphi: proctype:=proc
  200. - mode delphi: functype=funcresulttype
  201. - nested functions
  202. - reference to
  203. - @@ compare method in delphi mode
  204. - class-of
  205. - assign := nil, var
  206. - call class method
  207. - call constructor
  208. - operators =, <>
  209. - class var, property, method
  210. - Self in class method
  211. - typecast
  212. - class external
  213. - JS object or function as ancestor
  214. - does not descend from TObject
  215. - all members become external. case sensitive
  216. - has no hidden values like $class, $ancestor, $unitname, $init, $final
  217. - can be ancestor of a pascal class (not descend from TObject).
  218. - pascal class descendant can override methods
  219. - property works as normal, replaced by getter and setter
  220. - class-of
  221. - class var/function: works as in JS.
  222. - is and as operators
  223. - destructor forbidden
  224. - constructor must not be virtual
  225. - constructor 'new' -> new extclass(params)
  226. - constructor Name -> new extclass.name(params)
  227. - constructor Name external name '{}' -> {}
  228. - identifiers are renamed to avoid clashes with external names
  229. - call inherited
  230. - Pascal descendant can override newinstance
  231. - any class can be typecasted to any root class
  232. - class instances cannot access external class members (e.g. static class functions)
  233. - external class 'Array' bracket operator [integer] type jsvalue
  234. - external class 'Object' bracket operator [string] type jsvalue
  235. - typecast class type to JS Object, e.g. TJSObject(TObject)
  236. - typecast record type to JS Object, e.g. TJSObject(TPoint)
  237. - typecast interface type to JS Object, e.g. TJSObject(IUnknown)
  238. - for i in tjsobject do
  239. - nested classes
  240. - jsvalue
  241. - init as undefined
  242. - assign to jsvalue := integer, string, boolean, double, char
  243. - type cast base types to jsvalue
  244. - type cast jsvalue to base type
  245. integer: Math.floor(jsvalue) may return NaN
  246. boolean: !(jsvalue == false) works for numbers too 0==false
  247. double: rtl.getNumber(jsvalue) typeof(n)=="number"?n:NaN;
  248. string: ""+jsvalue
  249. char: rtl.getChar(jsvalue) ((typeof(c)!="string") && (c.length==1)) ? c : ""
  250. - enums: assign to jsvalue, typecast jsvalue to enum
  251. - class instance: assign to jsvalue, typecast jsvalue to a class
  252. - class of: assign to jsvalue, typecast jsvalue to a class-of
  253. - array of jsvalue,
  254. allow to assign any array to an array of jsvalue
  255. allow type casting to any array
  256. - parameter, result type, assign from/to untyped
  257. - operators equal, not equal
  258. - callback: assign to jsvalue, equal, not equal
  259. - jsvalue is class-type, jsvalue is class-of-type
  260. - for i in jsvalue do
  261. - RTTI
  262. - base types
  263. - $mod.$rtti
  264. - enum type tkEnumeration
  265. - set type tkSet
  266. - procedure type tkProcVar, tkMethod
  267. - class type tkClass
  268. - fields,
  269. - methods,
  270. - properties no params, no index, no defaultvalue
  271. - class forward
  272. - class-of type tkClassRef
  273. - dyn array type tkDynArray
  274. - static array type tkArray
  275. - record type tkRecord
  276. - no typeinfo for local types
  277. - built-in function typeinfo(): Pointer/TTypeInfo/...;
  278. - typeinfo(class) -> class.$rtti
  279. - WPO skip not used typeinfo
  280. - open array param
  281. - property stored and index modifier
  282. - property default value, nodefault
  283. - pointer
  284. - compare with and assign nil
  285. - typecast class, class-of, interface, array
  286. - ECMAScript6:
  287. - use 0b for binary literals
  288. - use 0o for octal literals
  289. - dotted unit names, namespaces
  290. - resourcestring
  291. - custom ranges
  292. - enum, int, AnsiChar
  293. - low(), high(), pred(), succ(), ord(),
  294. - rg(int), int(rg), enum:=rg,
  295. - rg:=rg, rg1:=rg2, rg:=enum, =, <>,
  296. - set of int/enum/AnsiChar range, in
  297. - array[rg], low(array), high(array), length(array)
  298. - enumeration for..in..do
  299. - enum, enum range, set of enum, set of enum range
  300. - int, int range, set of int, set of int range
  301. - char, char range, set of char, set of char range
  302. - array
  303. - class
  304. - for key in JSObject do
  305. - for value in JSArray do
  306. - Assert(bool[,string])
  307. - without sysutils: if(!bool) throw string
  308. - with sysutils: if(!bool) throw pas.sysutils.EAssertionFailed.$create("Create",[string])
  309. - Object checks:
  310. - Method call EInvalidCast, rtl.checkMethodCall
  311. - type cast to class-type and class-of-type, rtl.asExt, EInvalidCast
  312. - Range checks:
  313. - compile time: warnings to errors
  314. - assign int:=, int+=, enum:=, enum+=, intrange:=, intrange+=,
  315. enumrange:=, enumrange+=, char:=, char+=, charrange:=, charrange+=
  316. - procedure argument int, enum, intrange, enumrange, vhar, charrange
  317. - array[index1,index2,...] read and assign
  318. - string[index] read and assign
  319. - Interfaces:
  320. - autogenerate GUID
  321. - method resolution
  322. - delegation, property implements: intf or object, field or function,
  323. class field, class function
  324. - default property
  325. - Assigned(intfvar)
  326. - TGUID record
  327. - GuidVar:='{guid}', StringVar:=GuidVar, GuidVar:=IntfTypeOrVar,
  328. - GuidVar=IntfTypeOrVar, GuidVar=s
  329. - pass IntfTypeOrVar to GuidVar parameter
  330. - TGUIDString
  331. - GuidString:=IntfTypeOrVar, GuidString=IntfTypeOrVar
  332. - pass IntfTypeOrVar to GuidString parameter
  333. - CORBA: IntfVar:=nil, IntfVar:=IntfVar, IntfVar:=ObjVar;
  334. - CORBA: IntfVar=IntfVar2, IntfVar<>IntfVar2,
  335. - CORBA: IntfVar is IBird, IntfVar is TBird, ObjVar is IBird
  336. - CORBA: IntfVar2 as IBird, IntfVar2 as TBird, ObjVar as IBird
  337. - CORBA: IntfVar:=IBird(IntfVar2);',
  338. - CORBA: pass IntfVar as argument, pass classinstvar to intf argument
  339. - CORBA: IEnumerable
  340. - COM: IntfVar:=nil, IntfVar:=IntfVar, IntfVar:=ObjVar, IntfArg:=, IntfLocalVar:=
  341. - COM: IntfVar=IntfVar2, IntfVar<>IntfVar2,
  342. - COM: IntfVar is IBird, IntfVar is TBird, ObjVar is IBird
  343. - COM: IntfVar2 as IBird, IntfVar2 as TBird, ObjVar as IBird
  344. - COM: IntfVar:=IBird(IntfVar2);',
  345. - COM: pass IntfVar as argument, pass classinstvar to intf argument
  346. - COM: function result, release on exception
  347. - COM: addref/release for function call in expression
  348. - COM: delegation
  349. - COM: property in class, property in interface
  350. - COM: with interface do
  351. - COM: for interface in ... do
  352. - COM: pass IntfVar to untyped parameter
  353. - currency:
  354. - as nativeint*10000
  355. - CurA+CurB -> CurA+CurB
  356. - CurA-CurB -> CurA-CurB
  357. - CurA*CurB -> CurA*CurB/10000
  358. - CurA/CurB -> Math.floor(CurA/CurB*10000)
  359. - CurA^^CurB -> Math.floor(Math.pow(CurA/10000,CurB/10000)*10000)
  360. - Double:=Currency -> Double:=Currency/10000
  361. - Currency:=Double -> Currency:=Math.floor(Double*10000)
  362. - jsvalue := currency -> jsvalue:=currency/10000
  363. - simplify Math.floor(constnumber) to truncated constnumber
  364. - Pointer of record
  365. - p:=@r, p^:=r
  366. - p^.x, p.x
  367. - dispose, new
  368. - typecast byte(longword) -> value & $ff
  369. - typecast TJSFunction(func)
  370. - modeswitch OmitRTTI
  371. - debugger;
  372. - anonymous functions
  373. - assign
  374. - pass as argument
  375. - procedure val(const string; var enumtype; out int)
  376. - move all local types to global
  377. - class helpers:
  378. - ancestor
  379. - class var, const, sub type
  380. - method, class method, static class method
  381. - call methods, @method
  382. - constructor, not for external class
  383. - inherited, inherited name
  384. - property, class property
  385. - for in
  386. - record helpers:
  387. - in function allow assign Self
  388. - type helpers:
  389. - pass var, const, read only const
  390. - pass arg default, arg const, arg var, arg out
  391. - pass result element
  392. - pass function result
  393. - pass field, class field
  394. - pass property getter field, property getter function,
  395. - pass class property, static class property
  396. - pass array property
  397. - array of const, TVarRec
  398. - attributes
  399. - overflow check:
  400. -Co : Overflow checking of integer operations
  401. - generics
  402. - async procedure modifier
  403. - function await(const expr: T): T
  404. - function await(T; p: TJSPromise): T
  405. - constref
  406. - generics
  407. ToDos:
  408. - range check:
  409. type helper self:=
  410. - cmd line param to set modeswitch
  411. - Result:=inherited;
  412. - asm-block annotate/reference
  413. - pas() test or use or read or write
  414. - trailing [,,,]
  415. - bug: DoIt(typeinfo(i)) where DoIt is in another unit and has TTypeInfo
  416. - $OPTIMIZATION ON|OFF
  417. - $optimization REMOVEEMPTYPROCS
  418. - $optimization REMOVEEMPTYPROCS,RemoveNotUsedDeclarations-
  419. - static arrays
  420. - clone multi dim static array
  421. - RTTI
  422. - class property field/static/nonstatic
  423. - interfaces
  424. - array of interface
  425. - record member interface
  426. - 1 as TEnum, ERangeError
  427. - ifthen<T>
  428. - stdcall of methods: pass original 'this' as first parameter
  429. - property read Arr[0] https://bugs.freepascal.org/view.php?id=33416
  430. - write, writeln
  431. - call array of proc element without ()
  432. - enums with custom values
  433. - library
  434. - option overflow checking -Co
  435. +, -, *, Succ, Pred, Inc, Dec
  436. -CO : Check for possible overflow of integer operations
  437. -C3 : Turn on ieee error checking for constants
  438. - optimizations:
  439. see https://wiki.lazarus.freepascal.org/Pas2js_optimizations
  440. - objects
  441. - operator overloading
  442. - operator enumerator
  443. - inline
  444. - extended RTTI
  445. Debugging this unit: -d<x>
  446. VerbosePas2JS
  447. *)
  448. {$IFNDEF FPC_DOTTEDUNITS}
  449. unit FPPas2Js;
  450. {$ENDIF FPC_DOTTEDUNITS}
  451. {$mode objfpc}{$H+}
  452. {$inline on}
  453. {$ifdef fpc}
  454. {$define UsePChar}
  455. {$define HasInt64}
  456. {$IF FPC_FULLVERSION>30300}
  457. {$WARN 6018 off : Unreachable code}
  458. {$ENDIF}
  459. {$endif}
  460. {$IFOPT Q+}{$DEFINE OverflowCheckOn}{$ENDIF}
  461. {$IFOPT R+}{$DEFINE RangeCheckOn}{$ENDIF}
  462. interface
  463. {$IFDEF FPC_DOTTEDUNITS}
  464. uses
  465. {$ifdef pas2js}
  466. {$else}
  467. Fcl.AVLTree,
  468. {$endif}
  469. System.Classes, System.SysUtils, System.Math, System.Contnrs,
  470. Js.Base, Js.Tree, Js.Writer,
  471. Pascal.Tree, Pascal.Scanner, Pascal.ResolveEval, Pascal.Resolver;
  472. {$ELSE FPC_DOTTEDUNITS}
  473. uses
  474. Classes, SysUtils, math, contnrs,
  475. jsbase, jstree, jswriter,
  476. PasTree, PScanner, PasResolveEval, PasResolver;
  477. {$ENDIF FPC_DOTTEDUNITS}
  478. // message numbers
  479. const
  480. nPasElementNotSupported = 4001;
  481. nNotSupportedX = 4002;
  482. nUnaryOpcodeNotSupported = 4003;
  483. nBinaryOpcodeNotSupported = 4004;
  484. nInvalidNumber = 4005;
  485. nInitializedArraysNotSupported = 4006;
  486. nMemberExprMustBeIdentifier = 4007;
  487. nCantWriteSetLiteral = 4008;
  488. nInvalidAbsoluteLocation = 4009;
  489. nForInJSArrDefaultGetterNotExtBracketAccessor = 4010;
  490. nInvalidFunctionReference = 4011;
  491. nMissingExternalName = 4012;
  492. nVirtualMethodNameMustMatchExternal = 4013;
  493. nPublishedNameMustMatchExternal = 4014;
  494. nInvalidVariableModifier = 4015;
  495. nAWaitOnlyInAsyncProcedure = 4016;
  496. nNewInstanceFunctionMustBeVirtual = 4017;
  497. nNewInstanceFunctionMustHaveTwoParameters = 4018;
  498. nNewInstanceFunctionMustNotHaveOverloadAtX = 4019;
  499. nBracketAccessorOfExternalClassMustHaveOneParameter = 4020;
  500. nTypeXCannotBePublished = 4021;
  501. nNestedInheritedNeedsParameters = 4022;
  502. nFreeNeedsVar = 4023;
  503. nDuplicateGUIDXInYZ = 4024;
  504. nCantCallExtBracketAccessor = 4025;
  505. nJSNewNotSupported = 4026;
  506. nHelperClassMethodForExtClassMustBeStatic = 4027;
  507. nBitWiseOperationIs32Bit = 4028;
  508. nDuplicateMessageIdXAtY = 4029;
  509. nDispatchRequiresX = 4030;
  510. nConstRefNotForXAsConst = 4031;
  511. // resourcestring patterns of messages
  512. resourcestring
  513. sPasElementNotSupported = 'Pascal element not supported: %s';
  514. sNotSupportedX = 'Not supported: %s';
  515. sUnaryOpcodeNotSupported = 'Unary OpCode not yet supported "%s"';
  516. sBinaryOpcodeNotSupported = 'Binary OpCode not yet supported "%s"';
  517. sInvalidNumber = 'Invalid number "%s"';
  518. sInitializedArraysNotSupported = 'Initialized array variables not yet supported';
  519. sMemberExprMustBeIdentifier = 'Member expression must be an identifier';
  520. sCantWriteSetLiteral = 'Cannot write set literal';
  521. sInvalidAbsoluteLocation = 'Invalid absolute location';
  522. sForInJSArrDefaultGetterNotExtBracketAccessor = 'for-in-JS-array needs as default getter an external bracket accessor';
  523. sInvalidFunctionReference = 'Invalid function reference';
  524. sMissingExternalName = 'Missing external name';
  525. sVirtualMethodNameMustMatchExternal = 'Virtual method name must match external';
  526. sInvalidVariableModifier = 'Invalid variable modifier "%s"';
  527. sPublishedNameMustMatchExternal = 'Published name must match external';
  528. sAWaitOnlyInAsyncProcedure = 'await only available in async procedure';
  529. sAsyncFunctionOrPromise = 'async function or promise';
  530. sNewInstanceFunctionMustBeVirtual = 'NewInstance function must be virtual';
  531. sNewInstanceFunctionMustHaveTwoParameters = 'NewInstance function must have two parameters';
  532. sNewInstanceFunctionMustNotHaveOverloadAtX = 'NewInstance function must not have overload at %s';
  533. sBracketAccessorOfExternalClassMustHaveOneParameter = 'Bracket accessor of external class must have one parameter';
  534. sTypeXCannotBePublished = 'Type "%s" cannot be published';
  535. sNestedInheritedNeedsParameters = 'nested inherited needs parameters';
  536. sFreeNeedsVar = 'Free needs a variable';
  537. sDuplicateGUIDXInYZ = 'Duplicate GUID %s in %s and %s';
  538. sCantCallExtBracketAccessor = 'cannot call external bracket accessor, use a property instead';
  539. sJSNewNotSupported = 'Pascal class does not support the "new" constructor';
  540. sHelperClassMethodForExtClassMustBeStatic = 'Helper class method for external class must be static';
  541. sBitWiseOperationIs32Bit = 'Bitwise operation is 32-bit';
  542. sDuplicateMessageIdXAtY = 'Duplicate message id "%s" at %s';
  543. sDispatchRequiresX = 'Dispatch requires %s';
  544. sConstRefNotForXAsConst = 'ConstRef not yet implemented for %s. Treating as Const';
  545. const
  546. ExtClassBracketAccessor = '[]'; // external name '[]' marks the array param getter/setter
  547. IsExtModePasClassInstance = 1; // rtl.isExt param for is-class-instance
  548. IsExtModePasClass = 2; // rtl.isExt param for is-class
  549. LocalVarHide = '-';
  550. ExtRTTIVisPrivate = 0;
  551. ExtRTTIVisProtected = 1;
  552. ExtRTTIVisPublic = 2;
  553. ExtRTTIVisPublished = 3;
  554. ExtRTTIVisPublicPublished = 4; // in source published, in RTTI public
  555. ExtRTTIVisStrictPrivate = 5;
  556. ExtRTTIVisStrictProtected = 6;
  557. ExtRTTIVisDefaultField = ExtRTTIVisPublic;
  558. ExtRTTIVisDefaultMethod = ExtRTTIVisPublic;
  559. ExtRTTIVisDefaultProperty = ExtRTTIVisPublicPublished;
  560. type
  561. TPas2JSBuiltInName = (
  562. // functions
  563. pbifnArray_Concat,
  564. pbifnArray_ConcatN,
  565. pbifnArray_Copy,
  566. pbifnArray_DeleteR,
  567. pbifnArray_Equal,
  568. pbifnArray_Insert,
  569. pbifnArray_Managed,
  570. pbifnArray_Length,
  571. pbifnArray_Push,
  572. pbifnArray_PushN,
  573. pbifnArray_Reference,
  574. pbifnArray_SetLength,
  575. pbifnArray_Static_Clone,
  576. pbifnAs,
  577. pbifnAsExt,
  578. pbifnBitwiseLongwordFix,
  579. pbifnBitwiseNativeIntAnd,
  580. pbifnBitwiseNativeIntOr,
  581. pbifnBitwiseNativeIntShl,
  582. pbifnBitwiseNativeIntShr,
  583. pbifnBitwiseNativeIntXor,
  584. pbifnCheckMethodCall,
  585. pbifnCheckVersion,
  586. pbifnClassAncestorFunc,
  587. pbifnClassInstanceFree,
  588. pbifnClassInstanceNew,
  589. pbifnClassInitSpecialize,
  590. pbifnCreateClass,
  591. pbifnCreateClassExt,
  592. pbifnCreateHelper,
  593. pbifnGetChar,
  594. pbifnGetNumber,
  595. pbifnGetObject,
  596. pbifnGetResourcestring,
  597. pbifnHelperNew,
  598. pbifnIntf_AddRef,
  599. pbifnIntf_Release,
  600. pbifnIntfAddMap,
  601. pbifnIntfAsClass,
  602. pbifnIntfAsIntfT, // COM intfvar as intftype
  603. pbifnIntfCreate,
  604. pbifnIntfCreateTGUID,
  605. pbifnIntfExprRefsAdd,
  606. pbifnIntfExprRefsCreate,
  607. pbifnIntfExprRefsFree,
  608. pbifnIntfGetGUIDR,
  609. pbifnIntfGetIntfT,
  610. pbifnIntfGuidRToStr,
  611. pbifnIntfIsClass,
  612. pbifnIntfIsIntf, // COM intfvar is intftype
  613. pbifnIntfToClass,
  614. pbifnIntfSetIntfL,
  615. pbifnIntfSetIntfP,
  616. pbifnIntfStrToGUIDR,
  617. pbifnIntfQueryIntfIsT,
  618. pbifnIntfQueryIntfT,
  619. pbifnIs,
  620. pbifnIsExt,
  621. pbifnFloatToStr,
  622. pbifnValEnum,
  623. pbifnFreeLocalVar,
  624. pbifnFreeVar,
  625. pbifnLibraryMain,
  626. pbifnOverflowCheckInt,
  627. pbifnProcType_Create,
  628. pbifnProcType_CreateSafe,
  629. pbifnProcType_Equal,
  630. pbifnProgramMain,
  631. pbifnRaiseException, // rtl.raiseE
  632. pbifnRangeCheckArrayRead,
  633. pbifnRangeCheckArrayWrite,
  634. pbifnRangeCheckChar,
  635. pbifnRangeCheckInt,
  636. pbifnRangeCheckGetCharAt,
  637. pbifnRangeCheckSetCharAt,
  638. pbifnRecordAssign,
  639. pbifnRecordClone,
  640. pbifnRecordCreateType,
  641. pbifnRecordEqual,
  642. pbifnRecordNew,
  643. pbifnRTTIAddField, // typeinfos of tkclass and tkrecord have addField
  644. pbifnRTTIAddFields, // typeinfos of tkclass and tkrecord have addFields
  645. pbifnRTTIAddMethod,// " "
  646. pbifnRTTIAddProperty,// " "
  647. pbifnRTTIInherited, // typeinfo for type alias type $inherited
  648. pbifnRTTINewClass,// typeinfo creator of tkClass $Class
  649. pbifnRTTINewClassRef,// typeinfo of tkClassRef $ClassRef
  650. pbifnRTTINewDynArray,// typeinfo of tkDynArray $DynArray
  651. pbifnRTTINewEnum,// typeinfo of tkEnumeration $Enum
  652. pbifnRTTINewExtClass,// typeinfo creator of tkExtClass $ExtClass
  653. pbifnRTTINewInt,// typeinfo of tkInt $Int
  654. pbifnRTTINewInterface,// typeinfo creator of tkInterface $Interface
  655. pbifnRTTINewMethodVar,// typeinfo of tkMethod $MethodVar
  656. pbifnRTTINewPointer,// typeinfo of tkPointer $Pointer
  657. pbifnRTTINewProcSig,// rtl.newTIProcSig
  658. pbifnRTTINewProcVar,// typeinfo of tkProcVar $ProcVar
  659. pbifnRTTINewRecord,// typeinfo creator of tkRecord $Record
  660. pbifnRTTINewRefToProcVar,// typeinfo of tkRefToProcVar $RefToProcVar
  661. pbifnRTTINewSet,// typeinfo of tkSet $Set
  662. pbifnRTTINewStaticArray,// typeinfo of tkArray $StaticArray
  663. pbifnSetCharAt,
  664. pbifnSet_Clone,
  665. pbifnSet_Create,
  666. pbifnSet_Difference,
  667. pbifnSet_Equal,
  668. pbifnSet_Exclude,
  669. pbifnSet_GreaterEqual,
  670. pbifnSet_Include,
  671. pbifnSet_Intersect,
  672. pbifnSet_LowerEqual,
  673. pbifnSet_NotEqual,
  674. pbifnSet_Reference,
  675. pbifnSet_SymDiffSet,
  676. pbifnSet_Union,
  677. pbifnSpaceLeft,
  678. pbifnStringSetLength,
  679. pbifnTrunc, // rtl.trunc
  680. pbifnUnitInit,
  681. // variables
  682. pbivnExceptObject,
  683. pbivnIntfExprRefs,
  684. pbivnIntfGUID,
  685. pbivnIntfKind,
  686. pbivnIntfMaps,
  687. pbivnIntfRefCnt, // param for arrayClone, arraySetLength
  688. pbivnImplementation,
  689. pbivnImplCode,
  690. pbivnMessageInt,
  691. pbivnMessageStr,
  692. pbivnLibrary, // library
  693. pbivnLibraryVars, // library vars
  694. pbivnLocalModuleRef,
  695. pbivnLocalProcRef,
  696. pbivnLocalTypeRef,
  697. pbivnLoop,
  698. pbivnLoopEnd,
  699. pbivnLoopIn,
  700. pbivnModule,
  701. pbivnModules,
  702. pbivnPtrClass,
  703. pbivnPtrRecord,
  704. pbivnProcOk,
  705. pbivnProgram, // program
  706. pbivnResourceStrings,
  707. pbivnResourceStringOrig,
  708. pbivnRTL,
  709. pbivnRTTI, // $rtti
  710. pbivnRTTIArray_Dims,
  711. pbivnRTTIArray_ElType,
  712. pbivnRTTIClassRef_InstanceType,
  713. pbivnRTTIEnum_EnumType,
  714. pbivnRTTIInt_MaxValue,
  715. pbivnRTTIInt_MinValue,
  716. pbivnRTTIInt_OrdType,
  717. pbivnRTTILocal, // $r
  718. pbivnRTTIMemberAttributes, // attr
  719. pbivnRTTIMethodKind, // tTypeInfoMethodVar has methodkind
  720. pbivnRTTIPointer_RefType, // reftype
  721. pbivnRTTIProcFlags, // flags
  722. pbivnRTTIProc_InitSpec, // init
  723. pbivnRTTIProcVar_ProcSig, // procsig
  724. pbivnRTTIPropDefault, // Default
  725. pbivnRTTIPropIndex, // index
  726. pbivnRTTIPropStored, // stored
  727. pbivnRTTISet_CompType, // comptype
  728. pbivnRTTITypeAttributes, // attr
  729. pbivnRTTIExtClass_Ancestor, // ancestor
  730. pbivnRTTIExtClass_JSClass, // jsclass
  731. pbivnSelf,
  732. pbivnTObjectDestroy,
  733. pbivnWith,
  734. // types
  735. pbitnAnonymousPostfix,
  736. pbitnIntDouble,
  737. pbitnTI,
  738. pbitnTIClass,
  739. pbitnTIClassRef,
  740. pbitnTIDynArray,
  741. pbitnTIEnum,
  742. pbitnTIExtClass,
  743. pbitnTIHelper,
  744. pbitnTIInteger,
  745. pbitnTIInterface,
  746. pbitnTIMethodVar,
  747. pbitnTIPointer,
  748. pbitnTIProcVar,
  749. pbitnTIRecord,
  750. pbitnTIRefToProcVar,
  751. pbitnTISet,
  752. pbitnTIStaticArray,
  753. pbitnUIntDouble
  754. );
  755. const
  756. Pas2JSBuiltInNames: array[TPas2JSBuiltInName] of string = (
  757. 'arrayConcat', // rtl.arrayConcat pbifnArray_Concat
  758. 'arrayConcatN', // rtl.arrayConcatN pbifnArray_ConcatN
  759. 'arrayCopy', // rtl.arrayCopy pbifnArray_Copy
  760. 'arrayDeleteR', // rtl.arrayDeleteR pbifnArray_DeleteR
  761. 'arrayEq', // rtl.arrayEq pbifnArray_Equal
  762. 'arrayInsert', // rtl.arrayCopy pbifnArray_Insert
  763. 'arrayManaged', // rtl.arrayManaged pbifnArray_Managed
  764. 'length', // rtl.length pbifnArray_Length
  765. 'arrayPush', // rtl.arrayPush pbifnArray_Push
  766. 'arrayPushN', // rtl.arrayPushN pbifnArray_PushN
  767. 'arrayRef', // rtl.arrayRef pbifnArray_Reference
  768. 'arraySetLength', // rtl.arraySetLength pbifnArray_SetLength
  769. '$clone', // pbifnArray_Static_Clone
  770. 'as', // rtl.as pbifnAs
  771. 'asExt', // rtl.asExt pbifnAsExt
  772. 'lw', // pbifnBitwiseLongwordFix
  773. 'and', // pbifnBitwiseNativeIntAnd,
  774. 'or', // pbifnBitwiseNativeIntOr,
  775. 'shl', // pbifnBitwiseNativeIntShl,
  776. 'shr', // pbifnBitwiseNativeIntShr,
  777. 'xor', // pbifnBitwiseNativeIntXor,
  778. 'checkMethodCall', // pbifnCheckMethodCall
  779. 'checkVersion', // pbifnCheckVersion
  780. '$ancestorfunc', // pbifnClassAncestorFunc
  781. '$destroy', // pbifnClassInstanceFree
  782. '$create', // pbifnClassInstanceNew
  783. '$initSpec', // pbifnClassInitSpecialize
  784. 'createClass', // pbifnCreateClass rtl.createClass
  785. 'createClassExt', // pbifnCreateClassExt rtl.createClassExt
  786. 'createHelper', // pbifnCreateHelper rtl.createHelper
  787. 'getChar', // pbifnGetChar rtl.getChar
  788. 'getNumber', // pbifnGetNumber rtl.getNumber
  789. 'getObject', // pbifnGetObject rtl.getObject
  790. 'getResStr', // pbifnGetResourcestring rtl.getResStr
  791. '$new', // pbifnHelperNew helpertype.$new
  792. '_AddRef', // pbifnIntf_AddRef rtl._AddRef
  793. '_Release', // pbifnIntf_Release rtl._Release
  794. 'addIntf', // pbifnIntfAddMap rtl.addIntf
  795. 'intfAsClass', // pbifnIntfAsClass rtl.intfAsClass
  796. 'intfAsIntfT', // pbifnIntfAsIntfT rtl.intfAsIntfT
  797. 'createInterface', // pbifnIntfCreate rtl.createInterface
  798. 'createTGUID', // pbifnIntfCreateTGUID rtl.createTGUID
  799. 'ref', // pbifnIntfExprRefsAdd $ir.ref
  800. 'createIntfRefs', // pbifnIntfExprRefsCreate rtl.createIntfRefs
  801. 'free', // pbifnIntfExprRefsFree $ir.free
  802. 'getIntfGUIDR', // pbifnIntfGetGUIDR rtl.getIntfGUIDR
  803. 'getIntfT', // pbifnIntfGetIntfT rtl.getIntfT
  804. 'guidrToStr', // pbifnIntfGuidRToStr rtl.guidrToStr
  805. 'intfIsClass', // pbifnIntfIsClass rtl.intfIsClass
  806. 'intfIsIntfT', // pbifnIntfIsIntf rtl.intfIsIntfT
  807. 'intfToClass', // pbifnIntfToClass rtl.intfToClass
  808. 'setIntfL', // pbifnIntfSetIntfL rtl.setIntfL
  809. 'setIntfP', // pbifnIntfSetIntfP rtl.setIntfP
  810. 'strToGUIDR', // pbifnIntfStrToGUIDR rtl.strToGUIDR
  811. 'queryIntfIsT', // pbifnIntfQueryIntfIsT rtl.queryIntfIsT
  812. 'queryIntfT', // pbifnIntfQueryIntfT rtl.queryIntfT
  813. 'is', // pbifnIs rtl.is
  814. 'isExt', // pbifnIsExt rtl.isExt
  815. 'floatToStr', // pbifnFloatToStr rtl.floatToStr
  816. 'valEnum', // pbifnValEnum rtl.valEnum
  817. 'freeLoc', // pbifnFreeLocalVar rtl.freeLoc
  818. 'free', // pbifnFreeVar rtl.free
  819. '$main', // pbifnLibraryMain
  820. 'oc', // pbifnOverflowCheckInt rtl.oc
  821. 'createCallback', // pbifnProcType_Create rtl.createCallback
  822. 'createSafeCallback', // pbifnProcType_CreateSafe rtl.createSafeCallback
  823. 'eqCallback', // pbifnProcType_Equal rtl.eqCallback
  824. '$main', // pbifnProgramMain
  825. 'raiseE', // pbifnRaiseException rtl.raiseE
  826. 'rcArrR', // pbifnRangeCheckArrayRead rtl.rcArrR
  827. 'rcArrW', // pbifnRangeCheckArrayWrite rtl.rcArrW
  828. 'rcc', // pbifnRangeCheckChar rtl.rcc
  829. 'rc', // pbifnRangeCheckInt rtl.rc
  830. 'rcCharAt', // pbifnRangeCheckGetCharAt rtl.rcCharAt
  831. 'rcSetCharAt', // pbifnRangeCheckSetCharAt rtl.rcSetCharAt
  832. '$assign', // pbifnRecordAssign
  833. '$clone', // pbifnRecordClone
  834. 'recNewT', // pbifnRecordCreateType
  835. '$eq', // pbifnRecordEqual
  836. '$new', // pbifnRecordNew
  837. 'addField', // pbifnRTTIAddField
  838. 'addFields', // pbifnRTTIAddFields
  839. 'addMethod', // pbifnRTTIAddMethod
  840. 'addProperty', // pbifnRTTIAddProperty
  841. '$inherited', // pbifnRTTIInherited
  842. '$Class', // pbifnRTTINewClass tkClass
  843. '$ClassRef', // pbifnRTTINewClassRef
  844. '$DynArray', // pbifnRTTINewDynArray
  845. '$Enum', // pbifnRTTINewEnum
  846. '$ExtClass', // pbifnRTTINewExtClass
  847. '$Int', // pbifnRTTINewInt
  848. '$Interface', // pbifnRTTINewInterface
  849. '$MethodVar', // pbifnRTTINewMethodVar
  850. '$Pointer', // pbifnRTTINewPointer
  851. 'newTIProcSig', // pbifnRTTINewProcSig
  852. '$ProcVar', // pbifnRTTINewProcVar
  853. '$Record', // pbifnRTTINewRecord
  854. '$RefToProcVar', // pbifnRTTINewRefToProcVar
  855. '$Set', // pbifnRTTINewSet
  856. '$StaticArray', // pbifnRTTINewStaticArray
  857. 'setCharAt', // pbifnSetCharAt rtl.setCharAt
  858. 'cloneSet', // pbifnSet_Clone rtl.cloneSet
  859. 'createSet', // pbifnSet_Create rtl.createSet [...]
  860. 'diffSet', // pbifnSet_Difference rtl.diffSet -
  861. 'eqSet', // pbifnSet_Equal rtl.eqSet =
  862. 'excludeSet', // pbifnSet_Exclude rtl.excludeSet
  863. 'geSet', // pbifnSet_GreaterEqual rtl.geSet superset >=
  864. 'includeSet', // pbifnSet_Include rtl.includeSet
  865. 'intersectSet', // pbifnSet_Intersect rtl.intersectSet *
  866. 'leSet', // pbifnSet_LowerEqual rtl.leSet subset <=
  867. 'neSet', // pbifnSet_NotEqual rtl.neSet <>
  868. 'refSet', // pbifnSet_Reference rtl.refSet
  869. 'symDiffSet', // pbifnSet_SymDiffSet rtl.symDiffSet >< (symmetrical difference)
  870. 'unionSet', // pbifnSet_Union rtl.unionSet +
  871. 'spaceLeft', // pbifnSpaceLeft rtl.spaceLeft
  872. 'strSetLength', // pbifnStringSetLength rtl.strSetLength
  873. 'trunc', // pbifnTrunc
  874. '$init', // pbifnUnitInit
  875. '$e', // pbivnExceptObject
  876. '$ir', // pbivnIntfExprRefs
  877. '$guid',// pbivnIntfGUID
  878. '$kind', // pbivnIntfKind
  879. '$intfmaps', // pbivnIntfMaps
  880. 'R', // pbivnIntfRefCnt param for arrayClone
  881. '$impl', // pbivnImplementation
  882. '$implcode', // pbivnImplCode
  883. '$msgint', // pbivnMessageInt
  884. '$msgstr', // pbivnMessageStr
  885. 'library', // pbivnLibrary pas.library
  886. 'vars', // pbivnLibraryVars vars
  887. '$lm', // pbivnLocalModuleRef
  888. '$lp', // pbivnLocalProcRef
  889. '$lt', // pbivnLocalTypeRef
  890. '$l', // pbivnLoop
  891. '$end', // pbivnLoopEnd
  892. '$in', // pbivnLoopIn
  893. '$mod', // pbivnModule
  894. 'pas', // pbivnModules
  895. '$class', // pbivnPtrClass, ClassType
  896. '$record', // pbivnPtrRecord, hidden recordtype
  897. '$ok', // pbivnProcOk
  898. 'program', // pbivnProgram pas.program
  899. '$resourcestrings', // pbivnResourceStrings
  900. 'org', // pbivnResourceStringOrig
  901. 'rtl', // pbivnRTL
  902. '$rtti', // pbivnRTTI
  903. 'dims', // pbivnRTTIArray_Dims
  904. 'eltype', // pbivnRTTIArray_ElType
  905. 'instancetype', // pbivnRTTIClassRef_InstanceType
  906. 'enumtype', // pbivnRTTIEnum_EnumType
  907. 'maxvalue', // pbivnRTTIInt_MaxValue
  908. 'minvalue', // pbivnRTTIInt_MinValue
  909. 'ordtype', // pbivnRTTIInt_OrdType
  910. '$r', // pbivnRTTILocal
  911. 'attr', // pbivnRTTIMemberAttributes
  912. 'methodkind', // pbivnRTTIMethodKind
  913. 'reftype', // pbivnRTTIPointer_RefType
  914. 'flags', // pbivnRTTIProcFlags
  915. 'init', // pbivnRTTIProc_InitSpec
  916. 'procsig', // pbivnRTTIProcVar_ProcSig
  917. 'Default', // pbivnRTTIPropDefault
  918. 'index', // pbivnRTTIPropIndex
  919. 'stored', // pbivnRTTIPropStored
  920. 'comptype', // pbivnRTTISet_CompType
  921. 'attr', // pbivnRTTITypeAttributes
  922. 'ancestor', // pbivnRTTIExtClass_Ancestor
  923. 'jsclass', // pbivnRTTIExtClass_JSClass
  924. '$Self', // pbivnSelf
  925. 'tObjectDestroy', // pbivnTObjectDestroy rtl.tObjectDestroy
  926. '$with', // pbivnWith
  927. '$a', // pbitnAnonymousPostfix
  928. 'NativeInt', // pbitnIntDouble
  929. 'tTypeInfo', // pbitnTI
  930. 'tTypeInfoClass', // pbitnTIClass
  931. 'tTypeInfoClassRef', // pbitnTIClassRef
  932. 'tTypeInfoDynArray', // pbitnTIDynArray
  933. 'tTypeInfoEnum', // pbitnTIEnum
  934. 'tTypeInfoExtClass', // pbitnTIExtClass
  935. 'tTypeInfoHelper', // pbitnTIHelper
  936. 'tTypeInfoInteger', // pbitnTIInteger
  937. 'tTypeInfoInterface', // pbitnTIInterface
  938. 'tTypeInfoMethodVar', // pbitnTIMethodVar
  939. 'tTypeInfoPointer', // pbitnTIPointer
  940. 'tTypeInfoProcVar', // pbitnTIProcVar
  941. 'tTypeInfoRecord', // pbitnTIRecord
  942. 'tTypeInfoRefToProcVar', // pbitnTIRefToProcVar
  943. 'tTypeInfoSet', // pbitnTISet
  944. 'tTypeInfoStaticArray', // pbitnTIStaticArray
  945. 'NativeUInt' // pbitnUIntDouble
  946. );
  947. // reserved words, not usable as identifiers, not even as sub identifiers
  948. // pas2js will avoid name clashes, by changing the casing
  949. JSReservedWords: array[0..59] of string = (
  950. // keep sorted, first uppercase, then lowercase !
  951. '__extends',
  952. '_super',
  953. 'anonymous',
  954. 'apply',
  955. 'array',
  956. 'await',
  957. 'bind',
  958. 'break',
  959. 'call',
  960. 'case',
  961. 'catch',
  962. 'class',
  963. 'constructor',
  964. 'continue',
  965. 'default',
  966. 'delete',
  967. 'do',
  968. 'each',
  969. 'else',
  970. 'enum',
  971. 'escape',
  972. 'eval',
  973. 'export',
  974. 'extends',
  975. 'false',
  976. 'for',
  977. 'function',
  978. 'getPrototypeOf',
  979. 'hasOwnProperty',
  980. 'if',
  981. 'implements',
  982. 'import',
  983. 'in',
  984. 'instanceof',
  985. 'interface',
  986. 'isPrototypeOf',
  987. 'let',
  988. 'new',
  989. 'null',
  990. 'package',
  991. 'private',
  992. 'propertyIsEnumerable',
  993. 'protected',
  994. 'prototype',
  995. 'public',
  996. 'return',
  997. 'static',
  998. 'super',
  999. 'switch',
  1000. 'this',
  1001. 'throw',
  1002. 'toLocaleString',
  1003. 'toString',
  1004. 'true',
  1005. 'try',
  1006. 'undefined',
  1007. 'var',
  1008. 'while',
  1009. 'with',
  1010. 'yield'
  1011. );
  1012. // reserved words, not usable as global identifiers, can be used as sub identifiers
  1013. JSReservedGlobalWords: array[0..52] of string = (
  1014. // keep sorted, first uppercase, then lowercase !
  1015. 'Array',
  1016. 'ArrayBuffer',
  1017. 'Boolean',
  1018. 'DataView',
  1019. 'Date',
  1020. 'Error',
  1021. 'EvalError',
  1022. 'Float32Array',
  1023. 'Float64Array',
  1024. 'FormData',
  1025. 'Generator',
  1026. 'GeneratorFunction',
  1027. 'Infinity',
  1028. 'Int16Array',
  1029. 'Int32Array',
  1030. 'Int8Array',
  1031. 'InternalError',
  1032. 'JSON',
  1033. 'Map',
  1034. 'Math',
  1035. 'NaN',
  1036. 'Number',
  1037. 'Object',
  1038. 'Promise',
  1039. 'Proxy',
  1040. 'RangeError',
  1041. 'ReferenceError',
  1042. 'Reflect',
  1043. 'RegExp',
  1044. 'Set',
  1045. 'String',
  1046. 'Symbol',
  1047. 'SyntaxError',
  1048. 'TypeError',
  1049. 'URIError',
  1050. 'Uint16Array',
  1051. 'Uint32Array',
  1052. 'Uint8Array',
  1053. 'Uint8ClampedArray',
  1054. 'WeakMap',
  1055. 'WeakSet',
  1056. 'arguments',
  1057. 'decodeURI',
  1058. 'decodeURIComponent',
  1059. 'encodeURI',
  1060. 'encodeURIComponent',
  1061. 'isFinite',
  1062. 'isNaN',
  1063. 'parseFloat',
  1064. 'parseInt',
  1065. 'unescape',
  1066. 'uneval',
  1067. 'valueOf'
  1068. );
  1069. type
  1070. { EPas2JS }
  1071. EPas2JS = Class(Exception)
  1072. public
  1073. PasElement: TPasElement;
  1074. MsgNumber: integer;
  1075. Args: TMessageArgs;
  1076. Id: TMaxPrecInt;
  1077. MsgType: TMessageType;
  1078. end;
  1079. type
  1080. TPasToJsPlatform = (
  1081. PlatformBrowser,
  1082. PlatformNodeJS,
  1083. PlatformElectron,
  1084. PlatformModule
  1085. );
  1086. TPasToJsPlatforms = set of TPasToJsPlatform;
  1087. const
  1088. PasToJsPlatformNames: array[TPasToJsPlatform] of string = (
  1089. 'Browser',
  1090. 'NodeJS',
  1091. 'Electron',
  1092. 'Module'
  1093. );
  1094. type
  1095. TPasToJsProcessor = (
  1096. ProcessorECMAScript5,
  1097. ProcessorECMAScript6
  1098. );
  1099. TPasToJsProcessors = set of TPasToJsProcessor;
  1100. const
  1101. PasToJsProcessorNames: array[TPasToJsProcessor] of string = (
  1102. 'ECMAScript5',
  1103. 'ECMAScript6'
  1104. );
  1105. //------------------------------------------------------------------------------
  1106. // Pas2js built-in types
  1107. type
  1108. TPas2jsBaseType = (
  1109. pbtNone,
  1110. pbtJSValue
  1111. );
  1112. TPas2jsBaseTypes = set of TPas2jsBaseType;
  1113. const
  1114. Pas2jsBaseTypeNames: array[TPas2jsBaseType] of string = (
  1115. 'None',
  1116. 'JSValue'
  1117. );
  1118. type
  1119. TPas2jsBuiltInProc = (
  1120. pbpDebugger,
  1121. pbpAWait
  1122. );
  1123. const
  1124. Pas2jsBuiltInProcNames: array[TPas2jsBuiltInProc] of string = (
  1125. 'Debugger',
  1126. 'AWait'
  1127. );
  1128. const
  1129. ClassVarModifiersType = [vmClass,vmStatic];
  1130. LowJSNativeInt = MinSafeIntDouble;
  1131. HighJSNativeInt = MaxSafeIntDouble;
  1132. LowJSBoolean = false;
  1133. HighJSBoolean = true;
  1134. //------------------------------------------------------------------------------
  1135. // Element CustomData
  1136. type
  1137. { TPas2JsElementData }
  1138. TPas2JsElementData = Class(TPasElementBase)
  1139. private
  1140. FElement: TPasElement;
  1141. procedure SetElement(const AValue: TPasElement);
  1142. public
  1143. Owner: TObject; // e.g. a TPasToJSConverter
  1144. Next: TPas2JsElementData; // TPasToJSConverter uses this for its memory chain
  1145. constructor Create; virtual;
  1146. destructor Destroy; override;
  1147. property Element: TPasElement read FElement write SetElement; // can be TPasElement
  1148. end;
  1149. TPas2JsElementDataClass = class of TPas2JsElementData;
  1150. TPas2JSStoredLocalVar = class(TPasElementBase)
  1151. public
  1152. Name: string;
  1153. Element: TPasElement;
  1154. end;
  1155. TPas2JSStoredLocalVarArray = array of TPas2JSStoredLocalVar;
  1156. TPas2JSModuleScopeFlag = (
  1157. p2msfPromiseSearched // TJSPromise searched
  1158. );
  1159. TPas2JSModuleScopeFlags = set of TPas2JSModuleScopeFlag;
  1160. { TPas2JSModuleScope }
  1161. TPas2JSModuleScope = class(TPasModuleScope)
  1162. private
  1163. FJSPromiseClass: TPasClassType;
  1164. procedure SetJSPromiseClass(const AValue: TPasClassType);
  1165. public
  1166. FlagsJS: TPas2JSModuleScopeFlags;
  1167. SystemVarRecs: TPasFunction;
  1168. StoreJSLocalVars: TPas2JSStoredLocalVarArray; // only with coStoreImplJS
  1169. procedure ClearStoreJSLocalVars;
  1170. destructor Destroy; override;
  1171. property JSPromiseClass: TPasClassType read FJSPromiseClass write SetJSPromiseClass;
  1172. end;
  1173. { TPas2jsElevatedLocals }
  1174. TPas2jsElevatedLocals = class
  1175. private
  1176. FElevatedLocals: TPasResHashList; // list of TPasIdentifier, case insensitive
  1177. procedure InternalAdd(Item: TPasIdentifier);
  1178. procedure OnClear(Item, Dummy: pointer);
  1179. public
  1180. constructor Create;
  1181. destructor Destroy; override;
  1182. function Find(const Identifier: String): TPasIdentifier; inline;
  1183. function Add(const Identifier: String; El: TPasElement): TPasIdentifier; virtual;
  1184. end;
  1185. { TPas2JSPrecompiledJS - Option coStoreImplJS }
  1186. TPas2JSPrecompiledJS = class
  1187. public
  1188. BodyJS: string;
  1189. EmptyJS: boolean; // true if Body.Body=nil
  1190. GlobalJS: TStringList;
  1191. ShortRefs: TFPList; // list of TPasElement needing a SectionContext.AddLocalVar
  1192. procedure AddShortRef(El: TPasElement);
  1193. destructor Destroy; override;
  1194. end;
  1195. { TPas2JSSectionScope
  1196. JSElement is TJSSourceElements }
  1197. TPas2JSSectionScope = class(TPasSectionScope)
  1198. public
  1199. ElevatedLocals: TPas2jsElevatedLocals;
  1200. Renamed: boolean;
  1201. constructor Create; override;
  1202. destructor Destroy; override;
  1203. procedure WriteElevatedLocals(Prefix: string); virtual;
  1204. end;
  1205. { TPas2JSInitialFinalizationScope }
  1206. TPas2JSInitialFinalizationScope = class(TPasInitialFinalizationScope)
  1207. public
  1208. ImplJS: TPas2JSPrecompiledJS; // Option coStoreImplJS
  1209. destructor Destroy; override;
  1210. end;
  1211. TMessageIdToProc_List = TStringList;
  1212. { TPas2JSClassScope }
  1213. TPas2JSClassScope = class(TPasClassScope)
  1214. public
  1215. JSName: string;
  1216. NewInstanceFunction: TPasClassFunction;
  1217. GUID: string;
  1218. ElevatedLocals: TPas2jsElevatedLocals;
  1219. MemberOverloadsRenamed: boolean;
  1220. // Dispatch and message modifiers:
  1221. DispatchField: String;
  1222. DispatchStrField: String;
  1223. MsgIntToProc, MsgStrToProc: TMessageIdToProc_List; // not stored by filer
  1224. public
  1225. constructor Create; override;
  1226. destructor Destroy; override;
  1227. end;
  1228. { TPas2JSRecordScope }
  1229. TPas2JSRecordScope = class(TPasRecordScope)
  1230. public
  1231. JSName: string;
  1232. MemberOverloadsRenamed: boolean;
  1233. Managed: boolean; // true: needs reference counting
  1234. end;
  1235. { TPas2JSProcedureScope }
  1236. TPas2JSProcedureScope = class(TPasProcedureScope)
  1237. public
  1238. OverloadName: string;
  1239. JSName: string;
  1240. ResultVarName: string; // valid in implementation ProcScope, empty means use ResolverResultVar
  1241. BodyOverloadsRenamed: boolean;
  1242. ImplJS: TPas2JSPrecompiledJS; // Option coStoreImplJS: stored in ImplScope
  1243. procedure AddGlobalJS(const JS: string);
  1244. destructor Destroy; override;
  1245. end;
  1246. { TPas2JSArrayScope }
  1247. TPas2JSArrayScope = Class(TPasArrayScope)
  1248. public
  1249. JSName: string;
  1250. Managed: boolean; // true: needs reference counting
  1251. end;
  1252. { TPas2JSProcTypeScope }
  1253. TPas2JSProcTypeScope = Class(TPasProcTypeScope)
  1254. public
  1255. JSName: string;
  1256. end;
  1257. { TPas2JSWithExprScope }
  1258. TPas2JSWithExprScope = class(TPasWithExprScope)
  1259. public
  1260. WithVarName: string;
  1261. end;
  1262. { TPas2JSOverloadChgThisScope
  1263. Dummy scope to signal a change of the "this" on the overload scope stack }
  1264. TPas2JSOverloadChgThisScope = class(TPasIdentifierScope)
  1265. end;
  1266. { TResElDataPas2JSBaseType - CustomData for compiler built-in types (TPasUnresolvedSymbolRef), e.g. jsvalue }
  1267. TResElDataPas2JSBaseType = class(TResElDataBaseType)
  1268. public
  1269. JSBaseType: TPas2jsBaseType;
  1270. end;
  1271. //------------------------------------------------------------------------------
  1272. // TPas2JSResolver
  1273. const
  1274. msAllPas2jsModeSwitchesReadOnly = [
  1275. msClass,
  1276. msResult,
  1277. msRepeatForward,
  1278. msInitFinal,
  1279. msOut,
  1280. msDefaultPara,
  1281. msProperty,
  1282. msExcept,
  1283. msDefaultUnicodestring,
  1284. msCBlocks,
  1285. msFunctionReferences,
  1286. msAnonymousFunctions
  1287. ];
  1288. msAllPas2jsModeSwitches = msAllPas2jsModeSwitchesReadOnly+[
  1289. msDelphi,msObjfpc,
  1290. msNestedComment,
  1291. msAutoDeref,
  1292. msHintDirective,
  1293. msAdvancedRecords,
  1294. msExternalClass,
  1295. msTypeHelpers,
  1296. msArrayOperators,
  1297. msPrefixedAttributes,
  1298. msOmitRTTI,
  1299. msMultiHelpers,
  1300. msImplicitFunctionSpec,
  1301. msMultilineStrings,
  1302. msDelphiMultilineStrings];
  1303. bsAllPas2jsBoolSwitchesReadOnly = [
  1304. bsLongStrings
  1305. ];
  1306. bsAllPas2jsBoolSwitches = bsAllPas2jsBoolSwitchesReadOnly+[
  1307. bsAssertions,
  1308. bsRangeChecks,
  1309. bsWriteableConst,
  1310. bsTypeInfo,
  1311. bsOverflowChecks,
  1312. bsHints,
  1313. bsNotes,
  1314. bsWarnings,
  1315. bsMacro,
  1316. bsScopedEnums,
  1317. bsObjectChecks
  1318. ];
  1319. vsAllPas2jsValueSwitchesReadOnly = [];
  1320. vsAllPas2jsValueSwitches = vsAllPas2jsValueSwitchesReadOnly+[
  1321. vsInterfaces,
  1322. vsDispatchField,
  1323. vsDispatchStrField
  1324. ];
  1325. // default parser+scanner options
  1326. po_Pas2js = po_Resolver+[
  1327. po_AsmWhole,
  1328. po_ResolveStandardTypes,
  1329. po_ExtConstWithoutExpr,
  1330. po_StopOnUnitInterface,
  1331. po_AsyncProcs,
  1332. po_CheckDirectiveRTTI];
  1333. btAllJSBaseTypes = [
  1334. btChar,
  1335. btWideChar,
  1336. btString,
  1337. btUnicodeString,
  1338. btDouble,
  1339. btCurrency, // nativeint*10000 truncated
  1340. btBoolean,
  1341. btByteBool,
  1342. btWordBool,
  1343. btLongBool,
  1344. btByte,
  1345. btShortInt,
  1346. btWord,
  1347. btSmallInt,
  1348. btLongWord,
  1349. btLongint,
  1350. btUIntDouble,
  1351. btIntDouble,
  1352. btPointer
  1353. ];
  1354. bfAllJSBaseProcs = bfAllStandardProcs;
  1355. btAllJSStrings = [btString,btUnicodeString];
  1356. btAllJSChars = [btChar,btWideChar];
  1357. btAllJSStringAndChars = btAllJSStrings+btAllJSChars;
  1358. btAllJSFloats = [btDouble];
  1359. btAllJSBooleans = [btBoolean,btByteBool,btWordBool,btLongBool];
  1360. btAllJSInteger = [btByte,btShortInt,btWord,btSmallInt,btLongWord,btLongint,
  1361. btIntDouble,btUIntDouble,
  1362. btCurrency // in pas2js currency is more like an integer, instead of float
  1363. ];
  1364. btAllJSValueSrcTypes = [btNil,btUntyped,btPointer,btSet]+btAllJSInteger
  1365. +btAllJSStringAndChars+btAllJSFloats+btAllJSBooleans;
  1366. btAllJSValueTypeCastTo = btAllJSInteger
  1367. +btAllJSStringAndChars+btAllJSFloats+btAllJSBooleans+[btPointer];
  1368. btAllJSRangeCheckTypes = btAllJSInteger + btAllJSChars;
  1369. btAllJSOverflowAddSubType = [btIntDouble,btUIntDouble,btCurrency];
  1370. btAllJSOverflowMultType = [btLongWord,btLongint,btIntDouble,btUIntDouble,btCurrency];
  1371. DefaultPasResolverOptions = [
  1372. proFixCaseOfOverrides,
  1373. proClassPropertyNonStatic,
  1374. proPropertyAsVarParam,
  1375. proClassOfIs,
  1376. proExtClassInstanceNoTypeMembers,
  1377. proOpenAsDynArrays,
  1378. proProcTypeWithoutIsNested,
  1379. proMethodAddrAsPointer,
  1380. proSafecallAllowsDefault
  1381. ];
  1382. type
  1383. TPasToJsConverterOption = (
  1384. coLowerCase, // lowercase all identifiers, except conflicts with JS reserved words
  1385. coSwitchStatement, // convert case-of into switch instead of if-then-else
  1386. coEnumNumbers, // use enum numbers instead of names
  1387. coUseStrict, // insert 'use strict'
  1388. coNoTypeInfo, // do not generate RTTI
  1389. coEliminateDeadCode, // skip code that is never executed
  1390. coStoreImplJS, // store references to JS code in procscopes
  1391. coRTLVersionCheckMain, // insert rtl version check into main
  1392. coRTLVersionCheckSystem, // insert rtl version check into system unit init
  1393. coRTLVersionCheckUnit, // insert rtl version check into every unit init
  1394. coShortRefGlobals, // use short local variables for global identifiers
  1395. coObfuscateLocalIdentifiers // use auto generated names for private and local Pascal identifiers
  1396. );
  1397. TPasToJsConverterOptions = set of TPasToJsConverterOption;
  1398. const
  1399. DefaultPasToJSOptions = [coLowerCase];
  1400. type
  1401. TPas2JSResolver = class;
  1402. { TPas2jsPasScanner }
  1403. TPas2jsPasScanner = class(TPascalScanner)
  1404. private
  1405. FCompilerVersion: string;
  1406. FResolver: TPas2JSResolver;
  1407. FTargetPlatform: TPasToJsPlatform;
  1408. FTargetProcessor: TPasToJsProcessor;
  1409. protected
  1410. function HandleInclude(const Param: TPasScannerString): TToken; override;
  1411. procedure DoHandleOptimization(OptName, OptValue: TPasScannerString); override;
  1412. public
  1413. GlobalConvOptsEnabled: TPasToJsConverterOptions;
  1414. GlobalConvOptsDisabled: TPasToJsConverterOptions;
  1415. function ReadNonPascalTillEndToken(StopAtLineEnd: boolean): TToken;
  1416. override;
  1417. property CompilerVersion: string read FCompilerVersion write FCompilerVersion;
  1418. property Resolver: TPas2JSResolver read FResolver write FResolver;
  1419. property TargetPlatform: TPasToJsPlatform read FTargetPlatform write FTargetPlatform;
  1420. property TargetProcessor: TPasToJsProcessor read FTargetProcessor write FTargetProcessor;
  1421. end;
  1422. { TPas2JSResolverHub }
  1423. TPas2JSResolverHub = class(TPasResolverHub)
  1424. private
  1425. FJSDelaySpecialize: TFPList;// list of TPasGenericType
  1426. function GetJSDelaySpecializes(Index: integer): TPasGenericType;
  1427. public
  1428. constructor Create(TheOwner: TObject); override;
  1429. destructor Destroy; override;
  1430. procedure Reset; override;
  1431. // delayed type specialization
  1432. procedure AddJSDelaySpecialize(SpecType: TPasGenericType);
  1433. function IsJSDelaySpecialize(SpecType: TPasGenericType): boolean;
  1434. function JSDelaySpecializeCount: integer;
  1435. property JSDelaySpecializes[Index: integer]: TPasGenericType read GetJSDelaySpecializes;
  1436. end;
  1437. { TPas2JSResolver }
  1438. TPas2JSResolver = class(TPasResolver)
  1439. private
  1440. FJSBaseTypes: array[TPas2jsBaseType] of TPasUnresolvedSymbolRef;
  1441. FJSBuiltInProcs: array[TPas2jsBuiltInProc] of TResElDataBuiltInProc;
  1442. FExternalNames: TPasResHashList; // list of TPasIdentifier, case sensitive
  1443. FFirstElementData, FLastElementData: TPas2JsElementData;
  1444. function GetJSBaseTypes(aBaseType: TPas2jsBaseType): TPasUnresolvedSymbolRef; inline;
  1445. function GetJSBuiltInProcs(aProc: TPas2jsBuiltInProc): TResElDataBuiltInProc; inline;
  1446. procedure InternalAdd(Item: TPasIdentifier);
  1447. procedure OnClearHashItem(Item, Dummy: pointer);
  1448. protected
  1449. type
  1450. THasAnoFuncData = record
  1451. Expr: TProcedureExpr;
  1452. end;
  1453. PHasAnoFuncData = ^THasAnoFuncData;
  1454. procedure OnHasAnonymousEl(El: TPasElement; arg: pointer);
  1455. protected
  1456. type
  1457. THasElReadingDeclData = record
  1458. Decl: TPasElement;
  1459. El: TPasElement;
  1460. end;
  1461. PHasElReadingDeclData = ^THasElReadingDeclData;
  1462. procedure OnHasElReadingDecl(El: TPasElement; arg: pointer);
  1463. protected
  1464. type
  1465. TPRFindExtSystemClass = record
  1466. JSName: string;
  1467. ErrorPosEl: TPasElement;
  1468. Found: TPasClassType;
  1469. ElScope: TPasScope; // Where Found was found
  1470. StartScope: TPasScope; // where the search started
  1471. end;
  1472. PPRFindExtSystemClass = ^TPRFindExtSystemClass;
  1473. procedure OnFindExtSystemClass(El: TPasElement; ElScope, StartScope: TPasScope;
  1474. FindExtSystemClassData: Pointer; var Abort: boolean); virtual;
  1475. protected
  1476. // overloads: fix name clashes in JS
  1477. FOverloadScopes: TFPList; // list of TPasIdentifierScope
  1478. function HasOverloadIndex(El: TPasElement; WithElevatedLocal: boolean = false): boolean; virtual;
  1479. function GetOverloadIndex(Identifier: TPasIdentifier;
  1480. StopAt: TPasElement): integer;
  1481. function GetOverloadAt(Identifier: TPasIdentifier; var Index: integer): TPasIdentifier;
  1482. function GetOverloadIndex(El: TPasElement): integer;
  1483. function GetOverloadAt(const aName: String; Index: integer): TPasIdentifier;
  1484. function GetElevatedLocals(Scope: TPasScope): TPas2jsElevatedLocals;
  1485. function RenameOverload(El: TPasElement): boolean;
  1486. procedure RenameOverloadsInSection(aSection: TPasSection);
  1487. procedure RenameOverloads(DeclEl: TPasElement; Declarations: TFPList);
  1488. procedure RenameSubOverloads(Declarations: TFPList);
  1489. procedure RenameMembers(El: TPasMembersType);
  1490. procedure RenameSpecialized(SpecializedItem: TPRSpecializedItem);
  1491. procedure PushOverloadScopeSkip;
  1492. procedure PushOverloadScope(Scope: TPasIdentifierScope);
  1493. function PushOverloadClassOrRecScopes(Scope: TPasClassOrRecordScope; WithParents: boolean): integer;
  1494. procedure PopOverloadScope;
  1495. procedure RestoreOverloadScopeLvl(OldScopeCount: integer);
  1496. procedure ClearOverloadScopes;
  1497. protected
  1498. procedure AddType(El: TPasType); override;
  1499. procedure AddRecordType(El: TPasRecordType; TypeParams: TFPList); override;
  1500. procedure AddRecordVariant(El: TPasVariant); override;
  1501. procedure AddClassType(El: TPasClassType; TypeParams: TFPList); override;
  1502. procedure AddEnumType(El: TPasEnumType); override;
  1503. procedure ResolveImplAsm(El: TPasImplAsmStatement); override;
  1504. procedure ResolveNameExpr(El: TPasExpr; const aName: string;
  1505. Access: TResolvedRefAccess); override;
  1506. procedure ResolveFuncParamsExpr(Params: TParamsExpr;
  1507. Access: TResolvedRefAccess); override;
  1508. procedure FinishInterfaceSection(Section: TPasSection); override;
  1509. procedure FinishTypeSectionEl(El: TPasType); override;
  1510. procedure FinishModule(CurModule: TPasModule); override;
  1511. procedure FinishEnumType(El: TPasEnumType); override;
  1512. procedure FinishSetType(El: TPasSetType); override;
  1513. procedure FinishRecordType(El: TPasRecordType); override;
  1514. procedure FinishClassType(El: TPasClassType); override;
  1515. procedure FinishArrayType(El: TPasArrayType); override;
  1516. procedure FinishAncestors(aClass: TPasClassType); override;
  1517. procedure FinishVariable(El: TPasVariable); override;
  1518. procedure FinishArgument(El: TPasArgument); override;
  1519. procedure FinishProcedureType(El: TPasProcedureType); override;
  1520. procedure FinishProperty(PropEl: TPasProperty); override;
  1521. procedure FinishProcParamAccess(ProcType: TPasProcedureType;
  1522. Params: TParamsExpr); override;
  1523. procedure FinishPropertyParamAccess(Params: TParamsExpr; Prop: TPasProperty
  1524. ); override;
  1525. procedure FinishExportSymbol(El: TPasExportSymbol); override;
  1526. procedure ComputeArgumentExpr(const ArgResolved: TPasResolverResult;
  1527. Access: TArgumentAccess; Expr: TPasExpr; out ExprResolved: TPasResolverResult; SetReferenceFlags: boolean); override;
  1528. procedure FindCreatorArrayOfConst(Args: TFPList; ErrorEl: TPasElement);
  1529. function FindProc_ArrLitToArrayOfConst(ErrorEl: TPasElement): TPasFunction; virtual;
  1530. function FindSystemExternalClassType(const aClassName, JSName: string;
  1531. ErrorEl: TPasElement): TPasClassType; virtual;
  1532. function FindTJSPromise(ErrorEl: TPasElement): TPasClassType; virtual;
  1533. procedure CheckExternalClassConstructor(Ref: TResolvedReference); virtual;
  1534. procedure CheckConditionExpr(El: TPasExpr;
  1535. const ResolvedEl: TPasResolverResult); override;
  1536. procedure CheckNewInstanceFunction(ClassScope: TPas2JSClassScope); virtual;
  1537. function AddExternalName(const aName: string; El: TPasElement): TPasIdentifier; virtual;
  1538. function FindExternalName(const aName: String): TPasIdentifier; virtual;
  1539. procedure AddExternalPath(aName: string; El: TPasElement);
  1540. procedure AddElevatedLocal(El: TPasElement); virtual;
  1541. procedure ClearElementData; virtual;
  1542. function GenerateGUID(El: TPasClassType): string; virtual;
  1543. function CheckCallAsyncFuncResult(Param: TPasExpr; out ResolvedEl: TPasResolverResult): boolean; virtual;
  1544. protected
  1545. // generic/specialize
  1546. procedure SpecializeGenericIntf(SpecializedItem: TPRSpecializedItem);
  1547. override;
  1548. procedure SpecializeGenericImpl(SpecializedItem: TPRSpecializedItem);
  1549. override;
  1550. procedure SpecializeProcedure(GenEl, SpecEl: TPasProcedure;
  1551. SpecializedItem: TPRSpecializedItem); override;
  1552. function SpecializeParamsNeedDelay(SpecializedItem: TPRSpecializedItem): TPasElement; virtual;
  1553. function IsSpecializedNonStaticMethod(ProcType: TPasProcedureType): boolean;
  1554. protected
  1555. const
  1556. cJSValueConversion = 2*cTypeConversion;
  1557. // additional base types
  1558. function AddJSBaseType(const aName: string; Typ: TPas2jsBaseType): TResElDataPas2JSBaseType;
  1559. function CheckAssignCompatibilityCustom(const LHS,
  1560. RHS: TPasResolverResult; ErrorEl: TPasElement;
  1561. RaiseOnIncompatible: boolean; var Handled: boolean): integer; override;
  1562. function CheckTypeCastClassInstanceToClass(const FromClassRes,
  1563. ToClassRes: TPasResolverResult; ErrorEl: TPasElement): integer; override;
  1564. function CheckEqualCompatibilityCustomType(const LHS,
  1565. RHS: TPasResolverResult; ErrorEl: TPasElement;
  1566. RaiseOnIncompatible: boolean): integer; override;
  1567. function CheckForIn(Loop: TPasImplForLoop; const VarResolved,
  1568. InResolved: TPasResolverResult): boolean; override;
  1569. procedure ComputeUnaryNot(El: TUnaryExpr;
  1570. var ResolvedEl: TPasResolverResult; Flags: TPasResolverComputeFlags);
  1571. override;
  1572. procedure ComputeBinaryExprRes(Bin: TBinaryExpr; out
  1573. ResolvedEl: TPasResolverResult; Flags: TPasResolverComputeFlags;
  1574. var LeftResolved, RightResolved: TPasResolverResult); override;
  1575. // built-in functions
  1576. function BI_Exit_OnGetCallCompatibility(Proc: TResElDataBuiltInProc;
  1577. Expr: TPasExpr; RaiseOnError: boolean): integer; override;
  1578. function BI_Val_OnGetCallCompatibility(Proc: TResElDataBuiltInProc;
  1579. Expr: TPasExpr; RaiseOnError: boolean): integer; override;
  1580. procedure BI_TypeInfo_OnGetCallResult(Proc: TResElDataBuiltInProc;
  1581. Params: TParamsExpr; out ResolvedEl: TPasResolverResult); override;
  1582. function BI_Debugger_OnGetCallCompatibility(Proc: TResElDataBuiltInProc;
  1583. Expr: TPasExpr; RaiseOnError: boolean): integer; virtual;
  1584. function BI_AWait_OnGetCallCompatibility(Proc: TResElDataBuiltInProc;
  1585. Expr: TPasExpr; RaiseOnError: boolean): integer; virtual;
  1586. procedure BI_AWait_OnGetCallResult(Proc: TResElDataBuiltInProc;
  1587. Params: TParamsExpr; out ResolvedEl: TPasResolverResult); virtual;
  1588. procedure BI_AWait_OnEval(Proc: TResElDataBuiltInProc;
  1589. Params: TParamsExpr; Flags: TResEvalFlags; out Evaluated: TResEvalValue); virtual;
  1590. procedure BI_AWait_OnFinishParamsExpr(Proc: TResElDataBuiltInProc;
  1591. Params: TParamsExpr); virtual;
  1592. function IsPromiseClass(aClass: TPasClassType): Boolean;
  1593. public
  1594. constructor Create; reintroduce;
  1595. destructor Destroy; override;
  1596. procedure ClearBuiltInIdentifiers; override;
  1597. // base types
  1598. function IsJSBaseType(TypeEl: TPasType; Typ: TPas2jsBaseType): boolean;
  1599. function IsJSBaseType(const TypeResolved: TPasResolverResult;
  1600. Typ: TPas2jsBaseType; HasValue: boolean = false): boolean;
  1601. procedure AddObjFPCBuiltInIdentifiers(
  1602. const TheBaseTypes: TResolveBaseTypes;
  1603. const TheBaseProcs: TResolverBuiltInProcs); override;
  1604. function CheckTypeCastRes(const FromResolved,
  1605. ToResolved: TPasResolverResult; ErrorEl: TPasElement;
  1606. RaiseOnError: boolean): integer; override;
  1607. function FindLocalBuiltInSymbol(El: TPasElement): TPasElement; override;
  1608. property JSBaseTypes[aBaseType: TPas2jsBaseType]: TPasUnresolvedSymbolRef read GetJSBaseTypes;
  1609. property JSBuiltInProcs[aProc: TPas2jsBuiltInProc]: TResElDataBuiltInProc read GetJSBuiltInProcs;
  1610. // compute literals and constants
  1611. function ExtractPasStringLiteral(El: TPasElement; const S: String): TJSString; virtual;
  1612. function ResolverToJSValue(Value: TResEvalValue; ErrorEl: TPasElement): TJSValue; virtual;
  1613. function ComputeConstString(Expr: TPasExpr; StoreCustomData, NotEmpty: boolean): String; virtual;
  1614. procedure CheckAssignExprRangeToCustom(
  1615. const LeftResolved: TPasResolverResult; RValue: TResEvalValue;
  1616. RHS: TPasExpr); override;
  1617. function CheckAssignCompatibilityClasses(LType, RType: TPasClassType
  1618. ): integer; override;
  1619. function HasStaticArrayCloneFunc(Arr: TPasArrayType): boolean;
  1620. function IsTGUID(TypeEl: TPasRecordType): boolean; override;
  1621. function GetAssignGUIDString(TypeEl: TPasRecordType; Expr: TPasExpr; out GUID: TGuid): boolean;
  1622. procedure CheckDispatchField(Proc: TPasProcedure; Switch: TValueSwitch);
  1623. procedure AddMessageStr(var MsgToProc: TMessageIdToProc_List; const S: string; Proc: TPasProcedure);
  1624. procedure AddMessageIdToClassScope(Proc: TPasProcedure; EmitHints: boolean); virtual;
  1625. procedure ComputeElement(El: TPasElement; out ResolvedEl: TPasResolverResult;
  1626. Flags: TPasResolverComputeFlags; StartEl: TPasElement = nil); override;
  1627. procedure ComputeResultElement(El: TPasResultElement; out
  1628. ResolvedEl: TPasResolverResult; Flags: TPasResolverComputeFlags;
  1629. StartEl: TPasElement = nil); override;
  1630. // CustomData
  1631. function GetElementData(El: TPasElementBase;
  1632. DataClass: TPas2JsElementDataClass): TPas2JsElementData; virtual;
  1633. procedure AddElementData(Data: TPas2JsElementData); virtual;
  1634. function CreateElementData(DataClass: TPas2JsElementDataClass;
  1635. El: TPasElement): TPas2JsElementData; virtual;
  1636. // checking compatibilility
  1637. function CheckEqualCompatibilityUserType(const LHS,
  1638. RHS: TPasResolverResult; ErrorEl: TPasElement;
  1639. RaiseOnIncompatible: boolean): integer; override;
  1640. // utility
  1641. procedure RaiseMsg(const Id: TMaxPrecInt; MsgNumber: integer; const Fmt: String;
  1642. Args: array of const; ErrorPosEl: TPasElement); override;
  1643. function GetOverloadName(El: TPasElement): string;
  1644. function GetBaseDescription(const R: TPasResolverResult; AddPath: boolean=
  1645. false): string; override;
  1646. function HasTypeInfo(El: TPasType): boolean; override;
  1647. function HasExtRTTI(El: TPasMembersType): boolean; virtual;
  1648. function ProcHasImplElements(Proc: TPasProcedure): boolean; override;
  1649. function HasAnonymousFunctions(El: TPasImplElement): boolean;
  1650. function GetTopLvlProcScope(El: TPasElement): TPas2JSProcedureScope;
  1651. function ProcCanBePrecompiled(DeclProc: TPasProcedure): boolean; virtual;
  1652. function IsReadEqWrite(const ExprResolved: TPasResolverResult): boolean; virtual; // read and write uses the same JS accessor
  1653. function IsTObjectFreeMethod(El: TPasExpr): boolean; virtual;
  1654. function IsManagedJSType(TypeEl: TPasType): boolean; virtual;
  1655. function IsExternalBracketAccessor(El: TPasElement): boolean;
  1656. function IsExternalClassConstructor(El: TPasElement): boolean;
  1657. function IsForInExtArray(Loop: TPasImplForLoop; const VarResolved,
  1658. InResolved: TPasResolverResult; out ArgResolved, LengthResolved,
  1659. PropResultResolved: TPasResolverResult): boolean;
  1660. function IsHelperMethod(El: TPasElement): boolean; override;
  1661. function IsHelperForMember(El: TPasElement): boolean; virtual;
  1662. function ImplBlockReadsDecl(Block: TPasImplBlock; Decl: TPasElement): boolean; virtual;
  1663. end;
  1664. //------------------------------------------------------------------------------
  1665. // TConvertContext
  1666. type
  1667. TCtxAccess = (
  1668. caRead, // normal read
  1669. caAssign, // needs setter, aContext.AccessContext is TAssignContext
  1670. caByReference // needs path, getter and setter, aContext.AccessContext is TParamContext
  1671. );
  1672. TCtxVarKind = (
  1673. cvkNone,
  1674. cvkGlobal, // e.g. $mod, $impl, class type
  1675. cvkCurType, // e.g. PasElement is a class, js var is the current class (Self in a class method)
  1676. cvkInstance, // e.g. PasElement is a class, js var is the current instance (Self in method)
  1677. cvkHelperTemp // e.g. helper-for getter/setter
  1678. );
  1679. TCtxVarKinds = set of TCtxVarKind;
  1680. const
  1681. cvkAll = [cvkNone..cvkHelperTemp];
  1682. type
  1683. TFunctionContext = Class;
  1684. { TConvertContext }
  1685. TConvertContextClass = Class of TConvertContext;
  1686. TConvertContext = Class(TObject)
  1687. public
  1688. PasElement: TPasElement;
  1689. JSElement: TJSElement;
  1690. Resolver: TPas2JSResolver;
  1691. Parent: TConvertContext;
  1692. IsGlobal: boolean; // can hold constants and types
  1693. Access: TCtxAccess;
  1694. AccessContext: TConvertContext;
  1695. TmpVarCount: integer;
  1696. ScannerBoolSwitches: TBoolSwitches;
  1697. ScannerModeSwitches: TModeSwitches;
  1698. constructor Create(PasEl: TPasElement; JSEl: TJSElement; aParent: TConvertContext); virtual;
  1699. function GetRootModule: TPasModule;
  1700. function GetRootContext: TConvertContext;
  1701. function GetNonDotContext: TConvertContext;
  1702. function GetFunctionContext: TFunctionContext;
  1703. function GetLocalName(El: TPasElement; const Filter: TCtxVarKinds): string; virtual;
  1704. function GetSelfContext: TFunctionContext;
  1705. function GetContextOfPasElement(El: TPasElement): TConvertContext;
  1706. function GetFuncContextOfPasElement(El: TPasElement): TFunctionContext;
  1707. function GetContextOfType(aType: TConvertContextClass): TConvertContext;
  1708. function GetMainSectionContext: TFunctionContext;
  1709. function CurrentModeSwitches: TModeSwitches;
  1710. function GetGlobalFunc: TFunctionContext;
  1711. procedure WriteStack;
  1712. procedure DoWriteStack(Index: integer); virtual;
  1713. function ToString: string; override;
  1714. end;
  1715. { TRootContext }
  1716. TRootContext = Class(TConvertContext)
  1717. public
  1718. ResourceStrings: TJSVarDeclaration;
  1719. GlobalClassMethods: TArrayOfPasProcedure;
  1720. procedure AddGlobalClassMethod(p: TPasProcedure);
  1721. destructor Destroy; override;
  1722. end;
  1723. { TFCLocalIdentifier }
  1724. TFCLocalIdentifier = class
  1725. public
  1726. Element: TPasElement;
  1727. Name: string;
  1728. Kind: TCtxVarKind;
  1729. constructor Create(const aName: string; TheEl: TPasElement; aKind: TCtxVarKind);
  1730. end;
  1731. TFCLocalVars = array of TFCLocalIdentifier;
  1732. { TFunctionContext
  1733. Module Function: PasElement is TPasProcedure (ImplProc), ThisPas=nil
  1734. Method: PasElement is TPasProcedure (ImplProc), ThisPas is TPasMembersType }
  1735. TFunctionContext = Class(TConvertContext)
  1736. public
  1737. LocalVars: TFCLocalVars;
  1738. ThisVar: TFCLocalIdentifier;
  1739. IntfElReleases: TFPList; // list of TPasElement, that needs rtl._Release(<El>)
  1740. ResultNeedsIntfRelease: boolean;
  1741. IntfExprReleaseCount: integer; // >0 means needs $ir
  1742. BodySt: TJSElement;
  1743. TrySt: TJSTryFinallyStatement;
  1744. FinallyFirst, FinallyLast: TJSStatementList;
  1745. constructor Create(PasEl: TPasElement; JSEl: TJSElement;
  1746. aParent: TConvertContext); override;
  1747. destructor Destroy; override;
  1748. function AddLocalVar(aName: string; El: TPasElement; aKind: TCtxVarKind; AutoUnique: boolean): TFCLocalIdentifier;
  1749. function AddLocalJSVar(aName: string; AutoUnique: boolean): TFCLocalIdentifier;
  1750. procedure Add_InterfaceRelease(El: TPasElement);
  1751. function CreateLocalIdentifier(const Prefix: string; El: TPasElement; aKind: TCtxVarKind): string; virtual;
  1752. function ToString: string; override;
  1753. function GetLocalName(El: TPasElement; const Filter: TCtxVarKinds): string; override;
  1754. function IndexOfLocalVar(const aName: string): integer;
  1755. function IndexOfLocalVar(El: TPasElement; const Filter: TCtxVarKinds): integer;
  1756. function FindLocalVar(const aName: string; WithParents: boolean): TFCLocalIdentifier;
  1757. function FindPrecompiledVar(const aName: string; WithParents: boolean): TPas2JSStoredLocalVar; virtual;
  1758. function FindPrecompiledVar(El: TPasElement; WithParents: boolean): TPas2JSStoredLocalVar; virtual;
  1759. procedure DoWriteStack(Index: integer); override;
  1760. end;
  1761. { TObjectContext }
  1762. TObjectContext = Class(TConvertContext)
  1763. end;
  1764. { TSectionContext - interface/implementation/program/library
  1765. interface/program/library: PasElement is TPasModule, ThisPas is TPasModule
  1766. implementation: PasElement is TImplementationSection, ThisPas=nil }
  1767. TSectionContext = Class(TFunctionContext)
  1768. public
  1769. SrcElements: TJSSourceElements;
  1770. HeaderIndex: integer; // index in TJSSourceElements(JSElement).Statements
  1771. PrecompiledVars: TPas2JSStoredLocalVarArray; // copy from TPas2JSModuleScope, do not free
  1772. constructor Create(PasEl: TPasElement; JSEl: TJSElement; aParent: TConvertContext); override;
  1773. procedure AddHeaderStatement(JS: TJSElement);
  1774. function FindPrecompiledVar(const aName: string; WithParents: boolean
  1775. ): TPas2JSStoredLocalVar; override;
  1776. function FindPrecompiledVar(El: TPasElement; WithParents: boolean
  1777. ): TPas2JSStoredLocalVar; override;
  1778. end;
  1779. { TInterfaceSectionContext }
  1780. TInterfaceSectionContext = Class(TSectionContext)
  1781. public
  1782. ImplContext: TSectionContext;
  1783. ImplHeaderStatements: TFPList;
  1784. ImplSrcElements: TJSSourceElements;
  1785. ImplHeaderIndex: integer; // index in ImplSrcElements.Statements
  1786. destructor Destroy; override;
  1787. procedure AddImplHeaderStatement(JS: TJSElement);
  1788. end;
  1789. { TDotContext - used for converting eopSubIdent }
  1790. TDotContext = Class(TConvertContext)
  1791. public
  1792. LeftResolved: TPasResolverResult;
  1793. // created by ConvertElement if subident needs special translation:
  1794. JS: TJSElement;
  1795. end;
  1796. { TAssignContext - used for left side of an assign statement }
  1797. TAssignContext = Class(TConvertContext)
  1798. public
  1799. // set when creating:
  1800. LeftResolved: TPasResolverResult;
  1801. RightResolved: TPasResolverResult;
  1802. RightSide: TJSElement;
  1803. // created by ConvertElement if assign needs a call:
  1804. PropertyEl: TPasProperty;
  1805. Call: TJSCallExpression;
  1806. constructor Create(PasEl: TPasElement; JSEl: TJSElement; aParent: TConvertContext); override;
  1807. end;
  1808. { TParamContext }
  1809. TParamContext = Class(TConvertContext)
  1810. public
  1811. // set when creating:
  1812. Arg: TPasArgument;
  1813. Expr: TPasExpr;
  1814. ResolvedExpr: TPasResolverResult;
  1815. // created by ConvertElement:
  1816. Setter: TJSElement;
  1817. ReusingReference: boolean; // true = result is a reference, do not create another
  1818. constructor Create(PasEl: TPasElement; JSEl: TJSElement; aParent: TConvertContext); override;
  1819. end;
  1820. //------------------------------------------------------------------------------
  1821. // TPasToJSConverter
  1822. const
  1823. DefaultJSWriterOptions = [
  1824. {$IFDEF FPC_HAS_CPSTRING}
  1825. woUseUTF8,
  1826. {$ENDIF}
  1827. woCompactArrayLiterals,
  1828. woCompactObjectLiterals,
  1829. woCompactArguments];
  1830. type
  1831. { TPasToJSConverterGlobals - shared options }
  1832. TPasToJSConverterGlobals = class
  1833. private
  1834. FOwner: TObject;
  1835. public
  1836. BuiltInNames: array[TPas2JSBuiltInName] of string;
  1837. RTLVersion: TJSNumber;
  1838. TargetPlatform: TPasToJsPlatform;
  1839. TargetProcessor: TPasToJsProcessor;
  1840. constructor Create(TheOwner: TObject);
  1841. procedure Reset;
  1842. procedure ResetBuiltInNames;
  1843. property Owner: TObject read FOwner;
  1844. end;
  1845. TPas2JSIsElementUsedEvent = function(Sender: TObject; El: TPasElement): boolean of object;
  1846. TJSReservedWordList = array of String;
  1847. TRefPathKind = (
  1848. rpkPath, // e.g. "TObject"
  1849. rpkPathWithDot, // e.g. "TObject."
  1850. rpkPathAndName // e.g. "TObject.ClassName"
  1851. );
  1852. { TPasToJSConverter }
  1853. TPasToJSConverter = Class(TObject)
  1854. private
  1855. // inline at ttop, because fpc 3.1 requires inline implementation in front of use
  1856. function GetUseEnumNumbers: boolean; inline;
  1857. function GetUseLowerCase: boolean; inline;
  1858. function GetUseSwitchStatement: boolean; inline;
  1859. function GetBIName(bin: TPas2JSBuiltInName): string; inline;
  1860. private
  1861. {$IFDEF EnableForLoopRunnerCheck}
  1862. type
  1863. TForLoopFindData = record
  1864. ForLoop: TPasImplForLoop;
  1865. LoopVar: TPasElement;
  1866. FoundLoop: boolean;
  1867. LoopVarWrite: boolean; // true if first access of LoopVar after loop is a write
  1868. LoopVarRead: boolean; // true if first access of LoopVar after loop is a read
  1869. end;
  1870. PForLoopFindData = ^TForLoopFindData;
  1871. procedure ForLoop_OnProcBodyElement(El: TPasElement; arg: pointer);
  1872. {$ENDIF}
  1873. private
  1874. FGlobals: TPasToJSConverterGlobals;
  1875. FOnIsElementUsed: TPas2JSIsElementUsedEvent;
  1876. FOnIsTypeInfoUsed: TPas2JSIsElementUsedEvent;
  1877. FOptions: TPasToJsConverterOptions;
  1878. FReservedWords: TJSReservedWordList; // sorted with CompareStr
  1879. Procedure AddGlobalClassMethod(aContext: TConvertContext; P: TPasProcedure);
  1880. Function CreatePrimitiveDotExpr(Path: string; PosEl: TPasElement): TJSElement;
  1881. Function CreateSubDeclJSNameExpr(El: TPasElement; JSName: string;
  1882. AContext: TConvertContext; PosEl: TPasElement): TJSElement;
  1883. Function CreateSubDeclPasNameExpr(El: TPasElement; const PasName: string;
  1884. AContext: TConvertContext; PosEl: TPasElement = nil): TJSElement;
  1885. Function CreateSubDeclNameExpr(El: TPasElement;
  1886. AContext: TConvertContext; PosEl: TPasElement = nil): TJSElement;
  1887. Function CreateIdentifierExpr(El: TPasElement; AContext: TConvertContext): TJSElement;
  1888. Function CreateIdentifierExpr(AName: string; CheckGlobal: boolean; PosEl: TPasElement; AContext: TConvertContext): TJSElement;
  1889. Function CreateSwitchStatement(El: TPasImplCaseOf; AContext: TConvertContext): TJSElement;
  1890. Function CreateTypeDecl(El: TPasType; AContext: TConvertContext): TJSElement;
  1891. Function CreateVarDecl(El: TPasVariable; AContext: TConvertContext): TJSElement;
  1892. Procedure AddToSourceElements(Src: TJSSourceElements; El: TJSElement);
  1893. procedure RemoveFromSourceElements(Src: TJSSourceElements;
  1894. El: TJSElement);
  1895. procedure SetGlobals(const AValue: TPasToJSConverterGlobals);
  1896. procedure SetReservedWords(const AValue: TJSReservedWordList);
  1897. procedure SetUseEnumNumbers(const AValue: boolean);
  1898. procedure SetUseLowerCase(const AValue: boolean);
  1899. procedure SetUseSwitchStatement(const AValue: boolean);
  1900. protected
  1901. type
  1902. TMemberFunc = (mfInit, mfFinalize);
  1903. TConvertJSEvent = function(El: TPasElement; AContext: TConvertContext; Data: Pointer): TJSElement of object;
  1904. TCreateRefPathData = record
  1905. El: TPasElement;
  1906. Full: boolean;
  1907. Ref: TResolvedReference;
  1908. end;
  1909. PCreateRefPathData = ^TCreateRefPathData;
  1910. Function OnCreateReferencePathExpr(El: TPasElement; AContext : TConvertContext;
  1911. CreateRefPathData: Pointer): TJSElement;
  1912. protected
  1913. // Error functions
  1914. Procedure DoError(Id: TMaxPrecInt; Const Msg : String);
  1915. Procedure DoError(Id: TMaxPrecInt; Const Msg : String;
  1916. const Args: array of const);
  1917. Procedure DoError(Id: TMaxPrecInt; MsgNumber: integer; const MsgPattern: string;
  1918. const Args: array of const; El: TPasElement);
  1919. procedure RaiseNotSupported(El: TPasElement; AContext: TConvertContext; Id: TMaxPrecInt; const Msg: string = '');
  1920. procedure RaiseIdentifierNotFound(Identifier: string; El: TPasElement; Id: TMaxPrecInt);
  1921. procedure RaiseInconsistency(Id: TMaxPrecInt; El: TPasElement);
  1922. // Computation, value conversions
  1923. Function GetExpressionValueType(El: TPasExpr; AContext: TConvertContext ): TJSType; virtual;
  1924. Function GetPasIdentValueType(AName: String; AContext: TConvertContext): TJSType; virtual;
  1925. Function ComputeConstString(Expr: TPasExpr; AContext: TConvertContext; NotEmpty: boolean): String; virtual;
  1926. Function IsLiteralInteger(El: TJSElement; out Number: TMaxPrecInt): boolean;
  1927. Function IsLiteralNumber(El: TJSElement; out n: TJSNumber): boolean;
  1928. Function IsLiteralNull(El: TJSElement): boolean;
  1929. // Name mangling
  1930. Function GetOverloadName(El: TPasElement; AContext: TConvertContext): string;
  1931. Function CanClashWithGlobal(El: TPasElement): boolean;
  1932. Function TransformToJSName(ErrorEl: TPasElement; Const AName: String; CheckGlobal: boolean; AContext : TConvertContext): String; virtual;
  1933. Function TransformElToJSName(El: TPasElement; AContext : TConvertContext) : String; virtual;
  1934. Function TransformModuleName(El: TPasModule; AddModulesPrefix: boolean; AContext : TConvertContext) : String; virtual;
  1935. Function IsReservedWord(const aName: string; CheckGlobal: boolean): boolean; virtual;
  1936. Function GetTypeInfoName(El: TPasType; AContext: TConvertContext;
  1937. ErrorEl: TPasElement; Full: boolean = false): String; virtual;
  1938. Function TransformArgName(Arg: TPasArgument; AContext: TConvertContext): string; virtual;
  1939. Function CreateGlobalAliasForeign(El: TPasElement; JSPath: string; AContext: TConvertContext): string; virtual; // El in other module
  1940. Function CreateGlobalAliasNull(El: TPasElement; Prefix: TPas2JSBuiltInName;
  1941. SectionContext: TSectionContext): TFCLocalIdentifier; virtual;
  1942. Procedure CreateGlobalAlias_List(ElRefList: TFPList; AContext: TConvertContext); virtual;
  1943. Function ElNeedsGlobalAlias(El: TPasElement): boolean; virtual;
  1944. // utility functions for creating stuff
  1945. Function IsElementUsed(El: TPasElement): boolean; virtual;
  1946. Function IsSystemUnit(aModule: TPasModule): boolean; virtual;
  1947. Function HasTypeInfo(El: TPasType; AContext: TConvertContext): boolean; virtual;
  1948. Function IsClassRTTICreatedBefore(aClass: TPasClassType; Before: TPasElement; AConText: TConvertContext): boolean;
  1949. Function IsExprTemporaryVar(Expr: TPasExpr): boolean; virtual;
  1950. Function IsExprPropertySetterConst(Expr: TPasExpr; AContext: TConvertContext): boolean; virtual;
  1951. Procedure FindAvailableLocalName(var aName: string; JSExpr: TJSElement);
  1952. Function GetImplJSProcScope(El: TPasElement; Src: TJSSourceElements;
  1953. AContext: TConvertContext): TPas2JSProcedureScope;
  1954. Function SpecializeNeedsDelay(El: TPasGenericType; AContext: TConvertContext): boolean; virtual;
  1955. // Never create an element manually, always use the below functions
  1956. Function CreateElement(C: TJSElementClass; Src: TPasElement): TJSElement; virtual;
  1957. Function CreateFreeOrNewInstanceExpr(Ref: TResolvedReference;
  1958. AContext : TConvertContext): TJSCallExpression; virtual;
  1959. Function CreateFunctionSt(El: TPasElement; WithBody: boolean = true;
  1960. WithSrc: boolean = false): TJSFunctionDeclarationStatement;
  1961. Function CreateFunctionDef(El: TPasElement; WithBody: boolean = true;
  1962. WithSrc: boolean = false): TJSFuncDef;
  1963. Procedure CreateProcedureCall(var Call: TJSCallExpression; Args: TParamsExpr;
  1964. TargetProc: TPasProcedureType; AContext: TConvertContext); virtual;
  1965. Procedure CreateProcedureCallArgs(Elements: TJSArrayLiteralElements;
  1966. Args: TParamsExpr; TargetProc: TPasProcedureType; AContext: TConvertContext); virtual;
  1967. Function CreateProcCallArg(El: TPasExpr; TargetArg: TPasArgument;
  1968. AContext: TConvertContext): TJSElement; virtual;
  1969. Function CreateProcCallArgRef(El: TPasExpr; ResolvedEl: TPasResolverResult;
  1970. TargetArg: TPasArgument; AContext: TConvertContext): TJSElement; virtual;
  1971. Function CreateArrayEl(El: TPasExpr; AContext: TConvertContext): TJSElement; virtual;
  1972. Function CreateArrayEl(El: TPasExpr; JS: TJSElement; AContext: TConvertContext): TJSElement; virtual;
  1973. Function CreateArgumentAccess(Arg: TPasArgument; AContext: TConvertContext;
  1974. PosEl: TPasElement): TJSElement; virtual;
  1975. Function CreateUnary(const Members: array of string; E: TJSElement): TJSUnary;
  1976. Function CreateUnaryPlus(Expr: TJSElement; El: TPasElement): TJSUnaryPlusExpression;
  1977. Function CreateMemberExpression(const Members: array of string): TJSElement;
  1978. Function CreateCallExpression(El: TPasElement): TJSCallExpression;
  1979. Function CreateCallCharCodeAt(Arg: TJSElement; aNumber: integer; El: TPasElement): TJSCallExpression; virtual;
  1980. Function CreateCallFromCharCode(Arg: TJSElement; El: TPasElement): TJSCallExpression; virtual;
  1981. Function CreateUsesList(UsesSection: TPasSection; AContext : TConvertContext): TJSArrayLiteral;
  1982. // js statement list
  1983. Procedure AddToStatementList(var First, Last: TJSStatementList;
  1984. Add: TJSElement; Src: TPasElement); overload;
  1985. Procedure AddToStatementList(St: TJSStatementList; Add: TJSElement; Src: TPasElement); overload;
  1986. Procedure PrependToStatementList(var St: TJSElement; Add: TJSElement; PosEl: TPasElement);
  1987. // js var
  1988. Procedure AddToVarStatement(VarStat: TJSVariableStatement; Add: TJSElement;
  1989. Src: TPasElement);
  1990. Function CreateValInit(PasType: TPasType; Expr: TPasExpr; El: TPasElement;
  1991. AContext: TConvertContext): TJSElement; virtual;
  1992. Function CreateVarInit(El: TPasVariable; AContext: TConvertContext): TJSElement; virtual;
  1993. Function CreateVarStatement(const aName: String; Init: TJSElement;
  1994. El: TPasElement): TJSVariableStatement; virtual;
  1995. Function CreateVarDecl(const aName: String; Init: TJSElement; El: TPasElement): TJSVarDeclaration; virtual;
  1996. // misc
  1997. Function CreateExternalBracketAccessorCall(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  1998. Function CreateAssignStatement(LeftEl: TPasExpr; AssignContext: TAssignContext): TJSElement; virtual;
  1999. Function CreateGetEnumeratorLoop(El: TPasImplForLoop;
  2000. AContext: TConvertContext): TJSElement; virtual;
  2001. Function CreateCallRTLFreeLoc(Setter, Getter: TJSElement; Src: TPasElement): TJSElement; virtual;
  2002. Function CreateDotSplit(El: TPasElement; Expr: TJSElement): TJSElement; virtual;
  2003. Function CreateExportStatement(VarType: TJSVarType; AliasName: TJSString; InitJS: TJSElement; PosEl: TPasElement): TJSExportStatement; virtual;
  2004. Function CreatePrecompiledJS(El: TJSElement): string; virtual;
  2005. Procedure AddRTLVersionCheck(FuncContext: TFunctionContext; PosEl: TPasElement);
  2006. // JS literals
  2007. Function CreateLiteralNumber(El: TPasElement; const n: TJSNumber): TJSLiteral; virtual;
  2008. Function CreateLiteralFloat(El: TPasElement; const n: TJSNumber): TJSElement; virtual;
  2009. Function CreateLiteralHexNumber(El: TPasElement; const n: TMaxPrecInt; Digits: byte): TJSLiteral; virtual;
  2010. Function CreateLiteralString(El: TPasElement; const s: string): TJSLiteral; virtual;
  2011. Function CreateLiteralJSString(El: TPasElement; const s: TJSString): TJSLiteral; virtual;
  2012. Function CreateLiteralBoolean(El: TPasElement; b: boolean): TJSLiteral; virtual;
  2013. Function CreateLiteralNull(El: TPasElement): TJSLiteral; virtual;
  2014. Function CreateLiteralUndefined(El: TPasElement): TJSLiteral; virtual;
  2015. Function CreateLiteralCustomValue(El: TPasElement; const s: TJSString): TJSLiteral; virtual;
  2016. Function CreateSetLiteralElement(Expr: TPasExpr; AContext: TConvertContext): TJSElement; virtual;
  2017. Function CreateUnaryNot(El: TJSElement; Src: TPasElement): TJSUnaryNotExpression; virtual;
  2018. Procedure ConvertCharLiteralToInt(Lit: TJSLiteral; ErrorEl: TPasElement; AContext: TConvertContext); virtual;
  2019. Function ClonePrimaryExpression(El: TJSPrimaryExpression; Src: TPasElement): TJSPrimaryExpression;
  2020. // simple JS expressions
  2021. Function CreateMulNumber(El: TPasElement; JS: TJSElement; n: TMaxPrecInt): TJSElement; virtual;
  2022. Function CreateDivideNumber(El: TPasElement; JS: TJSElement; n: TMaxPrecInt): TJSElement; virtual;
  2023. Function CreateTruncFloor(El: TPasElement; JS: TJSElement; FloorAndCeil: boolean): TJSElement; virtual;
  2024. Function CreateDotNameExpr(PosEl: TPasElement; MExpr: TJSElement;
  2025. const aName: TJSString): TJSDotMemberExpression; virtual;
  2026. Function CreateDotExpression(aParent: TPasElement; Left, Right: TJSElement;
  2027. CheckRightIntfRef: boolean = false): TJSElement; virtual;
  2028. // range and overflow checks
  2029. Function CreateOverflowCheckCall(GetExpr: TJSElement; PosEl: TPasElement): TJSCallExpression; virtual;
  2030. Function CreateRangeCheckCall(GetExpr: TJSElement; MinVal, MaxVal: TMaxPrecInt;
  2031. RTLFunc: TPas2JSBuiltInName; PosEl: TPasElement): TJSCallExpression; virtual;
  2032. Function CreateRangeCheckCall_TypeRange(aType: TPasType; GetExpr: TJSElement;
  2033. AContext: TConvertContext; PosEl: TPasElement): TJSCallExpression; virtual;
  2034. Procedure PrepareAssignDifferentIntegers(El: TPasImplAssign; AssignContext: TAssignContext); virtual;
  2035. // reference
  2036. Function CreateReferencePath(El: TPasElement; AContext: TConvertContext;
  2037. Kind: TRefPathKind; Full: boolean = false; Ref: TResolvedReference = nil): string; virtual;
  2038. Function CreateReferencePathExpr(El: TPasElement; AContext: TConvertContext;
  2039. Full: boolean = false; Ref: TResolvedReference = nil): TJSElement; virtual;
  2040. Function CreateGlobalTypePath(El: TPasType; AContext: TConvertContext): string; virtual;
  2041. Function CreateStaticProcPath(El: TPasProcedure; AContext: TConvertContext): string; virtual;
  2042. Function CreateGlobalElPath(El: TPasElement; AContext: TConvertContext): string; virtual;
  2043. Function GetLocalName(El: TPasElement; const Filter: TCtxVarKinds; AContext: TConvertContext): string;
  2044. Function ProcCanHaveShortRef(Proc: TPasProcedure): boolean;
  2045. Procedure StoreImplJSLocal(El: TPasElement; AContext: TConvertContext); virtual;
  2046. Procedure StoreImplJSLocals(ModScope: TPas2JSModuleScope; IntfContext: TSectionContext); virtual;
  2047. Procedure RestoreImplJSLocals(ModScope: TPas2JSModuleScope; IntfContext: TSectionContext); virtual;
  2048. // section
  2049. Function CreateImplementationSection(El: TPasModule; IntfContext: TInterfaceSectionContext): TJSFunctionDeclarationStatement; virtual;
  2050. Procedure CreateInitSection(El: TPasModule; Src: TJSSourceElements; AContext: TConvertContext); virtual;
  2051. Procedure CreateExportsSection(El: TPasLibrary; Src: TJSSourceElements; AContext: TConvertContext); virtual;
  2052. Function AddRTLRun(El: TPasModule; ModuleName: string; Src: TJSSourceElements; AContext: TConvertContext): TJSCallExpression; virtual;
  2053. Procedure AddHeaderStatement(JS: TJSElement; PosEl: TPasElement; aContext: TConvertContext); virtual;
  2054. Procedure AddImplHeaderStatement(JS: TJSElement; PosEl: TPasElement; aContext: TConvertContext); virtual;
  2055. function AddDelayedInits(El: TPasModule; Src: TJSSourceElements; AContext: TConvertContext): boolean; virtual;
  2056. function CreateDelaySpecializeInit(El: TPasGenericType; AContext: TConvertContext): TJSElement; virtual;
  2057. // enum and sets
  2058. Function CreateReferencedSet(El: TPasElement; SetExpr: TJSElement): TJSElement; virtual;
  2059. // record
  2060. Function CreateRecordInit(aRecord: TPasRecordType; Expr: TPasExpr;
  2061. El: TPasElement; AContext: TConvertContext): TJSElement; virtual;
  2062. Function CreateRecordCallNew(PosEl: TPasElement; RecTypeEl: TPasRecordType;
  2063. AContext: TConvertContext): TJSCallExpression; virtual;
  2064. Function CreateRecordCallClone(PosEl: TPasElement; RecTypeEl: TPasRecordType;
  2065. RecordExpr: TJSElement; AContext: TConvertContext): TJSCallExpression; virtual;
  2066. Function CreateRecordFunctionNew(El: TPasRecordType; AContext: TConvertContext;
  2067. Fields: TFPList): TJSElement; virtual;
  2068. Function CreateRecordFunctionEqual(El: TPasRecordType; AContext: TConvertContext;
  2069. Fields: TFPList): TJSElement; virtual;
  2070. Function CreateRecordFunctionAssign(El: TPasRecordType; AContext: TConvertContext;
  2071. Fields: TFPList): TJSElement; virtual;
  2072. Procedure CreateRecordRTTI(El: TPasRecordType; Src: TJSSourceElements;
  2073. FuncContext: TFunctionContext; MembersSrc: TJSSourceElements;
  2074. MembersFuncContext: TFunctionContext); virtual;
  2075. Function CreateDelayedInitMembersFunction(PosEl: TPasElement; Src: TJSSourceElements;
  2076. FuncContext: TFunctionContext; out DelaySrc: TJSSourceElements): TFunctionContext; virtual;
  2077. // array
  2078. Function CreateArrayConcat(ElTypeResolved: TPasResolverResult; PosEl: TPasElement;
  2079. AContext: TConvertContext; IsAppend: boolean = false): TJSCallExpression; overload; virtual;
  2080. Function CreateArrayConcat(ArrayType: TPasArrayType; PosEl: TPasElement;
  2081. AContext: TConvertContext; IsAppend: boolean = false): TJSCallExpression; overload; virtual;
  2082. Function CreateArrayInit(ArrayType: TPasArrayType; Expr: TPasExpr;
  2083. El: TPasElement; AContext: TConvertContext): TJSElement; virtual;
  2084. Function CreateArrayRef(El: TPasElement; ArrayExpr: TJSElement): TJSElement; virtual;
  2085. Function CreateCmpArrayWithNil(El: TPasElement; JSArray: TJSElement;
  2086. OpCode: TExprOpCode): TJSElement; virtual;
  2087. Function CreateCloneStaticArray(El: TPasElement; ArrTypeEl: TPasArrayType;
  2088. ArrayExpr: TJSElement; AContext: TConvertContext): TJSElement; virtual;
  2089. Function CreateArrayManaged(El: TPasElement; RefCnt, aMode: integer; Arg: TJSElement): TJSCallExpression; virtual;
  2090. // class
  2091. Procedure AddClassConDestructorFunction(El: TPasClassType; Src: TJSSourceElements;
  2092. ClassContext: TConvertContext; IsTObject: boolean; Ancestor: TPasType;
  2093. Kind: TMemberFunc); virtual;
  2094. Procedure AddClassRTTI(El: TPasClassType; Src: TJSSourceElements;
  2095. FuncContext: TFunctionContext); virtual;
  2096. Procedure AddClassConstructors(FuncContext: TFunctionContext; PosEl: TPasElement); virtual;
  2097. Procedure AddClassMessageIds(El: TPasClassType; Src: TJSSourceElements;
  2098. FuncContext: TFunctionContext; pbivn: TPas2JSBuiltInName); virtual;
  2099. // callbacks
  2100. Function CreateCallback(Expr: TPasExpr; ResolvedEl: TPasResolverResult;
  2101. aSafeCall: boolean; AContext: TConvertContext): TJSElement; virtual;
  2102. Function CreateSafeCallback(Expr: TPasExpr; JS: TJSElement; AContext: TConvertContext): TJSElement; virtual;
  2103. // property
  2104. Function CreatePropertyGet(Prop: TPasProperty; Expr: TPasExpr;
  2105. AContext: TConvertContext; PosEl: TPasElement): TJSElement; virtual;
  2106. Function AppendPropertyAssignArgs(Call: TJSCallExpression; Prop: TPasProperty;
  2107. AssignContext: TAssignContext; PosEl: TPasElement): TJSCallExpression; virtual;
  2108. Function AppendPropertyReadArgs(Call: TJSCallExpression; Prop: TPasProperty;
  2109. aContext: TConvertContext; PosEl: TPasElement): TJSCallExpression; virtual;
  2110. Function CreateRaisePropReadOnly(PosEl: TPasElement): TJSElement; virtual;
  2111. // create elements for RTTI
  2112. Function CreateTypeInfoRef(El: TPasType; AContext: TConvertContext;
  2113. ErrorEl: TPasElement): TJSElement; virtual;
  2114. Function CreateRTTIArgList(Parent: TPasElement; Args: TFPList;
  2115. AContext: TConvertContext): TJSElement; virtual;
  2116. Procedure AddRTTIArgument(Arg: TPasArgument; TargetParams: TJSArrayLiteral;
  2117. AContext: TConvertContext); virtual;
  2118. Function GetClassBIName(El: TPasClassType; AContext: TConvertContext): string; virtual;
  2119. Function CreateRTTINewType(El: TPasType; const CallFuncName: string;
  2120. IsForward: boolean; AContext: TConvertContext; out ObjLit: TJSObjectLiteral): TJSCallExpression; virtual;
  2121. Function CreateRTTIAttributes(const Attr: TPasExprArray; PosEl: TPasElement; aContext: TConvertContext): TJSElement; virtual;
  2122. Function GetExtRTTIVisibilityParam(El: TPasElement; const Vis: TPasMembersType.TRTTIVisibilitySections): word; virtual;
  2123. Function CreateRTTIMemberField(ParentEl: TPasMembersType; Members: TFPList; Index: integer;
  2124. AContext: TConvertContext): TJSElement; virtual;
  2125. Function CreateRTTIMemberMethod(ParentEl: TPasMembersType; Members: TFPList; Index: integer;
  2126. AContext: TConvertContext): TJSElement; virtual;
  2127. Function CreateRTTIMemberProperty(ParentEl: TPasMembersType; Members: TFPList; Index: integer;
  2128. AContext: TConvertContext): TJSElement; virtual;
  2129. Procedure CreateRTTIAnonymous(El: TPasType; AContext: TConvertContext); virtual; // needed by precompiled files from 2.0.0
  2130. Function CreateRTTIAnonymousArray(El: TPasArrayType; AContext: TConvertContext): TJSCallExpression; virtual;
  2131. Function CreateRTTIMembers(El: TPasMembersType; Src: TJSSourceElements;
  2132. FuncContext: TFunctionContext; MembersSrc: TJSSourceElements;
  2133. MembersFuncContext: TFunctionContext; RTTIExpr: TJSElement;
  2134. NeedLocalVar: boolean): boolean; virtual;
  2135. // create elements for interfaces
  2136. Procedure AddIntfDelegations(ClassEl: TPasElement; Prop: TPasProperty;
  2137. FinishedGUIDs: TStringList; ObjLit: TJSObjectLiteral; aContext: TFunctionContext);
  2138. Function CreateGUIDObjLit(aTGUIDRecord: TPasRecordType; const GUID: TGUID;
  2139. PosEl: TPasElement; AContext: TConvertContext): TJSObjectLiteral;
  2140. Function CreateAssignManagedVar(const LeftResolved: TPasResolverResult;
  2141. var LHS, RHS: TJSElement; AContext: TConvertContext; PosEl: TPasElement): TJSElement; virtual;
  2142. Function IsInterfaceRef(Expr: TJSElement): boolean;
  2143. Function CreateAddRef(Expr: TJSElement; PosEl: TPasElement): TJSCallExpression;
  2144. Function CreateIntfRef(Expr: TJSElement; aContext: TConvertContext;
  2145. PosEl: TPasElement): TJSCallExpression; virtual;
  2146. Function RemoveIntfRef(Call: TJSCallExpression; AContext: TConvertContext): TJSElement;
  2147. Procedure CreateFunctionTryFinally(FuncContext: TFunctionContext);
  2148. Procedure AddFunctionFinallySt(NewEl: TJSElement; PosEl: TPasElement;
  2149. FuncContext: TFunctionContext);
  2150. Procedure AddFunctionFinallyRelease(SubEl: TPasElement; FuncContext: TFunctionContext); virtual;
  2151. Procedure AddInFrontOfFunctionTry(NewEl: TJSElement; PosEl: TPasElement;
  2152. FuncContext: TFunctionContext); virtual;
  2153. Procedure AddInterfaceReleases(FuncContext: TFunctionContext; PosEl: TPasElement); virtual;
  2154. Procedure AddInterfaceRelease_Result(FuncContext: TFunctionContext;
  2155. const ResultVarName: string; PosEl: TPasElement); virtual;
  2156. Procedure AddClassSupportedInterfaces(El: TPasClassType; Src: TJSSourceElements;
  2157. FuncContext: TFunctionContext); virtual;
  2158. // create elements for helpers
  2159. Function CreateCallHelperMethod(Proc: TPasProcedure; Expr: TPasExpr;
  2160. AContext: TConvertContext; Implicit: boolean = false): TJSCallExpression; virtual;
  2161. Procedure AddHelperConstructor(El: TPasClassType; Src: TJSSourceElements;
  2162. AContext: TConvertContext); virtual;
  2163. // Statements
  2164. Function ConvertImplBlockElements(El: TPasImplBlock; AContext: TConvertContext; NilIfEmpty: boolean): TJSElement; virtual;
  2165. Function ConvertBeginEndStatement(El: TPasImplBeginBlock; AContext: TConvertContext; NilIfEmpty: boolean): TJSElement; virtual;
  2166. Function ConvertStatement(El: TPasImplStatement; AContext: TConvertContext ): TJSElement; virtual;
  2167. Function ConvertAssignStatement(El: TPasImplAssign; AContext: TConvertContext): TJSElement; virtual;
  2168. Function ConvertDirectAssignArrayStatement(El: TPasImplAssign; AssignContext: TAssignContext): TJSElement; virtual;
  2169. Function ConvertDirectAssignArrayConcat(El: TPasImplAssign; Params: TParamsExpr; AssignContext: TAssignContext): TJSElement; virtual;
  2170. Function ConvertDirectAssignArrayAdd(El: TPasImplAssign; Bin: TBinaryExpr; AssignContext: TAssignContext): TJSElement; virtual;
  2171. Function ConvertRaiseStatement(El: TPasImplRaise; AContext: TConvertContext ): TJSElement; virtual;
  2172. Function ConvertIfStatement(El: TPasImplIfElse; AContext: TConvertContext ): TJSElement; virtual;
  2173. Function ConvertWhileStatement(El: TPasImplWhileDo; AContext: TConvertContext): TJSElement; virtual;
  2174. Function ConvertRepeatStatement(El: TPasImplRepeatUntil; AContext: TConvertContext): TJSElement; virtual;
  2175. Function ConvertForStatement(El: TPasImplForLoop; AContext: TConvertContext): TJSElement; virtual;
  2176. Function ConvertFinalizationSection(El: TFinalizationSection; AContext: TConvertContext): TJSElement; virtual;
  2177. Function ConvertInitializationSection(El: TPasModule; AContext: TConvertContext): TJSElement; virtual;
  2178. Function ConvertSimpleStatement(El: TPasImplSimple; AContext: TConvertContext): TJSElement; virtual;
  2179. Function ConvertWithStatement(El: TPasImplWithDo; AContext: TConvertContext): TJSElement; virtual;
  2180. Function ConvertTryStatement(El: TPasImplTry; AContext: TConvertContext ): TJSElement; virtual;
  2181. Function ConvertExceptOn(El: TPasImplExceptOn; AContext: TConvertContext): TJSElement;
  2182. Function ConvertCaseOfStatement(El: TPasImplCaseOf; AContext: TConvertContext): TJSElement;
  2183. Function ConvertAsmStatement(El: TPasImplAsmStatement; AContext: TConvertContext): TJSElement;
  2184. // Expressions
  2185. Function ConvertConstValue(Value: TResEvalValue; AContext: TConvertContext; El: TPasElement): TJSElement; virtual;
  2186. Function ConvertArrayValues(El: TArrayValues; AContext: TConvertContext): TJSElement; virtual;
  2187. Function ConvertInheritedExpr(El: TInheritedExpr; AContext: TConvertContext): TJSElement; virtual;
  2188. Function ConvertNilExpr(El: TNilExpr; AContext: TConvertContext): TJSElement; virtual;
  2189. Function ConvertCharToInt(Arg: TJSElement; PosEl: TPasElement; ArgContext: TConvertContext): TJSElement; virtual;
  2190. Function ConvertIntToInt(Arg: TJSElement; FromBT, ToBT: TResolverBaseType; PosEl: TPasElement; ArgContext: TConvertContext): TJSElement; virtual;
  2191. Function CreateBitWiseAnd(El: TPasElement; Value: TJSElement; const Mask: TMaxPrecInt; Shift: integer): TJSElement; virtual;
  2192. Function CreateBitWiseLongword(El: TPasElement; Value: TJSElement): TJSElement; virtual;
  2193. Function ConvertParamsExpr(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  2194. Function ConvertArrayParams(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  2195. Function ConvertFuncParams(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  2196. Function ConvertExternalConstructor(Left: TPasExpr; Ref: TResolvedReference;
  2197. ParamsExpr: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  2198. Function ConvertTObjectFree_Bin(Bin: TBinaryExpr; NameExpr: TPasExpr; AContext: TConvertContext): TJSElement; virtual;
  2199. Function ConvertTObjectFree_With(NameExpr: TPasExpr; AContext: TConvertContext): TJSElement; virtual;
  2200. Function ConvertTypeCastToBaseType(El: TParamsExpr; AContext: TConvertContext; ToBaseTypeData: TResElDataBaseType): TJSElement; virtual;
  2201. Function ConvertArrayOrSetLiteral(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  2202. Function ConvertBuiltIn_Length(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  2203. Function ConvertBuiltIn_SetLength(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  2204. Function ConvertBuiltIn_ExcludeInclude(El: TParamsExpr; AContext: TConvertContext; IsInclude: boolean): TJSElement; virtual;
  2205. Function ConvertBuiltInContinue(El: TPasExpr; AContext: TConvertContext): TJSElement; virtual;
  2206. Function ConvertBuiltInBreak(El: TPasExpr; AContext: TConvertContext): TJSElement; virtual;
  2207. Function ConvertBuiltIn_Exit(El: TPasExpr; AContext: TConvertContext): TJSElement; virtual;
  2208. Function ConvertBuiltIn_IncDec(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  2209. Function ConvertBuiltIn_Assigned(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  2210. Function ConvertBuiltIn_Chr(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  2211. Function ConvertBuiltIn_Ord(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  2212. Function ConvertBuiltIn_LowHigh(El: TParamsExpr; AContext: TConvertContext; IsLow: boolean): TJSElement; virtual;
  2213. Function ConvertBuiltIn_PredSucc(El: TParamsExpr; AContext: TConvertContext; IsPred: boolean): TJSElement; virtual;
  2214. Function ConvertBuiltIn_StrProc(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  2215. Function ConvertBuiltIn_StrFunc(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  2216. Function ConvertBuiltInStrParam(El: TPasExpr; AContext: TConvertContext; IsStrFunc, IsFirst: boolean): TJSElement; virtual;
  2217. Function ConvertBuiltIn_WriteStr(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  2218. Function ConvertBuiltIn_Val(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  2219. Function ConvertBuiltIn_LoHi(El: TParamsExpr; AContext: TConvertContext; IsLoFunc: Boolean): TJSElement; virtual;
  2220. Function ConvertBuiltIn_ConcatArray(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  2221. Function ConvertBuiltIn_ConcatString(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  2222. Function ConvertBuiltIn_CopyArray(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  2223. Function ConvertBuiltIn_InsertArray(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  2224. Function ConvertBuiltIn_DeleteArray(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  2225. Function ConvertBuiltIn_TypeInfo(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  2226. Function ConvertBuiltIn_GetTypeKind(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  2227. Function ConvertBuiltIn_Assert(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  2228. Function ConvertBuiltIn_New(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  2229. Function ConvertBuiltIn_Dispose(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  2230. Function ConvertBuiltIn_Default(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  2231. Function ConvertBuiltIn_Debugger(El: TPasExpr; AContext: TConvertContext): TJSElement; virtual;
  2232. Function ConvertBuiltIn_AWait(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  2233. Function ConvertRecordValues(El: TRecordValues; AContext: TConvertContext): TJSElement; virtual;
  2234. Function ConvertSelfExpression(El: TSelfExpr; AContext: TConvertContext): TJSElement; virtual;
  2235. Function ConvertBinaryExpression(El: TBinaryExpr; AContext: TConvertContext): TJSElement; virtual;
  2236. Function ConvertBinaryExpressionRes(El: TBinaryExpr; AContext: TConvertContext;
  2237. const LeftResolved, RightResolved: TPasResolverResult; var A,B: TJSElement): TJSElement; virtual;
  2238. function ConvertBinaryExpressionMultiAdd(El: TBinaryExpr; AContext: TConvertContext): TJSElement; virtual;
  2239. Function ConvertSubIdentExpression(El: TBinaryExpr; AContext: TConvertContext): TJSElement; virtual;
  2240. Function ConvertSubIdentExprCustom(El: TBinaryExpr; AContext: TConvertContext;
  2241. const OnConvertRight: TConvertJSEvent = nil; Data: Pointer = nil): TJSElement; virtual;
  2242. Function ConvertBoolConstExpression(El: TBoolConstExpr; AContext: TConvertContext): TJSElement; virtual;
  2243. Function ConvertPrimitiveExpression(El: TPrimitiveExpr; AContext: TConvertContext): TJSElement; virtual;
  2244. Function ConvertIdentifierExpr(El: TPasExpr; const aName: string; AContext : TConvertContext): TJSElement; virtual;
  2245. Function ConvertUnaryExpression(El: TUnaryExpr; AContext: TConvertContext): TJSElement; virtual;
  2246. Function ConvertInlineSpecializeExpr(El: TInlineSpecializeExpr; AContext: TConvertContext): TJSElement; virtual;
  2247. // Convert declarations
  2248. Function ConvertElement(El : TPasElement; AContext: TConvertContext) : TJSElement; virtual;
  2249. Function ConvertProperty(El: TPasProperty; AContext: TConvertContext ): TJSElement; virtual;
  2250. Function ConvertConst(El: TPasConst; AContext: TConvertContext): TJSElement; virtual;
  2251. Function ConvertDeclarations(El: TPasDeclarations; AContext: TConvertContext): TJSElement; virtual;
  2252. Function ConvertExportSymbol(El: TPasExportSymbol; AContext: TConvertContext): TJSElement; virtual;
  2253. Function ConvertExpression(El: TPasExpr; AContext: TConvertContext): TJSElement; virtual;
  2254. Function ConvertImplBlock(El: TPasImplBlock; AContext: TConvertContext ): TJSElement; virtual;
  2255. Function ConvertImplCommand(El: TPasImplCommand; AContext: TConvertContext ): TJSElement; virtual;
  2256. Function ConvertLabelMark(El: TPasImplLabelMark; AContext: TConvertContext): TJSElement; virtual;
  2257. Function ConvertLabels(El: TPasLabels; AContext: TConvertContext): TJSElement; virtual;
  2258. Function ConvertModule(El: TPasModule; AContext: TConvertContext): TJSElement; virtual;
  2259. Function ConvertPackage(El: TPasPackage; AContext: TConvertContext): TJSElement; virtual;
  2260. Function ConvertProcedure(El: TPasProcedure; AContext: TConvertContext): TJSElement; virtual;
  2261. Function ConvertResString(El: TPasResString; AContext: TConvertContext): TJSElement; virtual;
  2262. Function ConvertVariable(El: TPasVariable; AContext: TConvertContext): TJSElement; virtual;
  2263. Function ConvertRecordType(El: TPasRecordType; AContext: TConvertContext): TJSElement; virtual;
  2264. Function ConvertClassType(El: TPasClassType; AContext: TConvertContext): TJSElement; virtual;
  2265. Function ConvertClassForwardType(El: TPasClassType; AContext: TConvertContext): TJSElement; virtual;
  2266. Function ConvertClassOfType(El: TPasClassOfType; AContext: TConvertContext): TJSElement; virtual;
  2267. Function ConvertExtClassType(El: TPasClassType; AContext: TConvertContext): TJSElement; virtual;
  2268. Function ConvertEnumType(El: TPasEnumType; AContext: TConvertContext): TJSElement; virtual;
  2269. Function ConvertSetType(El: TPasSetType; AContext: TConvertContext): TJSElement; virtual;
  2270. Function ConvertRangeType(El: TPasRangeType; AContext: TConvertContext): TJSElement; virtual;
  2271. Function ConvertTypeAliasType(El: TPasTypeAliasType; AContext: TConvertContext): TJSElement; virtual;
  2272. Function ConvertPointerType(El: TPasPointerType; AContext: TConvertContext): TJSElement; virtual;
  2273. Function ConvertProcedureType(El: TPasProcedureType; AContext: TConvertContext): TJSElement; virtual;
  2274. Function ConvertArrayType(El: TPasArrayType; AContext: TConvertContext): TJSElement; virtual;
  2275. Public
  2276. // RTTI, TypeInfo constants
  2277. const
  2278. // TParamFlag
  2279. pfVar = 1;
  2280. pfConst = 2;
  2281. pfOut = 4;
  2282. pfArray = 8;
  2283. // TProcedureFlag
  2284. pfStatic = 1;
  2285. pfVarargs = 2;
  2286. pfExternal = 4;
  2287. pfSafeCall = 8;
  2288. pfAsync = $10;
  2289. // PropertyFlag
  2290. pfGetFunction = 1; // getter is a function
  2291. pfSetProcedure = 2; // setter is a function
  2292. pfStoredTrue = 0; // stored true, always
  2293. pfStoredFalse = 4; // stored false, never
  2294. pfStoredField = 8; // stored field, field name is in Stored
  2295. pfStoredFunction = 12; // stored function, function name is in Stored
  2296. pfHasIndex = 16; { if getter is function, append Index as last param
  2297. if setter is function, append Index as second last param }
  2298. pfClassProperty = 32; // class property
  2299. type
  2300. TMethodKind = (
  2301. mkProcedure, // 0 default
  2302. mkFunction, // 1
  2303. mkConstructor, // 2
  2304. mkDestructor, // 3
  2305. mkClassProcedure, // 4
  2306. mkClassFunction // 5
  2307. );
  2308. TOrdType = (
  2309. otSByte, // 0
  2310. otUByte, // 1
  2311. otSWord, // 2
  2312. otUWord, // 3
  2313. otSLong, // 4
  2314. otULong, // 5
  2315. otSIntDouble, // 6 NativeInt
  2316. otUIntDouble // 7 NativeUInt
  2317. );
  2318. Function GetOrdType(MinValue, MaxValue: TMaxPrecInt; ErrorEl: TPasElement): TOrdType; virtual;
  2319. Public
  2320. // array of const, TVarRec
  2321. const
  2322. pas2js_vtInteger = 0;
  2323. pas2js_vtBoolean = 1;
  2324. //vtChar = 2; // Delphi/FPC: ansichar
  2325. pas2js_vtExtended = 3; // Note: double in pas2js, PExtended in Delphi/FPC
  2326. //vtString = 4; // Delphi/FPC: PShortString
  2327. pas2js_vtPointer = 5;
  2328. //vtPChar = 6;
  2329. pas2js_vtObject = 7;
  2330. pas2js_vtClass = 8;
  2331. pas2js_vtWideChar = 9;
  2332. //vtPWideChar = 10;
  2333. //vtAnsiString = 11;
  2334. pas2js_vtCurrency = 12; // Note: currency in pas2js, PCurrency in Delphi/FPC
  2335. //vtVariant = 13;
  2336. pas2js_vtInterface = 14;
  2337. //vtWideString = 15;
  2338. //vtInt64 = 16;
  2339. //vtQWord = 17;
  2340. pas2js_vtUnicodeString = 18;
  2341. // only pas2js, not in Delphi/FPC:
  2342. pas2js_vtNativeInt = 19;
  2343. pas2js_vtJSValue = 20;
  2344. Public
  2345. Constructor Create;
  2346. Destructor Destroy; override;
  2347. Function ConvertPasElement(El: TPasElement; Resolver: TPas2JSResolver) : TJSElement;
  2348. // options
  2349. Property Options: TPasToJsConverterOptions read FOptions write FOptions default DefaultPasToJSOptions;
  2350. Property Globals: TPasToJSConverterGlobals read FGlobals write SetGlobals;
  2351. Property UseLowerCase: boolean read GetUseLowerCase write SetUseLowerCase default true;
  2352. Property UseSwitchStatement: boolean read GetUseSwitchStatement write SetUseSwitchStatement;// default false, because slower than "if" in many engines
  2353. Property UseEnumNumbers: boolean read GetUseEnumNumbers write SetUseEnumNumbers; // default false
  2354. Property OnIsElementUsed: TPas2JSIsElementUsedEvent read FOnIsElementUsed write FOnIsElementUsed;
  2355. Property OnIsTypeInfoUsed: TPas2JSIsElementUsedEvent read FOnIsTypeInfoUsed write FOnIsTypeInfoUsed;
  2356. Property ReservedWords: TJSReservedWordList read FReservedWords write SetReservedWords;
  2357. end;
  2358. var
  2359. JSTypeCaptions: array[TJSType] of string = (
  2360. 'undefined',
  2361. 'null',
  2362. 'boolean',
  2363. 'number',
  2364. 'string',
  2365. 'object',
  2366. 'reference',
  2367. 'completion'
  2368. );
  2369. function CodePointToJSString(u: longword): TJSString;
  2370. function PosLast(c: AnsiChar; const s: string): integer;
  2371. function JSEquals(A, B: TJSElement): boolean;
  2372. function dbgs(opts: TPasToJsConverterOptions): string; overload;
  2373. implementation
  2374. const
  2375. TempRefObjGetterName = 'get';
  2376. TempRefObjSetterName = 'set';
  2377. TempRefObjSetterArgName = 'v';
  2378. TempRefGetPathName = 'p';
  2379. TempRefSetPathName = 's';
  2380. TempRefParamName = 'a';
  2381. IdentChars = ['0'..'9', 'A'..'Z', 'a'..'z','_'];
  2382. AwaitSignature2 = 'function await(aType,TJSPromise):aType';
  2383. function CodePointToJSString(u: longword): TJSString;
  2384. begin
  2385. if u < $10000 then
  2386. // Note: codepoints $D800 - $DFFF are reserved
  2387. Result:=WideChar(u)
  2388. else
  2389. Result:=WideChar($D800+((u - $10000) shr 10))+WideChar($DC00+((u - $10000) and $3ff));
  2390. end;
  2391. function PosLast(c: AnsiChar; const s: string): integer;
  2392. begin
  2393. Result:=length(s);
  2394. while (Result>0) and (s[Result]<>c) do dec(Result);
  2395. end;
  2396. function JSEquals(A, B: TJSElement): boolean;
  2397. begin
  2398. if A=nil then
  2399. exit(B=nil)
  2400. else if B=nil then
  2401. exit(false)
  2402. else if A.ClassType<>B.ClassType then
  2403. exit(false);
  2404. if A.ClassType=TJSPrimaryExpressionIdent then
  2405. exit(TJSPrimaryExpressionIdent(A).Name=TJSPrimaryExpressionIdent(B).Name)
  2406. else if A.ClassType=TJSPrimaryExpressionThis then
  2407. else if A.ClassType=TJSDotMemberExpression then
  2408. Result:=JSEquals(TJSDotMemberExpression(A).MExpr,TJSDotMemberExpression(B).MExpr)
  2409. and (TJSDotMemberExpression(A).Name=TJSDotMemberExpression(B).Name)
  2410. else if A.ClassType=TJSBracketMemberExpression then
  2411. Result:=JSEquals(TJSBracketMemberExpression(A).MExpr,TJSBracketMemberExpression(B).MExpr)
  2412. and (TJSBracketMemberExpression(A).Name=TJSBracketMemberExpression(B).Name)
  2413. else
  2414. exit(false);
  2415. end;
  2416. function dbgs(opts: TPasToJsConverterOptions): string;
  2417. var
  2418. o: TPasToJsConverterOption;
  2419. h: string;
  2420. begin
  2421. Result:='';
  2422. for o in opts do
  2423. begin
  2424. if Result<>'' then Result:=Result+',';
  2425. str(o,h);
  2426. Result:=Result+h;
  2427. end;
  2428. Result:='['+Result+']';
  2429. end;
  2430. { TPas2JSInitialFinalizationScope }
  2431. destructor TPas2JSInitialFinalizationScope.Destroy;
  2432. begin
  2433. FreeAndNil(ImplJS);
  2434. inherited Destroy;
  2435. end;
  2436. { TInterfaceSectionContext }
  2437. destructor TInterfaceSectionContext.Destroy;
  2438. var
  2439. i: Integer;
  2440. El: TJSElement;
  2441. begin
  2442. if ImplHeaderStatements<>nil then
  2443. begin
  2444. for i:=0 to ImplHeaderStatements.Count-1 do
  2445. begin
  2446. El:=TJSElement(ImplHeaderStatements[i]);
  2447. El.Free;
  2448. end;
  2449. FreeAndNil(ImplHeaderStatements);
  2450. end;
  2451. inherited Destroy;
  2452. end;
  2453. procedure TInterfaceSectionContext.AddImplHeaderStatement(JS: TJSElement);
  2454. begin
  2455. if JS=nil then exit;
  2456. if ImplContext<>nil then
  2457. begin
  2458. // unit impl is currently created
  2459. ImplContext.AddHeaderStatement(JS);
  2460. end
  2461. else if ImplSrcElements<>nil then
  2462. begin
  2463. // unit impl finished -> e.g. during the initialization section
  2464. ImplSrcElements.Statements.InsertNode(ImplHeaderIndex).Node:=JS;
  2465. inc(ImplHeaderIndex);
  2466. end
  2467. else
  2468. begin
  2469. // unit impl not yet created
  2470. if ImplHeaderStatements=nil then
  2471. ImplHeaderStatements:=TFPList.Create;
  2472. ImplHeaderStatements.Add(JS);
  2473. end;
  2474. end;
  2475. { TPas2JSResolverHub }
  2476. function TPas2JSResolverHub.GetJSDelaySpecializes(Index: integer
  2477. ): TPasGenericType;
  2478. begin
  2479. Result:=TPasGenericType(FJSDelaySpecialize[Index]);
  2480. end;
  2481. constructor TPas2JSResolverHub.Create(TheOwner: TObject);
  2482. begin
  2483. inherited Create(TheOwner);
  2484. FJSDelaySpecialize:=TFPList.Create;
  2485. end;
  2486. destructor TPas2JSResolverHub.Destroy;
  2487. begin
  2488. FreeAndNil(FJSDelaySpecialize);
  2489. inherited Destroy;
  2490. end;
  2491. procedure TPas2JSResolverHub.Reset;
  2492. begin
  2493. inherited Reset;
  2494. FJSDelaySpecialize.Clear;
  2495. end;
  2496. procedure TPas2JSResolverHub.AddJSDelaySpecialize(SpecType: TPasGenericType);
  2497. begin
  2498. if FJSDelaySpecialize.IndexOf(SpecType)>=0 then
  2499. raise EPas2JS.Create('TPas2JSResolverHub.AddJSDelaySpecialize '+GetObjPath(SpecType));
  2500. FJSDelaySpecialize.Add(SpecType);
  2501. end;
  2502. function TPas2JSResolverHub.IsJSDelaySpecialize(SpecType: TPasGenericType): boolean;
  2503. begin
  2504. Result:=FJSDelaySpecialize.IndexOf(SpecType)>=0;
  2505. end;
  2506. function TPas2JSResolverHub.JSDelaySpecializeCount: integer;
  2507. begin
  2508. Result:=FJSDelaySpecialize.Count;
  2509. end;
  2510. { TPas2JSModuleScope }
  2511. procedure TPas2JSModuleScope.SetJSPromiseClass(const AValue: TPasClassType);
  2512. begin
  2513. if FJSPromiseClass=AValue then Exit;
  2514. FJSPromiseClass:=AValue;
  2515. end;
  2516. procedure TPas2JSModuleScope.ClearStoreJSLocalVars;
  2517. var
  2518. i: Integer;
  2519. begin
  2520. for i:=0 to length(StoreJSLocalVars)-1 do
  2521. FreeAndNil(StoreJSLocalVars[i]);
  2522. StoreJSLocalVars:=nil;
  2523. end;
  2524. destructor TPas2JSModuleScope.Destroy;
  2525. begin
  2526. ClearStoreJSLocalVars;
  2527. JSPromiseClass:=nil;
  2528. inherited Destroy;
  2529. end;
  2530. { TPas2JSClassScope }
  2531. constructor TPas2JSClassScope.Create;
  2532. begin
  2533. inherited Create;
  2534. ElevatedLocals:=TPas2jsElevatedLocals.Create;
  2535. end;
  2536. destructor TPas2JSClassScope.Destroy;
  2537. begin
  2538. FreeAndNil(ElevatedLocals);
  2539. FreeAndNil(MsgIntToProc);
  2540. FreeAndNil(MsgStrToProc);
  2541. inherited Destroy;
  2542. end;
  2543. { TRootContext }
  2544. procedure TRootContext.AddGlobalClassMethod(p: TPasProcedure);
  2545. begin
  2546. {$IF defined(fpc) and (FPC_FULLVERSION<30101)}
  2547. SetLength(GlobalClassMethods,length(GlobalClassMethods)+1);
  2548. GlobalClassMethods[length(GlobalClassMethods)-1]:=P;
  2549. {$ELSE}
  2550. Insert(P,GlobalClassMethods,length(GlobalClassMethods));
  2551. {$ENDIF}
  2552. end;
  2553. destructor TRootContext.Destroy;
  2554. begin
  2555. inherited Destroy;
  2556. end;
  2557. { TPasToJSConverterGlobals }
  2558. constructor TPasToJSConverterGlobals.Create(TheOwner: TObject);
  2559. begin
  2560. FOwner:=TheOwner;
  2561. ResetBuiltInNames;
  2562. end;
  2563. procedure TPasToJSConverterGlobals.Reset;
  2564. begin
  2565. RTLVersion:=1;
  2566. TargetPlatform:=PlatformBrowser;
  2567. TargetProcessor:=ProcessorECMAScript5;
  2568. ResetBuiltInNames;
  2569. end;
  2570. procedure TPasToJSConverterGlobals.ResetBuiltInNames;
  2571. var
  2572. n: TPas2JSBuiltInName;
  2573. begin
  2574. for n in TPas2JSBuiltInName do
  2575. BuiltInNames[n]:=Pas2JSBuiltInNames[n];
  2576. end;
  2577. { TPas2jsElevatedLocals }
  2578. procedure TPas2jsElevatedLocals.InternalAdd(Item: TPasIdentifier);
  2579. var
  2580. {$IFDEF fpc}
  2581. Index: Integer;
  2582. {$ENDIF}
  2583. OldItem: TPasIdentifier;
  2584. LoName: string;
  2585. begin
  2586. LoName:=lowercase(Item.Identifier);
  2587. {$IFDEF VerbosePasResolver}
  2588. if Item.Owner<>nil then
  2589. raise Exception.Create('20160925184110');
  2590. Item.Owner:=Self;
  2591. {$ENDIF}
  2592. {$IFDEF pas2js}
  2593. OldItem:=TPasIdentifier(FElevatedLocals.Find(LoName));
  2594. if OldItem<>nil then
  2595. begin
  2596. // insert LIFO - last in, first out
  2597. {$IFDEF VerbosePasResolver}
  2598. if lowercase(OldItem.Identifier)<>LoName then
  2599. raise Exception.Create('20181025113922');
  2600. {$ENDIF}
  2601. Item.NextSameIdentifier:=OldItem;
  2602. FElevatedLocals.Remove(LoName);
  2603. end;
  2604. FElevatedLocals.Add(LoName, Item);
  2605. {$ELSE}
  2606. Index:=FElevatedLocals.FindIndexOf(LoName);
  2607. //writeln(' Index=',Index);
  2608. if Index>=0 then
  2609. begin
  2610. // insert LIFO - last in, first out
  2611. OldItem:=TPasIdentifier(FElevatedLocals.List^[Index].Data);
  2612. {$IFDEF VerbosePasResolver}
  2613. if lowercase(OldItem.Identifier)<>LoName then
  2614. raise Exception.Create('20160925183438');
  2615. {$ENDIF}
  2616. Item.NextSameIdentifier:=OldItem;
  2617. FElevatedLocals.List^[Index].Data:=Item;
  2618. end
  2619. else
  2620. begin
  2621. FElevatedLocals.Add(LoName, Item);
  2622. end;
  2623. {$ENDIF}
  2624. {$IFDEF VerbosePasResolver}
  2625. if Find(Item.Identifier)<>Item then
  2626. raise Exception.Create('20160925183849');
  2627. {$ENDIF}
  2628. end;
  2629. procedure TPas2jsElevatedLocals.OnClear(Item, Dummy: pointer);
  2630. var
  2631. PasIdentifier: TPasIdentifier absolute Item;
  2632. Ident: TPasIdentifier;
  2633. begin
  2634. if Dummy=nil then ;
  2635. //writeln('TPasIdentifierScope.OnClearItem ',PasIdentifier.Identifier+':'+PasIdentifier.ClassName);
  2636. while PasIdentifier<>nil do
  2637. begin
  2638. Ident:=PasIdentifier;
  2639. PasIdentifier:=PasIdentifier.NextSameIdentifier;
  2640. Ident.Free;
  2641. end;
  2642. end;
  2643. constructor TPas2jsElevatedLocals.Create;
  2644. begin
  2645. inherited Create;
  2646. FElevatedLocals:=TPasResHashList.Create;
  2647. end;
  2648. destructor TPas2jsElevatedLocals.Destroy;
  2649. begin
  2650. FElevatedLocals.ForEachCall(@OnClear,nil);
  2651. {$IFDEF pas2js}
  2652. FElevatedLocals:=nil;
  2653. {$ELSE}
  2654. FreeAndNil(FElevatedLocals);
  2655. {$ENDIF}
  2656. inherited Destroy;
  2657. end;
  2658. // inline
  2659. function TPas2jsElevatedLocals.Find(const Identifier: String
  2660. ): TPasIdentifier;
  2661. begin
  2662. Result:=TPasIdentifier(FElevatedLocals.Find(lowercase(Identifier)));
  2663. end;
  2664. function TPas2jsElevatedLocals.Add(const Identifier: String;
  2665. El: TPasElement): TPasIdentifier;
  2666. var
  2667. Item: TPasIdentifier;
  2668. begin
  2669. //writeln('TPas2jsElevatedLocals.Add Identifier="',Identifier,'" El=',GetObjName(El));
  2670. Item:=TPasIdentifier.Create;
  2671. Item.Identifier:=Identifier;
  2672. Item.Element:=El;
  2673. InternalAdd(Item);
  2674. //writeln('TPas2jsElevatedLocals.Add END');
  2675. Result:=Item;
  2676. end;
  2677. { TPas2JSSectionScope }
  2678. constructor TPas2JSSectionScope.Create;
  2679. begin
  2680. inherited Create;
  2681. ElevatedLocals:=TPas2jsElevatedLocals.Create;
  2682. end;
  2683. destructor TPas2JSSectionScope.Destroy;
  2684. begin
  2685. FreeAndNil(ElevatedLocals);
  2686. inherited Destroy;
  2687. end;
  2688. procedure TPas2JSSectionScope.WriteElevatedLocals(Prefix: string);
  2689. begin
  2690. Prefix:=Prefix+' ';
  2691. ElevatedLocals.FElevatedLocals.ForEachCall(@OnWriteItem,Pointer(Prefix));
  2692. end;
  2693. { TPas2JSPrecompiledJS }
  2694. procedure TPas2JSPrecompiledJS.AddShortRef(El: TPasElement);
  2695. begin
  2696. if ShortRefs=nil then
  2697. ShortRefs:=TFPList.Create;
  2698. if ShortRefs.IndexOf(El)<0 then
  2699. ShortRefs.Add(El);
  2700. end;
  2701. destructor TPas2JSPrecompiledJS.Destroy;
  2702. begin
  2703. FreeAndNil(GlobalJS);
  2704. FreeAndNil(ShortRefs);
  2705. inherited Destroy;
  2706. end;
  2707. { TPas2JSProcedureScope }
  2708. procedure TPas2JSProcedureScope.AddGlobalJS(const JS: string);
  2709. begin
  2710. if ImplJS=nil then
  2711. raise Exception.Create('[20201018120133] TPas2JSProcedureScope.AddGlobalJS');
  2712. if ImplJS.GlobalJS=nil then
  2713. ImplJS.GlobalJS:=TStringList.Create;
  2714. ImplJS.GlobalJS.Add(Js);
  2715. end;
  2716. destructor TPas2JSProcedureScope.Destroy;
  2717. begin
  2718. FreeAndNil(ImplJS);
  2719. inherited Destroy;
  2720. end;
  2721. { TFCLocalIdentifier }
  2722. constructor TFCLocalIdentifier.Create(const aName: string; TheEl: TPasElement;
  2723. aKind: TCtxVarKind);
  2724. begin
  2725. Name:=aName;
  2726. Element:=TheEl;
  2727. Kind:=aKind;
  2728. end;
  2729. { TPas2jsPasScanner }
  2730. function TPas2jsPasScanner.HandleInclude(const Param: TPasScannerString): TToken;
  2731. procedure SetStr(s: string);
  2732. var
  2733. i: Integer;
  2734. h: String;
  2735. begin
  2736. Result:=tkString;
  2737. if s='' then
  2738. s:=''''''
  2739. else
  2740. for i:=length(s) downto 1 do
  2741. case s[i] of
  2742. #0..#31,#127:
  2743. begin
  2744. h:='#'+IntToStr(ord(s[i]));
  2745. if i>1 then h:=''''+h;
  2746. if (i<length(s)) and (s[i+1]<>'#') then
  2747. h:=h+'''';
  2748. s:=LeftStr(s,i-1)+h+copy(s,i+1,length(s));
  2749. end;
  2750. else
  2751. if i=length(s) then
  2752. s:=s+'''';
  2753. if s[i]='''' then
  2754. Insert('''',s,i);
  2755. if i=1 then
  2756. s:=''''+s;
  2757. end;
  2758. SetCurTokenString(s);
  2759. end;
  2760. procedure SetInteger(const i: TMaxPrecInt);
  2761. begin
  2762. Result:=tkNumber;
  2763. SetCurTokenString(IntToStr(i));
  2764. end;
  2765. var
  2766. Year, Month, Day, Hour, Minute, Second, MilliSecond: word;
  2767. i: Integer;
  2768. Scope: TPasScope;
  2769. begin
  2770. if (Param<>'') and (Param[1]='%') then
  2771. begin
  2772. if (length(Param)<3) or (Param[length(Param)]<>'%') then
  2773. begin
  2774. SetStr('');
  2775. DoLog(mtWarning,nWarnIllegalCompilerDirectiveX,SWarnIllegalCompilerDirectiveX,
  2776. ['$i '+Param]);
  2777. exit;
  2778. end;
  2779. if length(Param)>255 then
  2780. begin
  2781. SetStr('');
  2782. DoLog(mtWarning,nWarnIllegalCompilerDirectiveX,SWarnIllegalCompilerDirectiveX,
  2783. ['$i '+copy(Param,1,255)+'...']);
  2784. exit;
  2785. end;
  2786. case lowercase(Param) of
  2787. '%date%':
  2788. begin
  2789. // 'Y/M/D'
  2790. DecodeDate(Now,Year,Month,Day);
  2791. SetStr(IntToStr(Year)+'/'+IntToStr(Month)+'/'+IntToStr(Day));
  2792. exit;
  2793. end;
  2794. '%time%':
  2795. begin
  2796. // 'hh:mm:ss'
  2797. DecodeTime(Now,Hour,Minute,Second,MilliSecond);
  2798. SetStr(Format('%2d:%2d:%2d',[Hour,Minute,Second]));
  2799. exit;
  2800. end;
  2801. '%pas2jstarget%','%fpctarget%',
  2802. '%pas2jstargetos%','%fpctargetos%':
  2803. begin
  2804. SetStr(PasToJsPlatformNames[TargetPlatform]);
  2805. exit;
  2806. end;
  2807. '%pas2jstargetcpu%','%fpctargetcpu%':
  2808. begin
  2809. SetStr(PasToJsProcessorNames[TargetProcessor]);
  2810. exit;
  2811. end;
  2812. '%pas2jsversion%','%fpcversion%':
  2813. begin
  2814. SetStr(CompilerVersion);
  2815. exit;
  2816. end;
  2817. '%file%':
  2818. begin
  2819. SetStr(CurFilename);
  2820. exit;
  2821. end;
  2822. '%filename%':
  2823. begin
  2824. SetStr(ExtractFileName(CurFilename));
  2825. exit;
  2826. end;
  2827. '%unit%',
  2828. '%module%':
  2829. begin
  2830. SetStr(CurModuleName);
  2831. exit;
  2832. end;
  2833. '%line%':
  2834. begin
  2835. SetStr(IntToStr(CurRow));
  2836. exit;
  2837. end;
  2838. '%linenum%':
  2839. begin
  2840. SetInteger(CurRow);
  2841. exit;
  2842. end;
  2843. '%currentroutine%':
  2844. begin
  2845. if Resolver<>nil then
  2846. for i:=Resolver.ScopeCount-1 downto 0 do
  2847. begin
  2848. Scope:=Resolver.Scopes[i];
  2849. if (Scope.Element is TPasProcedure)
  2850. and (Scope.Element.Name<>'') then
  2851. begin
  2852. SetStr(Scope.Element.Name);
  2853. exit;
  2854. end;
  2855. end;
  2856. SetStr('<anonymous>');
  2857. exit;
  2858. end;
  2859. else
  2860. SetStr(GetEnvironmentVariable(copy(Param,2,length(Param)-2)));
  2861. exit;
  2862. end;
  2863. end;
  2864. Result:=inherited HandleInclude(Param);
  2865. end;
  2866. procedure TPas2jsPasScanner.DoHandleOptimization(OptName, OptValue: TPasScannerString);
  2867. procedure HandleBoolean(o: TPasToJsConverterOption; IsGlobalSwitch: boolean);
  2868. var
  2869. Enable: Boolean;
  2870. begin
  2871. Enable:=false;
  2872. case lowercase(OptValue) of
  2873. '','on','+': Enable:=true;
  2874. 'off','-': Enable:=false;
  2875. else
  2876. Error(nErrWrongSwitchToggle,SErrWrongSwitchToggle,[]);
  2877. end;
  2878. if IsGlobalSwitch and SkipGlobalSwitches then
  2879. begin
  2880. DoLog(mtWarning,nMisplacedGlobalCompilerSwitch,SMisplacedGlobalCompilerSwitch,[]);
  2881. exit;
  2882. end;
  2883. if Enable then
  2884. begin
  2885. Include(GlobalConvOptsEnabled,o);
  2886. Exclude(GlobalConvOptsDisabled,o);
  2887. end
  2888. else
  2889. begin
  2890. Include(GlobalConvOptsDisabled,o);
  2891. Exclude(GlobalConvOptsEnabled,o);
  2892. end;
  2893. end;
  2894. begin
  2895. case lowercase(OptName) of
  2896. 'enumnumbers':
  2897. HandleBoolean(coEnumNumbers,true);
  2898. 'usestrict':
  2899. HandleBoolean(coUseStrict,true);
  2900. 'jsshortrefglobals':
  2901. HandleBoolean(coShortRefGlobals,true);
  2902. 'jsobfuscatelocalidentifiers':
  2903. HandleBoolean(coObfuscateLocalIdentifiers,true);
  2904. else
  2905. DoLog(mtWarning,nWarnIllegalCompilerDirectiveX,sWarnIllegalCompilerDirectiveX,['optimization '+OptName]);
  2906. end;
  2907. end;
  2908. function TPas2jsPasScanner.ReadNonPascalTillEndToken(StopAtLineEnd: boolean
  2909. ): TToken;
  2910. var
  2911. StartPos, MyTokenPos: integer;
  2912. s: string;
  2913. l: integer;
  2914. Procedure CommitTokenPos;
  2915. begin
  2916. {$IFDEF Pas2js}
  2917. TokenPos:=MyTokenPos;
  2918. {$ELSE}
  2919. TokenPos:=PAnsiChar(s)+MyTokenPos-1;
  2920. {$ENDIF}
  2921. end;
  2922. Procedure Add;
  2923. var
  2924. AddLen: PtrInt;
  2925. begin
  2926. AddLen:=MyTokenPos-StartPos;
  2927. if AddLen=0 then
  2928. SetCurTokenString('')
  2929. else
  2930. begin
  2931. SetCurTokenString(CurTokenString+copy(CurLine,StartPos,AddLen));
  2932. StartPos:=MyTokenPos;
  2933. end;
  2934. end;
  2935. function DoEndOfLine: boolean;
  2936. begin
  2937. Add;
  2938. if StopAtLineEnd then
  2939. begin
  2940. ReadNonPascalTillEndToken := tkLineEnding;
  2941. CommitTokenPos;
  2942. SetCurToken(tkLineEnding);
  2943. FetchLine;
  2944. exit(true);
  2945. end;
  2946. if not FetchLine then
  2947. begin
  2948. ReadNonPascalTillEndToken := tkEOF;
  2949. SetCurToken(tkEOF);
  2950. exit(true);
  2951. end;
  2952. s:=CurLine;
  2953. l:=length(s);
  2954. MyTokenPos:=1;
  2955. StartPos:=MyTokenPos;
  2956. Result:=false;
  2957. end;
  2958. procedure HandleEscape;
  2959. begin
  2960. inc(MyTokenPos);
  2961. if (MyTokenPos<=l) and (s[MyTokenPos]>#31) then
  2962. inc(MyTokenPos);
  2963. end;
  2964. begin
  2965. SetCurTokenString('');
  2966. s:=CurLine;
  2967. l:=length(s);
  2968. {$IFDEF Pas2js}
  2969. MyTokenPos:=TokenPos;
  2970. {$ELSE}
  2971. {$IFDEF VerbosePas2JS}
  2972. if (TokenPos<PAnsiChar(s)) or (TokenPos>PAnsiChar(s)+length(s)) then
  2973. Error(nErrRangeCheck,'[20181109104812]');
  2974. {$ENDIF}
  2975. MyTokenPos:=TokenPos-PAnsiChar(s)+1;
  2976. {$ENDIF}
  2977. StartPos:=MyTokenPos;
  2978. repeat
  2979. if MyTokenPos>l then
  2980. if DoEndOfLine then exit;
  2981. case s[MyTokenPos] of
  2982. '\':
  2983. HandleEscape;
  2984. '''':
  2985. begin
  2986. inc(MyTokenPos);
  2987. repeat
  2988. if MyTokenPos>l then
  2989. Error(nErrOpenString,SErrOpenString);
  2990. case s[MyTokenPos] of
  2991. '\':
  2992. HandleEscape;
  2993. '''':
  2994. begin
  2995. inc(MyTokenPos);
  2996. break;
  2997. end;
  2998. #10,#13:
  2999. begin
  3000. // string literal missing closing apostroph
  3001. break;
  3002. end
  3003. else
  3004. inc(MyTokenPos);
  3005. end;
  3006. until false;
  3007. end;
  3008. '"':
  3009. begin
  3010. inc(MyTokenPos);
  3011. repeat
  3012. if MyTokenPos>l then
  3013. Error(nErrOpenString,SErrOpenString);
  3014. case s[MyTokenPos] of
  3015. '\':
  3016. HandleEscape;
  3017. '"':
  3018. begin
  3019. inc(MyTokenPos);
  3020. break;
  3021. end;
  3022. #10,#13:
  3023. begin
  3024. // string literal missing closing quote
  3025. break;
  3026. end
  3027. else
  3028. inc(MyTokenPos);
  3029. end;
  3030. until false;
  3031. end;
  3032. '`': // template literal
  3033. begin
  3034. inc(MyTokenPos);
  3035. repeat
  3036. while MyTokenPos>l do
  3037. if DoEndOfLine then
  3038. begin
  3039. if not StopAtLineEnd then
  3040. Error(nErrOpenString,SErrOpenString);
  3041. exit;
  3042. end;
  3043. case s[MyTokenPos] of
  3044. '\':
  3045. HandleEscape;
  3046. '`':
  3047. begin
  3048. inc(MyTokenPos);
  3049. break;
  3050. end;
  3051. // Note: template literals can span multiple lines
  3052. else
  3053. inc(MyTokenPos);
  3054. end;
  3055. until false;
  3056. end;
  3057. '/':
  3058. begin
  3059. inc(MyTokenPos);
  3060. if (MyTokenPos<=l) and (s[MyTokenPos]='/') then
  3061. begin
  3062. // skip Delphi comment //, see Note above
  3063. repeat
  3064. inc(MyTokenPos);
  3065. until (MyTokenPos>l) or (s[MyTokenPos] in [#10,#13]);
  3066. end;
  3067. end;
  3068. '0'..'9', 'A'..'Z', 'a'..'z','_':
  3069. begin
  3070. // number or identifier
  3071. if (CompareText(copy(s,MyTokenPos,3),'end')=0)
  3072. and ((MyTokenPos+3>l) or not (s[MyTokenPos+3] in IdentChars)) then
  3073. begin
  3074. // 'end' found
  3075. Add;
  3076. if CurTokenString<>'' then
  3077. begin
  3078. // return characters in front of 'end'
  3079. Result:=tkWhitespace;
  3080. CommitTokenPos;
  3081. SetCurToken(Result);
  3082. exit;
  3083. end;
  3084. // return 'end'
  3085. Result := tkend;
  3086. SetCurTokenString(copy(s,MyTokenPos,3));
  3087. inc(MyTokenPos,3);
  3088. CommitTokenPos;
  3089. SetCurToken(Result);
  3090. exit;
  3091. end
  3092. else
  3093. begin
  3094. // skip identifier
  3095. while (MyTokenPos<=l) and (s[MyTokenPos] in IdentChars) do
  3096. inc(MyTokenPos);
  3097. end;
  3098. end;
  3099. else
  3100. inc(MyTokenPos);
  3101. end;
  3102. until false;
  3103. end;
  3104. { TPas2JSResolver }
  3105. // inline
  3106. function TPas2JSResolver.GetJSBaseTypes(aBaseType: TPas2jsBaseType
  3107. ): TPasUnresolvedSymbolRef;
  3108. begin
  3109. Result:=FJSBaseTypes[aBaseType];
  3110. end;
  3111. function TPas2JSResolver.GetJSBuiltInProcs(aProc: TPas2jsBuiltInProc
  3112. ): TResElDataBuiltInProc;
  3113. begin
  3114. Result:=FJSBuiltInProcs[aProc];
  3115. end;
  3116. procedure TPas2JSResolver.InternalAdd(Item: TPasIdentifier);
  3117. var
  3118. {$IFDEF fpc}
  3119. Index: Integer;
  3120. {$ENDIF}
  3121. OldItem: TPasIdentifier;
  3122. aName: String;
  3123. begin
  3124. aName:=Item.Identifier;
  3125. {$IFDEF VerbosePasResolver}
  3126. if Item.Owner<>nil then
  3127. raise Exception.Create('20170322235419');
  3128. Item.Owner:=Self;
  3129. {$ENDIF}
  3130. {$IFDEF pas2js}
  3131. OldItem:=TPasIdentifier(FExternalNames.Find(aName));
  3132. if OldItem<>nil then
  3133. begin
  3134. // insert LIFO - last in, first out
  3135. {$IFDEF VerbosePasResolver}
  3136. if OldItem.Identifier<>aName then
  3137. raise Exception.Create('20181025114714');
  3138. {$ENDIF}
  3139. Item.NextSameIdentifier:=OldItem;
  3140. FExternalNames.Remove(aName);
  3141. end;
  3142. FExternalNames.Add(aName,Item);
  3143. {$ELSE}
  3144. Index:=FExternalNames.FindIndexOf(aName);
  3145. //writeln(' Index=',Index);
  3146. if Index>=0 then
  3147. begin
  3148. // insert LIFO - last in, first out
  3149. OldItem:=TPasIdentifier(FExternalNames.List^[Index].Data);
  3150. {$IFDEF VerbosePasResolver}
  3151. if OldItem.Identifier<>aName then
  3152. raise Exception.Create('20170322235429');
  3153. {$ENDIF}
  3154. Item.NextSameIdentifier:=OldItem;
  3155. FExternalNames.List^[Index].Data:=Item;
  3156. end
  3157. else
  3158. FExternalNames.Add(aName, Item);
  3159. {$ENDIF}
  3160. {$IFDEF VerbosePasResolver}
  3161. if FindExternalName(Item.Identifier)<>Item then
  3162. raise Exception.Create('20170322235433');
  3163. {$ENDIF}
  3164. end;
  3165. procedure TPas2JSResolver.OnClearHashItem(Item, Dummy: pointer);
  3166. var
  3167. PasIdentifier: TPasIdentifier absolute Item;
  3168. Ident: TPasIdentifier;
  3169. begin
  3170. if Dummy=nil then ;
  3171. //writeln('TPas2JSResolver.OnClearItem ',PasIdentifier.Identifier+':'+PasIdentifier.ClassName);
  3172. while PasIdentifier<>nil do
  3173. begin
  3174. Ident:=PasIdentifier;
  3175. PasIdentifier:=PasIdentifier.NextSameIdentifier;
  3176. Ident.Free;
  3177. end;
  3178. end;
  3179. procedure TPas2JSResolver.OnHasAnonymousEl(El: TPasElement; arg: pointer);
  3180. var
  3181. Data: PHasAnoFuncData absolute arg;
  3182. begin
  3183. if (El=nil) or (Data^.Expr<>nil) or (El.ClassType<>TProcedureExpr) then exit;
  3184. Data^.Expr:=TProcedureExpr(El);
  3185. end;
  3186. procedure TPas2JSResolver.OnHasElReadingDecl(El: TPasElement; arg: pointer);
  3187. var
  3188. Data: PHasElReadingDeclData absolute arg;
  3189. Ref: TResolvedReference;
  3190. begin
  3191. if Data^.El<>nil then exit;
  3192. if El.CustomData is TResolvedReference then
  3193. begin
  3194. Ref:=TResolvedReference(El.CustomData);
  3195. if (Ref.Declaration=Data^.Decl) and (Ref.Access in rraAllRead) then
  3196. begin
  3197. Data^.El:=El;
  3198. end;
  3199. end;
  3200. end;
  3201. procedure TPas2JSResolver.OnFindExtSystemClass(El: TPasElement; ElScope,
  3202. StartScope: TPasScope; FindExtSystemClassData: Pointer; var Abort: boolean);
  3203. var
  3204. Data: PPRFindExtSystemClass absolute FindExtSystemClassData;
  3205. aClass: TPasClassType;
  3206. begin
  3207. if Data^.Found<>nil then exit;
  3208. if not (El is TPasClassType) then exit;
  3209. aClass:=TPasClassType(El);
  3210. if not aClass.IsExternal then exit;
  3211. if aClass.Parent is TPasMembersType then
  3212. exit; // nested class
  3213. if aClass.ExternalName<>Data^.JSName then exit;
  3214. Data^.Found:=aClass;
  3215. Data^.ElScope:=ElScope;
  3216. Data^.StartScope:=StartScope;
  3217. Abort:=true;
  3218. end;
  3219. function TPas2JSResolver.HasOverloadIndex(El: TPasElement;
  3220. WithElevatedLocal: boolean): boolean;
  3221. var
  3222. C: TClass;
  3223. ProcScope: TPasProcedureScope;
  3224. begin
  3225. C:=El.ClassType;
  3226. if C=TPasProperty then
  3227. exit(false)
  3228. else if (C=TPasConst)
  3229. or C.InheritsFrom(TPasType) then
  3230. begin
  3231. if (not WithElevatedLocal) and (El.Parent is TProcedureBody) then
  3232. exit(false); // local const/type is counted via ElevatedLocals
  3233. if (C=TPasClassType) and TPasClassType(El).IsForward then
  3234. exit(false);
  3235. end
  3236. else if C.InheritsFrom(TPasProcedure) then
  3237. begin
  3238. if TPasProcedure(El).IsOverride then
  3239. exit(true); // using name of overridden
  3240. if El.Visibility=visPublished then
  3241. exit(false); // published elements are always using the pascal identifier
  3242. // Note: external proc pollutes the name space
  3243. ProcScope:=TPasProcedureScope(El.CustomData);
  3244. if ProcScope.DeclarationProc<>nil then
  3245. // implementation proc -> only count the header -> skip
  3246. exit(false);
  3247. if ProcScope.SpecializedFromItem<>nil then
  3248. exit(false);
  3249. end;
  3250. Result:=true;
  3251. end;
  3252. function TPas2JSResolver.GetOverloadIndex(Identifier: TPasIdentifier;
  3253. StopAt: TPasElement): integer;
  3254. // if not found return number of overloads
  3255. // if found return index in overloads
  3256. var
  3257. El: TPasElement;
  3258. begin
  3259. Result:=0;
  3260. // iterate from last added to first added
  3261. // Note: the first added has Index=0
  3262. while Identifier<>nil do
  3263. begin
  3264. El:=Identifier.Element;
  3265. Identifier:=Identifier.NextSameIdentifier;
  3266. if El=StopAt then
  3267. Result:=0
  3268. else if HasOverloadIndex(El) then
  3269. inc(Result);
  3270. end;
  3271. end;
  3272. function TPas2JSResolver.GetOverloadAt(Identifier: TPasIdentifier;
  3273. var Index: integer): TPasIdentifier;
  3274. // if found Result<>nil and Index=0
  3275. // if not found Result=nil and Index is reduced by number of overloads
  3276. var
  3277. El: TPasElement;
  3278. CurIdent: TPasIdentifier;
  3279. Count: Integer;
  3280. begin
  3281. if Identifier=nil then exit(nil);
  3282. // Note: the Identifier chain is from last added to first added
  3283. // -> get length of chain
  3284. Count:=0;
  3285. CurIdent:=Identifier;
  3286. while CurIdent<>nil do
  3287. begin
  3288. El:=CurIdent.Element;
  3289. CurIdent:=CurIdent.NextSameIdentifier;
  3290. if HasOverloadIndex(El) then
  3291. inc(Count);
  3292. end;
  3293. if Count<=Index then
  3294. begin
  3295. // Index is not in this scope
  3296. dec(Index);
  3297. exit(nil);
  3298. end;
  3299. // Index is in this scope -> find it
  3300. CurIdent:=Identifier;
  3301. while CurIdent<>nil do
  3302. begin
  3303. if HasOverloadIndex(CurIdent.Element) then
  3304. begin
  3305. dec(Count);
  3306. if (Index=Count) then
  3307. begin
  3308. Index:=0;
  3309. Result:=CurIdent;
  3310. exit;
  3311. end;
  3312. end;
  3313. CurIdent:=CurIdent.NextSameIdentifier;
  3314. end;
  3315. end;
  3316. function TPas2JSResolver.GetOverloadIndex(El: TPasElement): integer;
  3317. var
  3318. i, j, MaxDepth: Integer;
  3319. Identifier: TPasIdentifier;
  3320. Scope: TPasIdentifierScope;
  3321. CurEl: TPasElement;
  3322. ThisChanged: Boolean;
  3323. ElevatedLocals: TPas2jsElevatedLocals;
  3324. begin
  3325. Result:=0;
  3326. //if SameText(El.Name,'ci') then writeln('TPas2JSResolver.GetOverloadIndex ',GetObjPath(El),' HasOverloadIndex=',HasOverloadIndex(El,true));
  3327. if not HasOverloadIndex(El,true) then exit;
  3328. ThisChanged:=false;
  3329. MaxDepth:=FOverloadScopes.Count-1;
  3330. for i:=MaxDepth downto 0 do
  3331. begin
  3332. Scope:=TPasIdentifierScope(FOverloadScopes[i]);
  3333. if Scope.ClassType=TPas2JSOverloadChgThisScope then
  3334. begin
  3335. ThisChanged:=true;
  3336. continue;
  3337. end;
  3338. if i<MaxDepth then
  3339. begin
  3340. // Reason for "if i<MaxDepth":
  3341. // Because the elevated locals have their index after their global scope
  3342. // and before the next deeper (local) scope
  3343. // check elevated locals
  3344. ElevatedLocals:=GetElevatedLocals(Scope);
  3345. //if SameText(El.Name,'ci') then writeln('TPas2JSResolver.GetOverloadIndex ',GetObjPath(El),' Scope.Element=',GetObjName(Scope.Element),' ',ElevatedLocals<>nil);
  3346. if ElevatedLocals<>nil then
  3347. begin
  3348. Identifier:=ElevatedLocals.Find(El.Name);
  3349. j:=0;
  3350. // add count or index
  3351. while Identifier<>nil do
  3352. begin
  3353. CurEl:=Identifier.Element;
  3354. Identifier:=Identifier.NextSameIdentifier;
  3355. if CurEl=El then
  3356. j:=0
  3357. else
  3358. inc(j);
  3359. end;
  3360. inc(Result,j);
  3361. end;
  3362. end;
  3363. if not ThisChanged then
  3364. begin
  3365. // add count or index of this scope
  3366. Identifier:=Scope.FindLocalIdentifier(El.Name);
  3367. inc(Result,GetOverloadIndex(Identifier,El));
  3368. end;
  3369. end;
  3370. if ThisChanged then exit;
  3371. // element in global scope
  3372. // -> add count or index of the external scope
  3373. Identifier:=FindExternalName(El.Name);
  3374. inc(Result,GetOverloadIndex(Identifier,El));
  3375. end;
  3376. function TPas2JSResolver.GetOverloadAt(const aName: String; Index: integer
  3377. ): TPasIdentifier;
  3378. var
  3379. i, MaxDepth: Integer;
  3380. Scope: TPasIdentifierScope;
  3381. Skip: Boolean;
  3382. ElevatedLocals: TPas2jsElevatedLocals;
  3383. begin
  3384. Result:=nil;
  3385. Skip:=false;
  3386. MaxDepth:=FOverloadScopes.Count-1;
  3387. for i:=MaxDepth downto 0 do
  3388. begin
  3389. // find last added
  3390. Scope:=TPasIdentifierScope(FOverloadScopes[i]);
  3391. if Scope.ClassType=TPas2JSOverloadChgThisScope then
  3392. begin
  3393. Skip:=true;
  3394. continue;
  3395. end;
  3396. if i<MaxDepth then
  3397. begin
  3398. // check elevated locals
  3399. // Note: the elevated locals are after the section scope and
  3400. // before the next deeper scope
  3401. ElevatedLocals:=GetElevatedLocals(Scope);
  3402. if ElevatedLocals<>nil then
  3403. begin
  3404. Result:=ElevatedLocals.Find(aName);
  3405. Result:=GetOverloadAt(Result,Index);
  3406. if Result<>nil then
  3407. exit;
  3408. end;
  3409. end;
  3410. if not Skip then
  3411. begin
  3412. Result:=Scope.FindLocalIdentifier(aName);
  3413. Result:=GetOverloadAt(Result,Index);
  3414. if Result<>nil then
  3415. exit;
  3416. end;
  3417. end;
  3418. if Skip then exit;
  3419. // find in external names
  3420. Result:=FindExternalName(aName);
  3421. Result:=GetOverloadAt(Result,Index);
  3422. end;
  3423. function TPas2JSResolver.GetElevatedLocals(Scope: TPasScope
  3424. ): TPas2jsElevatedLocals;
  3425. var
  3426. C: TClass;
  3427. begin
  3428. C:=Scope.ClassType;
  3429. if C=TPas2JSSectionScope then
  3430. Result:=TPas2JSSectionScope(Scope).ElevatedLocals
  3431. else if C=TPas2JSClassScope then
  3432. Result:=TPas2JSClassScope(Scope).ElevatedLocals
  3433. else
  3434. Result:=nil;
  3435. end;
  3436. function TPas2JSResolver.RenameOverload(El: TPasElement): boolean;
  3437. var
  3438. OverloadIndex: Integer;
  3439. function GetDuplicate: TPasElement;
  3440. var
  3441. Duplicate: TPasIdentifier;
  3442. begin
  3443. Duplicate:=GetOverloadAt(El.Name,0);
  3444. Result:=Duplicate.Element;
  3445. end;
  3446. var
  3447. NewName: String;
  3448. Duplicate: TPasElement;
  3449. ProcScope: TPas2JSProcedureScope;
  3450. begin
  3451. // => count overloads in this section
  3452. OverloadIndex:=GetOverloadIndex(El);
  3453. //if SameText(El.Name,'ci') then writeln('TPas2JSResolver.RenameOverload ',GetObjPath(El),' ',OverloadIndex);
  3454. if OverloadIndex=0 then
  3455. Result:=false // there is no overload
  3456. else
  3457. begin
  3458. if (El.ClassType=TPasClassFunction)
  3459. and (El.Parent.ClassType=TPasClassType)
  3460. and (TPas2JSClassScope(TPasClassType(El.Parent).CustomData).NewInstanceFunction=El) then
  3461. begin
  3462. Duplicate:=GetDuplicate;
  3463. RaiseMsg(20170324234324,nNewInstanceFunctionMustNotHaveOverloadAtX,
  3464. sNewInstanceFunctionMustNotHaveOverloadAtX,[GetElementSourcePosStr(Duplicate)],El);
  3465. end;
  3466. if El.Visibility=visPublished then
  3467. begin
  3468. Duplicate:=GetDuplicate;
  3469. RaiseMsg(20170413220924,nDuplicateIdentifier,sDuplicateIdentifier,
  3470. [Duplicate.Name,GetElementSourcePosStr(Duplicate)],El);
  3471. end;
  3472. NewName:=El.Name+'$'+IntToStr(OverloadIndex);
  3473. {$IFDEF VerbosePas2JS}
  3474. writeln('TPas2JSResolver.RenameOverload "',El.Name,'" has overload. NewName="',NewName,'"');
  3475. {$ENDIF}
  3476. if (El.CustomData is TPas2JSProcedureScope) then
  3477. begin
  3478. ProcScope:=TPas2JSProcedureScope(El.CustomData);
  3479. ProcScope.OverloadName:=NewName;
  3480. if ProcScope.DeclarationProc<>nil then
  3481. RaiseInternalError(20180322233222,GetElementDbgPath(El));
  3482. if ProcScope.ImplProc<>nil then
  3483. TPas2JSProcedureScope(ProcScope.ImplProc.CustomData).OverloadName:=NewName;
  3484. if ProcScope.SpecializedFromItem<>nil then
  3485. RenameSpecialized(ProcScope.SpecializedFromItem);
  3486. end
  3487. else
  3488. El.Name:=NewName;
  3489. Result:=true;
  3490. end;
  3491. end;
  3492. procedure TPas2JSResolver.RenameOverloadsInSection(aSection: TPasSection);
  3493. var
  3494. IntfSection: TInterfaceSection;
  3495. OldScopeCount: Integer;
  3496. Scope: TPas2JSSectionScope;
  3497. begin
  3498. if aSection=nil then exit;
  3499. Scope:=aSection.CustomData as TPas2JSSectionScope;
  3500. if Scope.Renamed then
  3501. RaiseNotYetImplemented(20200601231236,aSection);
  3502. IntfSection:=nil;
  3503. OldScopeCount:=FOverloadScopes.Count;
  3504. if aSection.ClassType=TImplementationSection then
  3505. begin
  3506. IntfSection:=RootElement.InterfaceSection;
  3507. PushOverloadScope(IntfSection.CustomData as TPasIdentifierScope);
  3508. end;
  3509. PushOverloadScope(aSection.CustomData as TPasIdentifierScope);
  3510. RenameOverloads(aSection,aSection.Declarations);
  3511. RenameSubOverloads(aSection.Declarations);
  3512. RestoreOverloadScopeLvl(OldScopeCount);
  3513. Scope.Renamed:=true;
  3514. {$IFDEF VerbosePas2JS}
  3515. //writeln('TPas2JSResolver.RenameOverloadsInSection END ',GetObjName(aSection));
  3516. {$ENDIF}
  3517. end;
  3518. procedure TPas2JSResolver.RenameOverloads(DeclEl: TPasElement;
  3519. Declarations: TFPList);
  3520. var
  3521. i: Integer;
  3522. El: TPasElement;
  3523. Proc: TPasProcedure;
  3524. ProcScope, OvrProcScope, ImplProcScope: TPas2JSProcedureScope;
  3525. C: TClass;
  3526. begin
  3527. //IsExternalClass:=(DeclEl is TPasClassType) and (TPasClassType(DeclEl).IsExternal);
  3528. if DeclEl=nil then;
  3529. for i:=0 to Declarations.Count-1 do
  3530. begin
  3531. El:=TPasElement(Declarations[i]);
  3532. C:=El.ClassType;
  3533. if C.InheritsFrom(TPasProcedure) then
  3534. begin
  3535. Proc:=TPasProcedure(El);
  3536. ProcScope:=Proc.CustomData as TPas2JSProcedureScope;
  3537. //writeln('TPas2JSResolver.RenameOverloads Proc=',Proc.Name,' DeclarationProc=',GetObjName(ProcScope.DeclarationProc),' ImplProc=',GetObjName(ProcScope.ImplProc),' ClassScope=',GetObjName(ProcScope.ClassOrRecordScope));
  3538. if ProcScope.DeclarationProc<>nil then
  3539. // DeclarationProc already propagates to ImplProc
  3540. continue
  3541. else if Proc.IsOverride then
  3542. begin
  3543. // override -> copy name from overridden proc
  3544. if ProcScope.OverriddenProc=nil then
  3545. RaiseInternalError(20171205183502);
  3546. OvrProcScope:=TPas2JSProcedureScope(ProcScope.OverriddenProc.CustomData);
  3547. if OvrProcScope.OverloadName<>'' then
  3548. begin
  3549. ProcScope.OverloadName:=OvrProcScope.OverloadName;
  3550. if ProcScope.ImplProc<>nil then
  3551. begin
  3552. ImplProcScope:=TPas2JSProcedureScope(ProcScope.ImplProc.CustomData);
  3553. ImplProcScope.OverloadName:=ProcScope.OverloadName;
  3554. ImplProcScope.JSName:=ProcScope.JSName;
  3555. end;
  3556. end;
  3557. continue;
  3558. end
  3559. else if Proc.IsExternal then
  3560. begin
  3561. // Note: Pascal names of external procs are not in the generated JS,
  3562. // so no need to rename them
  3563. continue;
  3564. end
  3565. else
  3566. begin
  3567. // proc declaration (header, not body)
  3568. RenameOverload(Proc);
  3569. end;
  3570. end
  3571. else if C.InheritsFrom(TPasType) then
  3572. begin
  3573. if El.Parent is TProcedureBody then
  3574. RenameOverload(El);
  3575. end
  3576. else if C=TPasConst then
  3577. RenameOverload(El)
  3578. else if C.InheritsFrom(TPasVariable) then
  3579. begin
  3580. // class fields can have name clashes, record fields cannot
  3581. if El.Parent.ClassType=TPasClassType then
  3582. RenameOverload(El);
  3583. end;
  3584. end;
  3585. {$IFDEF VerbosePas2JS}
  3586. //writeln('TPas2JSResolver.RenameOverloads END ',GetObjName(DeclEl));
  3587. {$ENDIF}
  3588. end;
  3589. procedure TPas2JSResolver.RenameSubOverloads(Declarations: TFPList);
  3590. var
  3591. i, OldScopeCount: Integer;
  3592. El: TPasElement;
  3593. Proc, ImplProc: TPasProcedure;
  3594. ProcScope, ImplProcScope: TPas2JSProcedureScope;
  3595. C: TClass;
  3596. ProcBody: TProcedureBody;
  3597. begin
  3598. for i:=0 to Declarations.Count-1 do
  3599. begin
  3600. El:=TPasElement(Declarations[i]);
  3601. C:=El.ClassType;
  3602. if C.InheritsFrom(TPasProcedure) then
  3603. begin
  3604. Proc:=TPasProcedure(El);
  3605. ProcScope:=Proc.CustomData as TPas2JSProcedureScope;
  3606. ImplProc:=ProcScope.ImplProc;
  3607. if ImplProc<>nil then
  3608. ImplProcScope:=TPas2JSProcedureScope(ImplProc.CustomData)
  3609. else
  3610. begin
  3611. ImplProc:=Proc;
  3612. ImplProcScope:=ProcScope;
  3613. end;
  3614. {$IFDEF VerbosePas2JS}
  3615. //writeln('TPas2JSResolver.RenameSubOverloads ImplProc=',ImplProc.Name,' DeclarationProc=',GetObjName(ProcScope.DeclarationProc),' ClassScope=',GetObjName(ImplProcScope.ClassOrRecordScope));
  3616. {$ENDIF}
  3617. ProcBody:=ImplProc.Body;
  3618. if (ProcBody<>nil) and (not ImplProcScope.BodyOverloadsRenamed) then
  3619. begin
  3620. ImplProcScope.BodyOverloadsRenamed:=true;
  3621. OldScopeCount:=FOverloadScopes.Count;
  3622. if (ImplProcScope.ClassRecScope<>nil)
  3623. and not (Proc.Parent is TPasMembersType) then
  3624. begin
  3625. // push class scopes
  3626. PushOverloadClassOrRecScopes(ImplProcScope.ClassRecScope,true);
  3627. end;
  3628. PushOverloadScope(ImplProcScope);
  3629. // first rename all overloads on this level
  3630. RenameOverloads(ProcBody,ProcBody.Declarations);
  3631. // then process nested procedures
  3632. RenameSubOverloads(ProcBody.Declarations);
  3633. PopOverloadScope;
  3634. RestoreOverloadScopeLvl(OldScopeCount);
  3635. end;
  3636. end
  3637. else if (C=TPasClassType) or (C=TPasRecordType) then
  3638. RenameMembers(TPasMembersType(El));
  3639. end;
  3640. {$IFDEF VerbosePas2JS}
  3641. //writeln('TPas2JSResolver.RenameSubOverloads END');
  3642. {$ENDIF}
  3643. end;
  3644. procedure TPas2JSResolver.RenameMembers(El: TPasMembersType);
  3645. var
  3646. OldScopeCount: Integer;
  3647. ClassEl: TPasClassType;
  3648. ClassOrRecScope: TPasClassOrRecordScope;
  3649. RecScope: TPas2JSRecordScope;
  3650. ClassScope: TPas2JSClassScope;
  3651. begin
  3652. OldScopeCount:=FOverloadScopes.Count;
  3653. if El.ClassType=TPasClassType then
  3654. begin
  3655. ClassEl:=TPasClassType(El);
  3656. if ClassEl.IsForward then exit;
  3657. // add class and ancestor scopes
  3658. ClassScope:=El.CustomData as TPas2JSClassScope;
  3659. if ClassScope.MemberOverloadsRenamed then exit;
  3660. ClassScope.MemberOverloadsRenamed:=true;
  3661. ClassOrRecScope:=ClassScope;
  3662. end
  3663. else
  3664. begin
  3665. // add record scope
  3666. RecScope:=El.CustomData as TPas2JSRecordScope;
  3667. if RecScope.MemberOverloadsRenamed then exit;
  3668. RecScope.MemberOverloadsRenamed:=true;
  3669. ClassOrRecScope:=RecScope;
  3670. end;
  3671. PushOverloadClassOrRecScopes(ClassOrRecScope,false);
  3672. // first rename all overloads on this level
  3673. RenameOverloads(El,El.Members);
  3674. // then process nested procedures
  3675. RenameSubOverloads(El.Members);
  3676. // restore scope
  3677. RestoreOverloadScopeLvl(OldScopeCount);
  3678. end;
  3679. procedure TPas2JSResolver.RenameSpecialized(SpecializedItem: TPRSpecializedItem
  3680. );
  3681. var
  3682. GenScope: TPasGenericScope;
  3683. NewName: String;
  3684. begin
  3685. if SpecializedItem=nil then exit;
  3686. NewName:=SpecializedItem.GenericEl.Name+'$G'+IntToStr(SpecializedItem.Index+1);
  3687. GenScope:=TPasGenericScope(SpecializedItem.SpecializedEl.CustomData);
  3688. if GenScope is TPas2JSClassScope then
  3689. TPas2JSClassScope(GenScope).JSName:=NewName
  3690. else if GenScope is TPas2JSRecordScope then
  3691. TPas2JSRecordScope(GenScope).JSName:=NewName
  3692. else if GenScope is TPas2JSArrayScope then
  3693. TPas2JSArrayScope(GenScope).JSName:=NewName
  3694. else if GenScope is TPas2JSProcTypeScope then
  3695. TPas2JSProcTypeScope(GenScope).JSName:=NewName
  3696. else if GenScope is TPas2JSProcedureScope then
  3697. // handled in GetOverloadName
  3698. else
  3699. RaiseNotYetImplemented(20200906203342,SpecializedItem.SpecializedEl,GetObjName(GenScope));
  3700. {$IFDEF VerbosePas2JS}
  3701. writeln('TPas2JSResolver.RenameSpecialized GenericEl=',GetObjPath(SpecializedItem.GenericEl),' Spec=',GetObjPath(SpecializedItem.SpecializedEl),' JSName="',NewName,'"');
  3702. {$ENDIF}
  3703. end;
  3704. procedure TPas2JSResolver.PushOverloadScopeSkip;
  3705. begin
  3706. FOverloadScopes.Add(TPas2JSOverloadChgThisScope.Create);
  3707. end;
  3708. procedure TPas2JSResolver.PushOverloadScope(Scope: TPasIdentifierScope);
  3709. begin
  3710. if (FOverloadScopes.Count>0) and (TObject(FOverloadScopes[FOverloadScopes.Count-1])=Scope) then
  3711. RaiseNotYetImplemented(20200602000045,Scope.Element);
  3712. FOverloadScopes.Add(Scope);
  3713. end;
  3714. function TPas2JSResolver.PushOverloadClassOrRecScopes(
  3715. Scope: TPasClassOrRecordScope; WithParents: boolean): integer;
  3716. var
  3717. CurScope: TPasClassOrRecordScope;
  3718. aParent: TPasElement;
  3719. begin
  3720. Result:=FOverloadScopes.Count;
  3721. repeat
  3722. PushOverloadScopeSkip;
  3723. // push class and ancestors
  3724. CurScope:=Scope;
  3725. repeat
  3726. PushOverloadScope(CurScope);
  3727. if CurScope is TPas2JSClassScope then
  3728. CurScope:=TPas2JSClassScope(CurScope).AncestorScope
  3729. else
  3730. break;
  3731. until CurScope=nil;
  3732. if not WithParents then
  3733. exit;
  3734. aParent:=Scope.Element.Parent;
  3735. if not (aParent is TPasMembersType) then
  3736. exit;
  3737. // nested class -> push parent class scope...
  3738. Scope:=aParent.CustomData as TPasClassOrRecordScope;
  3739. until false;
  3740. end;
  3741. procedure TPas2JSResolver.PopOverloadScope;
  3742. var
  3743. i: Integer;
  3744. Scope: TPasIdentifierScope;
  3745. begin
  3746. i:=FOverloadScopes.Count-1;
  3747. if i<0 then
  3748. RaiseInternalError(20200723125456);
  3749. Scope:=TPasIdentifierScope(FOverloadScopes[i]);
  3750. if Scope.ClassType=TPas2JSOverloadChgThisScope then
  3751. Scope.Free;
  3752. FOverloadScopes.Delete(i);
  3753. end;
  3754. procedure TPas2JSResolver.RestoreOverloadScopeLvl(OldScopeCount: integer);
  3755. begin
  3756. while FOverloadScopes.Count>OldScopeCount do
  3757. PopOverloadScope;
  3758. end;
  3759. procedure TPas2JSResolver.ClearOverloadScopes;
  3760. begin
  3761. if FOverloadScopes=nil then exit;
  3762. while FOverloadScopes.Count>0 do
  3763. PopOverloadScope;
  3764. FreeAndNil(FOverloadScopes);
  3765. end;
  3766. procedure TPas2JSResolver.AddType(El: TPasType);
  3767. begin
  3768. inherited AddType(El);
  3769. if El.Parent is TProcedureBody then
  3770. // local type
  3771. AddElevatedLocal(El);
  3772. end;
  3773. procedure TPas2JSResolver.AddRecordType(El: TPasRecordType; TypeParams: TFPList
  3774. );
  3775. begin
  3776. inherited;
  3777. if (El.Name='') and (El.Parent.ClassType<>TPasVariant) then
  3778. begin
  3779. {$IFDEF VerbosePas2JS}
  3780. writeln('TPas2JSResolver.AddRecordType ',GetObjName(El.Parent));
  3781. {$ENDIF}
  3782. RaiseNotYetImplemented(20190408224556,El,'anonymous record type');
  3783. end;
  3784. if El.Parent is TProcedureBody then
  3785. // local record
  3786. AddElevatedLocal(El);
  3787. end;
  3788. procedure TPas2JSResolver.AddRecordVariant(El: TPasVariant);
  3789. begin
  3790. RaiseMsg(20220323145350,nNotSupportedX,sNotSupportedX,['variant record'],El);
  3791. end;
  3792. procedure TPas2JSResolver.AddClassType(El: TPasClassType; TypeParams: TFPList);
  3793. begin
  3794. inherited AddClassType(El,TypeParams);
  3795. end;
  3796. procedure TPas2JSResolver.AddEnumType(El: TPasEnumType);
  3797. begin
  3798. inherited AddEnumType(El);
  3799. if El.Parent is TProcedureBody then
  3800. // local enum type
  3801. AddElevatedLocal(El);
  3802. end;
  3803. procedure TPas2JSResolver.ResolveImplAsm(El: TPasImplAsmStatement);
  3804. {type
  3805. TAsmToken = (
  3806. atNone,
  3807. atWord,
  3808. atDot,
  3809. atRoundBracketOpen,
  3810. atRoundBracketClose
  3811. );
  3812. procedure Next;
  3813. begin
  3814. end;}
  3815. var
  3816. Lines: TStrings;
  3817. begin
  3818. Lines:=El.Tokens;
  3819. if Lines=nil then exit;
  3820. // ToDo: resolve explicit references
  3821. end;
  3822. procedure TPas2JSResolver.ResolveNameExpr(El: TPasExpr; const aName: string;
  3823. Access: TResolvedRefAccess);
  3824. procedure CheckTObjectFree(Ref: TResolvedReference);
  3825. // Ref is the ComputeElement of El
  3826. var
  3827. Bin: TBinaryExpr;
  3828. Left: TPasExpr;
  3829. LeftResolved: TPasResolverResult;
  3830. IdentEl: TPasElement;
  3831. C: TClass;
  3832. begin
  3833. if not IsTObjectFreeMethod(El) then exit;
  3834. // El is the TPrimitiveExpr of "Free"
  3835. if Ref.WithExprScope<>nil then
  3836. begin
  3837. // with expr do free
  3838. if GetNewInstanceExpr(Ref.WithExprScope.Expr)<>nil then
  3839. exit; // with TSomeClass.Create do Free -> ok
  3840. RaiseMsg(20170517092407,nFreeNeedsVar,sFreeNeedsVar,[],El);
  3841. end;
  3842. C:=El.Parent.ClassType;
  3843. if (C=TBinaryExpr) then
  3844. begin
  3845. Bin:=TBinaryExpr(El.Parent);
  3846. if (Bin.right<>El) or (Bin.OpCode<>eopSubIdent) then
  3847. RaiseMsg(20170516151950,nFreeNeedsVar,sFreeNeedsVar,[],El);
  3848. // expr.Free
  3849. if rrfImplicitCallWithoutParams in Ref.Flags then
  3850. // ".Free;" -> ok
  3851. else if Bin.Parent is TParamsExpr then
  3852. begin
  3853. if Bin.Parent.Parent is TPasExpr then
  3854. RaiseMsg(20170516161345,nFreeNeedsVar,sFreeNeedsVar,[],El);
  3855. // ".Free();" -> ok
  3856. end
  3857. else if Bin.Parent is TPasImplElement then
  3858. // ok
  3859. else
  3860. begin
  3861. {$IFDEF VerbosePas2JS}
  3862. writeln('TPas2JSResolver.ResolveNameExpr.CheckTObjectFree Bin.Parent=',GetObjName(Bin.Parent));
  3863. {$ENDIF}
  3864. RaiseMsg(20170516160347,nFreeNeedsVar,sFreeNeedsVar,[],El);
  3865. end;
  3866. Left:=Bin.left;
  3867. ComputeElement(Left,LeftResolved,[]);
  3868. if not (rrfReadable in LeftResolved.Flags) then
  3869. RaiseMsg(20170516152300,nFreeNeedsVar,sFreeNeedsVar,[],El);
  3870. if not (rrfWritable in LeftResolved.Flags) then
  3871. RaiseMsg(20170516152307,nFreeNeedsVar,sFreeNeedsVar,[],El);
  3872. IdentEl:=LeftResolved.IdentEl;
  3873. if IdentEl=nil then
  3874. RaiseMsg(20170516152401,nFreeNeedsVar,sFreeNeedsVar,[],El);
  3875. if IdentEl.ClassType=TPasArgument then
  3876. exit; // readable and writable argument -> ok
  3877. if (IdentEl.ClassType=TPasVariable)
  3878. or (IdentEl.ClassType=TPasConst) then
  3879. exit; // readable and writable variable -> ok
  3880. if (IdentEl.ClassType=TPasResultElement)
  3881. and (Left is TPrimitiveExpr) then
  3882. begin
  3883. // "Result.Free" -> ok
  3884. exit;
  3885. end;
  3886. {$IFDEF VerbosePas2JS}
  3887. writeln('CheckTObjectFree LeftResolved=',GetResolverResultDbg(LeftResolved));
  3888. {$ENDIF}
  3889. RaiseMsg(20170516152455,nFreeNeedsVar,sFreeNeedsVar,[],El);
  3890. end
  3891. else if C.InheritsFrom(TPasImplBlock) then
  3892. begin
  3893. // e.g. "begin Free end;" OR "if expr then Free;" -> ok
  3894. exit;
  3895. end;
  3896. RaiseMsg(20170516152454,nFreeNeedsVar,sFreeNeedsVar,[],El);
  3897. end;
  3898. procedure CheckResultEl(Ref: TResolvedReference);
  3899. // Ref.Declaration is TPasResultElement
  3900. var
  3901. CurEl: TPasElement;
  3902. Lvl: Integer;
  3903. ProcScope, CurProcScope: TPas2JSProcedureScope;
  3904. FuncType: TPasFunctionType;
  3905. begin
  3906. // result refers to a function result
  3907. // -> check if it is referring to a parent function result
  3908. Lvl:=0;
  3909. CurEl:=El;
  3910. CurProcScope:=nil;
  3911. while CurEl<>nil do
  3912. begin
  3913. if (CurEl is TPasProcedure)
  3914. and (TPasProcedure(CurEl).ProcType is TPasFunctionType) then
  3915. begin
  3916. inc(Lvl);
  3917. if not (CurEl.CustomData is TPas2JSProcedureScope) then
  3918. RaiseInternalError(20181210231858);
  3919. ProcScope:=TPas2JSProcedureScope(CurEl.CustomData);
  3920. if ProcScope.DeclarationProc is TPasFunction then
  3921. FuncType:=TPasFunctionType(ProcScope.DeclarationProc.ProcType)
  3922. else
  3923. FuncType:=TPasFunctionType(TPasProcedure(CurEl).ProcType);
  3924. if Lvl=1 then
  3925. begin
  3926. // current function (where the statement of El is)
  3927. if (FuncType.ResultEl=Ref.Declaration) then
  3928. exit; // accessing current function -> ok
  3929. // accessing Result variable of higher function -> need rename
  3930. // Note: ProcScope.ResultVarName only valid in implementation ProcScope
  3931. if ProcScope.ResultVarName<>'' then
  3932. exit; // is already renamed
  3933. CurProcScope:=ProcScope;
  3934. end;
  3935. end;
  3936. CurEl:=CurEl.Parent;
  3937. end;
  3938. if Lvl<2 then
  3939. RaiseNotYetImplemented(20171003112020,El);
  3940. // El refers to a higher Result variable
  3941. // -> current function needs another name for its Result variable
  3942. CurProcScope.ResultVarName:=ResolverResultVar+'$'+IntToStr(Lvl-1);
  3943. end;
  3944. var
  3945. Ref: TResolvedReference;
  3946. begin
  3947. inherited ResolveNameExpr(El, aName, Access);
  3948. if El.CustomData is TResolvedReference then
  3949. begin
  3950. Ref:=TResolvedReference(El.CustomData);
  3951. if (CompareText(aName,'free')=0) then
  3952. CheckTObjectFree(Ref)
  3953. else if (Ref.Declaration is TPasResultElement) then
  3954. CheckResultEl(Ref)
  3955. else if IsExternalClassConstructor(Ref.Declaration) then
  3956. CheckExternalClassConstructor(Ref);
  3957. end;
  3958. end;
  3959. procedure TPas2JSResolver.ResolveFuncParamsExpr(Params: TParamsExpr;
  3960. Access: TResolvedRefAccess);
  3961. var
  3962. Value: TPasExpr;
  3963. Ref: TResolvedReference;
  3964. begin
  3965. inherited ResolveFuncParamsExpr(Params, Access);
  3966. Value:=Params.Value;
  3967. if Value.CustomData is TResolvedReference then
  3968. begin
  3969. Ref:=TResolvedReference(Value.CustomData);
  3970. if IsExternalClassConstructor(Ref.Declaration) then
  3971. CheckExternalClassConstructor(Ref);
  3972. end;
  3973. end;
  3974. procedure TPas2JSResolver.FinishInterfaceSection(Section: TPasSection);
  3975. begin
  3976. inherited FinishInterfaceSection(Section);
  3977. if FOverloadScopes=nil then
  3978. begin
  3979. FOverloadScopes:=TFPList.Create;
  3980. RenameOverloadsInSection(Section);
  3981. end;
  3982. end;
  3983. procedure TPas2JSResolver.FinishTypeSectionEl(El: TPasType);
  3984. var
  3985. C: TClass;
  3986. TypeEl: TPasType;
  3987. begin
  3988. inherited FinishTypeSectionEl(El);
  3989. C:=El.ClassType;
  3990. if C=TPasPointerType then
  3991. begin
  3992. TypeEl:=ResolveAliasType(TPasPointerType(El).DestType);
  3993. if TypeEl.ClassType=TPasRecordType then
  3994. // ^record
  3995. else
  3996. RaiseMsg(20180423105726,nNotSupportedX,sNotSupportedX,['pointer of '+TPasPointerType(El).DestType.Name],El);
  3997. end;
  3998. end;
  3999. procedure TPas2JSResolver.FinishModule(CurModule: TPasModule);
  4000. var
  4001. ModuleClass: TClass;
  4002. begin
  4003. inherited FinishModule(CurModule);
  4004. if FOverloadScopes=nil then
  4005. FOverloadScopes:=TFPList.Create;
  4006. try
  4007. ModuleClass:=CurModule.ClassType;
  4008. if ModuleClass=TPasModule then
  4009. RenameOverloadsInSection(CurModule.ImplementationSection)
  4010. else if ModuleClass=TPasProgram then
  4011. RenameOverloadsInSection(TPasProgram(CurModule).ProgramSection)
  4012. else if CurModule.ClassType=TPasLibrary then
  4013. RenameOverloadsInSection(TPasLibrary(CurModule).LibrarySection)
  4014. else
  4015. RaiseNotYetImplemented(20170221000032,CurModule);
  4016. finally
  4017. ClearOverloadScopes;
  4018. end;
  4019. end;
  4020. procedure TPas2JSResolver.FinishEnumType(El: TPasEnumType);
  4021. var
  4022. i: Integer;
  4023. EnumValue: TPasEnumValue;
  4024. begin
  4025. inherited FinishEnumType(El);
  4026. for i:=0 to El.Values.Count-1 do
  4027. begin
  4028. EnumValue:=TPasEnumValue(El.Values[i]);
  4029. if EnumValue.Value<>nil then
  4030. RaiseNotYetImplemented(20180126202434,EnumValue,'enum const');
  4031. end;
  4032. end;
  4033. procedure TPas2JSResolver.FinishSetType(El: TPasSetType);
  4034. var
  4035. TypeEl: TPasType;
  4036. C: TClass;
  4037. RangeValue: TResEvalValue;
  4038. bt: TResolverBaseType;
  4039. begin
  4040. inherited FinishSetType(El);
  4041. TypeEl:=ResolveAliasType(El.EnumType);
  4042. C:=TypeEl.ClassType;
  4043. if C=TPasEnumType then
  4044. exit
  4045. else if C=TPasUnresolvedSymbolRef then
  4046. begin
  4047. if TypeEl.CustomData is TResElDataBaseType then
  4048. begin
  4049. bt:=TResElDataBaseType(TypeEl.CustomData).BaseType;
  4050. if bt in [btBoolean,btByte,btShortInt,btSmallInt,btWord,btChar,btWideChar] then
  4051. exit; // ok
  4052. {$IFDEF VerbosePas2JS}
  4053. writeln('TPas2JSResolver.FinishSetType El='+GetObjName(El)+' TypeEl=',GetObjName(TypeEl),' ',bt);
  4054. {$ENDIF}
  4055. RaiseMsg(20171110150000,nNotSupportedX,sNotSupportedX,['set of '+TypeEl.Name],El);
  4056. end;
  4057. end
  4058. else if C=TPasRangeType then
  4059. begin
  4060. RangeValue:=Eval(TPasRangeType(TypeEl).RangeExpr,[refConst]);
  4061. try
  4062. case RangeValue.Kind of
  4063. revkRangeInt:
  4064. begin
  4065. if TResEvalRangeInt(RangeValue).RangeEnd-TResEvalRangeInt(RangeValue).RangeStart>$ffff then
  4066. begin
  4067. {$IFDEF VerbosePas2JS}
  4068. writeln('TPas2JSResolver.FinishSetType El='+GetObjName(El)+' Range='+RangeValue.AsDebugString,' ',bt);
  4069. {$ENDIF}
  4070. RaiseMsg(20171110150159,nNotSupportedX,sNotSupportedX,['set of '+TypeEl.Name],El);
  4071. end;
  4072. exit;
  4073. end;
  4074. else
  4075. begin
  4076. {$IFDEF VerbosePas2JS}
  4077. writeln('TPas2JSResolver.FinishSetType El='+GetObjName(El)+' Range='+RangeValue.AsDebugString);
  4078. {$ENDIF}
  4079. RaiseMsg(20171110145211,nNotSupportedX,sNotSupportedX,['set of '+TypeEl.Name],El);
  4080. end;
  4081. end;
  4082. finally
  4083. ReleaseEvalValue(RangeValue);
  4084. end;
  4085. end;
  4086. {$IFDEF VerbosePas2JS}
  4087. writeln('TPas2JSResolver.FinishSetType El='+GetObjName(El)+' TypeEl=',GetObjName(TypeEl));
  4088. {$ENDIF}
  4089. RaiseMsg(20170415182320,nNotSupportedX,sNotSupportedX,['set of '+TypeEl.Name],El);
  4090. end;
  4091. procedure TPas2JSResolver.FinishRecordType(El: TPasRecordType);
  4092. begin
  4093. if (El.Variants<>nil) and (El.Variants.Count>0) then
  4094. RaiseMsg(20180104205309,nXIsNotSupported,sXIsNotSupported,['variant record'],TPasElement(El.Variants[0]));
  4095. inherited FinishRecordType(El);
  4096. end;
  4097. procedure TPas2JSResolver.FinishClassType(El: TPasClassType);
  4098. var
  4099. Scope, CurScope: TPas2JSClassScope;
  4100. Value: TResEvalValue;
  4101. begin
  4102. inherited FinishClassType(El);
  4103. if El.IsExternal then
  4104. begin
  4105. if El.ExternalName='' then
  4106. RaiseMsg(20170321151109,nMissingExternalName,sMissingExternalName,[],El);
  4107. AddExternalPath(El.ExternalName,El);
  4108. if El.RTTIVisibility.Fields<>[] then
  4109. RaiseNotYetImplemented(20250103153804,El,'RTTI for external class');
  4110. if El.RTTIVisibility.Methods<>[] then
  4111. RaiseNotYetImplemented(20250103153905,El,'RTTI for external class');
  4112. if El.RTTIVisibility.Properties<>[] then
  4113. RaiseNotYetImplemented(20250103153913,El,'RTTI for external class');
  4114. end;
  4115. if El.IsPacked then
  4116. RaiseMsg(20180326155616,nPasElementNotSupported,sPasElementNotSupported,
  4117. ['packed'],El);
  4118. if El.IsForward then
  4119. exit;
  4120. //writeln('TPas2JSResolver.FinishClassType START ',GetObjName(El));
  4121. Scope:=El.CustomData as TPas2JSClassScope;
  4122. case El.ObjKind of
  4123. okInterface:
  4124. begin
  4125. if not (El.InterfaceType in [citCom,citCorba]) then
  4126. RaiseMsg(20180326155612,nPasElementNotSupported,sPasElementNotSupported,
  4127. [InterfaceTypeNames[El.InterfaceType]],El);
  4128. if El.GUIDExpr<>nil then
  4129. begin
  4130. Value:=Eval(El.GUIDExpr,[refConst]);
  4131. try
  4132. case Value.Kind of
  4133. {$IFDEF FPC_HAS_CPSTRING}
  4134. revkString:
  4135. Scope.GUID:=TResEvalString(Value).S;
  4136. revkUnicodeString:
  4137. Scope.GUID:=UTF8Encode(TResEvalUTF16(Value).S);
  4138. {$ELSE}
  4139. revkUnicodeString:
  4140. Scope.GUID:=TResEvalUTF16(Value).S;
  4141. {$ENDIF}
  4142. else
  4143. RaiseXExpectedButYFound(20180326160602,'string literal',El.GUIDExpr.ElementTypeName,El.GUIDExpr);
  4144. end;
  4145. // test format?
  4146. finally
  4147. ReleaseEvalValue(Value);
  4148. end;
  4149. end
  4150. else
  4151. begin
  4152. // autogenerate GUID
  4153. Scope.GUID:=GenerateGUID(El);
  4154. end;
  4155. CurScope:=Scope;
  4156. repeat
  4157. CurScope:=TPas2JSClassScope(CurScope.AncestorScope);
  4158. if CurScope=nil then break;
  4159. if SameText(CurScope.GUID,Scope.GUID) then
  4160. RaiseMsg(20180330232206,nDuplicateGUIDXInYZ,sDuplicateGUIDXInYZ,
  4161. [Scope.GUID,El.Name,CurScope.Element.Name],El);
  4162. until false;
  4163. end;
  4164. end;
  4165. // clear MsgXToProc lists, they are created in ConvertClassType only for the needed procs
  4166. FreeAndNil(Scope.MsgIntToProc);
  4167. FreeAndNil(Scope.MsgStrToProc);
  4168. //writeln('TPas2JSResolver.FinishClassType END ',GetObjName(El));
  4169. end;
  4170. procedure TPas2JSResolver.FinishArrayType(El: TPasArrayType);
  4171. var
  4172. ElType: TPasType;
  4173. begin
  4174. inherited FinishArrayType(El);
  4175. ElType:=ResolveAliasType(El.ElType);
  4176. if IsManagedJSType(ElType) then
  4177. begin
  4178. if length(El.Ranges)>0 then
  4179. RaiseMsg(20250623180523,nNotSupportedX,sNotSupportedX,['static array of COM-interface'],El);
  4180. if El.CustomData=nil then
  4181. CreateScope(El,ScopeClass_Array);
  4182. (El.CustomData as TPas2JSArrayScope).Managed:=true;
  4183. end;
  4184. end;
  4185. procedure TPas2JSResolver.FinishAncestors(aClass: TPasClassType);
  4186. var
  4187. IntfList: TFPList;
  4188. i, j: Integer;
  4189. Scope, IntfScope: TPas2JSClassScope;
  4190. IntfType, OrigIntfType: TPasType;
  4191. GUIDs: TStringList;
  4192. begin
  4193. inherited FinishAncestors(aClass);
  4194. if aClass.Parent is TPasRecordType then
  4195. begin
  4196. if not (aClass.ObjKind in ([okClass]+okAllHelpers)) then
  4197. RaiseNotYetImplemented(20190105143752,aClass,GetElementTypeName(aClass)+' inside record');
  4198. end;
  4199. Scope:=TPas2JSClassScope(aClass.CustomData);
  4200. if Scope=nil then exit;
  4201. Scope.DispatchField:=CurrentParser.Scanner.CurrentValueSwitch[vsDispatchField];
  4202. Scope.DispatchStrField:=CurrentParser.Scanner.CurrentValueSwitch[vsDispatchStrField];
  4203. IntfList:=aClass.Interfaces;
  4204. GUIDs:=TStringList.Create;
  4205. try
  4206. for i:=0 to IntfList.Count-1 do
  4207. begin
  4208. OrigIntfType:=TPasType(IntfList[i]);
  4209. IntfType:=ResolveAliasType(OrigIntfType);
  4210. IntfScope:=TPas2JSClassScope(IntfType.CustomData);
  4211. j:=GUIDs.IndexOf(IntfScope.GUID);
  4212. if j>=0 then
  4213. RaiseMsg(20180330231220,nDuplicateGUIDXInYZ,sDuplicateGUIDXInYZ,
  4214. [IntfScope.GUID,OrigIntfType.Name,TpasElement(GUIDs.Objects[j]).Name],aClass); // ToDo: jump to interface expr
  4215. GUIDs.AddObject(IntfScope.GUID,OrigIntfType);
  4216. end;
  4217. finally
  4218. GUIDs.Free;
  4219. end;
  4220. end;
  4221. procedure TPas2JSResolver.FinishVariable(El: TPasVariable);
  4222. const
  4223. ClassFieldModifiersAllowed = [vmClass,vmStatic,vmExternal,vmPublic];
  4224. RecordVarModifiersAllowed = [vmClass,vmStatic,vmExternal,vmPublic];
  4225. LocalVarModifiersAllowed = [];
  4226. ImplementationVarModifiersAllowed = [vmExternal];
  4227. SectionVarModifiersAllowed = [vmExternal,vmPublic];
  4228. procedure RaiseVarModifierNotSupported(const Allowed: TVariableModifiers);
  4229. var
  4230. s: String;
  4231. m: TVariableModifier;
  4232. begin
  4233. s:='';
  4234. for m in TVariableModifiers do
  4235. if (m in El.VarModifiers) and not (m in Allowed) then
  4236. begin
  4237. str(m,s);
  4238. RaiseMsg(20170322134418,nInvalidVariableModifier,
  4239. sInvalidVariableModifier,[VariableModifierNames[m]],El);
  4240. end;
  4241. end;
  4242. var
  4243. ExtName: String;
  4244. ParentC: TClass;
  4245. AbsExpr: TPasExpr;
  4246. ResolvedAbsol: TPasResolverResult;
  4247. AbsIdent: TPasElement;
  4248. TypeEl, ElTypeEl: TPasType;
  4249. GUID: TGUID;
  4250. begin
  4251. inherited FinishVariable(El);
  4252. ParentC:=El.Parent.ClassType;
  4253. if El.AbsoluteExpr<>nil then
  4254. begin
  4255. // check 'absolute' alias
  4256. if vmExternal in El.VarModifiers then
  4257. RaiseMsg(20171226105002,nXModifierMismatchY,sXModifierMismatchY,
  4258. ['absolute','external'],El.AbsoluteExpr);
  4259. AbsExpr:=El.AbsoluteExpr;
  4260. ComputeElement(AbsExpr,ResolvedAbsol,[rcNoImplicitProc]);
  4261. AbsIdent:=ResolvedAbsol.IdentEl;
  4262. if ParentC=TProcedureBody then
  4263. begin
  4264. // local var
  4265. if (AbsIdent.Parent is TProcedureBody)
  4266. or (AbsIdent is TPasArgument)
  4267. or (AbsIdent is TPasResultElement) then
  4268. // ok
  4269. else
  4270. begin
  4271. {$IFDEF VerbosePas2JS}
  4272. writeln('TPas2JSResolver.FinishVariable absolute: El.Parent=',GetObjName(El.Parent),'.Parent=',GetObjName(El.Parent.Parent),' AbsParent=',GetObjName(AbsIdent.Parent),'.Parent=',GetObjName(AbsIdent.Parent.Parent));
  4273. {$ENDIF}
  4274. RaiseMsg(20171226102424,nInvalidAbsoluteLocation,sInvalidAbsoluteLocation,[],El.AbsoluteExpr);
  4275. end;
  4276. end
  4277. else
  4278. begin
  4279. RaiseMsg(20170728133340,nInvalidVariableModifier,
  4280. sInvalidVariableModifier,['absolute'],El);
  4281. end;
  4282. end;
  4283. if (ParentC=TPasClassType) then
  4284. begin
  4285. // class member
  4286. RaiseVarModifierNotSupported(ClassFieldModifiersAllowed);
  4287. if TPasClassType(El.Parent).IsExternal then
  4288. begin
  4289. // external class
  4290. if El.Visibility=visPublished then
  4291. // Note: an external class has no typeinfo
  4292. RaiseMsg(20170413221516,nSymbolCannotBePublished,sSymbolCannotBePublished,
  4293. [],El);
  4294. if not (vmExternal in El.VarModifiers) then
  4295. begin
  4296. // make variable external
  4297. if (El.ClassType=TPasVariable) or (El.ClassType=TPasConst) then
  4298. begin
  4299. if El.ExportName<>nil then
  4300. RaiseMsg(20170322134321,nInvalidVariableModifier,
  4301. sInvalidVariableModifier,['export name'],El.ExportName);
  4302. El.ExportName:=TPrimitiveExpr.Create(El,pekString,''''+El.Name+'''');
  4303. FOwnedElements.Add(El.ExportName);
  4304. end;
  4305. Include(El.VarModifiers,vmExternal);
  4306. end;
  4307. if (El.ClassType=TPasConst) and (TPasConst(El).Expr<>nil) then
  4308. // external const with expression is not writable
  4309. TPasConst(El).IsConst:=true;
  4310. end;
  4311. end
  4312. else if ParentC=TPasRecordType then
  4313. begin
  4314. // record member
  4315. RaiseVarModifierNotSupported(RecordVarModifiersAllowed);
  4316. if IsManagedJSType(El.VarType) then
  4317. RaiseMsg(20180404135105,nNotSupportedX,sNotSupportedX,['COM-interface as record member'],El);
  4318. if (El.ClassType=TPasConst) and (TPasConst(El).Expr<>nil)
  4319. and (vmExternal in TPasConst(El).VarModifiers) then
  4320. // external const with expression is not writable
  4321. TPasConst(El).IsConst:=true;
  4322. end
  4323. else if ParentC=TProcedureBody then
  4324. begin
  4325. // local var
  4326. RaiseVarModifierNotSupported(LocalVarModifiersAllowed);
  4327. if El.ClassType=TPasConst then
  4328. begin
  4329. // local const. Can be writable!
  4330. AddElevatedLocal(El);
  4331. end;
  4332. end
  4333. else if ParentC=TPasImplExceptOn then
  4334. // except on var
  4335. RaiseVarModifierNotSupported(LocalVarModifiersAllowed)
  4336. else if ParentC=TImplementationSection then
  4337. // implementation var
  4338. RaiseVarModifierNotSupported(ImplementationVarModifiersAllowed)
  4339. else if ParentC.InheritsFrom(TPasSection) then
  4340. begin
  4341. // interface/program/library var
  4342. RaiseVarModifierNotSupported(SectionVarModifiersAllowed);
  4343. end
  4344. else
  4345. begin
  4346. {$IFDEF VerbosePas2JS}
  4347. writeln('TPas2JSResolver.FinishVariable ',GetObjPath(El));
  4348. {$ENDIF}
  4349. RaiseNotYetImplemented(20170324151259,El);
  4350. end;
  4351. if vmExternal in El.VarModifiers then
  4352. begin
  4353. // compute constant
  4354. if El.LibraryName<>nil then
  4355. RaiseMsg(20170227094227,nPasElementNotSupported,sPasElementNotSupported,
  4356. ['library'],El.ExportName);
  4357. if El.ExportName=nil then
  4358. RaiseMsg(20170227100750,nMissingExternalName,sMissingExternalName,[],El);
  4359. ExtName:=ComputeConstString(El.ExportName,true,true);
  4360. if (El.Visibility=visPublished) and (ExtName<>El.Name) then
  4361. RaiseMsg(20170407002940,nPublishedNameMustMatchExternal,
  4362. sPublishedNameMustMatchExternal,[],El.ExportName);
  4363. // add external name to FExternalNames
  4364. if (El.Parent is TPasSection)
  4365. or ((El.ClassType=TPasConst) and (El.Parent is TPasProcedure)) then
  4366. AddExternalPath(ExtName,El.ExportName);
  4367. end;
  4368. if El.VarType<>nil then
  4369. begin
  4370. TypeEl:=ResolveAliasType(El.VarType);
  4371. if TypeEl.ClassType=TPasPointerType then
  4372. begin
  4373. ElTypeEl:=ResolveAliasType(TPasPointerType(TypeEl).DestType);
  4374. if ElTypeEl.ClassType=TPasRecordType then
  4375. // ^record
  4376. else
  4377. RaiseMsg(20180423110113,nNotSupportedX,sNotSupportedX,['pointer'],El);
  4378. end;
  4379. if El.Expr<>nil then
  4380. begin
  4381. if IsManagedJSType(TypeEl) then
  4382. begin
  4383. if El.Expr is TNilExpr then
  4384. // ok
  4385. else
  4386. RaiseMsg(20250623135850,nNotSupportedX,sNotSupportedX,['initial value of managed type'],El.Expr);
  4387. end;
  4388. if (TypeEl.ClassType=TPasRecordType) then
  4389. begin
  4390. if GetAssignGUIDString(TPasRecordType(TypeEl),El.Expr,GUID) then
  4391. // e.g. IObjectInstance: TGuid = '{D91C9AF4-3C93-420F-A303-BF5BA82BFD23}'
  4392. else
  4393. ;
  4394. end;
  4395. end;
  4396. end;
  4397. end;
  4398. procedure TPas2JSResolver.FinishArgument(El: TPasArgument);
  4399. var
  4400. TypeEl, ElTypeEl: TPasType;
  4401. C: TClass;
  4402. begin
  4403. inherited FinishArgument(El);
  4404. if El.ArgType<>nil then
  4405. begin
  4406. TypeEl:=ResolveAliasType(El.ArgType);
  4407. C:=TypeEl.ClassType;
  4408. if C=TPasPointerType then
  4409. begin
  4410. ElTypeEl:=ResolveAliasType(TPasPointerType(TypeEl).DestType);
  4411. if ElTypeEl.ClassType=TPasRecordType then
  4412. // ^record
  4413. else
  4414. RaiseMsg(20180423110239,nNotSupportedX,sNotSupportedX,['pointer'],El);
  4415. end;
  4416. if El.Access=argConstRef then
  4417. begin
  4418. if (C=TPasRecordType) or (C=TPasArrayType) then
  4419. // argConstRef works same as argConst for records -> ok
  4420. else
  4421. LogMsg(20191215133912,mtWarning,nConstRefNotForXAsConst,sConstRefNotForXAsConst,
  4422. [GetElementTypeName(TypeEl)],El);
  4423. end;
  4424. end;
  4425. end;
  4426. procedure TPas2JSResolver.FinishProcedureType(El: TPasProcedureType);
  4427. var
  4428. Proc: TPasProcedure;
  4429. pm: TProcedureModifier;
  4430. ExtName: String;
  4431. C: TClass;
  4432. AClassOrRec: TPasMembersType;
  4433. ClassOrRecScope: TPasClassOrRecordScope;
  4434. AClass: TPasClassType;
  4435. ClassScope: TPas2JSClassScope;
  4436. ptm: TProcTypeModifier;
  4437. TypeEl, ElTypeEl, HelperForType: TPasType;
  4438. FuncType: TPasFunctionType;
  4439. begin
  4440. inherited FinishProcedureType(El);
  4441. if El is TPasFunctionType then
  4442. begin
  4443. FuncType:=TPasFunctionType(El);
  4444. if FuncType.ResultEl<>nil then
  4445. begin
  4446. TypeEl:=ResolveAliasType(FuncType.ResultEl.ResultType);
  4447. if TypeEl.ClassType=TPasPointerType then
  4448. begin
  4449. ElTypeEl:=ResolveAliasType(TPasPointerType(TypeEl).DestType);
  4450. if ElTypeEl.ClassType=TPasRecordType then
  4451. // ^record
  4452. else
  4453. RaiseMsg(20180423110824,nNotSupportedX,sNotSupportedX,['pointer'],El);
  4454. end;
  4455. end;
  4456. end;
  4457. if El.Parent is TPasProcedure then
  4458. begin
  4459. Proc:=TPasProcedure(El.Parent);
  4460. // calling convention
  4461. if El.CallingConvention<>ccDefault then
  4462. RaiseMsg(20170211214731,nNotSupportedX,sNotSupportedX,
  4463. [cCallingConventions[El.CallingConvention]],Proc);
  4464. for pm in Proc.Modifiers do
  4465. if (not (pm in [pmVirtual, pmAbstract, pmOverride,
  4466. pmOverload, pmMessage, pmReintroduce,
  4467. pmInline, pmAssembler, pmPublic,
  4468. pmExternal, pmForward])) then
  4469. RaiseNotYetImplemented(20170208142159,El,'modifier '+ModifierNames[pm]);
  4470. for ptm in Proc.ProcType.Modifiers do
  4471. if (not (ptm in [ptmOfObject,ptmVarargs,ptmStatic,ptmAsync])) then
  4472. RaiseNotYetImplemented(20170411171454,El,'modifier '+ProcTypeModifiers[ptm]);
  4473. // check pmPublic
  4474. if [pmPublic,pmExternal]<=Proc.Modifiers then
  4475. RaiseMsg(20170324150149,nInvalidXModifierY,
  4476. sInvalidXModifierY,[Proc.ElementTypeName,'public, external'],Proc);
  4477. if (Proc.PublicName<>nil) then
  4478. RaiseMsg(20170324150417,nPasElementNotSupported,sPasElementNotSupported,
  4479. ['public name'],Proc.PublicName);
  4480. // modifier dispid
  4481. if Proc.DispIDExpr<>nil then
  4482. RaiseMsg(20190303225224,nPasElementNotSupported,sPasElementNotSupported,
  4483. ['dispid'],Proc.DispIDExpr);
  4484. // modifier message
  4485. if Proc.MessageExpr<>nil then
  4486. begin
  4487. if (not (Proc.Parent is TPasClassType))
  4488. or (TPasClassType(Proc.Parent).ObjKind<>okClass) then
  4489. RaiseMsg(20190303231445,nInvalidXModifierY,sInvalidXModifierY,['message','at non class method'],Proc.MessageExpr);
  4490. if TPasClassType(Proc.Parent).IsExternal then
  4491. RaiseMsg(20190304002235,nInvalidXModifierY,sInvalidXModifierY,['message','in external class'],Proc.MessageExpr);
  4492. AddMessageIdToClassScope(Proc,true);
  4493. end;
  4494. if Proc.Parent is TPasMembersType then
  4495. begin
  4496. // class/record member
  4497. AClassOrRec:=TPasMembersType(Proc.Parent);
  4498. ClassOrRecScope:=AClassOrRec.CustomData as TPasClassOrRecordScope;
  4499. if ClassOrRecScope is TPas2JSClassScope then
  4500. begin
  4501. AClass:=TPasClassType(AClassOrRec);
  4502. ClassScope:=TPas2JSClassScope(ClassOrRecScope);
  4503. if AClass.IsExternal then
  4504. begin
  4505. // external class -> make method external
  4506. if not (pmExternal in Proc.Modifiers) then
  4507. begin
  4508. if Proc.LibrarySymbolName<>nil then
  4509. RaiseMsg(20170322142158,nInvalidXModifierY,
  4510. sInvalidXModifierY,[Proc.ElementTypeName,'symbol name'],Proc.LibrarySymbolName);
  4511. Proc.Modifiers:=Proc.Modifiers+[pmExternal];
  4512. Proc.LibrarySymbolName:=TPrimitiveExpr.Create(Proc,pekString,''''+Proc.Name+'''');
  4513. FOwnedElements.Add(Proc.LibrarySymbolName);
  4514. end;
  4515. if Proc.Visibility=visPublished then
  4516. // Note: an external class has no typeinfo
  4517. RaiseMsg(20170413221327,nSymbolCannotBePublished,sSymbolCannotBePublished,
  4518. [],Proc);
  4519. C:=Proc.ClassType;
  4520. if (C=TPasProcedure) or (C=TPasFunction) then
  4521. // ok
  4522. else if (C=TPasClassProcedure) or (C=TPasClassFunction) then
  4523. // ok
  4524. else if C=TPasConstructor then
  4525. begin
  4526. if Proc.IsVirtual then
  4527. // constructor of external class can't be overriden -> forbid virtual
  4528. RaiseMsg(20170323100447,nInvalidXModifierY,sInvalidXModifierY,
  4529. [Proc.ElementTypeName,'virtual,external'],Proc);
  4530. ComputeConstString(Proc.LibrarySymbolName,true,true);
  4531. end
  4532. else
  4533. RaiseMsg(20170322163210,nPasElementNotSupported,sPasElementNotSupported,
  4534. [Proc.ElementTypeName],Proc);
  4535. end
  4536. else
  4537. // Pascal class, not external
  4538. case AClass.ObjKind of
  4539. okClass:
  4540. begin
  4541. if (ClassScope.NewInstanceFunction=nil)
  4542. and (Proc.ClassType=TPasClassFunction)
  4543. and (ClassScope.AncestorScope<>nil)
  4544. and (TPasClassType(ClassScope.AncestorScope.Element).IsExternal)
  4545. and (Proc.Visibility in [visProtected,visPublic,visPublished])
  4546. and (TPasClassFunction(Proc).FuncType.ResultEl.ResultType=AClassOrRec)
  4547. and (Proc.Modifiers-[pmVirtual,pmAssembler]=[])
  4548. and (Proc.ProcType.Modifiers*[ptmOfObject]=[ptmOfObject]) then
  4549. begin
  4550. // The first non private class function in a Pascal class descending
  4551. // from an external class
  4552. // -> this is the NewInstance function
  4553. ClassScope.NewInstanceFunction:=TPasClassFunction(Proc);
  4554. CheckNewInstanceFunction(ClassScope);
  4555. end;
  4556. end;
  4557. okInterface:
  4558. begin
  4559. for pm in Proc.Modifiers do
  4560. if not (pm in [pmOverload, pmReintroduce]) then
  4561. RaiseMsg(20180329141108,nInvalidXModifierY,
  4562. sInvalidXModifierY,[Proc.ElementTypeName,ModifierNames[pm]],Proc);
  4563. end;
  4564. okClassHelper,okRecordHelper,okTypeHelper:
  4565. begin
  4566. HelperForType:=ResolveAliasType(AClass.HelperForType);
  4567. if HelperForType.ClassType=TPasClassType then
  4568. begin
  4569. if TPasClassType(HelperForType).IsExternal then
  4570. begin
  4571. // method of a class helper for external class
  4572. if IsClassMethod(Proc) and not (ptmStatic in El.Modifiers) then
  4573. RaiseMsg(20190201165259,nHelperClassMethodForExtClassMustBeStatic,
  4574. sHelperClassMethodForExtClassMustBeStatic,[],El);
  4575. if Proc.ClassType=TPasConstructor then
  4576. RaiseNotYetImplemented(20190206153655,El);
  4577. end;
  4578. end;
  4579. if Proc.IsExternal then
  4580. begin
  4581. if not (HelperForType is TPasMembersType) then
  4582. RaiseMsg(20190314225457,nNotSupportedX,sNotSupportedX,['external method in type helper'],El);
  4583. end;
  4584. end;
  4585. end;
  4586. end
  4587. else
  4588. begin
  4589. AClass:=nil;
  4590. ClassScope:=nil;
  4591. end;
  4592. end;
  4593. if pmExternal in Proc.Modifiers then
  4594. begin
  4595. // external proc
  4596. // external override -> unneeded information, probably a bug
  4597. if Proc.IsOverride then
  4598. RaiseMsg(20170321101715,nInvalidXModifierY,sInvalidXModifierY,
  4599. [Proc.ElementTypeName,'override,external'],Proc);
  4600. if Proc.LibraryExpr<>nil then
  4601. RaiseMsg(20170211220712,nPasElementNotSupported,sPasElementNotSupported,
  4602. ['external library name'],Proc.LibraryExpr);
  4603. if Proc.LibrarySymbolName=nil then
  4604. RaiseMsg(20170227095454,nMissingExternalName,sMissingExternalName,
  4605. ['missing external name'],Proc);
  4606. for pm in [pmAssembler,pmForward,pmNoReturn,pmInline] do
  4607. if pm in Proc.Modifiers then
  4608. RaiseMsg(20170323100842,nInvalidXModifierY,sInvalidXModifierY,
  4609. [Proc.ElementTypeName,ModifierNames[pm]],Proc);
  4610. // compute external name
  4611. ExtName:=ComputeConstString(Proc.LibrarySymbolName,true,true);
  4612. // a virtual must have the external name, so that override works
  4613. if Proc.IsVirtual and (Proc.Name<>ExtName) then
  4614. RaiseMsg(20170321090049,nVirtualMethodNameMustMatchExternal,
  4615. sVirtualMethodNameMustMatchExternal,[],Proc.LibrarySymbolName);
  4616. // a published must have the external name, so that streaming works
  4617. if (Proc.Visibility=visPublished) then
  4618. begin
  4619. if (Proc.Name<>ExtName) then
  4620. RaiseMsg(20170407002940,nPublishedNameMustMatchExternal,
  4621. sPublishedNameMustMatchExternal,[],Proc.LibrarySymbolName);
  4622. if ExtName=ExtClassBracketAccessor then
  4623. RaiseMsg(20170409211805,nSymbolCannotBePublished,
  4624. sSymbolCannotBePublished,[],Proc.LibrarySymbolName);
  4625. end;
  4626. if Proc.Parent is TPasSection then
  4627. AddExternalPath(ExtName,Proc.LibrarySymbolName);
  4628. end;
  4629. end
  4630. else
  4631. begin
  4632. // proc type, not proc
  4633. if not (El.CallingConvention in [ccDefault,ccSafeCall]) then
  4634. RaiseMsg(20200516134717,nNotSupportedX,sNotSupportedX,
  4635. [cCallingConventions[El.CallingConvention]],El);
  4636. end;
  4637. end;
  4638. procedure TPas2JSResolver.FinishProperty(PropEl: TPasProperty);
  4639. var
  4640. Getter, Setter: TPasElement;
  4641. GetterIsBracketAccessor, SetterIsBracketAccessor: Boolean;
  4642. Arg: TPasArgument;
  4643. ArgResolved: TPasResolverResult;
  4644. ParentC: TClass;
  4645. IndexExpr: TPasExpr;
  4646. PropArgs: TFPList;
  4647. begin
  4648. inherited FinishProperty(PropEl);
  4649. ParentC:=PropEl.Parent.ClassType;
  4650. if (ParentC=TPasClassType) then
  4651. begin
  4652. // class member
  4653. if TPasClassType(PropEl.Parent).IsExternal then
  4654. begin
  4655. // external class
  4656. if PropEl.Visibility=visPublished then
  4657. // Note: an external class has no typeinfo
  4658. RaiseMsg(20170413221703,nSymbolCannotBePublished,sSymbolCannotBePublished,
  4659. [],PropEl);
  4660. end;
  4661. end
  4662. else if ParentC=TPasRecordType then
  4663. // record member
  4664. else
  4665. RaiseNotYetImplemented(20190105144817,PropEl);
  4666. Getter:=GetPasPropertyGetter(PropEl);
  4667. GetterIsBracketAccessor:=IsExternalBracketAccessor(Getter);
  4668. Setter:=GetPasPropertySetter(PropEl);
  4669. SetterIsBracketAccessor:=IsExternalBracketAccessor(Setter);
  4670. IndexExpr:=GetPasPropertyIndex(PropEl);
  4671. PropArgs:=GetPasPropertyArgs(PropEl);
  4672. if GetterIsBracketAccessor then
  4673. begin
  4674. if (PropArgs.Count<>1) or (IndexExpr<>nil) then
  4675. RaiseMsg(20170403001743,nBracketAccessorOfExternalClassMustHaveOneParameter,
  4676. sBracketAccessorOfExternalClassMustHaveOneParameter,
  4677. [],PropEl);
  4678. end;
  4679. if SetterIsBracketAccessor then
  4680. begin
  4681. if (PropArgs.Count<>1) or (IndexExpr<>nil) then
  4682. RaiseMsg(20170403001806,nBracketAccessorOfExternalClassMustHaveOneParameter,
  4683. sBracketAccessorOfExternalClassMustHaveOneParameter,
  4684. [],PropEl);
  4685. end;
  4686. if GetterIsBracketAccessor or SetterIsBracketAccessor then
  4687. begin
  4688. Arg:=TPasArgument(PropArgs[0]);
  4689. if not (Arg.Access in [argDefault,argConst]) then
  4690. RaiseMsg(20170403090225,nXExpectedButYFound,sXExpectedButYFound,
  4691. ['default or "const"',AccessNames[Arg.Access]],PropEl);
  4692. ComputeElement(Arg,ArgResolved,[rcType],Arg);
  4693. if not (ArgResolved.BaseType in (btAllJSInteger+btAllJSStringAndChars+btAllJSBooleans+btAllJSFloats)) then
  4694. RaiseMsg(20170403090628,nIncompatibleTypesGotExpected,
  4695. sIncompatibleTypesGotExpected,
  4696. [GetResolverResultDescription(ArgResolved,true),'string'],Arg);
  4697. end;
  4698. end;
  4699. procedure TPas2JSResolver.FinishProcParamAccess(ProcType: TPasProcedureType;
  4700. Params: TParamsExpr);
  4701. begin
  4702. inherited FinishProcParamAccess(ProcType, Params);
  4703. FindCreatorArrayOfConst(ProcType.Args,Params);
  4704. end;
  4705. procedure TPas2JSResolver.FinishPropertyParamAccess(Params: TParamsExpr;
  4706. Prop: TPasProperty);
  4707. var
  4708. Args: TFPList;
  4709. begin
  4710. inherited FinishPropertyParamAccess(Params, Prop);
  4711. Args:=GetPasPropertyArgs(Prop);
  4712. if Args=nil then
  4713. RaiseNotYetImplemented(20190215210914,Params,GetObjName(Prop));
  4714. FindCreatorArrayOfConst(Args,Params);
  4715. end;
  4716. procedure TPas2JSResolver.FinishExportSymbol(El: TPasExportSymbol);
  4717. var
  4718. ResolvedEl: TPasResolverResult;
  4719. DeclEl: TPasElement;
  4720. C: TClass;
  4721. Proc: TPasProcedure;
  4722. V: TPasVariable;
  4723. begin
  4724. if El.Parent is TLibrarySection then
  4725. // ok
  4726. else
  4727. // everywhere else: not supported
  4728. RaiseMsg(20210106224720,nNotSupportedX,sNotSupportedX,['non library export'],El.ExportIndex);
  4729. if El.ExportIndex<>nil then
  4730. RaiseMsg(20210106223403,nNotSupportedX,sNotSupportedX,['export index'],El.ExportIndex);
  4731. inherited FinishExportSymbol(El);
  4732. ComputeElement(El,ResolvedEl,[]);
  4733. DeclEl:=ResolvedEl.IdentEl;
  4734. if DeclEl=nil then
  4735. RaiseMsg(20210106223620,nSymbolCannotBeExportedFromALibrary,
  4736. sSymbolCannotBeExportedFromALibrary,[],El);
  4737. if DeclEl is TPasResultElement then
  4738. DeclEl:=DeclEl.Parent.Parent;
  4739. C:=DeclEl.ClassType;
  4740. if DeclEl.Parent=nil then
  4741. RaiseMsg(20220206142534,nSymbolCannotBeExportedFromALibrary,
  4742. sSymbolCannotBeExportedFromALibrary,[],El);
  4743. if DeclEl.Parent is TPasSection then
  4744. // global
  4745. else if (DeclEl is TPasProcedure) and TPasProcedure(DeclEl).IsStatic then
  4746. // static proc
  4747. else
  4748. RaiseMsg(20210106224436,nSymbolCannotBeExportedFromALibrary,
  4749. sSymbolCannotBeExportedFromALibrary,[],El);
  4750. if not (El.Parent is TLibrarySection) then
  4751. // disable exports in units
  4752. RaiseMsg(20211022224239,nSymbolCannotBeExportedFromALibrary,
  4753. sSymbolCannotBeExportedFromALibrary,[],El);
  4754. if C.InheritsFrom(TPasProcedure) then
  4755. begin
  4756. Proc:=TPasProcedure(DeclEl);
  4757. if Proc.IsExternal or Proc.IsAbstract then
  4758. RaiseMsg(20211021225630,nSymbolCannotBeExportedFromALibrary,
  4759. sSymbolCannotBeExportedFromALibrary,[],El);
  4760. end
  4761. else if (C=TPasVariable) or (C=TPasConst) then
  4762. begin
  4763. V:=TPasVariable(DeclEl);
  4764. if vmExternal in V.VarModifiers then
  4765. RaiseMsg(20211021225634,nSymbolCannotBeExportedFromALibrary,
  4766. sSymbolCannotBeExportedFromALibrary,[],El);
  4767. end
  4768. else
  4769. begin
  4770. {$IFDEF VerbosePas2JS}
  4771. writeln('TPas2JSResolver.FinishExportSymbol ',GetObjPath(El));
  4772. {$ENDIF}
  4773. RaiseMsg(20210106223621,nSymbolCannotBeExportedFromALibrary,
  4774. sSymbolCannotBeExportedFromALibrary,[],El);
  4775. end;
  4776. end;
  4777. procedure TPas2JSResolver.ComputeArgumentExpr(
  4778. const ArgResolved: TPasResolverResult; Access: TArgumentAccess;
  4779. Expr: TPasExpr; out ExprResolved: TPasResolverResult;
  4780. SetReferenceFlags: boolean);
  4781. var
  4782. RightEl: TPasExpr;
  4783. Ref: TResolvedReference;
  4784. begin
  4785. inherited ComputeArgumentExpr(ArgResolved, Access, Expr, ExprResolved,
  4786. SetReferenceFlags);
  4787. if SetReferenceFlags
  4788. and (Access in [argDefault, argConst])
  4789. and ((ArgResolved.BaseType=btUntyped)
  4790. or IsJSBaseType(ArgResolved,pbtJSValue,true{must have rrfReadable}))
  4791. and (ExprResolved.LoTypeEl is TPasRecordType) then
  4792. begin
  4793. // passing a record to an untyped or jsvalue parameter -> mark fields as "read" too
  4794. RightEl:=GetRightMostExpr(Expr);
  4795. if RightEl.CustomData is TResolvedReference then
  4796. begin
  4797. Ref:=TResolvedReference(RightEl.CustomData);
  4798. Include(Ref.Flags,rrfUseFields);
  4799. end;
  4800. end;
  4801. end;
  4802. procedure TPas2JSResolver.FindCreatorArrayOfConst(Args: TFPList;
  4803. ErrorEl: TPasElement);
  4804. var
  4805. i: Integer;
  4806. Arg: TPasArgument;
  4807. begin
  4808. for i:=0 to Args.Count-1 do
  4809. begin
  4810. Arg:=TPasArgument(Args[i]);
  4811. if not IsArrayOfConst(Arg.ArgType) then continue;
  4812. FindProc_ArrLitToArrayOfConst(ErrorEl);
  4813. end;
  4814. end;
  4815. function TPas2JSResolver.FindProc_ArrLitToArrayOfConst(ErrorEl: TPasElement
  4816. ): TPasFunction;
  4817. var
  4818. aMod, UtilsMod: TPasModule;
  4819. ModScope: TPas2JSModuleScope;
  4820. SectionScope: TPasSectionScope;
  4821. Identifier: TPasIdentifier;
  4822. El: TPasElement;
  4823. FuncType: TPasFunctionType;
  4824. begin
  4825. aMod:=RootElement;
  4826. ModScope:=aMod.CustomData as TPas2JSModuleScope;
  4827. Result:=ModScope.SystemVarRecs;
  4828. if Result<>nil then exit;
  4829. // find unit in uses clauses
  4830. UtilsMod:=FindUsedUnitname('system',aMod);
  4831. if UtilsMod=nil then
  4832. RaiseIdentifierNotFound(20190215211531,'System.VarRecs',ErrorEl);
  4833. // find class in interface
  4834. if UtilsMod.InterfaceSection=nil then
  4835. RaiseIdentifierNotFound(20190215211538,'System.VarRecs',ErrorEl);
  4836. // find function VarRecs
  4837. SectionScope:=NoNil(UtilsMod.InterfaceSection.CustomData) as TPasSectionScope;
  4838. Identifier:=SectionScope.FindLocalIdentifier('VarRecs');
  4839. if Identifier=nil then
  4840. RaiseIdentifierNotFound(20190215211551,'System.VarRecs',ErrorEl);
  4841. El:=Identifier.Element;
  4842. if El.ClassType<>TPasFunction then
  4843. RaiseXExpectedButYFound(20190215211559,'function System.VarRecs',GetElementTypeName(El),ErrorEl);
  4844. Result:=TPasFunction(El);
  4845. ModScope.SystemVarRecs:=Result;
  4846. // check signature
  4847. FuncType:=Result.ProcType as TPasFunctionType;
  4848. if FuncType.Args.Count>0 then
  4849. RaiseXExpectedButYFound(20190215211953,'function System.VarRecs with 0 args',
  4850. IntToStr(FuncType.Args.Count),ErrorEl);
  4851. if FuncType.Modifiers<>[ptmVarargs] then
  4852. RaiseXExpectedButYFound(20190215212151,'function System.VarRecs; varargs',
  4853. '?',ErrorEl);
  4854. if FuncType.CallingConvention<>ccDefault then
  4855. RaiseXExpectedButYFound(20190215211824,'function System.VarRecs with default calling convention',
  4856. cCallingConventions[FuncType.CallingConvention],ErrorEl);
  4857. end;
  4858. function TPas2JSResolver.FindSystemExternalClassType(const aClassName,
  4859. JSName: string; ErrorEl: TPasElement): TPasClassType;
  4860. var
  4861. Data: TPRFindExtSystemClass;
  4862. Abort: boolean;
  4863. begin
  4864. Data:=Default(TPRFindExtSystemClass);
  4865. Data.ErrorPosEl:=ErrorEl;
  4866. Data.JSName:=JSName;
  4867. Abort:=false;
  4868. IterateGlobalElements(aClassName,@OnFindExtSystemClass,@Data,Abort);
  4869. Result:=Data.Found;
  4870. if (ErrorEl<>nil) and (Result=nil) then
  4871. RaiseIdentifierNotFound(20200526095647,aClassName+' = class external name '''+JSName+'''',ErrorEl);
  4872. end;
  4873. function TPas2JSResolver.FindTJSPromise(ErrorEl: TPasElement): TPasClassType;
  4874. var
  4875. aMod: TPasModule;
  4876. ModScope: TPas2JSModuleScope;
  4877. begin
  4878. aMod:=RootElement;
  4879. ModScope:=aMod.CustomData as TPas2JSModuleScope;
  4880. Result:=ModScope.JSPromiseClass;
  4881. if p2msfPromiseSearched in ModScope.FlagsJS then
  4882. exit; // use cache
  4883. Result:=FindSystemExternalClassType('TJSPromise','Promise',ErrorEl);
  4884. ModScope.JSPromiseClass:=Result;
  4885. Include(ModScope.FlagsJS,p2msfPromiseSearched);
  4886. end;
  4887. procedure TPas2JSResolver.CheckExternalClassConstructor(Ref: TResolvedReference
  4888. );
  4889. var
  4890. TypeEl: TPasType;
  4891. begin
  4892. if not (Ref.Context is TResolvedRefCtxConstructor) then
  4893. RaiseMsg(20180511165144,nJSNewNotSupported,sJSNewNotSupported,[],Ref.Element);
  4894. TypeEl:=TResolvedRefCtxConstructor(Ref.Context).Typ;
  4895. if TypeEl.ClassType=TPasClassType then
  4896. begin
  4897. // ClassType.new
  4898. if not TPasClassType(TypeEl).IsExternal then
  4899. RaiseMsg(20180511165316,nJSNewNotSupported,sJSNewNotSupported,[],Ref.Element);
  4900. end
  4901. else if TypeEl.ClassType=TPasClassOfType then
  4902. begin
  4903. TypeEl:=ResolveAliasType(TPasClassOfType(TypeEl).DestType);
  4904. if TypeEl.ClassType=TPasClassType then
  4905. begin
  4906. // ClassOfVar.new
  4907. if not TPasClassType(TypeEl).IsExternal then
  4908. RaiseMsg(20180511175309,nJSNewNotSupported,sJSNewNotSupported,[],Ref.Element);
  4909. end;
  4910. end;
  4911. end;
  4912. procedure TPas2JSResolver.CheckConditionExpr(El: TPasExpr;
  4913. const ResolvedEl: TPasResolverResult);
  4914. begin
  4915. if (ResolvedEl.BaseType=btCustom) and (IsJSBaseType(ResolvedEl,pbtJSValue)) then
  4916. exit;
  4917. inherited CheckConditionExpr(El, ResolvedEl);
  4918. end;
  4919. procedure TPas2JSResolver.CheckNewInstanceFunction(ClassScope: TPas2JSClassScope
  4920. );
  4921. var
  4922. Proc: TPasClassFunction;
  4923. Args: TFPList;
  4924. Arg: TPasArgument;
  4925. ResolvedArg: TPasResolverResult;
  4926. begin
  4927. Proc:=ClassScope.NewInstanceFunction;
  4928. // proc modifiers override and external were already checked
  4929. // visibility was already checked
  4930. // function result type was already checked
  4931. if not Proc.IsVirtual then
  4932. RaiseMsg(20170324231040,nNewInstanceFunctionMustBeVirtual,
  4933. sNewInstanceFunctionMustBeVirtual,[],Proc);
  4934. Args:=Proc.ProcType.Args;
  4935. if Args.Count<2 then
  4936. RaiseMsg(20170324232247,nNewInstanceFunctionMustHaveTwoParameters,
  4937. sNewInstanceFunctionMustHaveTwoParameters,[],Proc.ProcType);
  4938. // first param must be a string
  4939. Arg:=TPasArgument(Args[0]);
  4940. if Arg.Access<>argDefault then
  4941. RaiseMsg(20170324232655,nIncompatibleTypeArgNo,sIncompatibleTypeArgNo,
  4942. ['1',AccessNames[Arg.Access],'default (none)'],Arg);
  4943. if Arg.ArgType=nil then
  4944. RaiseMsg(20170324233201,nIncompatibleTypeArgNo,sIncompatibleTypeArgNo,
  4945. ['1','untyped','String'],Arg);
  4946. ComputeElement(Arg.ArgType,ResolvedArg,[rcType]);
  4947. if ResolvedArg.BaseType<>btString then
  4948. RaiseMsg(20170324233348,nIncompatibleTypeArgNo,sIncompatibleTypeArgNo,
  4949. ['1',GetResolverResultDescription(ResolvedArg),'String'],Arg);
  4950. // second param must be const untyped
  4951. Arg:=TPasArgument(Args[1]);
  4952. if Arg.Access<>argConst then
  4953. RaiseMsg(20170324233457,nIncompatibleTypeArgNo,sIncompatibleTypeArgNo,
  4954. ['2',AccessNames[Arg.Access],'const'],Arg);
  4955. if Arg.ArgType<>nil then
  4956. RaiseMsg(20170324233508,nIncompatibleTypeArgNo,sIncompatibleTypeArgNo,
  4957. ['2','type','untyped'],Arg);
  4958. end;
  4959. function TPas2JSResolver.AddExternalName(const aName: string; El: TPasElement
  4960. ): TPasIdentifier;
  4961. var
  4962. Item: TPasIdentifier;
  4963. begin
  4964. //writeln('TPas2JSResolver.AddExternalIdentifier Name="',aName,'" El=',GetObjName(El));
  4965. Item:=TPasIdentifier.Create;
  4966. Item.Identifier:=aName;
  4967. Item.Element:=El;
  4968. InternalAdd(Item);
  4969. //writeln('TPas2JSResolver.AddExternalIdentifier END');
  4970. Result:=Item;
  4971. end;
  4972. function TPas2JSResolver.FindExternalName(const aName: String
  4973. ): TPasIdentifier;
  4974. begin
  4975. Result:=TPasIdentifier(FExternalNames.Find(aName));
  4976. {$IFDEF VerbosePasResolver}
  4977. {AllowWriteln}
  4978. if (Result<>nil) and (Result.Owner<>Self) then
  4979. begin
  4980. writeln('TPas2JSResolver.FindExternalName Result.Owner<>Self Owner='+GetObjName(Result.Owner));
  4981. raise Exception.Create('20170322235814');
  4982. end;
  4983. {AllowWriteln-}
  4984. {$ENDIF}
  4985. end;
  4986. procedure TPas2JSResolver.AddExternalPath(aName: string; El: TPasElement);
  4987. // add aName and the first identifier of aName
  4988. var
  4989. p: integer;
  4990. begin
  4991. aName:=Trim(aName);
  4992. if aName='' then exit;
  4993. AddExternalName(aName,El);
  4994. p:=1;
  4995. while (p<=length(aName)) and (aName[p] in ['a'..'z','A'..'Z','0'..'9','_','$']) do
  4996. inc(p);
  4997. if p>length(aName) then exit;
  4998. AddExternalName(LeftStr(aName,p-1),El);
  4999. end;
  5000. procedure TPas2JSResolver.AddElevatedLocal(El: TPasElement);
  5001. var
  5002. i: Integer;
  5003. ElevatedLocals: TPas2jsElevatedLocals;
  5004. Scope: TPasScope;
  5005. ProcScope: TPas2JSProcedureScope;
  5006. begin
  5007. i:=ScopeCount-1;
  5008. while (i>=0) do
  5009. begin
  5010. Scope:=Scopes[i];
  5011. if Scope is TPas2JSProcedureScope then
  5012. begin
  5013. ProcScope:=TPas2JSProcedureScope(Scope);
  5014. if ProcScope.ClassRecScope<>nil then
  5015. Scope:=ProcScope.ClassRecScope;
  5016. end;
  5017. ElevatedLocals:=GetElevatedLocals(Scope);
  5018. if ElevatedLocals<>nil then
  5019. begin
  5020. ElevatedLocals.Add(El.Name,El);
  5021. exit;
  5022. end;
  5023. dec(i);
  5024. end;
  5025. RaiseNotYetImplemented(20180420131358,El);
  5026. end;
  5027. procedure TPas2JSResolver.ClearElementData;
  5028. var
  5029. Data, Next: TPas2JsElementData;
  5030. begin
  5031. Data:=FFirstElementData;
  5032. while Data<>nil do
  5033. begin
  5034. Next:=Data.Next;
  5035. Data.Free;
  5036. Data:=Next;
  5037. end;
  5038. FFirstElementData:=nil;
  5039. FLastElementData:=nil;
  5040. FExternalNames.ForEachCall(@OnClearHashItem,nil);
  5041. FExternalNames.Clear;
  5042. end;
  5043. function TPas2JSResolver.GenerateGUID(El: TPasClassType): string;
  5044. var
  5045. Name: String;
  5046. i, BytePos, BitPos, v: Integer;
  5047. Member: TPasElement;
  5048. Bytes: array[0..15] of byte;
  5049. List: TStringList;
  5050. Scope: TPas2JSClassScope;
  5051. begin
  5052. Name:=El.PathName;
  5053. Scope:=TPas2JSClassScope(El.CustomData);
  5054. if Scope.AncestorScope<>nil then
  5055. begin
  5056. // use ancestor GUID as start
  5057. Name:=TPas2JSClassScope(Scope.AncestorScope).GUID+Name;
  5058. end;
  5059. List:=TStringList.Create;
  5060. for i:=0 to El.Members.Count-1 do
  5061. begin
  5062. Member:=TPasElement(El.Members[i]);
  5063. if Member is TPasProcedure then
  5064. List.Add(Member.Name);
  5065. end;
  5066. List.Sort;
  5067. for i:=0 to List.Count-1 do
  5068. Name:=Name+','+List[i];
  5069. List.Free;
  5070. BytePos:=0;
  5071. BitPos:=0;
  5072. {$IFDEF fpc}
  5073. FillByte({%H-}Bytes[0],16,0);
  5074. {$ENDIF}
  5075. for i:=1 to length(Name) do
  5076. begin
  5077. // read 16-bit
  5078. v:=(Bytes[BytePos] shl 8)+Bytes[(BytePos+1) and 15];
  5079. // change some bits
  5080. v:=v+integer((ord(Name[i]) shl (11-BitPos)));
  5081. // write 16 bit
  5082. Bytes[BytePos]:=(v shr 8) and $ff;
  5083. Bytes[(BytePos+1) and 15]:=v and $ff;
  5084. inc(BitPos,5);
  5085. if BitPos>7 then
  5086. begin
  5087. dec(BitPos,8);
  5088. BytePos:=(BytePos+1) and 15;
  5089. end;
  5090. end;
  5091. // set version 3
  5092. Bytes[6]:=(Bytes[6] and $f)+(3 shl 4);
  5093. // set variant 2
  5094. Bytes[8]:=(Bytes[8] and $3f)+(2 shl 6);
  5095. Result:='{';
  5096. for i:=0 to 3 do Result:=Result+HexStr(Bytes[i],2);
  5097. Result:=Result+'-';
  5098. for i:=4 to 5 do Result:=Result+HexStr(Bytes[i],2);
  5099. Result:=Result+'-';
  5100. for i:=6 to 7 do Result:=Result+HexStr(Bytes[i],2);
  5101. Result:=Result+'-';
  5102. for i:=8 to 9 do Result:=Result+HexStr(Bytes[i],2);
  5103. Result:=Result+'-';
  5104. for i:=10 to 15 do Result:=Result+HexStr(Bytes[i],2);
  5105. Result:=Result+'}';
  5106. end;
  5107. function TPas2JSResolver.CheckCallAsyncFuncResult(Param: TPasExpr; out
  5108. ResolvedEl: TPasResolverResult): boolean;
  5109. var
  5110. PathEnd: TPasExpr;
  5111. Ref: TResolvedReference;
  5112. Decl: TPasElement;
  5113. DeclFunc: TPasFunction;
  5114. begin
  5115. Result:=false;
  5116. PathEnd:=GetPathEndIdent(Param,true);
  5117. if (PathEnd<>nil) and (PathEnd.CustomData is TResolvedReference) then
  5118. begin
  5119. Ref:=TResolvedReference(PathEnd.CustomData);
  5120. Decl:=Ref.Declaration;
  5121. if Decl is TPasFunction then
  5122. begin
  5123. DeclFunc:=TPasFunction(Decl);
  5124. if DeclFunc.IsAsync then
  5125. begin
  5126. // await(CallAsyncFunction) -> use Pascal result type (not TJSPromise)
  5127. // Note the missing rcCall flag
  5128. ComputeResultElement(DeclFunc.FuncType.ResultEl,ResolvedEl,[],PathEnd);
  5129. exit(true);
  5130. end;
  5131. end;
  5132. end;
  5133. ResolvedEl:=Default(TPasResolverResult);
  5134. end;
  5135. procedure TPas2JSResolver.SpecializeGenericIntf(
  5136. SpecializedItem: TPRSpecializedItem);
  5137. var
  5138. El: TPasElement;
  5139. begin
  5140. inherited SpecializeGenericIntf(SpecializedItem);
  5141. RenameSpecialized(SpecializedItem);
  5142. El:=SpecializedItem.SpecializedEl;
  5143. if (El is TPasGenericType)
  5144. and IsFullySpecialized(TPasGenericType(El))
  5145. and (SpecializeParamsNeedDelay(SpecializedItem)<>nil) then
  5146. TPas2JSResolverHub(Hub).AddJSDelaySpecialize(TPasGenericType(El));
  5147. end;
  5148. procedure TPas2JSResolver.SpecializeGenericImpl(
  5149. SpecializedItem: TPRSpecializedItem);
  5150. var
  5151. El: TPasElement;
  5152. begin
  5153. inherited SpecializeGenericImpl(SpecializedItem);
  5154. El:=SpecializedItem.SpecializedEl;
  5155. if El is TPasMembersType then
  5156. begin
  5157. if FOverloadScopes=nil then
  5158. begin
  5159. FOverloadScopes:=TFPList.Create;
  5160. try
  5161. RenameMembers(TPasMembersType(El));
  5162. finally
  5163. ClearOverloadScopes;
  5164. end;
  5165. end;
  5166. end;
  5167. end;
  5168. procedure TPas2JSResolver.SpecializeProcedure(GenEl, SpecEl: TPasProcedure;
  5169. SpecializedItem: TPRSpecializedItem);
  5170. var
  5171. GenProcScope, SpecProcScope: TPas2JSProcedureScope;
  5172. begin
  5173. GenProcScope:=GenEl.CustomData as TPas2JSProcedureScope;
  5174. SpecProcScope:=SpecEl.CustomData as TPas2JSProcedureScope;
  5175. if SpecializedItem=nil then
  5176. begin
  5177. SpecProcScope.OverloadName:=GenProcScope.OverloadName;
  5178. SpecProcScope.JSName:=GenProcScope.JSName;
  5179. // SpecProcScope.ResultVarName is set on demand
  5180. end;
  5181. inherited SpecializeProcedure(GenEl, SpecEl, SpecializedItem);
  5182. end;
  5183. function TPas2JSResolver.SpecializeParamsNeedDelay(
  5184. SpecializedItem: TPRSpecializedItem): TPasElement;
  5185. // finds first specialize param defined later than the generic
  5186. // For example: generic in the unit interface, param in implementation
  5187. // or param in another unit, not used by the generic
  5188. var
  5189. Gen: TPasElement;
  5190. GenMod, ParamMod: TPasModule;
  5191. Params: TPasTypeArray;
  5192. Param: TPasType;
  5193. i: Integer;
  5194. GenSection, ParamSection: TPasSection;
  5195. ParamResolver, GenResolver: TPasResolver;
  5196. begin
  5197. Result:=nil;
  5198. if SpecializedItem=nil then exit;
  5199. Gen:=SpecializedItem.GenericEl;
  5200. GenSection:=GetParentSection(Gen);
  5201. if not (GenSection is TInterfaceSection) then
  5202. exit; // generic in unit implementation/program/library -> params cannot be defined in a later section -> no delay needed
  5203. GenMod:=nil;
  5204. GenResolver:=nil;
  5205. // ToDo: delay only, if either RTTI or class var using a param
  5206. Params:=SpecializedItem.Params;
  5207. for i:=0 to length(Params)-1 do
  5208. begin
  5209. Param:=ResolveAliasType(Params[i],false);
  5210. if Param.ClassType=TPasUnresolvedSymbolRef then
  5211. continue; // built-in type -> no delay needed
  5212. if (Param.CustomData is TPasGenericScope)
  5213. and (TPasGenericScope(Param.CustomData).GenericStep<psgsInterfaceParsed) then
  5214. exit(Param); // specialization is within param itself -> needs delay
  5215. ParamSection:=GetParentSection(Param);
  5216. if ParamSection=GenSection then
  5217. continue; // same section -> no delay needed
  5218. // not in same section
  5219. ParamMod:=ParamSection.GetModule;
  5220. if GenMod=nil then
  5221. GenMod:=GenSection.GetModule;
  5222. if ParamMod=GenMod then
  5223. exit(Param); // generic in unit interface, param in implementation
  5224. // param in another unit
  5225. if ParamSection is TImplementationSection then
  5226. exit(Param); // generic in unit interface, param in another implementation
  5227. // param in another unit interface
  5228. if GenResolver=nil then
  5229. GenResolver:=GetResolver(GenMod);
  5230. ParamResolver:=GetResolver(ParamMod);
  5231. if (ParamResolver.FinishedInterfaceIndex>GenResolver.FinishedInterfaceIndex)
  5232. or (ParamResolver.FinishedInterfaceIndex=0) // 0 means currently parsing
  5233. then
  5234. exit(Param); // param in a later unit interface
  5235. // generic in a later unit interface -> no delay needed
  5236. end;
  5237. end;
  5238. function TPas2JSResolver.IsSpecializedNonStaticMethod(
  5239. ProcType: TPasProcedureType): boolean;
  5240. var
  5241. Proc: TPasProcedure;
  5242. Scope: TPas2JSProcedureScope;
  5243. begin
  5244. if not (ProcType.Parent is TPasProcedure) then
  5245. exit(false); // not a method
  5246. Proc:=TPasProcedure(ProcType.Parent);
  5247. if Proc.IsStatic or Proc.IsExternal then
  5248. exit(false);
  5249. if not (Proc.Parent is TPasMembersType) then
  5250. exit(false); // not a method
  5251. Scope:=TPas2JSProcedureScope(Proc.CustomData);
  5252. if Scope.SpecializedFromItem=nil then
  5253. exit(false);
  5254. Result:=true;
  5255. end;
  5256. function TPas2JSResolver.AddJSBaseType(const aName: string; Typ: TPas2jsBaseType
  5257. ): TResElDataPas2JSBaseType;
  5258. var
  5259. El: TPasUnresolvedSymbolRef;
  5260. begin
  5261. El:=AddCustomBaseType(aName,TResElDataPas2JSBaseType);
  5262. if Typ<>pbtNone then
  5263. FJSBaseTypes[Typ]:=El;
  5264. Result:=TResElDataPas2JSBaseType(El.CustomData);
  5265. Result.JSBaseType:=Typ;
  5266. end;
  5267. function TPas2JSResolver.CheckAssignCompatibilityCustom(const LHS,
  5268. RHS: TPasResolverResult; ErrorEl: TPasElement; RaiseOnIncompatible: boolean;
  5269. var Handled: boolean): integer;
  5270. var
  5271. LeftBaseType: TPas2jsBaseType;
  5272. LArray: TPasArrayType;
  5273. ElTypeResolved: TPasResolverResult;
  5274. LTypeEl, RTypeEl: TPasType;
  5275. TIName: String;
  5276. begin
  5277. Result:=cIncompatible;
  5278. //writeln('TPas2JSResolver.CheckAssignCompatibilityCustom LHS=',GetResolverResultDbg(LHS),' RHS=',GetResolverResultDbg(RHS));
  5279. if LHS.BaseType=btCustom then
  5280. begin
  5281. if not (LHS.LoTypeEl is TPasUnresolvedSymbolRef) then
  5282. begin
  5283. {$IFDEF VerbosePas2JS}
  5284. writeln('TPas2JSResolver.CheckAssignCompatibilityCustomBaseType LHS=',GetResolverResultDbg(LHS));
  5285. {$ENDIF}
  5286. RaiseInternalError(20170325114554);
  5287. end;
  5288. if not (LHS.LoTypeEl.CustomData is TResElDataPas2JSBaseType) then
  5289. exit;
  5290. Handled:=true;
  5291. LeftBaseType:=TResElDataPas2JSBaseType(LHS.LoTypeEl.CustomData).JSBaseType;
  5292. if LeftBaseType=pbtJSValue then
  5293. begin
  5294. // assign to a JSValue
  5295. if rrfReadable in RHS.Flags then
  5296. begin
  5297. // RHS is a value
  5298. if (RHS.BaseType in btAllJSValueSrcTypes) then
  5299. Result:=cJSValueConversion // type cast to JSValue
  5300. else if RHS.BaseType=btCustom then
  5301. begin
  5302. if IsJSBaseType(RHS,pbtJSValue) then
  5303. Result:=cExact;
  5304. end
  5305. else if RHS.BaseType=btContext then
  5306. Result:=cJSValueConversion
  5307. else if (RHS.BaseType=btProc) and (RHS.IdentEl=nil) then
  5308. begin
  5309. // JSValue:=anonymousproc
  5310. Result:=cExact;
  5311. end;
  5312. end
  5313. else if RHS.BaseType=btContext then
  5314. begin
  5315. // RHS is not a value
  5316. if RHS.IdentEl<>nil then
  5317. begin
  5318. if RHS.IdentEl.ClassType=TPasClassType then
  5319. Result:=cJSValueConversion; // RHS is a class type
  5320. end;
  5321. end;
  5322. end;
  5323. end
  5324. else if (LHS.BaseType=btContext) then
  5325. begin
  5326. LTypeEl:=LHS.LoTypeEl;
  5327. RTypeEl:=RHS.LoTypeEl;
  5328. if (LTypeEl.ClassType=TPasArrayType)
  5329. and (rrfReadable in RHS.Flags) then
  5330. begin
  5331. LArray:=TPasArrayType(LTypeEl);
  5332. if length(LArray.Ranges)>0 then
  5333. exit;
  5334. if (RHS.BaseType<>btContext) or (RTypeEl.ClassType<>TPasArrayType) then
  5335. exit;
  5336. ComputeElement(GetArrayElType(LArray),ElTypeResolved,[rcType]);
  5337. if IsJSBaseType(ElTypeResolved,pbtJSValue) then
  5338. begin
  5339. // array of jsvalue := array
  5340. Handled:=true;
  5341. Result:=cJSValueConversion;
  5342. end;
  5343. end
  5344. else if (LTypeEl.ClassType=TPasClassType)
  5345. and (rrfReadable in RHS.Flags)
  5346. and (RHS.BaseType=btPointer)
  5347. and IsSameType(RTypeEl,BaseTypes[btPointer],prraNone)
  5348. then
  5349. begin
  5350. TIName:=Pas2JSBuiltInNames[pbivnRTL]+'.'+Pas2JSBuiltInNames[pbitnTI];
  5351. if IsExternalClass_Name(TPasClassType(LTypeEl),TIName) then
  5352. begin
  5353. // aTTypeInfo:=aPointer
  5354. Handled:=true;
  5355. Result:=cTypeConversion;
  5356. end;
  5357. end;
  5358. end;
  5359. if RaiseOnIncompatible then ;
  5360. if ErrorEl=nil then ;
  5361. end;
  5362. function TPas2JSResolver.CheckTypeCastClassInstanceToClass(const FromClassRes,
  5363. ToClassRes: TPasResolverResult; ErrorEl: TPasElement): integer;
  5364. // type cast not related classes
  5365. var
  5366. ToClass, FromClass: TPasClassType;
  5367. ToClassScope, FromClassScope: TPas2JSClassScope;
  5368. ToSpecItem, FromSpecItem: TPRSpecializedItem;
  5369. i: Integer;
  5370. ToParam, FromParam: TPasType;
  5371. begin
  5372. if FromClassRes.BaseType=btNil then exit(cExact);
  5373. ToClass:=ToClassRes.LoTypeEl as TPasClassType;
  5374. ToClassScope:=ToClass.CustomData as TPas2JSClassScope;
  5375. if ToClassScope.AncestorScope=nil then
  5376. // type cast to root class
  5377. exit(cTypeConversion+1);
  5378. ToSpecItem:=ToClassScope.SpecializedFromItem;
  5379. if ToSpecItem<>nil then
  5380. begin
  5381. FromClass:=FromClassRes.LoTypeEl as TPasClassType;
  5382. FromClassScope:=FromClass.CustomData as TPas2JSClassScope;
  5383. FromSpecItem:=FromClassScope.SpecializedFromItem;
  5384. if FromSpecItem<>nil then
  5385. begin
  5386. // typecast a specialized instance to a specialized type TA<>(aB<>)
  5387. if FromSpecItem.GenericEl=ToSpecItem.GenericEl then
  5388. begin
  5389. // typecast to same generic class
  5390. Result:=cTypeConversion+1;
  5391. for i:=0 to length(FromSpecItem.Params)-1 do
  5392. begin
  5393. FromParam:=FromSpecItem.Params[i];
  5394. ToParam:=ToSpecItem.Params[i];
  5395. if IsSameType(FromParam,ToParam,prraAlias)
  5396. or IsJSBaseType(FromParam,pbtJSValue)
  5397. or IsJSBaseType(ToParam,pbtJSValue) then
  5398. // ok
  5399. else
  5400. begin
  5401. Result:=cIncompatible;
  5402. break;
  5403. end;
  5404. end;
  5405. if Result<cIncompatible then
  5406. exit; // e.g. TGen<JSValue>(aGen<Word>) or TGen<Word>(aGen<JSValue>)
  5407. end;
  5408. end;
  5409. end;
  5410. Result:=cIncompatible;
  5411. if ErrorEl=nil then ;
  5412. end;
  5413. function TPas2JSResolver.CheckEqualCompatibilityCustomType(const LHS,
  5414. RHS: TPasResolverResult; ErrorEl: TPasElement; RaiseOnIncompatible: boolean
  5415. ): integer;
  5416. var
  5417. LeftBaseType: TPas2jsBaseType;
  5418. begin
  5419. Result:=cIncompatible;
  5420. if LHS.BaseType=btCustom then
  5421. begin
  5422. if not (LHS.LoTypeEl is TPasUnresolvedSymbolRef) then
  5423. begin
  5424. {$IFDEF VerbosePas2JS}
  5425. writeln('TPas2JSResolver.CheckEqualCompatibilityCustomType LHS=',GetResolverResultDbg(LHS));
  5426. {$ENDIF}
  5427. RaiseInternalError(20170330005841);
  5428. end;
  5429. if not (LHS.LoTypeEl.CustomData is TResElDataPas2JSBaseType) then
  5430. exit;
  5431. LeftBaseType:=TResElDataPas2JSBaseType(LHS.LoTypeEl.CustomData).JSBaseType;
  5432. if LeftBaseType=pbtJSValue then
  5433. begin
  5434. if (rrfReadable in LHS.Flags) then
  5435. begin
  5436. if (rrfReadable in RHS.Flags) then
  5437. begin
  5438. if RHS.BaseType in btAllJSValueSrcTypes then
  5439. Result:=cJSValueConversion
  5440. else if RHS.BaseType=btCustom then
  5441. begin
  5442. if IsJSBaseType(RHS,pbtJSValue) then
  5443. Result:=cExact;
  5444. end
  5445. else if RHS.BaseType=btContext then
  5446. Result:=cJSValueConversion;
  5447. end
  5448. else if RHS.BaseType=btContext then
  5449. begin
  5450. // right side is not a value
  5451. if RHS.IdentEl<>nil then
  5452. begin
  5453. if RHS.IdentEl.ClassType=TPasClassType then
  5454. Result:=cJSValueConversion; // RHS is a class
  5455. end;
  5456. end;
  5457. end;
  5458. end;
  5459. end
  5460. else if RHS.BaseType=btCustom then
  5461. exit(CheckEqualCompatibilityCustomType(RHS,LHS,ErrorEl,RaiseOnIncompatible))
  5462. else
  5463. RaiseInternalError(20170330005725);
  5464. end;
  5465. function TPas2JSResolver.CheckForIn(Loop: TPasImplForLoop; const VarResolved,
  5466. InResolved: TPasResolverResult): boolean;
  5467. var
  5468. TypeEl: TPasType;
  5469. ArgResolved, LengthResolved, PropResultResolved: TPasResolverResult;
  5470. begin
  5471. if InResolved.BaseType=btCustom then
  5472. begin
  5473. if IsJSBaseType(InResolved,pbtJSValue,true) then
  5474. begin
  5475. // for string in jsvalue do ...
  5476. if not (VarResolved.BaseType in btAllStrings) then
  5477. RaiseXExpectedButYFound(20180423185800,'string',GetResolverResultDescription(VarResolved,true),Loop.StartExpr);
  5478. exit(true);
  5479. end;
  5480. end
  5481. else if InResolved.BaseType=btContext then
  5482. begin
  5483. TypeEl:=InResolved.LoTypeEl;
  5484. if (TypeEl.ClassType=TPasClassType) and TPasClassType(TypeEl).IsExternal then
  5485. begin
  5486. // for key in JSClass do ...
  5487. if IsForInExtArray(Loop,VarResolved,InResolved,ArgResolved,
  5488. LengthResolved,PropResultResolved) then
  5489. exit(true);
  5490. // for key in JSObject do
  5491. if not (VarResolved.BaseType in btAllStrings) then
  5492. RaiseXExpectedButYFound(20180423191611,'string',GetResolverResultDescription(VarResolved,true),Loop.StartExpr);
  5493. exit(true);
  5494. end;
  5495. end;
  5496. Result:=false;
  5497. end;
  5498. procedure TPas2JSResolver.ComputeUnaryNot(El: TUnaryExpr;
  5499. var ResolvedEl: TPasResolverResult; Flags: TPasResolverComputeFlags);
  5500. begin
  5501. if ResolvedEl.BaseType=btCustom then
  5502. begin
  5503. if IsJSBaseType(ResolvedEl,pbtJSValue,true) then
  5504. begin
  5505. SetResolverValueExpr(ResolvedEl,btBoolean,BaseTypes[btBoolean],BaseTypes[btBoolean],
  5506. El,[rrfReadable]);
  5507. exit;
  5508. end;
  5509. end;
  5510. inherited ComputeUnaryNot(El, ResolvedEl, Flags);
  5511. end;
  5512. procedure TPas2JSResolver.ComputeBinaryExprRes(Bin: TBinaryExpr; out
  5513. ResolvedEl: TPasResolverResult; Flags: TPasResolverComputeFlags;
  5514. var LeftResolved, RightResolved: TPasResolverResult);
  5515. procedure SetBaseType(BaseType: TResolverBaseType);
  5516. begin
  5517. SetResolverValueExpr(ResolvedEl,BaseType,BaseTypes[BaseType],BaseTypes[BaseType],
  5518. Bin,[rrfReadable]);
  5519. end;
  5520. var
  5521. RightTypeEl: TPasType;
  5522. begin
  5523. if (LeftResolved.BaseType=btCustom)
  5524. or (RightResolved.BaseType=btCustom) then
  5525. case Bin.OpCode of
  5526. eopIs:
  5527. if IsJSBaseType(LeftResolved,pbtJSValue,true) then
  5528. begin
  5529. // aJSValue is x
  5530. if (RightResolved.IdentEl is TPasType)
  5531. and (ResolveAliasType(TPasType(RightResolved.IdentEl)) is TPasClassType) then
  5532. begin
  5533. // e.g. if aJSValue is TObject then ;
  5534. SetBaseType(btBoolean);
  5535. exit;
  5536. end;
  5537. RightTypeEl:=RightResolved.LoTypeEl;
  5538. if (RightTypeEl is TPasClassOfType) then
  5539. begin
  5540. // e.g. if aJSValue is TClass then ;
  5541. // or if aJSValue is ImageClass then ;
  5542. SetBaseType(btBoolean);
  5543. exit;
  5544. end;
  5545. end;
  5546. end;
  5547. inherited ComputeBinaryExprRes(Bin, ResolvedEl, Flags, LeftResolved,
  5548. RightResolved);
  5549. end;
  5550. function TPas2JSResolver.BI_Exit_OnGetCallCompatibility(
  5551. Proc: TResElDataBuiltInProc; Expr: TPasExpr; RaiseOnError: boolean): integer;
  5552. var
  5553. Params: TParamsExpr;
  5554. CtxProc: TPasProcedure;
  5555. ParamResolved: TPasResolverResult;
  5556. Param: TPasExpr;
  5557. begin
  5558. if (Expr is TParamsExpr) and (length(TParamsExpr(Expr).Params)=1) then
  5559. begin
  5560. Params:=TParamsExpr(Expr);
  5561. CtxProc:=GetParentProc(Expr,true);
  5562. if (CtxProc<>nil) and CtxProc.IsAsync then
  5563. begin
  5564. // inside async proc
  5565. Param:=Params.Params[0];
  5566. ComputeElement(Param,ParamResolved,[]);
  5567. if (rrfReadable in ParamResolved.Flags)
  5568. and (ParamResolved.BaseType=btContext)
  5569. and (ParamResolved.LoTypeEl is TPasClassType)
  5570. and IsPromiseClass(TPasClassType(ParamResolved.LoTypeEl)) then
  5571. begin
  5572. // "exit(aPromise)" inside async proc
  5573. exit(cCompatible);
  5574. end;
  5575. end;
  5576. end;
  5577. Result:=inherited BI_Exit_OnGetCallCompatibility(Proc, Expr, RaiseOnError);
  5578. end;
  5579. function TPas2JSResolver.BI_Val_OnGetCallCompatibility(
  5580. Proc: TResElDataBuiltInProc; Expr: TPasExpr; RaiseOnError: boolean): integer;
  5581. var
  5582. Params: TParamsExpr;
  5583. Param: TPasExpr;
  5584. ParamResolved: TPasResolverResult;
  5585. bt: TResolverBaseType;
  5586. C: TClass;
  5587. begin
  5588. Result:=inherited;
  5589. Params:=TParamsExpr(Expr);
  5590. Param:=Params.Params[1];
  5591. ComputeElement(Param,ParamResolved,[]);
  5592. Result:=cIncompatible;
  5593. bt:=ParamResolved.BaseType;
  5594. if bt=btRange then
  5595. bt:=ParamResolved.SubType;
  5596. if bt=btContext then
  5597. begin
  5598. C:=ParamResolved.LoTypeEl.ClassType;
  5599. if (C=TPasEnumType) or (C=TPasRangeType) then
  5600. Result:=cExact
  5601. end;
  5602. if Result=cIncompatible then
  5603. exit(CheckRaiseTypeArgNo(20181214142349,2,Param,ParamResolved,
  5604. 'enum variable',RaiseOnError));
  5605. end;
  5606. procedure TPas2JSResolver.BI_TypeInfo_OnGetCallResult(
  5607. Proc: TResElDataBuiltInProc; Params: TParamsExpr; out
  5608. ResolvedEl: TPasResolverResult);
  5609. // if an external type with the right name and external name is in scope return
  5610. // that, otherwise btPointer
  5611. var
  5612. Param: TPasExpr;
  5613. ParamResolved: TPasResolverResult;
  5614. C: TClass;
  5615. TIName: String;
  5616. FindData: TPRFindData;
  5617. Abort: boolean;
  5618. bt: TResolverBaseType;
  5619. jbt: TPas2jsBaseType;
  5620. TypeEl: TPasType;
  5621. FoundClass: TPasClassType;
  5622. ScopeDepth: Integer;
  5623. TemplType: TPasGenericTemplateType;
  5624. ConEl: TPasElement;
  5625. ConToken: TToken;
  5626. ResultEl: TPasResultElement;
  5627. begin
  5628. Param:=Params.Params[0];
  5629. ComputeElement(Param,ParamResolved,[rcNoImplicitProc]);
  5630. if ParamResolved.LoTypeEl=nil then
  5631. RaiseInternalError(20170413090726);
  5632. if (ParamResolved.BaseType=btProc) and (ParamResolved.IdentEl is TPasFunction) then
  5633. begin
  5634. // typeinfo of function result -> resolve once
  5635. ResultEl:=TPasFunction(ParamResolved.IdentEl).FuncType.ResultEl;
  5636. ComputeResultElement(ResultEl,ParamResolved,[]);
  5637. Include(ParamResolved.Flags,rrfReadable);
  5638. if ParamResolved.LoTypeEl=nil then
  5639. RaiseInternalError(20170421124923);
  5640. end;
  5641. TypeEl:=ParamResolved.LoTypeEl;
  5642. C:=TypeEl.ClassType;
  5643. TIName:='';
  5644. //writeln('TPas2JSResolver.BI_TypeInfo_OnGetCallResult TypeEl=',GetObjName(TypeEl));
  5645. if C=TPasUnresolvedSymbolRef then
  5646. begin
  5647. if TypeEl.CustomData is TResElDataPas2JSBaseType then
  5648. begin
  5649. jbt:=TResElDataPas2JSBaseType(TypeEl.CustomData).JSBaseType;
  5650. if jbt=pbtJSValue then
  5651. TIName:=Pas2JSBuiltInNames[pbitnTI];
  5652. end
  5653. else if TypeEl.CustomData is TResElDataBaseType then
  5654. begin
  5655. bt:=TResElDataBaseType(TypeEl.CustomData).BaseType;
  5656. if bt in (btAllJSInteger+[btCurrency]) then
  5657. TIName:=Pas2JSBuiltInNames[pbitnTIInteger]
  5658. else if bt in [btString,btChar,btDouble,btBoolean] then
  5659. TIName:=Pas2JSBuiltInNames[pbitnTI]
  5660. else if bt=btPointer then
  5661. TIName:=Pas2JSBuiltInNames[pbitnTIPointer];
  5662. end;
  5663. end
  5664. else if ParamResolved.BaseType=btContext then
  5665. begin
  5666. if C=TPasEnumType then
  5667. TIName:=Pas2JSBuiltInNames[pbitnTIEnum]
  5668. else if C=TPasSetType then
  5669. TIName:=Pas2JSBuiltInNames[pbitnTISet]
  5670. else if C.InheritsFrom(TPasProcedureType) then
  5671. begin
  5672. if TPasProcedureType(TypeEl).IsReferenceTo then
  5673. TIName:=Pas2JSBuiltInNames[pbitnTIRefToProcVar]
  5674. else if TPasProcedureType(TypeEl).IsOfObject then
  5675. TIName:=Pas2JSBuiltInNames[pbitnTIMethodVar]
  5676. else
  5677. TIName:=Pas2JSBuiltInNames[pbitnTIProcVar];
  5678. end
  5679. else if C=TPasRecordType then
  5680. TIName:=Pas2JSBuiltInNames[pbitnTIRecord]
  5681. else if C=TPasClassType then
  5682. case TPasClassType(TypeEl).ObjKind of
  5683. okClass:
  5684. if TPasClassType(TypeEl).IsExternal then
  5685. TIName:=Pas2JSBuiltInNames[pbitnTIExtClass]
  5686. else
  5687. TIName:=Pas2JSBuiltInNames[pbitnTIClass];
  5688. okInterface: TIName:=Pas2JSBuiltInNames[pbitnTIInterface];
  5689. okClassHelper,okRecordHelper,okTypeHelper: TIName:=Pas2JSBuiltInNames[pbitnTIHelper];
  5690. else
  5691. RaiseNotYetImplemented(20180328195807,Param);
  5692. end
  5693. else if C=TPasClassOfType then
  5694. begin
  5695. if rrfReadable in ParamResolved.Flags then
  5696. TIName:=Pas2JSBuiltInNames[pbitnTIClass]
  5697. else
  5698. TIName:=Pas2JSBuiltInNames[pbitnTIClassRef];
  5699. end
  5700. else if C=TPasArrayType then
  5701. begin
  5702. if length(TPasArrayType(TypeEl).Ranges)>0 then
  5703. TIName:=Pas2JSBuiltInNames[pbitnTIStaticArray]
  5704. else
  5705. TIName:=Pas2JSBuiltInNames[pbitnTIDynArray];
  5706. end
  5707. else if C=TPasPointerType then
  5708. TIName:=Pas2JSBuiltInNames[pbitnTIPointer]
  5709. else if C=TPasGenericTemplateType then
  5710. begin
  5711. TemplType:=TPasGenericTemplateType(TypeEl);
  5712. if length(TemplType.Constraints)>0 then
  5713. begin
  5714. ConEl:=TemplType.Constraints[0];
  5715. ConToken:=GetGenericConstraintKeyword(ConEl);
  5716. case ConToken of
  5717. tkrecord: TIName:=Pas2JSBuiltInNames[pbitnTIRecord];
  5718. tkclass,tkConstructor: TIName:=Pas2JSBuiltInNames[pbitnTIClass];
  5719. else
  5720. if not (ConEl is TPasType) then
  5721. RaiseNotYetImplemented(20191018180031,ConEl,GetObjPath(Param));
  5722. TypeEl:=ResolveAliasType(TPasType(ConEl));
  5723. if TypeEl is TPasClassType then
  5724. case TPasClassType(TypeEl).ObjKind of
  5725. okClass:
  5726. if TPasClassType(TypeEl).IsExternal then
  5727. TIName:=Pas2JSBuiltInNames[pbitnTIExtClass]
  5728. else
  5729. TIName:=Pas2JSBuiltInNames[pbitnTIClass];
  5730. okInterface:
  5731. TIName:=Pas2JSBuiltInNames[pbitnTIInterface];
  5732. else
  5733. RaiseNotYetImplemented(20200927100825,ConEl,GetObjPath(Param));
  5734. end
  5735. else
  5736. RaiseNotYetImplemented(20191018180131,ConEl,GetObjPath(Param));
  5737. end;
  5738. end;
  5739. if TIName='' then
  5740. begin
  5741. // generic template without constraints
  5742. TIName:=Pas2JSBuiltInNames[pbitnTI];
  5743. end;
  5744. end;
  5745. end
  5746. else if ParamResolved.BaseType=btSet then
  5747. begin
  5748. if ParamResolved.IdentEl is TPasSetType then
  5749. TIName:=Pas2JSBuiltInNames[pbitnTISet];
  5750. end
  5751. else if ParamResolved.BaseType=btRange then
  5752. begin
  5753. ConvertRangeToElement(ParamResolved);
  5754. if ParamResolved.BaseType in btAllJSInteger then
  5755. TIName:=Pas2JSBuiltInNames[pbitnTIInteger]
  5756. else if ParamResolved.BaseType in [btChar,btBoolean] then
  5757. TIName:=Pas2JSBuiltInNames[pbitnTI]
  5758. else if ParamResolved.BaseType=btContext then
  5759. begin
  5760. TypeEl:=ParamResolved.LoTypeEl;
  5761. C:=TypeEl.ClassType;
  5762. if C=TPasEnumType then
  5763. TIName:=Pas2JSBuiltInNames[pbitnTIEnum];
  5764. end;
  5765. end
  5766. else if C=TPasRangeType then
  5767. begin
  5768. if ParamResolved.BaseType in btAllJSInteger then
  5769. TIName:=Pas2JSBuiltInNames[pbitnTIInteger]
  5770. else if ParamResolved.BaseType in [btChar,btBoolean] then
  5771. TIName:=Pas2JSBuiltInNames[pbitnTI]
  5772. end;
  5773. //writeln('TPas2JSResolver.BI_TypeInfo_OnGetCallResult TIName=',TIName,' ',GetObjName(TypeEl));
  5774. if TIName='' then
  5775. begin
  5776. {$IFDEF VerbosePas2JS}
  5777. writeln('TPas2JSResolver.BI_TypeInfo_OnGetCallResult ',GetResolverResultDbg(ParamResolved));
  5778. {$ENDIF}
  5779. RaiseNotYetImplemented(20170413091852,Param);
  5780. end;
  5781. // search for TIName
  5782. ScopeDepth:=StashSubExprScopes;
  5783. FindData:=Default(TPRFindData);
  5784. FindData.ErrorPosEl:=Params;
  5785. Abort:=false;
  5786. IterateElements(TIName,@OnFindFirst,@FindData,Abort);
  5787. RestoreStashedScopes(ScopeDepth);
  5788. {$IFDEF VerbosePas2JS}
  5789. writeln('TPas2JSResolver.BI_TypeInfo_OnGetCallResult TIName="',TIName,'" FindData.Found="',GetObjName(FindData.Found),'"');
  5790. {$ENDIF}
  5791. if FindData.Found is TPasType then
  5792. begin
  5793. TypeEl:=ResolveAliasType(TPasType(FindData.Found));
  5794. if TypeEl.ClassType=TPasClassType then
  5795. begin
  5796. FoundClass:=TPasClassType(FindData.Found);
  5797. if FoundClass.IsExternal
  5798. and (FoundClass.ExternalName=Pas2JSBuiltInNames[pbivnRTL]+'.'+TIName) then
  5799. begin
  5800. // use external class definition
  5801. {$IFDEF VerbosePas2JS}
  5802. writeln('TPas2JSResolver.BI_TypeInfo_OnGetCallResult FindData.Found="',FindData.Found.ParentPath,'"');
  5803. {$ENDIF}
  5804. SetResolverTypeExpr(ResolvedEl,btContext,FoundClass,TPasType(FindData.Found),[rrfReadable]);
  5805. exit;
  5806. end;
  5807. end;
  5808. end;
  5809. // default: btPointer
  5810. SetResolverTypeExpr(ResolvedEl,btPointer,BaseTypes[btPointer],BaseTypes[btPointer],[rrfReadable]);
  5811. if Proc=nil then ;
  5812. end;
  5813. function TPas2JSResolver.BI_Debugger_OnGetCallCompatibility(
  5814. Proc: TResElDataBuiltInProc; Expr: TPasExpr; RaiseOnError: boolean): integer;
  5815. // debugger;
  5816. begin
  5817. if Expr is TParamsExpr then
  5818. Result:=CheckBuiltInMaxParamCount(Proc,TParamsExpr(Expr),0,RaiseOnError)
  5819. else
  5820. Result:=cExact;
  5821. end;
  5822. function TPas2JSResolver.BI_AWait_OnGetCallCompatibility(
  5823. Proc: TResElDataBuiltInProc; Expr: TPasExpr; RaiseOnError: boolean): integer;
  5824. // await(T; p: TJSPromise): T
  5825. // await(T; jsvalue): T
  5826. // await(AsyncFuncWithResultT): T
  5827. // await(AsyncProc);
  5828. var
  5829. Params: TParamsExpr;
  5830. Param: TPasExpr;
  5831. ParamResolved, Param2Resolved: TPasResolverResult;
  5832. ParentProc: TPasProcedure;
  5833. TypeEl: TPasType;
  5834. function CheckProcedureAsync(const Proc: TPasProcedureType): Boolean;
  5835. var
  5836. FunctionType: TPasFunctionType absolute Proc;
  5837. begin
  5838. Result := Proc.IsAsync or ((Proc is TPasFunctionType)
  5839. and ((FunctionType.ResultEl.ResultType is TPasClassType) and IsPromiseClass(FunctionType.ResultEl.ResultType as TPasClassType))
  5840. or (FunctionType.ResultEl.ResultType is TPasSpecializeType) and (IsPromiseClass(TPasSpecializeType(FunctionType.ResultEl.ResultType).DestType as TPasClassType)));
  5841. if not Result then
  5842. begin
  5843. {$IFDEF VerbosePas2JS}
  5844. writeln('TPas2JSResolver.BI_AWait_OnGetCallCompatibility ',GetResolverResultDbg(ParamResolved));
  5845. {$ENDIF}
  5846. if RaiseOnError then
  5847. RaiseMsg(20201229232446, nXExpectedButYFound, sXExpectedButYFound, [
  5848. sAsyncFunctionOrPromise, GetResolverResultDescription(ParamResolved)], Expr);
  5849. end;
  5850. end;
  5851. begin
  5852. Result:=cIncompatible;
  5853. // check if inside async proc
  5854. ParentProc:=GetParentProc(Expr,true);
  5855. if (ParentProc=nil) or not ParentProc.IsAsync then
  5856. begin
  5857. if RaiseOnError then
  5858. RaiseMsg(20200519153349,nAWaitOnlyInAsyncProcedure,sAWaitOnlyInAsyncProcedure,[],Expr);
  5859. exit;
  5860. end;
  5861. if not CheckBuiltInMinParamCount(Proc,Expr,1,RaiseOnError) then
  5862. exit;
  5863. Params:=TParamsExpr(Expr);
  5864. Param:=Params.Params[0];
  5865. ComputeElement(Param,ParamResolved,[]);
  5866. if (rrfReadable in ParamResolved.Flags) then
  5867. begin
  5868. // function await(value)
  5869. // must be the only parameter
  5870. Result:=CheckBuiltInMaxParamCount(Proc,Params,1,RaiseOnError);
  5871. if Result=cIncompatible then exit;
  5872. TypeEl:=ParamResolved.LoTypeEl;
  5873. if (ParamResolved.IdentEl is TPasResultElement) then
  5874. begin
  5875. // await(AsyncFuncCall)
  5876. if not CheckProcedureAsync(TPasProcedureType(ParamResolved.IdentEl.Parent)) then
  5877. Exit(cIncompatible);
  5878. end
  5879. else if (ParamResolved.BaseType=btContext)
  5880. and (TypeEl is TPasProcedureType) then
  5881. begin
  5882. // await(AsyncFuncTypeVar)
  5883. if not CheckProcedureAsync(TPasProcedureType(TypeEl)) then
  5884. Exit(cIncompatible);
  5885. end
  5886. else if (ParamResolved.BaseType=btContext)
  5887. and (ParamResolved.IdentEl is TPasProcedure) then
  5888. begin
  5889. if not CheckProcedureAsync(TPasProcedure(ParamResolved.IdentEl).ProcType) then
  5890. Exit(cIncompatible)
  5891. end
  5892. else
  5893. begin
  5894. {$IFDEF VerbosePas2JS}
  5895. writeln('TPas2JSResolver.BI_AWait_OnGetCallCompatibility ',GetResolverResultDbg(ParamResolved));
  5896. {$ENDIF}
  5897. if RaiseOnError then
  5898. RaiseMsg(20201229224920,nXExpectedButYFound,sXExpectedButYFound,['async function',GetResolverResultDescription(ParamResolved)],Expr)
  5899. else
  5900. exit(cIncompatible);
  5901. end;
  5902. end
  5903. else if ParamResolved.BaseType=btProc then
  5904. begin
  5905. // e.g. await(Proc)
  5906. if Expr.Parent is TPasExpr then
  5907. begin
  5908. if RaiseOnError then
  5909. RaiseMsg(20200523232827,nXExpectedButYFound,sXExpectedButYFound,['async function',GetResolverResultDescription(ParamResolved)],Expr);
  5910. exit;
  5911. end;
  5912. Result:=CheckBuiltInMaxParamCount(Proc,Params,1,RaiseOnError);
  5913. end
  5914. else
  5915. begin
  5916. TypeEl:=ParamResolved.LoTypeEl;
  5917. if (TypeEl is TPasUnresolvedSymbolRef)
  5918. and (TypeEl.CustomData is TResElDataBaseType) then
  5919. // base type
  5920. else if (TypeEl<>nil) and (ParamResolved.IdentEl is TPasType) then
  5921. begin
  5922. // custom type
  5923. if (ParamResolved.BaseType=btContext)
  5924. and (ParamResolved.LoTypeEl is TPasClassType)
  5925. and IsPromiseClass(TPasClassType(ParamResolved.LoTypeEl)) then
  5926. begin
  5927. // awit(TJSPromise,x) -> await resolves all promises
  5928. exit(CheckRaiseTypeArgNo(20201120001741,1,Param,ParamResolved,'non Promise type',RaiseOnError));
  5929. end;
  5930. end
  5931. else
  5932. exit(CheckRaiseTypeArgNo(20200519151816,1,Param,ParamResolved,'jsvalue',RaiseOnError));
  5933. // function await(type,...)
  5934. if length(Params.Params)<2 then
  5935. begin
  5936. if RaiseOnError then
  5937. RaiseMsg(20200520090749,nWrongNumberOfParametersForCallTo,
  5938. sWrongNumberOfParametersForCallTo,[AwaitSignature2],Params);
  5939. exit(cIncompatible);
  5940. end;
  5941. // check second param TJSPromise
  5942. Param:=Params.Params[1];
  5943. if CheckCallAsyncFuncResult(Param,Param2Resolved) then
  5944. begin
  5945. // await(T,CallAsyncFuncResultS)
  5946. if (Param2Resolved.BaseType=btContext)
  5947. and (Param2Resolved.LoTypeEl is TPasClassType)
  5948. and IsPromiseClass(TPasClassType(Param2Resolved.LoTypeEl)) then
  5949. begin
  5950. // await(T,CallAsyncFuncReturningPromise) -> good
  5951. end
  5952. else
  5953. begin
  5954. // await(T,CallAsyncFuncResultS)
  5955. // Note: Actually this case is not needed, as you can simply write await(AsyncCall)
  5956. // but it helps some parsers and some people find it more readable
  5957. // make sure you cannot shoot yourself in the foot: -> check T=S OR S is T
  5958. ParamResolved.Flags:=[rrfReadable,rrfWritable];
  5959. ParamResolved.IdentEl:=nil;
  5960. Result:=CheckParamResCompatibility(Param,Param2Resolved,ParamResolved,1,RaiseOnError,false);
  5961. exit;
  5962. end;
  5963. end
  5964. else
  5965. begin
  5966. ComputeElement(Param,Param2Resolved,[]);
  5967. if not (rrfReadable in Param2Resolved.Flags) then
  5968. exit(CheckRaiseTypeArgNo(20200520091707,2,Param,Param2Resolved,
  5969. 'instance of TJSPromise',RaiseOnError));
  5970. if (Param2Resolved.BaseType=btContext)
  5971. and (Param2Resolved.LoTypeEl is TPasClassType)
  5972. and IsPromiseClass(TPasClassType(Param2Resolved.LoTypeEl)) then
  5973. // await(T,aPromise)
  5974. else if IsJSBaseType(Param2Resolved,pbtJSValue) then
  5975. // await(T,jsvalue)
  5976. else if (Param2Resolved.IdentEl is TPasArgument)
  5977. and (Param2Resolved.LoTypeEl=nil) then
  5978. // await(T,UntypedArg)
  5979. else
  5980. exit(CheckRaiseTypeArgNo(20200520091708,2,Param,Param2Resolved,
  5981. 'TJSPromise',RaiseOnError));
  5982. end;
  5983. Result:=CheckBuiltInMaxParamCount(Proc,Params,2,RaiseOnError,AwaitSignature2);
  5984. end;
  5985. end;
  5986. procedure TPas2JSResolver.BI_AWait_OnGetCallResult(Proc: TResElDataBuiltInProc;
  5987. Params: TParamsExpr; out ResolvedEl: TPasResolverResult);
  5988. // function await(const Expr: T): T
  5989. // function await(T; p: TJSPromise): T
  5990. // await(Proc());
  5991. var
  5992. Param: TPasExpr;
  5993. begin
  5994. Param:=Params.Params[0];
  5995. if length(Params.Params)=1 then
  5996. begin
  5997. // await(AsyncFuncCall)
  5998. if CheckCallAsyncFuncResult(Param,ResolvedEl) then
  5999. begin
  6000. // await(CallAsynFuncResultT): T
  6001. if (ResolvedEl.BaseType=btContext)
  6002. and (ResolvedEl.LoTypeEl is TPasClassType)
  6003. and IsPromiseClass(TPasClassType(ResolvedEl.LoTypeEl)) then
  6004. // async function returns a promise, await resolve all promises -> need final type as first param
  6005. RaiseMsg(20201229235932,nWrongNumberOfParametersForCallTo,
  6006. sWrongNumberOfParametersForCallTo,[AwaitSignature2],Param);
  6007. exit;
  6008. end;
  6009. end
  6010. else
  6011. begin
  6012. // await(T;promise):T
  6013. end;
  6014. ComputeElement(Param,ResolvedEl,[]);
  6015. ResolvedEl.IdentEl:=nil;
  6016. Include(ResolvedEl.Flags,rrfReadable);
  6017. if Proc=nil then ;
  6018. end;
  6019. procedure TPas2JSResolver.BI_AWait_OnEval(Proc: TResElDataBuiltInProc;
  6020. Params: TParamsExpr; Flags: TResEvalFlags; out Evaluated: TResEvalValue);
  6021. var
  6022. Param: TPasExpr;
  6023. ParamResolved: TPasResolverResult;
  6024. begin
  6025. Evaluated:=nil;
  6026. if length(Params.Params)<>1 then
  6027. exit;
  6028. Param:=Params.Params[0];
  6029. ComputeElement(Param,ParamResolved,[]);
  6030. Evaluated:=Eval(Param,Flags);
  6031. if Proc=nil then ;
  6032. end;
  6033. procedure TPas2JSResolver.BI_AWait_OnFinishParamsExpr(
  6034. Proc: TResElDataBuiltInProc; Params: TParamsExpr);
  6035. var
  6036. P: TPasExprArray;
  6037. Param, PathEnd: TPasExpr;
  6038. Ref: TResolvedReference;
  6039. Decl, IdentEl, SubEl: TPasElement;
  6040. ResolvedEl, ParamResolved: TPasResolverResult;
  6041. Implicit, IsPromise: Boolean;
  6042. TypeEl: TPasType;
  6043. begin
  6044. if Proc=nil then ;
  6045. P:=Params.Params;
  6046. if P=nil then ;
  6047. Param:=P[0];
  6048. FinishCallArgAccess(Param,rraRead);
  6049. if length(P)=1 then
  6050. begin
  6051. // await(expr)
  6052. PathEnd:=GetPathEndIdent(Param,false);
  6053. if (PathEnd<>nil) and (PathEnd.CustomData is TResolvedReference) then
  6054. begin
  6055. // await(a.b)
  6056. Ref:=TResolvedReference(PathEnd.CustomData);
  6057. Decl:=Ref.Declaration;
  6058. Implicit:=false;
  6059. if (Decl is TPasVariable) or (Decl.ClassType=TPasArgument) then
  6060. begin
  6061. ComputeElement(Decl,ResolvedEl,[rcNoImplicitProcType]);
  6062. if IsProcedureType(ResolvedEl,true) then
  6063. Implicit:=true;
  6064. end
  6065. else if (Decl is TPasProcedure) then
  6066. Implicit:=true;
  6067. if Implicit then begin
  6068. // implicit call
  6069. Exclude(Ref.Flags,rrfNoImplicitCallWithoutParams);
  6070. Include(Ref.Flags,rrfImplicitCallWithoutParams);
  6071. end;
  6072. end
  6073. else
  6074. begin
  6075. ComputeElement(Param,ParamResolved,[]);
  6076. IsPromise:=false;
  6077. TypeEl:=ParamResolved.LoTypeEl;
  6078. IdentEl:=ParamResolved.IdentEl;
  6079. if TypeEl.ClassType=TPasClassType then
  6080. IsPromise:=IsPromiseClass(TPasClassType(TypeEl))
  6081. else if (ParamResolved.BaseType=btProc) and (IdentEl=nil)
  6082. and (TypeEl is TPasProcedureType) then
  6083. IsPromise:=TPasProcedureType(TypeEl).IsAsync
  6084. else if IdentEl is TPasProcedure then
  6085. IsPromise:=TPasProcedure(ParamResolved.IdentEl).IsAsync
  6086. else if IdentEl is TPasResultElement then
  6087. begin
  6088. SubEl:=TPasResultElement(IdentEl).Parent;
  6089. if (SubEl is TPasFunctionType) then
  6090. IsPromise:=TPasFunctionType(SubEl).IsAsync;
  6091. end;
  6092. {$IFDEF VerbosePas2JS}
  6093. writeln('TPas2JSResolver.BI_AWait_OnFinishParamsExpr Param=',GetObjPath(Param),' ParamResolved=',GetResolverResultDbg(ParamResolved));
  6094. {$ENDIF}
  6095. if not IsPromise then
  6096. LogMsg(20201116000324,mtHint,nAwaitWithoutPromise,sAwaitWithoutPromise,[],Param);
  6097. end;
  6098. end;
  6099. if length(P)>1 then
  6100. FinishCallArgAccess(P[1],rraRead);
  6101. if length(P)>2 then
  6102. RaiseNotYetImplemented(20200525142451,Params);
  6103. end;
  6104. constructor TPas2JSResolver.Create;
  6105. var
  6106. bt: TPas2jsBaseType;
  6107. begin
  6108. inherited;
  6109. // prefer overloads of GUID with string
  6110. cInterfaceToTGUID:=cTypeConversion+2;
  6111. cInterfaceToString:=cTypeConversion+1;
  6112. {$IFDEF FPC_HAS_CPSTRING}
  6113. ExprEvaluator.DefaultSourceCodePage:=CP_UTF8;
  6114. ExprEvaluator.DefaultStringCodePage:=CP_UTF16;
  6115. {$ENDIF}
  6116. FExternalNames:=TPasResHashList.Create;
  6117. StoreSrcColumns:=true;
  6118. Options:=Options+DefaultPasResolverOptions;
  6119. ScopeClass_Class:=TPas2JSClassScope;
  6120. ScopeClass_InitialFinalization:=TPas2JSInitialFinalizationScope;
  6121. ScopeClass_Module:=TPas2JSModuleScope;
  6122. ScopeClass_Procedure:=TPas2JSProcedureScope;
  6123. ScopeClass_Record:=TPas2JSRecordScope;
  6124. ScopeClass_Array:=TPas2JSArrayScope;
  6125. ScopeClass_ProcType:=TPas2JSProcTypeScope;
  6126. ScopeClass_Section:=TPas2JSSectionScope;
  6127. ScopeClass_WithExpr:=TPas2JSWithExprScope;
  6128. for bt in [pbtJSValue] do
  6129. AddJSBaseType(Pas2jsBaseTypeNames[bt],bt);
  6130. AnonymousElTypePostfix:=Pas2JSBuiltInNames[pbitnAnonymousPostfix];
  6131. BaseTypeChar:=btWideChar;
  6132. BaseTypeString:=btUnicodeString;
  6133. BaseTypeLength:=btIntDouble;
  6134. end;
  6135. destructor TPas2JSResolver.Destroy;
  6136. begin
  6137. ClearElementData;
  6138. {$IFDEF pas2js}
  6139. FExternalNames:=nil;
  6140. {$ELSE}
  6141. FreeAndNil(FExternalNames);
  6142. {$ENDIF}
  6143. ClearOverloadScopes;
  6144. inherited Destroy;
  6145. end;
  6146. procedure TPas2JSResolver.ClearBuiltInIdentifiers;
  6147. var
  6148. bt: TPas2jsBaseType;
  6149. pbp: TPas2jsBuiltInProc;
  6150. begin
  6151. inherited ClearBuiltInIdentifiers;
  6152. for bt in TPas2jsBaseType do
  6153. FJSBaseTypes[bt]:=nil;
  6154. for pbp in TPas2jsBuiltInProc do
  6155. FJSBuiltInProcs[pbp]:=nil;
  6156. end;
  6157. function TPas2JSResolver.IsJSBaseType(TypeEl: TPasType; Typ: TPas2jsBaseType
  6158. ): boolean;
  6159. begin
  6160. Result:=(TypeEl is TPasUnresolvedSymbolRef)
  6161. and (CompareText(TypeEl.Name,Pas2jsBaseTypeNames[Typ])=0)
  6162. and (TypeEl.CustomData is TResElDataPas2JSBaseType);
  6163. end;
  6164. function TPas2JSResolver.IsJSBaseType(const TypeResolved: TPasResolverResult;
  6165. Typ: TPas2jsBaseType; HasValue: boolean): boolean;
  6166. begin
  6167. if (TypeResolved.BaseType<>btCustom) or not IsJSBaseType(TypeResolved.LoTypeEl,Typ) then
  6168. exit(false);
  6169. if HasValue and not (rrfReadable in TypeResolved.Flags) then
  6170. exit(false);
  6171. Result:=true;
  6172. end;
  6173. function TPas2JSResolver.IsPromiseClass(aClass: TPasClassType): Boolean;
  6174. begin
  6175. Result := IsExternalClass_Name(aClass, 'Promise');
  6176. end;
  6177. procedure TPas2JSResolver.AddObjFPCBuiltInIdentifiers(
  6178. const TheBaseTypes: TResolveBaseTypes;
  6179. const TheBaseProcs: TResolverBuiltInProcs);
  6180. var
  6181. InvalidTypes: TResolveBaseTypes;
  6182. bt: TResolverBaseType;
  6183. InvalidProcs: TResolverBuiltInProcs;
  6184. bf: TResolverBuiltInProc;
  6185. begin
  6186. InvalidTypes:=TheBaseTypes-btAllJSBaseTypes;
  6187. if InvalidTypes<>[] then
  6188. for bt in InvalidTypes do
  6189. RaiseInternalError(20170409180202,BaseTypeNames[bt]);
  6190. InvalidProcs:=TheBaseProcs-bfAllJSBaseProcs;
  6191. if InvalidProcs<>[] then
  6192. for bf in InvalidProcs do
  6193. RaiseInternalError(20170409180246,ResolverBuiltInProcNames[bf]);
  6194. inherited AddObjFPCBuiltInIdentifiers(TheBaseTypes-[btUIntDouble,btIntDouble],TheBaseProcs);
  6195. if btUIntDouble in TheBaseTypes then
  6196. AddBaseType(Pas2JSBuiltInNames[pbitnUIntDouble],btUIntDouble);
  6197. if btIntDouble in TheBaseTypes then
  6198. AddBaseType(Pas2JSBuiltInNames[pbitnIntDouble],btIntDouble);
  6199. FJSBuiltInProcs[pbpDebugger]:=AddBuiltInProc(Pas2jsBuiltInProcNames[pbpDebugger],
  6200. 'procedure Debugger',
  6201. @BI_Debugger_OnGetCallCompatibility,nil,
  6202. nil,nil,bfCustom,[bipfCanBeStatement]);
  6203. FJSBuiltInProcs[pbpAWait]:=AddBuiltInProc(Pas2jsBuiltInProcNames[pbpAWait],
  6204. 'function await(const Expr: T): T',
  6205. @BI_AWait_OnGetCallCompatibility,@BI_AWait_OnGetCallResult,
  6206. @BI_AWait_OnEval,@BI_AWait_OnFinishParamsExpr,bfCustom,[bipfCanBeStatement]);
  6207. end;
  6208. function TPas2JSResolver.CheckTypeCastRes(const FromResolved,
  6209. ToResolved: TPasResolverResult; ErrorEl: TPasElement; RaiseOnError: boolean
  6210. ): integer;
  6211. function Incompatible(Id: TMaxPrecInt): integer;
  6212. begin
  6213. if RaiseOnError then
  6214. RaiseIncompatibleTypeRes(Id,nIllegalTypeConversionTo,
  6215. [],FromResolved,ToResolved,ErrorEl);
  6216. Result:=cIncompatible;
  6217. end;
  6218. var
  6219. JSBaseType: TPas2jsBaseType;
  6220. C: TClass;
  6221. ToClass: TPasClassType;
  6222. ToTypeEl, FromTypeEl: TPasType;
  6223. begin
  6224. Result:=cIncompatible;
  6225. {$IFDEF VerbosePas2JS}
  6226. writeln('TPas2JSResolver.CheckTypeCastRes To=',GetResolverResultDbg(ToResolved),' From=',GetResolverResultDbg(FromResolved));
  6227. {$ENDIF}
  6228. if rrfReadable in FromResolved.Flags then
  6229. begin
  6230. if (ToResolved.BaseType=btCustom) then
  6231. begin
  6232. ToTypeEl:=ToResolved.LoTypeEl;
  6233. if not (ToTypeEl is TPasUnresolvedSymbolRef) then
  6234. RaiseInternalError(20170325142826);
  6235. if (ToTypeEl.CustomData is TResElDataPas2JSBaseType) then
  6236. begin
  6237. // type cast to pas2js type, e.g. JSValue(V)
  6238. JSBaseType:=TResElDataPas2JSBaseType(ToTypeEl.CustomData).JSBaseType;
  6239. if JSBaseType=pbtJSValue then
  6240. begin
  6241. if (FromResolved.BaseType in btAllJSValueSrcTypes) then
  6242. Result:=cCompatible // type cast to JSValue
  6243. else if FromResolved.BaseType=btCustom then
  6244. begin
  6245. if IsJSBaseType(FromResolved,pbtJSValue) then
  6246. Result:=cExact;
  6247. end
  6248. else if FromResolved.BaseType=btContext then
  6249. Result:=cCompatible;
  6250. end;
  6251. exit;
  6252. end;
  6253. end
  6254. else if FromResolved.BaseType=btCustom then
  6255. begin
  6256. FromTypeEl:=FromResolved.LoTypeEl;
  6257. if not (FromTypeEl is TPasUnresolvedSymbolRef) then
  6258. RaiseInternalError(20170325143016);
  6259. if (FromTypeEl.CustomData is TResElDataPas2JSBaseType) then
  6260. begin
  6261. // type cast a pas2js value, e.g. T(jsvalue)
  6262. JSBaseType:=TResElDataPas2JSBaseType(FromTypeEl.CustomData).JSBaseType;
  6263. if JSBaseType=pbtJSValue then
  6264. begin
  6265. if (ToResolved.BaseType in btAllJSValueTypeCastTo) then
  6266. Result:=cCompatible // type cast JSValue to simple base type
  6267. else if ToResolved.BaseType=btContext then
  6268. begin
  6269. // typecast JSValue to user type
  6270. Result:=cCompatible;
  6271. end;
  6272. end;
  6273. exit;
  6274. end;
  6275. end
  6276. else if ToResolved.BaseType=btContext then
  6277. begin
  6278. ToTypeEl:=ToResolved.LoTypeEl;
  6279. C:=ToTypeEl.ClassType;
  6280. if C=TPasClassType then
  6281. begin
  6282. ToClass:=TPasClassType(ToTypeEl);
  6283. if ToClass.IsExternal then
  6284. begin
  6285. if (FromResolved.BaseType in btAllJSStringAndChars) then
  6286. begin
  6287. if IsExternalClass_Name(ToClass,'String') then
  6288. // TJSString(aString)
  6289. exit(cExact);
  6290. end
  6291. else if (FromResolved.BaseType=btArrayLit) then
  6292. begin
  6293. if IsExternalClass_Name(ToClass,'Array') then
  6294. // TJSArray([...])
  6295. exit(cExact);
  6296. end
  6297. else if (FromResolved.BaseType=btContext) then
  6298. begin
  6299. FromTypeEl:=FromResolved.LoTypeEl;
  6300. if FromTypeEl.ClassType=TPasArrayType then
  6301. begin
  6302. if IsExternalClass_Name(ToClass,'Array')
  6303. or IsExternalClass_Name(ToClass,'Object') then
  6304. // TJSArray(AnArray) or TJSObject(AnArray)
  6305. exit(cExact);
  6306. end
  6307. else if FromTypeEl.ClassType=TPasRecordType then
  6308. begin
  6309. if IsExternalClass_Name(ToClass,'Object') then
  6310. // TJSObject(aRecord)
  6311. exit(cExact);
  6312. end
  6313. else if FromTypeEl.ClassType=TPasClassOfType then
  6314. begin
  6315. if IsExternalClass_Name(ToClass,'Object') then
  6316. // TJSObject(ImgClass)
  6317. exit(cExact);
  6318. end
  6319. else if FromTypeEl.InheritsFrom(TPasProcedureType) then
  6320. begin
  6321. if IsExternalClass_Name(ToClass,'Function')
  6322. or IsExternalClass_Name(ToClass,'Object') then
  6323. // TJSFunction(@Proc) or TJSFunction(ProcVar)
  6324. exit(cExact);
  6325. end
  6326. else if FromTypeEl.ClassType=TPasClassType then
  6327. begin
  6328. if TPasClassType(FromTypeEl).IsExternal
  6329. and (msDelphi in CurrentParser.CurrentModeswitches)
  6330. and not (bsObjectChecks in CurrentParser.Scanner.CurrentBoolSwitches) then
  6331. // ExtClass(ExtClass) -> allow in mode delphi and no objectchecks
  6332. exit(cAliasExact); // $mode delphi
  6333. end;
  6334. end;
  6335. end;
  6336. end
  6337. else if C=TPasArrayType then
  6338. begin
  6339. if (FromResolved.BaseType=btContext) then
  6340. begin
  6341. FromTypeEl:=FromResolved.LoTypeEl;
  6342. if (FromTypeEl.ClassType=TPasClassType)
  6343. and TPasClassType(FromTypeEl).IsExternal
  6344. and (IsExternalClass_Name(TPasClassType(FromTypeEl),'Array')
  6345. or IsExternalClass_Name(TPasClassType(FromTypeEl),'Object')) then
  6346. begin
  6347. // type cast external Array/Object to an array
  6348. exit(cCompatible);
  6349. end;
  6350. end;
  6351. end
  6352. else if C=TPasRecordType then
  6353. begin
  6354. // typecast to recordtype
  6355. if FromResolved.BaseType=btUntyped then
  6356. // recordtype(untyped) -> ok
  6357. else if FromResolved.BaseType=btContext then
  6358. begin
  6359. FromTypeEl:=FromResolved.LoTypeEl;
  6360. if FromTypeEl=ToTypeEl then
  6361. exit(cAliasExact)
  6362. else
  6363. // FPC/Delphi allow typecasting records of same size, pas2js does not
  6364. exit(Incompatible(20180503134526));
  6365. end
  6366. else
  6367. exit(Incompatible(20180503134528));
  6368. end
  6369. else if C.InheritsFrom(TPasProcedureType) then
  6370. begin
  6371. // typecast to proctype
  6372. if FromResolved.BaseType=btContext then
  6373. begin
  6374. FromTypeEl:=FromResolved.LoTypeEl;
  6375. if FromTypeEl.ClassType=TPasClassType then
  6376. begin
  6377. if IsExternalClass_Name(TPasClassType(FromTypeEl),'Function') then
  6378. // TProcType(aJSFunction)
  6379. exit(cCompatible);
  6380. end;
  6381. end;
  6382. end;
  6383. end;
  6384. end
  6385. else if FromResolved.IdentEl is TPasType then
  6386. begin
  6387. // FromResolved is a type
  6388. FromTypeEl:=ResolveAliasType(TPasType(FromResolved.IdentEl));
  6389. if ToResolved.BaseType=btContext then
  6390. begin
  6391. ToTypeEl:=ToResolved.LoTypeEl;
  6392. if (ToTypeEl.ClassType=TPasClassType)
  6393. and TPasClassType(ToTypeEl).IsExternal
  6394. and (TPasClassType(ToTypeEl).ExternalName='Object') // do not allow typecast to a descendant!
  6395. then
  6396. begin
  6397. // type cast to JS Object, not a descendant
  6398. if (FromTypeEl.ClassType=TPasClassType)
  6399. or (FromTypeEl.ClassType=TPasRecordType) then
  6400. // e.g. TJSObject(TObject)
  6401. exit(cTypeConversion+1);
  6402. end;
  6403. end;
  6404. end;
  6405. Result:=inherited CheckTypeCastRes(FromResolved,ToResolved,ErrorEl,RaiseOnError);
  6406. end;
  6407. function TPas2JSResolver.FindLocalBuiltInSymbol(El: TPasElement): TPasElement;
  6408. var
  6409. Data: TObject;
  6410. pbp: TPas2jsBuiltInProc;
  6411. begin
  6412. Result:=inherited FindLocalBuiltInSymbol(El);
  6413. if Result<>nil then exit;
  6414. Data:=El.CustomData;
  6415. if Data is TResElDataPas2JSBaseType then
  6416. Result:=JSBaseTypes[TResElDataPas2JSBaseType(Data).JSBaseType]
  6417. else if (Data.ClassType=TResElDataBuiltInProc)
  6418. and (TResElDataBuiltInProc(Data).BuiltIn=bfCustom) then
  6419. for pbp in TPas2jsBuiltInProc do
  6420. if El.Name=Pas2jsBuiltInProcNames[pbp] then
  6421. Result:=FJSBuiltInProcs[pbp].Element;
  6422. end;
  6423. function TPas2JSResolver.ExtractPasStringLiteral(El: TPasElement;
  6424. const S: String): TJSString;
  6425. { Extracts the value from a Pascal string literal
  6426. S is a Pascal string literal e.g. 'Line'#10
  6427. '' empty string
  6428. '''' => "'"
  6429. #decimal
  6430. #$hex
  6431. ^l l is a letter a-z
  6432. Note that invalid UTF-8 sequences are checked by the scanner
  6433. }
  6434. var
  6435. p, StartP, l: integer;
  6436. procedure Err(id: TMaxPrecInt);
  6437. begin
  6438. RaiseMsg(id,nIllegalCharConst,sIllegalCharConst,[],El);
  6439. end;
  6440. function ReadNumber: integer;
  6441. var
  6442. c: AnsiChar;
  6443. begin
  6444. Result:=0;
  6445. inc(p);
  6446. if p>l then
  6447. Err(20170207155121);
  6448. if S[p]='$' then
  6449. begin
  6450. // #$hexnumber
  6451. inc(p);
  6452. StartP:=p;
  6453. while p<=l do
  6454. begin
  6455. c:=S[p];
  6456. case c of
  6457. '0'..'9': Result:=Result*16+ord(c)-ord('0');
  6458. 'a'..'f': Result:=Result*16+ord(c)-ord('a')+10;
  6459. 'A'..'F': Result:=Result*16+ord(c)-ord('A')+10;
  6460. else break;
  6461. end;
  6462. if Result>$10ffff then
  6463. Err(20170207164657);
  6464. inc(p);
  6465. end;
  6466. if p=StartP then
  6467. Err(20170207164956);
  6468. end
  6469. else
  6470. begin
  6471. // #decimalnumber
  6472. StartP:=p;
  6473. while p<=l do
  6474. begin
  6475. c:=S[p];
  6476. case c of
  6477. '0'..'9': Result:=Result*10+ord(c)-ord('0');
  6478. else break;
  6479. end;
  6480. if Result>$10ffff then
  6481. Err(20170207171140);
  6482. inc(p);
  6483. end;
  6484. if p=StartP then
  6485. Err(20170207171148);
  6486. end;
  6487. end;
  6488. var
  6489. c: AnsiChar;
  6490. i, j: Integer;
  6491. begin
  6492. Result:='';
  6493. {$IFDEF VerbosePas2JS}
  6494. writeln('TPasToJSConverter.ExtractPasStringLiteral S="',S,'" ',{$IFDEF pas2js}copy(s,100){$ELSE}RawStrToCaption(S,100){$ENDIF},' ',length(S));
  6495. {$ENDIF}
  6496. if S='' then
  6497. RaiseInternalError(20170207154543);
  6498. p:=1;
  6499. l:=length(S);
  6500. while p<=l do
  6501. case S[p] of
  6502. '''':
  6503. begin
  6504. inc(p);
  6505. StartP:=p;
  6506. repeat
  6507. if p>l then
  6508. Err(20170207155120);
  6509. c:=S[p];
  6510. case c of
  6511. '''':
  6512. begin
  6513. if p>StartP then
  6514. Result:=Result+StrToJSString(copy(S,StartP,p-StartP)); // todo error on invalid UTF-8 sequence
  6515. inc(p);
  6516. StartP:=p;
  6517. if (p>l) or (S[p]<>'''') then
  6518. break;
  6519. Result:=Result+'''';
  6520. inc(p);
  6521. StartP:=p;
  6522. end;
  6523. else
  6524. inc(p);
  6525. end;
  6526. until false;
  6527. if p>StartP then
  6528. Result:=Result+StrToJSString(copy(S,StartP,p-StartP)); // todo error on invalid UTF-8 sequence
  6529. end;
  6530. '#':
  6531. begin
  6532. // number
  6533. i:=ReadNumber;
  6534. if (i>=$D800) and (i<=$DFFF) and (p<l) and (S[p]='#') then
  6535. begin
  6536. // surrogate
  6537. j:=ReadNumber;
  6538. if (j>=$DC00) and (j<$DFFF) then
  6539. Result:=Result+CodePointToJSString((i and $3FF) shl 10 + (j and $3ff) + $10000)
  6540. else
  6541. // invalid surrogate -> write as two \u
  6542. Result:=Result+CodePointToJSString(i)+CodePointToJSString(j)
  6543. end
  6544. else
  6545. Result:=Result+CodePointToJSString(i);
  6546. end;
  6547. '^':
  6548. begin
  6549. // ^A is #1
  6550. inc(p);
  6551. if p>l then
  6552. Err(20181025125920);
  6553. c:=S[p];
  6554. case c of
  6555. 'a'..'z': Result:=Result+TJSChar(ord(c)-ord('a')+1);
  6556. 'A'..'Z': Result:=Result+TJSChar(ord(c)-ord('A')+1);
  6557. else Err(20170207160412);
  6558. end;
  6559. inc(p);
  6560. end;
  6561. else
  6562. Err(20170207154653);
  6563. end;
  6564. {$IFDEF VerbosePas2JS}
  6565. {AllowWriteln}
  6566. writeln('TPasToJSConverter.ExtractPasStringLiteral Result="',Result,'"');
  6567. //for i:=1 to length(Result) do
  6568. // writeln(' Result[',i,']',HexStr(ord(Result[i]),4));
  6569. {AllowWriteln-}
  6570. {$ENDIF}
  6571. end;
  6572. function TPas2JSResolver.ResolverToJSValue(Value: TResEvalValue;
  6573. ErrorEl: TPasElement): TJSValue;
  6574. begin
  6575. Result:=nil;
  6576. if Value=nil then exit;
  6577. case Value.Kind of
  6578. revkBool: Result:=TJSValue.Create(TResEvalBool(Value).B);
  6579. revkInt: Result:=TJSValue.Create(TJSNumber(TResEvalInt(Value).Int));
  6580. revkUInt: Result:=TJSValue.Create(TJSNumber(TResEvalUInt(Value).UInt));
  6581. revkFloat: Result:=TJSValue.Create(TJSNumber(TResEvalFloat(Value).FloatValue));
  6582. {$IFDEF FPC_HAS_CPSTRING}
  6583. revkString: Result:=TJSValue.Create(TJSString(
  6584. ExprEvaluator.GetUnicodeStr(TResEvalString(Value).S,ErrorEl)));
  6585. {$ENDIF}
  6586. revkUnicodeString: Result:=TJSValue.Create(TJSString(TResEvalUTF16(Value).S));
  6587. else
  6588. {$IFDEF VerbosePas2JS}
  6589. writeln('TPas2JSResolver.ResolverToJSValue ',Value.AsDebugString);
  6590. {$ENDIF}
  6591. RaiseNotYetImplemented(20170914092413,ErrorEl,'');
  6592. end;
  6593. end;
  6594. function TPas2JSResolver.ComputeConstString(Expr: TPasExpr; StoreCustomData,
  6595. NotEmpty: boolean): String;
  6596. var
  6597. Value: TResEvalValue;
  6598. begin
  6599. Result:='';
  6600. if Expr=nil then
  6601. RaiseInternalError(20170215123600);
  6602. Value:=Eval(Expr,[refAutoConst],StoreCustomData);
  6603. if Value<>nil then
  6604. try
  6605. case Value.Kind of
  6606. {$IFDEF FPC_HAS_CPSTRING}
  6607. revkString: Result:=ExprEvaluator.GetUTF8Str(TResEvalString(Value).S,Expr);
  6608. revkUnicodeString: Result:=UTF8Encode(TResEvalUTF16(Value).S);
  6609. {$ELSE}
  6610. revkUnicodeString: Result:=TResEvalUTF16(Value).S;
  6611. {$ENDIF}
  6612. else
  6613. str(Value.Kind,Result);
  6614. RaiseXExpectedButYFound(20170211221121,'string literal',Result,Expr);
  6615. end;
  6616. finally
  6617. ReleaseEvalValue(Value);
  6618. end;
  6619. if NotEmpty and (Result='') then
  6620. RaiseXExpectedButYFound(20170321085318,'string literal','empty',Expr);
  6621. end;
  6622. procedure TPas2JSResolver.CheckAssignExprRangeToCustom(
  6623. const LeftResolved: TPasResolverResult; RValue: TResEvalValue; RHS: TPasExpr);
  6624. var
  6625. LeftBaseType: TPas2jsBaseType;
  6626. begin
  6627. if (LeftResolved.BaseType<>btCustom) then
  6628. exit;
  6629. if not (LeftResolved.LoTypeEl is TPasUnresolvedSymbolRef) then
  6630. begin
  6631. {$IFDEF VerbosePas2JS}
  6632. writeln('TPas2JSResolver.CheckAssignExprRangeToCustom LeftResolved=',GetResolverResultDbg(LeftResolved));
  6633. {$ENDIF}
  6634. RaiseInternalError(20170902165913);
  6635. end;
  6636. if not (LeftResolved.LoTypeEl.CustomData is TResElDataPas2JSBaseType) then
  6637. exit;
  6638. LeftBaseType:=TResElDataPas2JSBaseType(LeftResolved.LoTypeEl.CustomData).JSBaseType;
  6639. if LeftBaseType=pbtJSValue then
  6640. // jsvalue:=someconst -> ok
  6641. else
  6642. RaiseNotYetImplemented(20170902170153,RHS);
  6643. if RHS=nil then ;
  6644. if RValue=nil then ;
  6645. end;
  6646. function TPas2JSResolver.CheckAssignCompatibilityClasses(LType,
  6647. RType: TPasClassType): integer;
  6648. // LType and RType are not related
  6649. var
  6650. LeftScope, RightScope: TPas2JSClassScope;
  6651. LeftSpecItem, RightSpecItem: TPRSpecializedItem;
  6652. i: Integer;
  6653. LeftParam, RightParam: TPasType;
  6654. begin
  6655. Result:=cIncompatible;
  6656. if LType.IsExternal and RType.IsExternal then
  6657. begin
  6658. LeftScope:=TPas2JSClassScope(LType.CustomData);
  6659. RightScope:=TPas2JSClassScope(RType.CustomData);
  6660. LeftSpecItem:=LeftScope.SpecializedFromItem;
  6661. RightSpecItem:=RightScope.SpecializedFromItem;
  6662. if (LeftSpecItem<>nil) and (RightSpecItem<>nil)
  6663. and (LeftSpecItem.GenericEl=RightSpecItem.GenericEl) then
  6664. begin
  6665. Result:=cExact;
  6666. for i:=0 to length(LeftSpecItem.Params)-1 do
  6667. begin
  6668. LeftParam:=LeftSpecItem.Params[i];
  6669. RightParam:=RightSpecItem.Params[i];
  6670. if IsSameType(LeftParam,RightParam,prraAlias)
  6671. or IsJSBaseType(LeftParam,pbtJSValue) then
  6672. // e.g. TExt<jsvalue>:=aExt<word>
  6673. else
  6674. begin
  6675. Result:=cIncompatible;
  6676. break;
  6677. end;
  6678. end;
  6679. end;
  6680. end;
  6681. end;
  6682. function TPas2JSResolver.HasStaticArrayCloneFunc(Arr: TPasArrayType): boolean;
  6683. var
  6684. l: Integer;
  6685. ElType: TPasType;
  6686. begin
  6687. l:=length(Arr.Ranges);
  6688. case l of
  6689. 0:
  6690. Result:=false; // dyn array
  6691. 1:
  6692. begin
  6693. // 1-dim static array
  6694. ElType:=ResolveAliasType(Arr.ElType);
  6695. if ElType is TPasArrayType then
  6696. Result:=length(TPasArrayType(ElType).Ranges)>0
  6697. else if ElType is TPasRecordType then
  6698. Result:=true
  6699. else if ElType is TPasSetType then
  6700. Result:=true
  6701. else
  6702. Result:=false; // can use arr.slice(0)
  6703. end
  6704. else
  6705. Result:=true; // multi dim static array
  6706. end;
  6707. end;
  6708. function TPas2JSResolver.IsTGUID(TypeEl: TPasRecordType): boolean;
  6709. var
  6710. Members: TFPList;
  6711. El: TPasElement;
  6712. MemberIndex, i: Integer;
  6713. begin
  6714. Result:=false;
  6715. if not SameText(TypeEl.Name,'TGUID') then exit;
  6716. Members:=TypeEl.Members;
  6717. i:=1;
  6718. for MemberIndex:=0 to Members.Count-1 do
  6719. begin
  6720. El:=TPasElement(Members[MemberIndex]);
  6721. if (El.ClassType<>TPasVariable) then continue;
  6722. if SameText(El.Name,'D'+IntToStr(i)) then
  6723. begin
  6724. if i=4 then exit(true);
  6725. inc(i);
  6726. end;
  6727. end;
  6728. end;
  6729. function TPas2JSResolver.GetAssignGUIDString(TypeEl: TPasRecordType;
  6730. Expr: TPasExpr; out GUID: TGuid): boolean;
  6731. var
  6732. Value: TResEvalValue;
  6733. GUIDStr: String;
  6734. begin
  6735. Result:=false;
  6736. if Expr=nil then exit;
  6737. if not IsTGUID(TypeEl) then exit;
  6738. Value:=Eval(Expr,[refAutoConst]);
  6739. try
  6740. case Value.Kind of
  6741. {$IFDEF FPC_HAS_CPSTRING}
  6742. revkString: GUIDStr:=ExprEvaluator.GetUTF8Str(TResEvalString(Value).S,Expr);
  6743. revkUnicodeString: GUIDStr:=UTF8Encode(TResEvalUTF16(Value).S);
  6744. {$ELSE}
  6745. revkUnicodeString: GUIDStr:=TResEvalUTF16(Value).S;
  6746. {$ENDIF}
  6747. else
  6748. RaiseXExpectedButYFound(20180415092350,'GUID string literal',Value.AsString,Expr);
  6749. end;
  6750. if not TryStringToGUID(GUIDStr,GUID) then
  6751. RaiseXExpectedButYFound(20180415092351,'GUID string literal',Value.AsString,Expr);
  6752. Result:=true;
  6753. finally
  6754. ReleaseEvalValue(Value);
  6755. end;
  6756. end;
  6757. procedure TPas2JSResolver.CheckDispatchField(Proc: TPasProcedure;
  6758. Switch: TValueSwitch);
  6759. var
  6760. ProcScope: TPas2JSProcedureScope;
  6761. ClassScope: TPas2JSClassScope;
  6762. FieldName: String;
  6763. Args, Members: TFPList;
  6764. Arg: TPasArgument;
  6765. ArgType: TPasType;
  6766. i: Integer;
  6767. Member: TPasElement;
  6768. MemberResolved: TPasResolverResult;
  6769. begin
  6770. Args:=Proc.ProcType.Args;
  6771. if Args.Count<>1 then
  6772. RaiseNotYetImplemented(20190311213959,Proc);
  6773. Arg:=TPasArgument(Args[0]);
  6774. if Arg.ArgType=nil then
  6775. exit; // untyped arg
  6776. ProcScope:=TPas2JSProcedureScope(Proc.CustomData);
  6777. ClassScope:=TPas2JSClassScope(ProcScope.ClassRecScope);
  6778. FieldName:='';
  6779. while ClassScope<>nil do
  6780. begin
  6781. case Switch of
  6782. vsDispatchField:
  6783. if ClassScope.DispatchField<>'' then
  6784. begin
  6785. FieldName:=ClassScope.DispatchField;
  6786. break;
  6787. end;
  6788. vsDispatchStrField:
  6789. if ClassScope.DispatchStrField<>'' then
  6790. begin
  6791. FieldName:=ClassScope.DispatchStrField;
  6792. break;
  6793. end;
  6794. else
  6795. RaiseNotYetImplemented(20190311213650,Proc,'');
  6796. end;
  6797. ClassScope:=ClassScope.AncestorScope as TPas2JSClassScope;
  6798. end;
  6799. if FieldName='' then exit;
  6800. // there is a Dispatch(str) method with a directive -> check field
  6801. ArgType:=ResolveAliasType(Arg.ArgType);
  6802. if not (ArgType is TPasMembersType) then
  6803. begin
  6804. LogMsg(20190311214257,mtWarning,nDispatchRequiresX,sDispatchRequiresX,['record type'],Arg);
  6805. exit;
  6806. end;
  6807. Members:=TPasMembersType(ArgType).Members;
  6808. for i:=0 to Members.Count-1 do
  6809. begin
  6810. Member:=TPasElement(Members[i]);
  6811. if SameText(Member.Name,FieldName) then
  6812. begin
  6813. if Member.ClassType<>TPasVariable then
  6814. begin
  6815. LogMsg(20190311215218,mtWarning,nDispatchRequiresX,sDispatchRequiresX,['field variable "'+FieldName+'"'],Arg);
  6816. exit;
  6817. end;
  6818. // field found -> check type
  6819. ComputeElement(TPasVariable(Member).VarType,MemberResolved,[rcType],Arg);
  6820. case Switch of
  6821. vsDispatchField:
  6822. if not (MemberResolved.BaseType in btAllJSInteger) then
  6823. begin
  6824. LogMsg(20190311215215,mtWarning,nDispatchRequiresX,sDispatchRequiresX,['integer field "'+FieldName+'"'],Arg);
  6825. exit;
  6826. end;
  6827. vsDispatchStrField:
  6828. if not (MemberResolved.BaseType in btAllJSStrings) then
  6829. begin
  6830. LogMsg(20190312125025,mtWarning,nDispatchRequiresX,sDispatchRequiresX,['string field "'+FieldName+'"'],Arg);
  6831. exit;
  6832. end;
  6833. end;
  6834. // check name case
  6835. if Member.Name<>FieldName then
  6836. begin
  6837. LogMsg(20190311221651,mtWarning,nDispatchRequiresX,sDispatchRequiresX,['field name to match exactly "'+FieldName+'"'],Arg);
  6838. exit;
  6839. end;
  6840. exit;
  6841. end;
  6842. end;
  6843. LogMsg(20190311214710,mtWarning,nDispatchRequiresX,sDispatchRequiresX,['record field "'+FieldName+'"'],Arg);
  6844. end;
  6845. procedure TPas2JSResolver.AddMessageStr(var MsgToProc: TMessageIdToProc_List;
  6846. const S: string; Proc: TPasProcedure);
  6847. var
  6848. i: Integer;
  6849. begin
  6850. if MsgToProc=nil then
  6851. MsgToProc:=TMessageIdToProc_List.Create
  6852. else
  6853. begin
  6854. // check duplicate
  6855. for i:=0 to MsgToProc.Count-1 do
  6856. if MsgToProc[i]=S then
  6857. RaiseMsg(20190303233647,nDuplicateMessageIdXAtY,sDuplicateMessageIdXAtY,
  6858. [S,GetElementSourcePosStr(TPasProcedure(MsgToProc.Objects[i]).MessageExpr)],Proc.MessageExpr);
  6859. end;
  6860. MsgToProc.AddObject(S,Proc);
  6861. end;
  6862. procedure TPas2JSResolver.AddMessageIdToClassScope(Proc: TPasProcedure;
  6863. EmitHints: boolean);
  6864. var
  6865. AClass: TPasClassType;
  6866. ClassScope: TPas2JSClassScope;
  6867. Expr: TPasExpr;
  6868. Value: TResEvalValue;
  6869. begin
  6870. AClass:=TPasClassType(Proc.Parent);
  6871. ClassScope:=TPas2JSClassScope(AClass.CustomData);
  6872. Expr:=Proc.MessageExpr;
  6873. Value:=Eval(Expr,[refConst]);
  6874. if Value=nil then
  6875. RaiseMsg(20190303225651,nIllegalExpressionAfterX,sIllegalExpressionAfterX,['message modifier'],Expr);
  6876. try
  6877. case Value.Kind of
  6878. {$ifdef FPC_HAS_CPSTRING}
  6879. revkString:
  6880. begin
  6881. AddMessageStr(ClassScope.MsgStrToProc,ExprEvaluator.GetUTF8Str(TResEvalString(Value).S,Expr),Proc);
  6882. if EmitHints then
  6883. CheckDispatchField(Proc,vsDispatchStrField);
  6884. end;
  6885. {$ENDIF}
  6886. revkUnicodeString:
  6887. begin
  6888. AddMessageStr(ClassScope.MsgStrToProc,String(TResEvalUTF16(Value).S),Proc);
  6889. if EmitHints then
  6890. CheckDispatchField(Proc,vsDispatchStrField);
  6891. end;
  6892. revkInt:
  6893. begin
  6894. AddMessageStr(ClassScope.MsgIntToProc,IntToStr(TResEvalInt(Value).Int),Proc);
  6895. if EmitHints then
  6896. CheckDispatchField(Proc,vsDispatchField);
  6897. end
  6898. else
  6899. RaiseXExpectedButYFound(20190303225849,'integer constant',Value.AsString,Expr);
  6900. end;
  6901. finally
  6902. ReleaseEvalValue(Value);
  6903. end;
  6904. end;
  6905. procedure TPas2JSResolver.ComputeElement(El: TPasElement; out
  6906. ResolvedEl: TPasResolverResult; Flags: TPasResolverComputeFlags;
  6907. StartEl: TPasElement);
  6908. var
  6909. Proc: TPasProcedure;
  6910. JSPromiseClass: TPasClassType;
  6911. begin
  6912. if (rcCall in Flags) and (El is TPasProcedure) then
  6913. begin
  6914. Proc:=TPasProcedure(El);
  6915. if Proc.IsAsync then
  6916. begin
  6917. // an async function call returns a TJSPromise
  6918. JSPromiseClass:=FindTJSPromise(StartEl);
  6919. SetResolverIdentifier(ResolvedEl, btContext, El, JSPromiseClass,
  6920. JSPromiseClass, [rrfReadable, rrfWritable]);
  6921. Exit;
  6922. end;
  6923. end;
  6924. inherited ComputeElement(El,ResolvedEl,Flags,StartEl);
  6925. end;
  6926. procedure TPas2JSResolver.ComputeResultElement(El: TPasResultElement; out
  6927. ResolvedEl: TPasResolverResult; Flags: TPasResolverComputeFlags;
  6928. StartEl: TPasElement);
  6929. var
  6930. FuncType: TPasFunctionType;
  6931. Proc: TPasProcedure;
  6932. begin
  6933. if (rcCall in Flags) and (El.Parent is TPasFunctionType) then
  6934. begin
  6935. FuncType:=TPasFunctionType(El.Parent);
  6936. if FuncType.Parent is TPasProcedure then
  6937. begin
  6938. Proc:=TPasProcedure(FuncType.Parent);
  6939. if Proc.IsAsync then
  6940. begin
  6941. ComputeElement(Proc, ResolvedEl, Flags, StartEl);
  6942. Exit;
  6943. end;
  6944. end;
  6945. end;
  6946. inherited ComputeResultElement(El, ResolvedEl, Flags, StartEl);
  6947. end;
  6948. function TPas2JSResolver.GetElementData(El: TPasElementBase;
  6949. DataClass: TPas2JsElementDataClass): TPas2JsElementData;
  6950. begin
  6951. Result:=nil;
  6952. repeat
  6953. if El.InheritsFrom(DataClass) then
  6954. exit(TPas2JsElementData(El));
  6955. if El.CustomData=nil then exit;
  6956. El:=El.CustomData as TPasElementBase;
  6957. until false;
  6958. end;
  6959. procedure TPas2JSResolver.AddElementData(Data: TPas2JsElementData);
  6960. begin
  6961. Data.Owner:=Self;
  6962. if FFirstElementData<>nil then
  6963. begin
  6964. FLastElementData.Next:=Data;
  6965. FLastElementData:=Data;
  6966. end
  6967. else
  6968. begin
  6969. FFirstElementData:=Data;
  6970. FLastElementData:=Data;
  6971. end;
  6972. end;
  6973. function TPas2JSResolver.CreateElementData(DataClass: TPas2JsElementDataClass;
  6974. El: TPasElement): TPas2JsElementData;
  6975. begin
  6976. Result:=DataClass.Create;
  6977. Result.Element:=El;
  6978. AddElementData(Result);
  6979. end;
  6980. function TPas2JSResolver.CheckEqualCompatibilityUserType(const LHS,
  6981. RHS: TPasResolverResult; ErrorEl: TPasElement; RaiseOnIncompatible: boolean
  6982. ): integer;
  6983. begin
  6984. Result:=inherited CheckEqualCompatibilityUserType(LHS,RHS,ErrorEl,RaiseOnIncompatible);
  6985. if Result=cIncompatible then exit;
  6986. if (LHS.LoTypeEl is TPasArrayType)
  6987. and (length(TPasArrayType(LHS.LoTypeEl).Ranges)>0) then
  6988. RaiseMsg(20200508103543,nXIsNotSupported,sXIsNotSupported,['compare static array'],ErrorEl);
  6989. if (RHS.LoTypeEl is TPasArrayType)
  6990. and (length(TPasArrayType(RHS.LoTypeEl).Ranges)>0) then
  6991. RaiseMsg(20200508103544,nXIsNotSupported,sXIsNotSupported,['compare static array'],ErrorEl);
  6992. end;
  6993. procedure TPas2JSResolver.RaiseMsg(const Id: TMaxPrecInt; MsgNumber: integer;
  6994. const Fmt: String; Args: array of const;
  6995. ErrorPosEl: TPasElement);
  6996. begin
  6997. {$IFDEF VerbosePas2JS}
  6998. writeln('TPas2JSResolver.RaiseMsg [',Id,']');
  6999. {$ENDIF}
  7000. inherited RaiseMsg(Id, MsgNumber, Fmt, Args, ErrorPosEl);
  7001. end;
  7002. function TPas2JSResolver.GetOverloadName(El: TPasElement): string;
  7003. var
  7004. Data: TObject;
  7005. ProcScope, GenScope: TPas2JSProcedureScope;
  7006. GenEl: TPasElement;
  7007. begin
  7008. Data:=El.CustomData;
  7009. if Data is TPasGenericScope then
  7010. begin
  7011. if Data is TPas2JSProcedureScope then
  7012. begin
  7013. ProcScope:=TPas2JSProcedureScope(Data);
  7014. if ProcScope.SpecializedFromItem<>nil then
  7015. begin
  7016. // specialized proc -> generic name + '$G' + index
  7017. GenEl:=ProcScope.SpecializedFromItem.GenericEl;
  7018. GenScope:=TPas2JSProcedureScope(GenEl.CustomData);
  7019. Result:=GenScope.OverloadName;
  7020. if Result='' then
  7021. Result:=GenEl.Name+'$';
  7022. Result:=Result+'G'+IntToStr(ProcScope.SpecializedFromItem.Index+1);
  7023. end
  7024. else
  7025. Result:=ProcScope.OverloadName;
  7026. end
  7027. else if Data is TPas2JSArrayScope then
  7028. Result:=TPas2JSArrayScope(Data).JSName
  7029. else if Data is TPas2JSProcTypeScope then
  7030. Result:=TPas2JSProcTypeScope(Data).JSName
  7031. else if Data is TPas2JSRecordScope then
  7032. Result:=TPas2JSRecordScope(Data).JSName
  7033. else if Data is TPas2JSClassScope then
  7034. Result:=TPas2JSClassScope(Data).JSName
  7035. else
  7036. Result:='';
  7037. if Result<>'' then exit;
  7038. end;
  7039. Result:=El.Name;
  7040. end;
  7041. function TPas2JSResolver.GetBaseDescription(const R: TPasResolverResult;
  7042. AddPath: boolean): string;
  7043. begin
  7044. if (R.BaseType=btCustom) and (R.LoTypeEl.CustomData is TResElDataPas2JSBaseType) then
  7045. Result:=Pas2jsBaseTypeNames[TResElDataPas2JSBaseType(R.LoTypeEl.CustomData).JSBaseType]
  7046. else
  7047. Result:=inherited GetBaseDescription(R, AddPath);
  7048. end;
  7049. function TPas2JSResolver.HasTypeInfo(El: TPasType): boolean;
  7050. begin
  7051. Result:=inherited HasTypeInfo(El);
  7052. if not Result then exit;
  7053. if El.Parent is TProcedureBody then
  7054. Result:=false;
  7055. end;
  7056. function TPas2JSResolver.HasExtRTTI(El: TPasMembersType): boolean;
  7057. var
  7058. Members: TFPList;
  7059. i: Integer;
  7060. ChildEl: TPasElement;
  7061. V: TPasMembersType.TRTTIVisibility;
  7062. begin
  7063. Result:=false;
  7064. V:=El.RTTIVisibility;
  7065. if (V.Fields=[])
  7066. and (V.Methods=[])
  7067. and (V.Properties=[]) then exit;
  7068. Members:=El.Members;
  7069. for i:=0 to Members.Count-1 do
  7070. begin
  7071. ChildEl:=TPasElement(Members[i]);
  7072. if El.HasExtRTTI(ChildEl) then
  7073. exit(true);
  7074. end;
  7075. end;
  7076. function TPas2JSResolver.ProcHasImplElements(Proc: TPasProcedure): boolean;
  7077. var
  7078. Scope: TPas2JSProcedureScope;
  7079. begin
  7080. Result:=inherited ProcHasImplElements(Proc);
  7081. if Result then exit;
  7082. // no body elements found -> check precompiled
  7083. Scope:=Proc.CustomData as TPas2JSProcedureScope;
  7084. if Scope.ImplProc<>nil then
  7085. Scope:=Scope.ImplProc.CustomData as TPas2JSProcedureScope;
  7086. if (Scope.ImplJS<>nil) and (Scope.ImplJS.BodyJS<>'') then
  7087. Result:=not Scope.ImplJS.EmptyJS;
  7088. end;
  7089. function TPas2JSResolver.HasAnonymousFunctions(El: TPasImplElement): boolean;
  7090. var
  7091. Data: THasAnoFuncData;
  7092. begin
  7093. if El=nil then
  7094. exit(false);
  7095. Data:=default(THasAnoFuncData);
  7096. El.ForEachCall(@OnHasAnonymousEl,@Data);
  7097. Result:=Data.Expr<>nil;
  7098. end;
  7099. function TPas2JSResolver.GetTopLvlProcScope(El: TPasElement
  7100. ): TPas2JSProcedureScope;
  7101. var
  7102. Proc: TPasProcedure;
  7103. begin
  7104. Result:=nil;
  7105. while El<>nil do
  7106. begin
  7107. if El is TPasProcedure then
  7108. begin
  7109. Proc:=TPasProcedure(El);
  7110. if Proc.CustomData is TPas2JSProcedureScope then
  7111. Result:=TPas2JSProcedureScope(Proc.CustomData);
  7112. exit;
  7113. end;
  7114. El:=El.Parent;
  7115. end;
  7116. end;
  7117. function TPas2JSResolver.ProcCanBePrecompiled(DeclProc: TPasProcedure): boolean;
  7118. var
  7119. El: TPasElement;
  7120. TemplTypes: TFPList;
  7121. ProcScope: TPas2JSProcedureScope;
  7122. GenScope: TPasGenericScope;
  7123. begin
  7124. if GetProcTemplateTypes(DeclProc)<>nil then
  7125. exit(false); // generic DeclProc
  7126. ProcScope:=DeclProc.CustomData as TPas2JSProcedureScope;
  7127. if ProcScope.SpecializedFromItem<>nil then
  7128. exit(false); // specialized generic DeclProc
  7129. El:=DeclProc;
  7130. repeat
  7131. El:=El.Parent;
  7132. if El=nil then
  7133. exit(true); // ok
  7134. if El is TPasProcedure then
  7135. exit(false); // DeclProc is a local DeclProc
  7136. if El is TPasGenericType then
  7137. begin
  7138. TemplTypes:=TPasGenericType(El).GenericTemplateTypes;
  7139. if (TemplTypes<>nil) and (TemplTypes.Count>0) then
  7140. exit(false); // method of a generic class/record type
  7141. GenScope:=El.CustomData as TPasGenericScope;
  7142. if GenScope.SpecializedFromItem<>nil then
  7143. exit(false); // method of a specialized class/record type
  7144. end;
  7145. until false;
  7146. end;
  7147. function TPas2JSResolver.IsReadEqWrite(const ExprResolved: TPasResolverResult
  7148. ): boolean;
  7149. var
  7150. C: TClass;
  7151. IdentEl, Setter, Getter: TPasElement;
  7152. Prop: TPasProperty;
  7153. begin
  7154. if not (rrfReadable in ExprResolved.Flags) then exit;
  7155. if not (rrfWritable in ExprResolved.Flags) then exit;
  7156. Result:=false;
  7157. IdentEl:=ExprResolved.IdentEl;
  7158. if ExprResolved.BaseType=btContext then
  7159. begin
  7160. if IdentEl<>nil then
  7161. begin
  7162. C:=IdentEl.ClassType;
  7163. if (C=TPasVariable) or (C=TPasConst) or (C=TPasResultElement) then
  7164. exit(true)
  7165. else if (C=TPasArgument) then
  7166. exit(true)
  7167. else if (C=TPasProperty) then
  7168. begin
  7169. Prop:=TPasProperty(IdentEl);
  7170. Getter:=GetPasPropertyGetter(Prop);
  7171. if not (Getter is TPasVariable) then
  7172. exit;
  7173. Setter:=GetPasPropertySetter(Prop);
  7174. Result:=Getter=Setter;
  7175. end;
  7176. end;
  7177. end;
  7178. end;
  7179. function TPas2JSResolver.IsTObjectFreeMethod(El: TPasExpr): boolean;
  7180. var
  7181. Ref: TResolvedReference;
  7182. Decl: TPasElement;
  7183. begin
  7184. Result:=false;
  7185. if El=nil then exit;
  7186. if El.ClassType<>TPrimitiveExpr then exit;
  7187. if not (El.CustomData is TResolvedReference) then exit;
  7188. Ref:=TResolvedReference(El.CustomData);
  7189. if CompareText(TPrimitiveExpr(El).Value,'free')<>0 then exit;
  7190. Decl:=Ref.Declaration;
  7191. if not (Decl.ClassType=TPasProcedure)
  7192. or (Decl.Parent.ClassType<>TPasClassType)
  7193. or (CompareText(Decl.Parent.Name,'tobject')<>0)
  7194. or (pmExternal in TPasProcedure(Decl).Modifiers)
  7195. or (TPasProcedure(Decl).ProcType.Args.Count>0) then
  7196. exit;
  7197. Result:=true;
  7198. end;
  7199. function TPas2JSResolver.IsManagedJSType(TypeEl: TPasType): boolean;
  7200. begin
  7201. Result:=false;
  7202. if TypeEl=nil then exit;
  7203. TypeEl:=ResolveAliasType(TypeEl);
  7204. if (TypeEl.ClassType=TPasClassType)
  7205. and (TPasClassType(TypeEl).ObjKind=okInterface)
  7206. and (TPasClassType(TypeEl).InterfaceType=citCom) then
  7207. Result:=true
  7208. else if TypeEl is TPasArrayType then
  7209. Result:=(TypeEl.CustomData<>nil) and (TypeEl.CustomData as TPas2JSArrayScope).Managed
  7210. else if TypeEl is TPasRecordType then
  7211. Result:=(TypeEl.CustomData as TPas2JSRecordScope).Managed;
  7212. end;
  7213. function TPas2JSResolver.IsExternalBracketAccessor(El: TPasElement): boolean;
  7214. var
  7215. ExtName: String;
  7216. begin
  7217. if (not (El is TPasProcedure)) or (TPasProcedure(El).LibrarySymbolName=nil) then
  7218. exit(false);
  7219. ExtName:=ComputeConstString(TPasProcedure(El).LibrarySymbolName,false,false);
  7220. Result:=ExtName=ExtClassBracketAccessor;
  7221. end;
  7222. function TPas2JSResolver.IsExternalClassConstructor(El: TPasElement): boolean;
  7223. var
  7224. P: TPasElement;
  7225. begin
  7226. if (El.ClassType=TPasConstructor)
  7227. and (pmExternal in TPasConstructor(El).Modifiers) then
  7228. begin
  7229. P:=El.Parent;
  7230. if (P<>nil) and (P.ClassType=TPasClassType) and TPasClassType(P).IsExternal then
  7231. exit(true);
  7232. end;
  7233. Result:=false;
  7234. end;
  7235. function TPas2JSResolver.IsForInExtArray(Loop: TPasImplForLoop;
  7236. const VarResolved, InResolved: TPasResolverResult; out ArgResolved,
  7237. LengthResolved, PropResultResolved: TPasResolverResult): boolean;
  7238. var
  7239. TypeEl: TPasType;
  7240. aClass: TPasClassType;
  7241. ClassScope: TPas2JSClassScope;
  7242. DefProp: TPasProperty;
  7243. Arg0: TPasArgument;
  7244. Getter: TPasElement;
  7245. ClassDotScope: TPasDotClassScope;
  7246. Ident: TPasIdentifier;
  7247. LengthVar: TPasVariable;
  7248. begin
  7249. Result:=false;
  7250. ArgResolved:=Default(TPasResolverResult);
  7251. LengthResolved:=Default(TPasResolverResult);
  7252. PropResultResolved:=Default(TPasResolverResult);
  7253. TypeEl:=InResolved.LoTypeEl;
  7254. if (TypeEl.ClassType<>TPasClassType) or not TPasClassType(TypeEl).IsExternal then
  7255. begin
  7256. {$IFDEF VerboseIsForInExtArray}
  7257. writeln('TPas2JSResolver.IsForInExtArray TypeEl ',GetObjName(TypeEl));
  7258. {$ENDIF}
  7259. exit;
  7260. end;
  7261. // for key in JSClass do ...
  7262. aClass:=TPasClassType(TypeEl);
  7263. ClassScope:=TPas2JSClassScope(aClass.CustomData);
  7264. // check has default property
  7265. DefProp:=ClassScope.DefaultProperty;
  7266. if (DefProp=nil) or (DefProp.Args.Count<>1) then
  7267. begin
  7268. {$IFDEF VerboseIsForInExtArray}
  7269. writeln('TPas2JSResolver.IsForInExtArray DefProp ');
  7270. {$ENDIF}
  7271. exit;
  7272. end;
  7273. // check default property is array property
  7274. Arg0:=TPasArgument(DefProp.Args[0]);
  7275. if not (Arg0.Access in [argDefault,argConst]) then
  7276. begin
  7277. {$IFDEF VerboseIsForInExtArray}
  7278. writeln('TPas2JSResolver.IsForInExtArray Arg0 ');
  7279. {$ENDIF}
  7280. exit;
  7281. end;
  7282. // check default array property has an integer as parameter
  7283. ComputeElement(Arg0,ArgResolved,[]);
  7284. if not (ArgResolved.BaseType in btAllJSInteger) then
  7285. begin
  7286. {$IFDEF VerboseIsForInExtArray}
  7287. writeln('TPas2JSResolver.IsForInExtArray ArgResolved=',GetResolverResultDbg(ArgResolved));
  7288. {$ENDIF}
  7289. exit;
  7290. end;
  7291. // find aClass.Length
  7292. ClassDotScope:=PushClassDotScope(aClass);
  7293. Ident:=ClassDotScope.FindIdentifier('length');
  7294. PopScope;
  7295. // check 'length' is const/variable/property
  7296. if (Ident=nil) or not (Ident.Element is TPasVariable) then
  7297. begin
  7298. {$IFDEF VerboseIsForInExtArray}
  7299. writeln('TPas2JSResolver.IsForInExtArray Length ');
  7300. {$ENDIF}
  7301. exit;
  7302. end;
  7303. LengthVar:=TPasVariable(Ident.Element);
  7304. // check 'length' is same type as Arg0
  7305. ComputeElement(LengthVar,LengthResolved,[]);
  7306. if not IsSameType(LengthResolved.LoTypeEl,ArgResolved.LoTypeEl,prraNone) then
  7307. begin
  7308. {$IFDEF VerboseIsForInExtArray}
  7309. writeln('TPas2JSResolver.IsForInExtArray LengthResolved=',GetResolverResultDbg(LengthResolved),' ArgResolved=',GetResolverResultDbg(ArgResolved));
  7310. {$ENDIF}
  7311. exit;
  7312. end;
  7313. // InResolved has default getter and length -> use array enumerator
  7314. Result:=true;
  7315. // check getter is external bracket accessor
  7316. Getter:=GetPasPropertyGetter(DefProp);
  7317. if not IsExternalBracketAccessor(Getter) then
  7318. RaiseMsg(20180519141636,nForInJSArrDefaultGetterNotExtBracketAccessor,
  7319. sForInJSArrDefaultGetterNotExtBracketAccessor,[],Loop.StartExpr);
  7320. // check var fits the property type
  7321. ComputeElement(DefProp.VarType,PropResultResolved,[]);
  7322. Include(PropResultResolved.Flags,rrfReadable);
  7323. //writeln('IsForInExtArray VarResolved=',GetResolverResultDbg(VarResolved),' PropResultResolved=',GetResolverResultDbg(PropResultResolved));
  7324. CheckAssignResCompatibility(VarResolved,PropResultResolved,Loop.VariableName,true);
  7325. end;
  7326. function TPas2JSResolver.IsHelperMethod(El: TPasElement): boolean;
  7327. begin
  7328. Result:=inherited IsHelperMethod(El);
  7329. if not Result then exit;
  7330. Result:=not TPasProcedure(El).IsExternal;
  7331. end;
  7332. function TPas2JSResolver.IsHelperForMember(El: TPasElement): boolean;
  7333. var
  7334. Parent: TPasElement;
  7335. begin
  7336. if El=nil then
  7337. exit(false);
  7338. Parent:=El.Parent;
  7339. if (Parent=nil) or (Parent.ClassType<>TPasClassType)
  7340. or (TPasClassType(Parent).HelperForType=nil) then
  7341. exit(false);
  7342. if El is TPasProcedure then
  7343. Result:=TPasProcedure(El).IsExternal
  7344. else if El is TPasVariable then
  7345. Result:=vmExternal in TPasVariable(El).VarModifiers
  7346. else
  7347. Result:=false;
  7348. end;
  7349. function TPas2JSResolver.ImplBlockReadsDecl(Block: TPasImplBlock;
  7350. Decl: TPasElement): boolean;
  7351. var
  7352. Data: THasElReadingDeclData;
  7353. begin
  7354. Data.Decl:=Decl;
  7355. Data.El:=nil;
  7356. Block.ForEachCall(@OnHasElReadingDecl,@Data);
  7357. Result:=Data.El<>nil;
  7358. end;
  7359. { TParamContext }
  7360. constructor TParamContext.Create(PasEl: TPasElement; JSEl: TJSElement;
  7361. aParent: TConvertContext);
  7362. begin
  7363. inherited Create(PasEl, JSEl, aParent);
  7364. Access:=caAssign;
  7365. AccessContext:=Self;
  7366. end;
  7367. { TPas2JsElementData }
  7368. procedure TPas2JsElementData.SetElement(const AValue: TPasElement);
  7369. var
  7370. Data: TPasElementBase;
  7371. begin
  7372. if FElement=AValue then Exit;
  7373. if FElement<>nil then
  7374. begin
  7375. Data:=FElement;
  7376. while Data.CustomData<>Self do
  7377. if Data.CustomData is TPasElementBase then
  7378. Data:=TPasElementBase(Data.CustomData)
  7379. else
  7380. begin
  7381. {$IFDEF VerbosePas2JS}
  7382. writeln('TPas2JsElementData.SetElement REMOVE ',ClassName);
  7383. writeln(' ',GetObjName(Data.CustomData));
  7384. {$ENDIF}
  7385. raise EPas2JS.Create('');
  7386. end;
  7387. Data.CustomData:=CustomData;
  7388. end;
  7389. FElement:=AValue;
  7390. if FElement<>nil then
  7391. begin
  7392. Data:=FElement;
  7393. while Data.CustomData is TPasElementBase do
  7394. Data:=TPasElementBase(Data.CustomData);
  7395. if Data.CustomData<>nil then
  7396. begin
  7397. {$IFDEF VerbosePas2JS}
  7398. writeln('TPas2JsElementData.SetElement INSERT ',ClassName);
  7399. writeln(' ',GetObjName(Data.CustomData));
  7400. {$ENDIF}
  7401. raise EPas2JS.Create('');
  7402. end;
  7403. Data.CustomData:=Self;
  7404. end;
  7405. end;
  7406. constructor TPas2JsElementData.Create;
  7407. begin
  7408. end;
  7409. destructor TPas2JsElementData.Destroy;
  7410. begin
  7411. Element:=nil;
  7412. Next:=nil;
  7413. Owner:=nil;
  7414. inherited Destroy;
  7415. end;
  7416. { TAssignContext }
  7417. constructor TAssignContext.Create(PasEl: TPasElement; JSEl: TJSElement;
  7418. aParent: TConvertContext);
  7419. begin
  7420. inherited Create(PasEl, JSEl, aParent);
  7421. Access:=caAssign;
  7422. AccessContext:=Self;
  7423. end;
  7424. { TSectionContext }
  7425. constructor TSectionContext.Create(PasEl: TPasElement; JSEl: TJSElement;
  7426. aParent: TConvertContext);
  7427. begin
  7428. inherited;
  7429. IsGlobal:=true;
  7430. SrcElements:=JSEl as TJSSourceElements;
  7431. end;
  7432. procedure TSectionContext.AddHeaderStatement(JS: TJSElement);
  7433. begin
  7434. if JS=nil then exit;
  7435. SrcElements.Statements.InsertNode(HeaderIndex).Node:=JS;
  7436. inc(HeaderIndex);
  7437. end;
  7438. function TSectionContext.FindPrecompiledVar(const aName: string;
  7439. WithParents: boolean): TPas2JSStoredLocalVar;
  7440. var
  7441. i: Integer;
  7442. begin
  7443. for i:=0 to length(PrecompiledVars)-1 do
  7444. begin
  7445. Result:=PrecompiledVars[i];
  7446. if Result.Name=aName then
  7447. exit;
  7448. end;
  7449. if not WithParents then
  7450. exit(nil);
  7451. Result:=inherited FindPrecompiledVar(aName,WithParents);
  7452. end;
  7453. function TSectionContext.FindPrecompiledVar(El: TPasElement;
  7454. WithParents: boolean): TPas2JSStoredLocalVar;
  7455. var
  7456. i: Integer;
  7457. begin
  7458. for i:=0 to length(PrecompiledVars)-1 do
  7459. begin
  7460. Result:=PrecompiledVars[i];
  7461. if Result.Element=El then
  7462. exit;
  7463. end;
  7464. if not WithParents then
  7465. exit(nil);
  7466. Result:=inherited FindPrecompiledVar(El, WithParents);
  7467. end;
  7468. { TFunctionContext }
  7469. constructor TFunctionContext.Create(PasEl: TPasElement; JSEl: TJSElement;
  7470. aParent: TConvertContext);
  7471. begin
  7472. inherited Create(PasEl, JSEl, aParent);
  7473. ThisVar:=TFCLocalIdentifier.Create('this',nil,cvkNone);
  7474. SetLength(LocalVars,1);
  7475. LocalVars[0]:=ThisVar;
  7476. end;
  7477. destructor TFunctionContext.Destroy;
  7478. var
  7479. i: Integer;
  7480. begin
  7481. FreeAndNil(IntfElReleases);
  7482. for i:=0 to length(LocalVars)-1 do
  7483. FreeAndNil(LocalVars[i]);
  7484. ThisVar:=nil;
  7485. inherited Destroy;
  7486. end;
  7487. function TFunctionContext.AddLocalVar(aName: string; El: TPasElement;
  7488. aKind: TCtxVarKind; AutoUnique: boolean): TFCLocalIdentifier;
  7489. var
  7490. l: Integer;
  7491. Ident, V: TFCLocalIdentifier;
  7492. PV: TPas2JSStoredLocalVar;
  7493. begin
  7494. Ident:=FindLocalVar(aName,true);
  7495. if Ident<>nil then
  7496. begin
  7497. if AutoUnique then
  7498. aName:=CreateLocalIdentifier(aName,El,aKind)
  7499. else
  7500. begin
  7501. V:=FindLocalVar(aName,false);
  7502. if V=nil then
  7503. // overriding parent context
  7504. else if El<>V.Element then
  7505. // adding an alias, e.g. "this" for classtype and SelfArg
  7506. else
  7507. begin
  7508. {$IFDEF VerbosePas2JS}
  7509. writeln('TFunctionContext.AddLocalVar [20200608131330] Duplicate "'+aName+'" El='+GetObjPath(El),' Old=',GetObjPath(Ident.Element));
  7510. {$ENDIF}
  7511. raise EPas2JS.Create('[20200608131330] "'+aName+'" El='+GetObjPath(El));
  7512. end;
  7513. end;
  7514. end
  7515. else if aKind=cvkGlobal then
  7516. begin
  7517. // check precompiled names
  7518. PV:=FindPrecompiledVar(El,true);
  7519. if PV<>nil then
  7520. aName:=PV.Name;
  7521. end;
  7522. // add
  7523. l:=length(LocalVars);
  7524. SetLength(LocalVars,l+1);
  7525. Result:=TFCLocalIdentifier.Create(aName,El,aKind);
  7526. LocalVars[l]:=Result;
  7527. end;
  7528. function TFunctionContext.AddLocalJSVar(aName: string; AutoUnique: boolean
  7529. ): TFCLocalIdentifier;
  7530. begin
  7531. Result:=AddLocalVar(aName,nil,cvkNone,AutoUnique);
  7532. end;
  7533. procedure TFunctionContext.Add_InterfaceRelease(El: TPasElement);
  7534. begin
  7535. if IntfElReleases=nil then
  7536. IntfElReleases:=TFPList.Create;
  7537. if IntfElReleases.IndexOf(El)>=0 then exit;
  7538. IntfElReleases.Add(El);
  7539. end;
  7540. function TFunctionContext.CreateLocalIdentifier(const Prefix: string;
  7541. El: TPasElement; aKind: TCtxVarKind): string;
  7542. var
  7543. l: Integer;
  7544. PV: TPas2JSStoredLocalVar;
  7545. begin
  7546. // check precompiled names
  7547. if aKind=cvkGlobal then
  7548. begin
  7549. PV:=FindPrecompiledVar(El,true);
  7550. if PV<>nil then
  7551. exit(PV.Name);
  7552. end;
  7553. // find new name
  7554. Result:=Prefix;
  7555. l:=0;
  7556. while (FindLocalVar(Result,true)<>nil)
  7557. or ((aKind=cvkGlobal) and (FindPrecompiledVar(Result,true)<>nil)) do
  7558. begin
  7559. inc(l);
  7560. Result:=Prefix+IntToStr(l);
  7561. end;
  7562. end;
  7563. function TFunctionContext.ToString: string;
  7564. var
  7565. s: string;
  7566. begin
  7567. Result:=inherited ToString;
  7568. if ThisVar.Element<>nil then
  7569. begin
  7570. str(ThisVar.Kind,s);
  7571. Result:=Result+' this,Kind='+s+',El='+GetObjPath(ThisVar.Element);
  7572. end;
  7573. end;
  7574. function TFunctionContext.GetLocalName(El: TPasElement;
  7575. const Filter: TCtxVarKinds): string;
  7576. function Check(V: TFCLocalIdentifier; FuncCtx: TFunctionContext): boolean;
  7577. begin
  7578. Result:=false;
  7579. if (V.Name<>'') and (V.Element=El) and (V.Kind in Filter) then
  7580. begin
  7581. // found a candidate
  7582. if (V.Name='this') and (FuncCtx<>Self) then
  7583. exit;
  7584. if (Filter<>cvkAll) then
  7585. begin
  7586. if FindLocalVar(V.Name,true)<>V then
  7587. exit; // another var in a lower context hides this var
  7588. end;
  7589. Result:=true;
  7590. end;
  7591. end;
  7592. var
  7593. V: TFCLocalIdentifier;
  7594. FuncCtx: TFunctionContext;
  7595. i: Integer;
  7596. begin
  7597. if El=nil then exit('');
  7598. FuncCtx:=Self;
  7599. repeat
  7600. if Check(FuncCtx.ThisVar,FuncCtx) then
  7601. exit('this');
  7602. for i:=0 to length(FuncCtx.LocalVars)-1 do
  7603. begin
  7604. V:=FuncCtx.LocalVars[i];
  7605. if Check(V,FuncCtx) then
  7606. exit(V.Name);
  7607. end;
  7608. FuncCtx:=FuncCtx.Parent.GetFunctionContext;
  7609. until FuncCtx=nil;
  7610. Result:='';
  7611. end;
  7612. function TFunctionContext.IndexOfLocalVar(const aName: string): integer;
  7613. var
  7614. i: Integer;
  7615. begin
  7616. for i:=0 to length(LocalVars)-1 do
  7617. if LocalVars[i].Name=aName then exit(i);
  7618. Result:=-1;
  7619. end;
  7620. function TFunctionContext.IndexOfLocalVar(El: TPasElement;
  7621. const Filter: TCtxVarKinds): integer;
  7622. var
  7623. i: Integer;
  7624. begin
  7625. if El=nil then exit(-1);
  7626. for i:=0 to length(LocalVars)-1 do
  7627. if (LocalVars[i].Element=El) and (LocalVars[i].Kind in Filter) then
  7628. exit(i);
  7629. Result:=-1;
  7630. end;
  7631. function TFunctionContext.FindLocalVar(const aName: string; WithParents: boolean
  7632. ): TFCLocalIdentifier;
  7633. var
  7634. i: Integer;
  7635. ParentFC: TFunctionContext;
  7636. begin
  7637. i:=IndexOfLocalVar(aName);
  7638. if i>=0 then
  7639. exit(LocalVars[i]);
  7640. if (not WithParents) or (Parent=nil) then
  7641. exit(nil);
  7642. ParentFC:=Parent.GetFunctionContext;
  7643. if ParentFC=nil then
  7644. exit(nil);
  7645. Result:=ParentFC.FindLocalVar(aName,true);
  7646. end;
  7647. function TFunctionContext.FindPrecompiledVar(const aName: string;
  7648. WithParents: boolean): TPas2JSStoredLocalVar;
  7649. var
  7650. ParentFC: TFunctionContext;
  7651. begin
  7652. if (not WithParents) or (Parent=nil) then
  7653. exit(nil);
  7654. ParentFC:=Parent.GetFunctionContext;
  7655. if ParentFC=nil then
  7656. exit(nil);
  7657. Result:=ParentFC.FindPrecompiledVar(aName,true);
  7658. end;
  7659. function TFunctionContext.FindPrecompiledVar(El: TPasElement;
  7660. WithParents: boolean): TPas2JSStoredLocalVar;
  7661. var
  7662. ParentFC: TFunctionContext;
  7663. begin
  7664. if (not WithParents) or (Parent=nil) then
  7665. exit(nil);
  7666. ParentFC:=Parent.GetFunctionContext;
  7667. if ParentFC=nil then
  7668. exit(nil);
  7669. Result:=ParentFC.FindPrecompiledVar(El,true);
  7670. end;
  7671. procedure TFunctionContext.DoWriteStack(Index: integer);
  7672. var
  7673. i: Integer;
  7674. begin
  7675. inherited DoWriteStack(Index);
  7676. {AllowWriteln}
  7677. for i:=0 to length(LocalVars)-1 do
  7678. writeln(' ',i,' ',LocalVars[i].Name,': ',GetObjName(LocalVars[i].Element),' ',LocalVars[i].Kind);
  7679. {AllowWriteln-}
  7680. end;
  7681. { TConvertContext }
  7682. constructor TConvertContext.Create(PasEl: TPasElement; JSEl: TJSElement;
  7683. aParent: TConvertContext);
  7684. begin
  7685. PasElement:=PasEl;
  7686. JSElement:=JsEl;
  7687. Parent:=aParent;
  7688. if Parent<>nil then
  7689. begin
  7690. Resolver:=Parent.Resolver;
  7691. Access:=aParent.Access;
  7692. AccessContext:=aParent.AccessContext;
  7693. ScannerBoolSwitches:=aParent.ScannerBoolSwitches;
  7694. ScannerModeSwitches:=aParent.ScannerModeSwitches;
  7695. end;
  7696. end;
  7697. function TConvertContext.GetRootModule: TPasModule;
  7698. var
  7699. aContext: TConvertContext;
  7700. begin
  7701. aContext:=Self;
  7702. while aContext.Parent<>nil do
  7703. aContext:=aContext.Parent;
  7704. if aContext.PasElement is TPasModule then
  7705. Result:=TPasModule(aContext.PasElement)
  7706. else
  7707. Result:=nil;
  7708. end;
  7709. function TConvertContext.GetRootContext: TConvertContext;
  7710. begin
  7711. Result:=Self;
  7712. while Result.Parent<>nil do
  7713. Result:=Result.Parent;
  7714. end;
  7715. function TConvertContext.GetNonDotContext: TConvertContext;
  7716. begin
  7717. Result:=Self;
  7718. while Result is TDotContext do
  7719. Result:=Result.Parent;
  7720. end;
  7721. function TConvertContext.GetFunctionContext: TFunctionContext;
  7722. begin
  7723. Result:=TFunctionContext(GetContextOfType(TFunctionContext));
  7724. end;
  7725. function TConvertContext.GetLocalName(El: TPasElement;
  7726. const Filter: TCtxVarKinds): string;
  7727. begin
  7728. if Parent<>nil then
  7729. Result:=Parent.GetLocalName(El,Filter)
  7730. else
  7731. Result:='';
  7732. end;
  7733. function TConvertContext.GetSelfContext: TFunctionContext;
  7734. var
  7735. Ctx: TConvertContext;
  7736. FuncContext: TFunctionContext;
  7737. V: TFCLocalIdentifier;
  7738. begin
  7739. Ctx:=Self;
  7740. while Ctx<>nil do
  7741. begin
  7742. if (Ctx is TFunctionContext) then
  7743. begin
  7744. FuncContext:=TFunctionContext(Ctx);
  7745. V:=FuncContext.ThisVar;
  7746. if (V.Element is TPasMembersType)
  7747. and (V.Kind in [cvkGlobal,cvkCurType,cvkInstance]) then
  7748. exit(FuncContext);
  7749. end;
  7750. Ctx:=Ctx.Parent;
  7751. end;
  7752. Result:=nil;
  7753. end;
  7754. function TConvertContext.GetContextOfPasElement(El: TPasElement
  7755. ): TConvertContext;
  7756. var
  7757. ctx: TConvertContext;
  7758. begin
  7759. Result:=nil;
  7760. ctx:=Self;
  7761. repeat
  7762. if ctx.PasElement=El then
  7763. exit(ctx);
  7764. ctx:=ctx.Parent;
  7765. until ctx=nil;
  7766. end;
  7767. function TConvertContext.GetFuncContextOfPasElement(El: TPasElement
  7768. ): TFunctionContext;
  7769. var
  7770. ctx: TConvertContext;
  7771. Scope: TPas2JSProcedureScope;
  7772. begin
  7773. Result:=nil;
  7774. if El is TPasProcedure then
  7775. begin
  7776. Scope:=TPas2JSProcedureScope(El.CustomData);
  7777. if Scope.ImplProc<>nil then
  7778. El:=Scope.ImplProc;
  7779. end;
  7780. ctx:=Self;
  7781. repeat
  7782. if (ctx.PasElement=El) and (ctx is TFunctionContext) then
  7783. exit(TFunctionContext(ctx));
  7784. ctx:=ctx.Parent;
  7785. until ctx=nil;
  7786. end;
  7787. function TConvertContext.GetContextOfType(aType: TConvertContextClass
  7788. ): TConvertContext;
  7789. var
  7790. ctx: TConvertContext;
  7791. begin
  7792. Result:=nil;
  7793. ctx:=Self;
  7794. repeat
  7795. if ctx is aType then
  7796. exit(ctx);
  7797. ctx:=ctx.Parent;
  7798. until ctx=nil;
  7799. end;
  7800. function TConvertContext.GetMainSectionContext: TFunctionContext;
  7801. var
  7802. Ctx: TConvertContext;
  7803. begin
  7804. Ctx:=Self;
  7805. repeat
  7806. if Ctx is TSectionContext then
  7807. Result:=TSectionContext(Ctx);
  7808. Ctx:=Ctx.Parent;
  7809. until Ctx=nil;
  7810. end;
  7811. function TConvertContext.CurrentModeSwitches: TModeSwitches;
  7812. begin
  7813. if Resolver=nil then
  7814. Result:=OBJFPCModeSwitches
  7815. else
  7816. Result:=Resolver.CurrentParser.CurrentModeswitches;
  7817. end;
  7818. function TConvertContext.GetGlobalFunc: TFunctionContext;
  7819. var
  7820. Ctx: TConvertContext;
  7821. begin
  7822. Ctx:=Self;
  7823. while (Ctx<>nil) do
  7824. begin
  7825. if Ctx.IsGlobal and (Ctx.JSElement<>nil) and (Ctx is TFunctionContext) then
  7826. exit(TFunctionContext(Ctx));
  7827. Ctx:=Ctx.Parent;
  7828. end;
  7829. Result:=nil;
  7830. end;
  7831. procedure TConvertContext.WriteStack;
  7832. {AllowWriteln}
  7833. var
  7834. SelfCtx: TFunctionContext;
  7835. procedure W(Index: integer; AContext: TConvertContext);
  7836. begin
  7837. if AContext=SelfCtx then
  7838. writeln(' SelfContext:');
  7839. AContext.DoWriteStack(Index);
  7840. if AContext.Parent<>nil then
  7841. W(Index+1,AContext.Parent);
  7842. end;
  7843. begin
  7844. SelfCtx:=GetSelfContext;
  7845. writeln('TConvertContext.WriteStack: START');
  7846. W(1,Self);
  7847. writeln('TConvertContext.WriteStack: END');
  7848. end;
  7849. {AllowWriteln-}
  7850. procedure TConvertContext.DoWriteStack(Index: integer);
  7851. begin
  7852. {AllowWriteln}
  7853. writeln(' ',Index,' ',ToString);
  7854. {AllowWriteln-}
  7855. end;
  7856. function TConvertContext.ToString: string;
  7857. begin
  7858. Result:='['+ClassName+']'
  7859. +' pas='+GetObjName(PasElement)
  7860. +' js='+GetObjName(JSElement)
  7861. +' Global='+BoolToStr(IsGlobal,true);
  7862. end;
  7863. { TPasToJSConverter }
  7864. // inline
  7865. function TPasToJSConverter.GetUseEnumNumbers: boolean;
  7866. begin
  7867. Result:=coEnumNumbers in FOptions;
  7868. end;
  7869. // inline
  7870. function TPasToJSConverter.GetUseLowerCase: boolean;
  7871. begin
  7872. Result:=coLowerCase in FOptions;
  7873. end;
  7874. // inline
  7875. function TPasToJSConverter.GetUseSwitchStatement: boolean;
  7876. begin
  7877. Result:=coSwitchStatement in FOptions;
  7878. end;
  7879. // inline
  7880. function TPasToJSConverter.GetBIName(bin: TPas2JSBuiltInName): string;
  7881. begin
  7882. Result:=FGlobals.BuiltInNames[bin];
  7883. end;
  7884. procedure TPasToJSConverter.AddGlobalClassMethod(aContext: TConvertContext;
  7885. P: TPasProcedure);
  7886. var
  7887. RootContext: TConvertContext;
  7888. begin
  7889. RootContext:=aContext.GetRootContext;
  7890. if not (RootContext is TRootContext) then
  7891. DoError(20190226232141,RootContext.ClassName);
  7892. TRootContext(RootContext).AddGlobalClassMethod(P);
  7893. end;
  7894. procedure TPasToJSConverter.AddToSourceElements(Src: TJSSourceElements;
  7895. El: TJSElement);
  7896. Var
  7897. List : TJSStatementList;
  7898. AddEl : TJSElement;
  7899. begin
  7900. While El<>nil do
  7901. begin
  7902. if El is TJSStatementList then
  7903. begin
  7904. List:=El as TJSStatementList;
  7905. // List.A is first statement, List.B is next in list, chained.
  7906. // -> add A, continue with B and free List
  7907. AddEl:=List.A;
  7908. El:=List.B;
  7909. List.A:=Nil;
  7910. List.B:=Nil;
  7911. FreeAndNil(List);
  7912. end
  7913. else
  7914. begin
  7915. AddEl:=El;
  7916. El:=Nil;
  7917. end;
  7918. Src.Statements.AddNode.Node:=AddEl;
  7919. end;
  7920. end;
  7921. procedure TPasToJSConverter.RemoveFromSourceElements(Src: TJSSourceElements;
  7922. El: TJSElement);
  7923. var
  7924. Statements: TJSElementNodes;
  7925. i: Integer;
  7926. begin
  7927. Statements:=Src.Statements;
  7928. for i:=Statements.Count-1 downto 0 do
  7929. if Statements[i].Node=El then
  7930. Statements.Delete(i);
  7931. end;
  7932. procedure TPasToJSConverter.SetGlobals(const AValue: TPasToJSConverterGlobals);
  7933. begin
  7934. if FGlobals=AValue then Exit;
  7935. if (FGlobals<>nil) and (FGlobals.Owner=Self) then
  7936. FreeAndNil(FGlobals);
  7937. FGlobals:=AValue;
  7938. end;
  7939. procedure TPasToJSConverter.SetReservedWords(const AValue: TJSReservedWordList
  7940. );
  7941. var
  7942. i: Integer;
  7943. begin
  7944. if FReservedWords=AValue then Exit;
  7945. for i:=0 to length(AValue)-2 do
  7946. if CompareStr(AValue[i],AValue[i+1])>=0 then
  7947. raise Exception.Create('TPasToJSConverter.SetPreservedWords "'+AValue[i]+'" >= "'+AValue[i+1]+'"');
  7948. FReservedWords:=AValue;
  7949. end;
  7950. function TPasToJSConverter.ConvertModule(El: TPasModule;
  7951. AContext: TConvertContext): TJSElement;
  7952. (*
  7953. Program:
  7954. rtl.module('program',
  7955. [<uses1>,<uses2>, ...],
  7956. function(){
  7957. var $mod = this;
  7958. <programsection>
  7959. this.$main=function(){
  7960. <initialization>
  7961. };
  7962. });
  7963. Library:
  7964. rtl.module('library',
  7965. [<uses1>,<uses2>, ...],
  7966. function(){
  7967. var $mod = this;
  7968. <librarysection>
  7969. this.$main=function(){
  7970. <initialization>
  7971. };
  7972. });
  7973. rtl.run('library');
  7974. var li = pas['library'];
  7975. export const func1 = pas.unit1.func1;
  7976. export const var1 = li.var1;
  7977. Unit without implementation:
  7978. rtl.module('<unitname>',
  7979. [<interface uses1>,<uses2>, ...],
  7980. function(){
  7981. var $mod = this;
  7982. this.$impl = $impl;
  7983. <interface>
  7984. this.$init=function(){
  7985. <initialization>
  7986. };
  7987. });
  7988. Unit with implementation:
  7989. rtl.module('<unitname>',
  7990. [<interface uses1>,<uses2>, ...],
  7991. function(){
  7992. var $mod = this;
  7993. var $impl = $mod.$impl;
  7994. <interface>
  7995. $impl.$code=function(){
  7996. };
  7997. this.$init=function(){
  7998. <initialization>
  7999. };
  8000. },
  8001. [<implementation uses1>,<uses2>, ...],
  8002. );
  8003. *)
  8004. Var
  8005. aResolver: TPas2JSResolver;
  8006. OuterSrc , Src: TJSSourceElements;
  8007. RegModuleCall, Call: TJSCallExpression;
  8008. ArgArray: TJSArguments;
  8009. FunDecl, ImplFunc: TJSFunctionDeclarationStatement;
  8010. UsesSection: TPasSection;
  8011. ModuleName, ModVarName: String;
  8012. IntfContext: TSectionContext;
  8013. ImplVarSt: TJSVariableStatement;
  8014. HasImplCode, ok, NeedRTLCheckVersion: Boolean;
  8015. Prg: TPasProgram;
  8016. Lib: TPasLibrary;
  8017. ImplFuncAssignSt: TJSSimpleAssignStatement;
  8018. IntfSecCtx: TInterfaceSectionContext;
  8019. ModScope: TPas2JSModuleScope;
  8020. begin
  8021. Result:=Nil;
  8022. aResolver:=AContext.Resolver;
  8023. if aResolver<>nil then
  8024. ModScope:=El.CustomData as TPas2JSModuleScope
  8025. else
  8026. ModScope:=nil;
  8027. OuterSrc:=TJSSourceElements(CreateElement(TJSSourceElements, El));
  8028. Result:=OuterSrc;
  8029. IntfContext:=nil;
  8030. ok:=false;
  8031. try
  8032. // create 'rtl.module(...)'
  8033. RegModuleCall:=CreateCallExpression(El);
  8034. AddToSourceElements(OuterSrc,RegModuleCall);
  8035. RegModuleCall.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),'module']);
  8036. ArgArray := RegModuleCall.Args;
  8037. RegModuleCall.Args:=ArgArray;
  8038. // add module name parameter
  8039. ModuleName:=TransformModuleName(El,false,AContext);
  8040. ArgArray.Elements.AddElement.Expr:=CreateLiteralString(El,ModuleName);
  8041. // add interface-uses-section parameter: [<interface uses1>,<uses2>, ...]
  8042. UsesSection:=nil;
  8043. if (El is TPasProgram) then
  8044. UsesSection:=TPasProgram(El).ProgramSection
  8045. else if (El is TPasLibrary) then
  8046. UsesSection:=TPasLibrary(El).LibrarySection
  8047. else
  8048. UsesSection:=El.InterfaceSection;
  8049. ArgArray.Elements.AddElement.Expr:=CreateUsesList(UsesSection,AContext);
  8050. // add interface parameter: function(){}
  8051. FunDecl:=CreateFunctionSt(El,true,true);
  8052. ArgArray.AddElement(FunDecl);
  8053. Src:=FunDecl.AFunction.Body.A as TJSSourceElements;
  8054. if coUseStrict in Options then
  8055. // "use strict" must be the first statement in a function
  8056. AddToSourceElements(Src,CreateLiteralString(El,'use strict'));
  8057. NeedRTLCheckVersion:=(coRTLVersionCheckUnit in Options)
  8058. or ((coRTLVersionCheckSystem in Options) and IsSystemUnit(El));
  8059. if NeedRTLCheckVersion then
  8060. begin
  8061. Call:=CreateCallExpression(El);
  8062. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnCheckVersion)]);
  8063. Call.AddArg(CreateLiteralNumber(El,FGlobals.RTLVersion));
  8064. AddToSourceElements(Src,Call);
  8065. end;
  8066. ImplVarSt:=nil;
  8067. if El.ClassType=TPasModule then
  8068. IntfContext:=TInterfaceSectionContext.Create(El,Src,AContext)
  8069. else
  8070. IntfContext:=TSectionContext.Create(El,Src,AContext);
  8071. // add "var $mod = this;"
  8072. IntfContext.ThisVar.Element:=El;
  8073. IntfContext.ThisVar.Kind:=cvkGlobal;
  8074. if El.CustomData is TPasModuleScope then
  8075. IntfContext.ScannerBoolSwitches:=TPasModuleScope(El.CustomData).BoolSwitches;
  8076. ModVarName:=GetBIName(pbivnModule);
  8077. IntfContext.AddLocalVar(ModVarName,El,cvkGlobal,false);
  8078. AddToSourceElements(Src,CreateVarStatement(ModVarName,
  8079. CreatePrimitiveDotExpr('this',El),El));
  8080. if (ModScope<>nil) then
  8081. RestoreImplJSLocals(ModScope,IntfContext);
  8082. if (El is TPasProgram) then
  8083. begin // program
  8084. Prg:=TPasProgram(El);
  8085. if Assigned(Prg.ProgramSection) then
  8086. AddToSourceElements(Src,ConvertDeclarations(Prg.ProgramSection,IntfContext));
  8087. HasImplCode:=AddDelayedInits(Prg,Src,IntfContext);
  8088. CreateInitSection(Prg,Src,IntfContext);
  8089. end
  8090. else if El is TPasLibrary then
  8091. begin // library
  8092. Lib:=TPasLibrary(El);
  8093. if Assigned(Lib.LibrarySection) then
  8094. AddToSourceElements(Src,ConvertDeclarations(Lib.LibrarySection,IntfContext));
  8095. HasImplCode:=AddDelayedInits(Lib,Src,IntfContext);
  8096. CreateInitSection(Lib,Src,IntfContext);
  8097. end
  8098. else
  8099. begin // unit
  8100. IntfSecCtx:=TInterfaceSectionContext(IntfContext);
  8101. if Assigned(El.ImplementationSection) then
  8102. begin
  8103. // add var $impl = $mod.$impl
  8104. ImplVarSt:=CreateVarStatement(GetBIName(pbivnImplementation),
  8105. CreateMemberExpression([ModVarName,GetBIName(pbivnImplementation)]),El);
  8106. AddToSourceElements(Src,ImplVarSt);
  8107. // register local var $impl
  8108. IntfSecCtx.AddLocalVar(GetBIName(pbivnImplementation),El.ImplementationSection,cvkGlobal,false);
  8109. end;
  8110. if Assigned(El.InterfaceSection) then
  8111. AddToSourceElements(Src,ConvertDeclarations(El.InterfaceSection,IntfSecCtx));
  8112. ImplFunc:=CreateImplementationSection(El,IntfSecCtx);
  8113. // add $mod.$implcode = ImplFunc;
  8114. ImplFuncAssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  8115. ImplFuncAssignSt.LHS:=CreateMemberExpression([ModVarName,GetBIName(pbivnImplCode)]);
  8116. ImplFuncAssignSt.Expr:=ImplFunc;
  8117. AddToSourceElements(Src,ImplFuncAssignSt);
  8118. // append initialization section
  8119. CreateInitSection(El,Src,IntfSecCtx);
  8120. if TJSSourceElements(ImplFunc.AFunction.Body.A).Statements.Count>0 then
  8121. HasImplCode:=true
  8122. else
  8123. begin
  8124. // empty implementation
  8125. // remove unneeded $impl from interface
  8126. RemoveFromSourceElements(Src,ImplVarSt);
  8127. // remove unneeded $mod.$implcode = function(){}
  8128. RemoveFromSourceElements(Src,ImplFuncAssignSt);
  8129. // keep impl uses section
  8130. HasImplCode:=(El.ImplementationSection<>nil)
  8131. and (length(El.ImplementationSection.UsesClause)>0);
  8132. end;
  8133. if HasImplCode then
  8134. // add implementation uses list: [<implementation uses1>,<uses2>, ...]
  8135. ArgArray.AddElement(CreateUsesList(El.ImplementationSection,AContext));
  8136. end; // end unit
  8137. if (ModScope<>nil) and (coStoreImplJS in Options) then
  8138. StoreImplJSLocals(ModScope,IntfContext);
  8139. if El is TPasLibrary then
  8140. begin
  8141. // library: rtl.run('library');
  8142. Lib:=TPasLibrary(El);
  8143. AddRTLRun(Lib,ModuleName,OuterSrc,AContext);
  8144. CreateExportsSection(Lib,OuterSrc,AContext);
  8145. end
  8146. else if (El is TPasProgram) and (Globals.TargetPlatform in [PlatformNodeJS,PlatformModule]) then
  8147. // program: rtl.run();
  8148. AddRTLRun(El,'',OuterSrc,AContext);
  8149. ok:=true;
  8150. finally
  8151. IntfContext.Free;
  8152. if not ok then
  8153. FreeAndNil(Result);
  8154. end;
  8155. end;
  8156. function TPasToJSConverter.CreateElement(C: TJSElementClass; Src: TPasElement
  8157. ): TJSElement;
  8158. var
  8159. Line, Col: Integer;
  8160. begin
  8161. if Assigned(Src) then
  8162. begin
  8163. TPasResolver.UnmangleSourceLineNumber(Src.SourceLinenumber,Line,Col);
  8164. Result:=C.Create(Line,Col,Src.SourceFilename);
  8165. end
  8166. else
  8167. Result:=C.Create(0,0);
  8168. end;
  8169. function TPasToJSConverter.CreateFreeOrNewInstanceExpr(Ref: TResolvedReference;
  8170. AContext: TConvertContext): TJSCallExpression;
  8171. // class: create "$create("ProcName")"
  8172. // record: create "$new().ProcName()"
  8173. var
  8174. C, SubCall: TJSCallExpression;
  8175. Proc: TPasProcedure;
  8176. ProcScope: TPasProcedureScope;
  8177. ClassRecScope: TPasClassOrRecordScope;
  8178. ClassOrRec: TPasElement;
  8179. ArgEx: TJSLiteral;
  8180. FunName, ProcName: String;
  8181. DotExpr: TJSDotMemberExpression;
  8182. begin
  8183. Result:=nil;
  8184. //writeln('TPasToJSConverter.CreateFreeOrNewInstanceExpr Ref.Declaration=',GetObjName(Ref.Declaration));
  8185. Proc:=Ref.Declaration as TPasProcedure;
  8186. if Proc.Name='' then
  8187. RaiseInconsistency(20170125191914,Proc);
  8188. //writeln('TPasToJSConverter.CreateFreeOrNewInstanceExpr Proc.Name=',Proc.Name);
  8189. ProcScope:=Proc.CustomData as TPasProcedureScope;
  8190. //writeln('TPasToJSConverter.CreateFreeOrNewInstanceExpr ProcScope.Element=',GetObjName(ProcScope.Element),' ProcScope.ClassScope=',GetObjName(ProcScope.ClassOrRecordScope),' ProcScope.DeclarationProc=',GetObjName(ProcScope.DeclarationProc),' ProcScope.ImplProc=',GetObjName(ProcScope.ImplProc),' ProcScope.CustomData=',GetObjName(ProcScope.CustomData));
  8191. ClassRecScope:=ProcScope.ClassRecScope;
  8192. ClassOrRec:=ClassRecScope.Element;
  8193. if ClassOrRec.Name='' then
  8194. RaiseInconsistency(20170125191923,ClassOrRec);
  8195. C:=CreateCallExpression(Ref.Element);
  8196. try
  8197. ProcName:=TransformElToJSName(Proc,AContext);
  8198. if ClassOrRec.ClassType=TPasRecordType then
  8199. begin
  8200. // create "path.$new()"
  8201. FunName:=CreateReferencePath(Proc,AContext,rpkPathWithDot,false,Ref)+GetBIName(pbifnRecordNew);
  8202. SubCall:=CreateCallExpression(Ref.Element);
  8203. SubCall.Expr:=CreatePrimitiveDotExpr(FunName,Ref.Element);
  8204. // append ".ProcName"
  8205. DotExpr:=CreateDotNameExpr(Ref.Element,SubCall,TJSString(ProcName));
  8206. // as call: "path.$new().ProcName()"
  8207. C.Expr:=DotExpr;
  8208. end
  8209. else
  8210. begin
  8211. // add "$create()"
  8212. if rrfNewInstance in Ref.Flags then
  8213. FunName:=GetBIName(pbifnClassInstanceNew)
  8214. else
  8215. FunName:=GetBIName(pbifnClassInstanceFree);
  8216. FunName:=CreateReferencePath(Proc,AContext,rpkPathWithDot,false,Ref)+FunName;
  8217. C.Expr:=CreatePrimitiveDotExpr(FunName,Ref.Element);
  8218. // parameter: "ProcName"
  8219. ArgEx := CreateLiteralString(Ref.Element,ProcName);
  8220. C.AddArg(ArgEx);
  8221. end;
  8222. Result:=C;
  8223. finally
  8224. if Result=nil then
  8225. C.Free;
  8226. end;
  8227. end;
  8228. function TPasToJSConverter.CreateFunctionSt(El: TPasElement; WithBody: boolean;
  8229. WithSrc: boolean): TJSFunctionDeclarationStatement;
  8230. var
  8231. FuncSt: TJSFunctionDeclarationStatement;
  8232. begin
  8233. FuncSt:=TJSFunctionDeclarationStatement(CreateElement(TJSFunctionDeclarationStatement,El));
  8234. Result:=FuncSt;
  8235. FuncSt.AFunction:=CreateFunctionDef(El,WithBody,WithSrc);
  8236. end;
  8237. function TPasToJSConverter.CreateFunctionDef(El: TPasElement;
  8238. WithBody: boolean; WithSrc: boolean): TJSFuncDef;
  8239. begin
  8240. Result:=TJSFuncDef.Create;
  8241. if WithBody then
  8242. begin
  8243. Result.Body:=TJSFunctionBody(CreateElement(TJSFunctionBody,El));
  8244. if WithSrc then
  8245. Result.Body.A:=TJSSourceElements(CreateElement(TJSSourceElements, El));
  8246. end;
  8247. end;
  8248. function TPasToJSConverter.ConvertUnaryExpression(El: TUnaryExpr;
  8249. AContext: TConvertContext): TJSElement;
  8250. procedure NotSupported(Id: TMaxPrecInt);
  8251. var
  8252. ResolvedEl: TPasResolverResult;
  8253. begin
  8254. if AContext.Resolver<>nil then
  8255. begin
  8256. AContext.Resolver.ComputeElement(El.Operand,ResolvedEl,[],El);
  8257. DoError(Id,nIllegalQualifierInFrontOf,sIllegalQualifierInFrontOf,
  8258. [OpcodeStrings[El.OpCode],AContext.Resolver.GetResolverResultDescription(ResolvedEl)],El);
  8259. end
  8260. else
  8261. DoError(Id,nUnaryOpcodeNotSupported,sUnaryOpcodeNotSupported,
  8262. [OpcodeStrings[El.OpCode]],El);
  8263. end;
  8264. function DerefPointer(TypeEl: TPasType): boolean;
  8265. begin
  8266. if TypeEl.ClassType=TPasRecordType then
  8267. begin
  8268. // PRecordVar^ -> PRecordVar
  8269. ConvertUnaryExpression:=ConvertExpression(El.Operand,AContext);
  8270. exit(true);
  8271. end;
  8272. Result:=false;
  8273. end;
  8274. Var
  8275. U : TJSUnaryExpression;
  8276. E : TJSElement;
  8277. ResolvedEl: TPasResolverResult;
  8278. BitwiseNot, NeedLongWordBitFix: Boolean;
  8279. aResolver: TPas2JSResolver;
  8280. TypeEl, SubTypeEl: TPasType;
  8281. begin
  8282. if AContext=nil then ;
  8283. aResolver:=AContext.Resolver;
  8284. Result:=Nil;
  8285. U:=nil;
  8286. Case El.OpCode of
  8287. eopAdd:
  8288. begin
  8289. E:=ConvertExpression(El.Operand,AContext);
  8290. U:=CreateUnaryPlus(E,El);
  8291. U.A:=E;
  8292. end;
  8293. eopSubtract:
  8294. begin
  8295. E:=ConvertExpression(El.Operand,AContext);
  8296. U:=TJSUnaryMinusExpression(CreateElement(TJSUnaryMinusExpression,El));
  8297. U.A:=E;
  8298. end;
  8299. eopNot:
  8300. begin
  8301. E:=ConvertExpression(El.Operand,AContext);
  8302. BitwiseNot:=true;
  8303. if aResolver<>nil then
  8304. begin
  8305. aResolver.ComputeElement(El.Operand,ResolvedEl,[]);
  8306. BitwiseNot:=ResolvedEl.BaseType in btAllJSInteger;
  8307. NeedLongWordBitFix:=ResolvedEl.BaseType=btLongWord;
  8308. end
  8309. else
  8310. NeedLongWordBitFix:=false;
  8311. if BitwiseNot then
  8312. begin
  8313. U:=TJSUnaryInvExpression(CreateElement(TJSUnaryInvExpression,El));
  8314. U.A:=E;
  8315. if NeedLongWordBitFix then
  8316. exit(CreateBitWiseLongword(El,U));
  8317. end
  8318. else
  8319. U:=CreateUnaryNot(E,El);
  8320. end;
  8321. eopAddress:
  8322. begin
  8323. if aResolver=nil then
  8324. NotSupported(20180423162321);
  8325. aResolver.ComputeElement(El.Operand,ResolvedEl,[rcNoImplicitProc]);
  8326. {$IFDEF VerbosePas2JS}
  8327. writeln('TPasToJSConverter.ConvertUnaryExpression ',GetResolverResultDbg(ResolvedEl));
  8328. {$ENDIF}
  8329. if ResolvedEl.BaseType=btProc then
  8330. begin
  8331. if ResolvedEl.IdentEl is TPasProcedure then
  8332. begin
  8333. Result:=CreateCallback(El.Operand,ResolvedEl,false,AContext);
  8334. exit;
  8335. end;
  8336. end
  8337. else if (ResolvedEl.BaseType=btContext) then
  8338. begin
  8339. TypeEl:=ResolvedEl.LoTypeEl;
  8340. if TypeEl.ClassType=TPasRecordType then
  8341. begin
  8342. // @RecVar -> RecVar
  8343. Result:=ConvertExpression(El.Operand,AContext);
  8344. exit;
  8345. end;
  8346. end;
  8347. end;
  8348. eopDeref:
  8349. begin
  8350. if aResolver=nil then
  8351. NotSupported(20180423162350);
  8352. aResolver.ComputeElement(El.Operand,ResolvedEl,[rcNoImplicitProc]);
  8353. if ResolvedEl.BaseType=btPointer then
  8354. begin
  8355. TypeEl:=ResolvedEl.LoTypeEl;
  8356. if DerefPointer(TypeEl) then exit;
  8357. end
  8358. else if (ResolvedEl.BaseType=btContext) then
  8359. begin
  8360. TypeEl:=ResolvedEl.LoTypeEl;
  8361. if TypeEl.ClassType=TPasPointerType then
  8362. begin
  8363. SubTypeEl:=aResolver.ResolveAliasType(TPasPointerType(TypeEl).DestType);
  8364. if DerefPointer(SubTypeEl) then exit;
  8365. end;
  8366. end;
  8367. end;
  8368. eopMemAddress:
  8369. begin
  8370. // @@ProcVar -> ProcVar
  8371. Result:=ConvertExpression(El.Operand,AContext);
  8372. exit;
  8373. end;
  8374. end;
  8375. if U=nil then
  8376. NotSupported(20180423162324);
  8377. Result:=U;
  8378. end;
  8379. function TPasToJSConverter.ConvertInlineSpecializeExpr(
  8380. El: TInlineSpecializeExpr; AContext: TConvertContext): TJSElement;
  8381. begin
  8382. Result:=ConvertExpression(El.NameExpr,AContext);
  8383. end;
  8384. function TPasToJSConverter.GetExpressionValueType(El: TPasExpr;
  8385. AContext: TConvertContext): TJSType;
  8386. Function CombineValueType(A,B : TJSType) : TJSType;
  8387. begin
  8388. If (A=jstUNDEFINED) then
  8389. Result:=B
  8390. else if (B=jstUNDEFINED) then
  8391. Result:=A
  8392. else
  8393. Result:=A; // pick the first
  8394. end;
  8395. Var
  8396. A,B : TJSType;
  8397. begin
  8398. if (El is TBoolConstExpr) then
  8399. Result:=jstBoolean
  8400. else if (El is TPrimitiveExpr) then
  8401. begin
  8402. Case El.Kind of
  8403. pekIdent : Result:=GetPasIdentValueType(El.Name,AContext);
  8404. pekNumber : Result:=jstNumber;
  8405. pekString,pekStringMultiLine : Result:=jstString;
  8406. pekSet : Result:=jstUNDEFINED;
  8407. pekNil : Result:=jstNull;
  8408. pekBoolConst : Result:=jstBoolean;
  8409. pekRange : Result:=jstUNDEFINED;
  8410. pekFuncParams : Result:=jstUNDEFINED;
  8411. pekArrayParams : Result:=jstUNDEFINED;
  8412. pekListOfExp : Result:=jstUNDEFINED;
  8413. pekInherited : Result:=jstUNDEFINED;
  8414. pekSelf : Result:=jstObject;
  8415. end
  8416. end
  8417. else if (El is TUnaryExpr) then
  8418. Result:=GetExpressionValueType(TUnaryExpr(El).Operand,AContext)
  8419. else if (El is TBinaryExpr) then
  8420. begin
  8421. A:=GetExpressionValueType(TBinaryExpr(El).Left,AContext);
  8422. B:=GetExpressionValueType(TBinaryExpr(El).Right,AContext);
  8423. Result:=CombineValueType(A,B);
  8424. end
  8425. else
  8426. result:=jstUndefined
  8427. end;
  8428. function TPasToJSConverter.GetPasIdentValueType(AName: String;
  8429. AContext: TConvertContext): TJSType;
  8430. begin
  8431. if AContext=nil then ;
  8432. if AName='' then ;
  8433. Result:=jstUNDEFINED;
  8434. end;
  8435. function TPasToJSConverter.ComputeConstString(Expr: TPasExpr;
  8436. AContext: TConvertContext; NotEmpty: boolean): String;
  8437. var
  8438. Prim: TPrimitiveExpr;
  8439. begin
  8440. if AContext.Resolver<>nil then
  8441. Result:=AContext.Resolver.ComputeConstString(Expr,false,NotEmpty)
  8442. else
  8443. begin
  8444. // fall back:
  8445. Result:='';
  8446. if Expr is TPrimitiveExpr then
  8447. begin
  8448. Prim:=TPrimitiveExpr(Expr);
  8449. case Prim.Kind of
  8450. pekString:
  8451. begin
  8452. Result:=Prim.Value;
  8453. Result:={$IFDEF pas2js}DeQuoteString{$ELSE}AnsiDequotedStr{$ENDIF}(Result,'''');
  8454. end;
  8455. else
  8456. RaiseNotSupported(Prim,AContext,20170215124733);
  8457. end;
  8458. end
  8459. else
  8460. RaiseNotSupported(Expr,AContext,20170322121331);
  8461. end;
  8462. end;
  8463. function TPasToJSConverter.IsLiteralInteger(El: TJSElement; out
  8464. Number: TMaxPrecInt): boolean;
  8465. var
  8466. Value: TJSValue;
  8467. begin
  8468. Result:=false;
  8469. if not (El is TJSLiteral) then exit;
  8470. Value:=TJSLiteral(El).Value;
  8471. if (Value.ValueType=jstNumber) then
  8472. try
  8473. Number:=Round(Value.AsNumber);
  8474. if Number=Value.AsNumber then
  8475. exit(true);
  8476. except
  8477. end;
  8478. end;
  8479. function TPasToJSConverter.IsLiteralNumber(El: TJSElement; out n: TJSNumber
  8480. ): boolean;
  8481. var
  8482. Value: TJSValue;
  8483. begin
  8484. if not (El is TJSLiteral) then exit(false);
  8485. Value:=TJSLiteral(El).Value;
  8486. if Value.ValueType<>jstNumber then exit(false);
  8487. Result:=true;
  8488. n:=Value.AsNumber;
  8489. end;
  8490. function TPasToJSConverter.IsLiteralNull(El: TJSElement): boolean;
  8491. begin
  8492. Result:=(El is TJSLiteral) and TJSLiteral(El).Value.IsNull;
  8493. end;
  8494. function TPasToJSConverter.GetOverloadName(El: TPasElement;
  8495. AContext: TConvertContext): string;
  8496. begin
  8497. if AContext.Resolver<>nil then
  8498. Result:=AContext.Resolver.GetOverloadName(El)
  8499. else
  8500. Result:=El.Name;
  8501. end;
  8502. function TPasToJSConverter.CanClashWithGlobal(El: TPasElement): boolean;
  8503. // returns true for JS variables accessed directly, i.e. without dot prefix
  8504. // which therefore must be checked if they clash with global JS identifiers.
  8505. var
  8506. C: TClass;
  8507. begin
  8508. C:=El.ClassType;
  8509. if C=TPasArgument then
  8510. Result:=true
  8511. else if El.Parent is TProcedureBody then
  8512. Result:=true
  8513. else if El.Parent is TPasImplExceptOn then
  8514. Result:=true
  8515. else
  8516. Result:=false;
  8517. end;
  8518. function TPasToJSConverter.ConvertBinaryExpression(El: TBinaryExpr;
  8519. AContext: TConvertContext): TJSElement;
  8520. Const
  8521. BinClasses : Array [TExprOpCode] of TJSBinaryClass = (
  8522. Nil, //eopEmpty,
  8523. TJSAdditiveExpressionPlus, // +
  8524. TJSAdditiveExpressionMinus, // -
  8525. TJSMultiplicativeExpressionMul, // *
  8526. TJSMultiplicativeExpressionDiv, // /
  8527. TJSMultiplicativeExpressionDiv, // div
  8528. TJSMultiplicativeExpressionMod, // mod
  8529. Nil, //eopPower
  8530. TJSURShiftExpression, // shr
  8531. TJSLShiftExpression, // shl
  8532. Nil, // Not
  8533. Nil, // And
  8534. Nil, // Or
  8535. Nil, // XOr
  8536. TJSEqualityExpressionSEQ,
  8537. TJSEqualityExpressionSNE,
  8538. TJSRelationalExpressionLT,
  8539. TJSRelationalExpressionGT,
  8540. TJSRelationalExpressionLE,
  8541. TJSRelationalExpressionGE,
  8542. Nil, // In
  8543. TJSRelationalExpressionInstanceOf, // is
  8544. Nil, // As
  8545. Nil, // Symmetrical diff
  8546. Nil, // Address,
  8547. Nil, // Deref
  8548. Nil, // MemAddress
  8549. Nil // SubIndent,
  8550. );
  8551. Var
  8552. LeftResolved, RightResolved: TPasResolverResult;
  8553. procedure NotSupportedRes(id: TMaxPrecInt);
  8554. begin
  8555. {$IFDEF VerbosePas2JS}
  8556. writeln('TPasToJSConverter.ConvertBinaryExpression.NotSupportedRes',
  8557. ' Left=',GetResolverResultDbg(LeftResolved),
  8558. ' Op=',ExprKindNames[El.Kind],
  8559. ' Right=',GetResolverResultDbg(RightResolved));
  8560. {$ENDIF}
  8561. RaiseNotSupported(El,AContext,id,
  8562. GetResolverResultDbg(LeftResolved)+ExprKindNames[El.Kind]
  8563. +GetResolverResultDbg(RightResolved));
  8564. end;
  8565. function BitwiseOpNeedLongwordFix: boolean;
  8566. begin
  8567. Result:=((LeftResolved.BaseType=btLongWord) and (RightResolved.BaseType<=btLongWord))
  8568. or ((RightResolved.BaseType=btLongWord) and (LeftResolved.BaseType<=btLongWord));
  8569. end;
  8570. function CreateBitwiseLongwordOp(A, B: TJSElement; C: TJSBinaryClass): TJSElement;
  8571. var
  8572. R: TJSBinary;
  8573. begin
  8574. R:=TJSBinary(CreateElement(C,El));
  8575. R.A:=A;
  8576. R.B:=B;
  8577. Result:=CreateBitWiseLongword(El,R);
  8578. end;
  8579. var
  8580. R : TJSBinary;
  8581. C : TJSBinaryClass;
  8582. A,B: TJSElement;
  8583. UseBitwiseOp: Boolean;
  8584. Call: TJSCallExpression;
  8585. Flags: TPasResolverComputeFlags;
  8586. ModeSwitches: TModeSwitches;
  8587. aResolver: TPas2JSResolver;
  8588. LeftTypeEl, RightTypeEl: TPasType;
  8589. OldAccess: TCtxAccess;
  8590. begin
  8591. Result:=Nil;
  8592. aResolver:=AContext.Resolver;
  8593. case El.OpCode of
  8594. eopAdd:
  8595. begin
  8596. Result:=ConvertBinaryExpressionMultiAdd(El,aContext);
  8597. exit;
  8598. end;
  8599. eopSubIdent:
  8600. begin
  8601. Result:=ConvertSubIdentExpression(El,AContext);
  8602. exit;
  8603. end;
  8604. eopNone:
  8605. if El.left is TInheritedExpr then
  8606. begin
  8607. Result:=ConvertInheritedExpr(TInheritedExpr(El.left),AContext);
  8608. exit;
  8609. end;
  8610. end;
  8611. OldAccess:=AContext.Access;
  8612. AContext.Access:=caRead;
  8613. Call:=nil;
  8614. A:=nil;
  8615. B:=nil;
  8616. try
  8617. A:=ConvertExpression(El.left,AContext);
  8618. B:=ConvertExpression(El.right,AContext);
  8619. if aResolver<>nil then
  8620. begin
  8621. ModeSwitches:=AContext.CurrentModeSwitches;
  8622. // compute left
  8623. Flags:=[];
  8624. if El.OpCode in [eopEqual,eopNotEqual] then
  8625. if not (msDelphi in ModeSwitches) then
  8626. Flags:=[rcNoImplicitProcType];
  8627. aResolver.ComputeElement(El.left,LeftResolved,Flags);
  8628. // compute right
  8629. Flags:=[];
  8630. if (El.OpCode in [eopEqual,eopNotEqual])
  8631. and not (msDelphi in ModeSwitches) then
  8632. begin
  8633. if LeftResolved.BaseType=btNil then
  8634. Flags:=[rcNoImplicitProcType]
  8635. else if aResolver.IsProcedureType(LeftResolved,true) then
  8636. Flags:=[rcNoImplicitProcType]
  8637. else
  8638. Flags:=[];
  8639. end;
  8640. aResolver.ComputeElement(El.right,RightResolved,Flags);
  8641. Result:=ConvertBinaryExpressionRes(El,AContext,LeftResolved,RightResolved,A,B);
  8642. if Result<>nil then exit;
  8643. {$IFDEF VerbosePas2JS}
  8644. writeln('TPasToJSConverter.ConvertBinaryExpression Left=',GetResolverResultDbg(LeftResolved),' Right=',GetResolverResultDbg(RightResolved));
  8645. {$ENDIF}
  8646. end;
  8647. C:=BinClasses[El.OpCode];
  8648. if C=nil then
  8649. Case El.OpCode of
  8650. eopAs :
  8651. begin
  8652. // "A as B"
  8653. Call:=CreateCallExpression(El);
  8654. LeftTypeEl:=LeftResolved.LoTypeEl;
  8655. RightTypeEl:=RightResolved.LoTypeEl;
  8656. if LeftTypeEl is TPasClassType then
  8657. begin
  8658. if RightTypeEl is TPasClassType then
  8659. case TPasClassType(LeftTypeEl).ObjKind of
  8660. okClass:
  8661. case TPasClassType(RightTypeEl).ObjKind of
  8662. okClass:
  8663. // ClassInstVar is ClassType
  8664. if TPasClassType(RightResolved.LoTypeEl).IsExternal then
  8665. // B is external class -> "rtl.asExt(A,B)"
  8666. Call.Expr:=CreatePrimitiveDotExpr(GetBIName(pbivnRTL)+'.'+GetBIName(pbifnAsExt),El)
  8667. else
  8668. // otherwise -> "rtl.as(A,B)"
  8669. Call.Expr:=CreatePrimitiveDotExpr(GetBIName(pbivnRTL)+'.'+GetBIName(pbifnAs),El);
  8670. okInterface:
  8671. begin
  8672. // ClassInstVar as IntfType
  8673. case TPasClassType(RightTypeEl).InterfaceType of
  8674. citCom:
  8675. begin
  8676. // COM: $ir.ref(rtl.queryIntfT(objVar,intftype),"id")
  8677. Call.Expr:=CreatePrimitiveDotExpr(GetBIName(pbivnRTL)+'.'+GetBIName(pbifnIntfQueryIntfT),El);
  8678. Call.AddArg(A);
  8679. Call.AddArg(B);
  8680. Call:=CreateIntfRef(Call,AContext,El);
  8681. Result:=Call;
  8682. exit;
  8683. end;
  8684. citCorba:
  8685. // CORBA: rtl.getIntfT(objVar,intftype)
  8686. Call.Expr:=CreatePrimitiveDotExpr(GetBIName(pbivnRTL)+'.'+GetBIName(pbifnIntfGetIntfT),El);
  8687. else RaiseNotSupported(El,AContext,20180401225752){%H-};
  8688. end;
  8689. end
  8690. else
  8691. NotSupportedRes(20180327214535);
  8692. end;
  8693. okInterface:
  8694. case TPasClassType(RightTypeEl).ObjKind of
  8695. okClass:
  8696. // IntfVar as ClassType -> rtl.intfAsClass(intfvar,classtype)
  8697. Call.Expr:=CreatePrimitiveDotExpr(GetBIName(pbivnRTL)+'.'+GetBIName(pbifnIntfAsClass),El);
  8698. okInterface:
  8699. // IntfVar as IntfType
  8700. if TPasClassType(LeftTypeEl).InterfaceType=citCom then
  8701. // COM -> "rtl.intfAsIntfT(A,B)"
  8702. Call.Expr:=CreatePrimitiveDotExpr(GetBIName(pbivnRTL)+'.'+GetBIName(pbifnIntfAsIntfT),El)
  8703. else
  8704. // CORBA -> "rtl.as(A,B)"
  8705. Call.Expr:=CreatePrimitiveDotExpr(GetBIName(pbivnRTL)+'.'+GetBIName(pbifnAs),El);
  8706. else
  8707. NotSupportedRes(20180327214545);
  8708. end;
  8709. else
  8710. NotSupportedRes(20180327214559);
  8711. end
  8712. else if RightTypeEl is TPasClassOfType then
  8713. begin
  8714. // ClassInstVar is ClassOfType -> "rtl.as(A,B)"
  8715. Call.Expr:=CreatePrimitiveDotExpr(GetBIName(pbivnRTL)+'.'+GetBIName(pbifnAs),El);
  8716. end;
  8717. end;
  8718. Call.AddArg(A);
  8719. Call.AddArg(B);
  8720. Result:=Call;
  8721. exit;
  8722. end;
  8723. eopAnd:
  8724. begin
  8725. if aResolver<>nil then
  8726. begin
  8727. UseBitwiseOp:=((LeftResolved.BaseType in btAllJSInteger)
  8728. or (RightResolved.BaseType in btAllJSInteger));
  8729. if UseBitwiseOp then
  8730. begin
  8731. if (LeftResolved.BaseType in [btIntDouble,btUIntDouble])
  8732. and (RightResolved.BaseType in [btIntDouble,btUIntDouble]) then
  8733. begin
  8734. Call:=CreateCallExpression(El);
  8735. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnBitwiseNativeIntAnd)]);
  8736. Call.AddArg(A);
  8737. Call.AddArg(B);
  8738. Result:=Call;
  8739. exit;
  8740. end
  8741. else if BitwiseOpNeedLongwordFix then
  8742. begin
  8743. Result:=CreateBitwiseLongwordOp(A,B,TJSBitwiseAndExpression);
  8744. exit;
  8745. end;
  8746. end;
  8747. end
  8748. else
  8749. UseBitwiseOp:=(GetExpressionValueType(El.left,AContext)=jstNumber)
  8750. or (GetExpressionValueType(El.right,AContext)=jstNumber);
  8751. if UseBitwiseOp then
  8752. C:=TJSBitwiseAndExpression
  8753. else
  8754. C:=TJSLogicalAndExpression;
  8755. end;
  8756. eopOr:
  8757. begin
  8758. if aResolver<>nil then
  8759. begin
  8760. UseBitwiseOp:=((LeftResolved.BaseType in btAllJSInteger)
  8761. or (RightResolved.BaseType in btAllJSInteger));
  8762. if UseBitwiseOp then
  8763. begin
  8764. if ((LeftResolved.BaseType in [btIntDouble,btUIntDouble])
  8765. or (RightResolved.BaseType in [btIntDouble,btUIntDouble])) then
  8766. begin
  8767. Call:=CreateCallExpression(El);
  8768. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnBitwiseNativeIntOr)]);
  8769. Call.AddArg(A);
  8770. Call.AddArg(B);
  8771. Result:=Call;
  8772. exit;
  8773. end
  8774. else if BitwiseOpNeedLongwordFix then
  8775. begin
  8776. Result:=CreateBitwiseLongwordOp(A,B,TJSBitwiseOrExpression);
  8777. exit;
  8778. end;
  8779. end;
  8780. end
  8781. else
  8782. UseBitwiseOp:=(GetExpressionValueType(El.left,AContext)=jstNumber)
  8783. or (GetExpressionValueType(El.right,AContext)=jstNumber);
  8784. if UseBitwiseOp then
  8785. C:=TJSBitwiseOrExpression
  8786. else
  8787. C:=TJSLogicalOrExpression;
  8788. end;
  8789. eopXor:
  8790. begin
  8791. if aResolver<>nil then
  8792. begin
  8793. UseBitwiseOp:=((LeftResolved.BaseType in btAllJSInteger)
  8794. or (RightResolved.BaseType in btAllJSInteger));
  8795. if UseBitwiseOp then
  8796. begin
  8797. if ((LeftResolved.BaseType in [btIntDouble,btUIntDouble])
  8798. or (RightResolved.BaseType in [btIntDouble,btUIntDouble])) then
  8799. begin
  8800. Call:=CreateCallExpression(El);
  8801. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnBitwiseNativeIntXor)]);
  8802. Call.AddArg(A);
  8803. Call.AddArg(B);
  8804. Result:=Call;
  8805. exit;
  8806. end
  8807. else if BitwiseOpNeedLongwordFix then
  8808. begin
  8809. Result:=CreateBitwiseLongwordOp(A,B,TJSBitwiseXOrExpression);
  8810. exit;
  8811. end;
  8812. end;
  8813. end
  8814. else
  8815. UseBitwiseOp:=(GetExpressionValueType(El.left,AContext)=jstNumber)
  8816. or (GetExpressionValueType(El.right,AContext)=jstNumber);
  8817. if UseBitwiseOp then
  8818. C:=TJSBitwiseXOrExpression
  8819. else
  8820. C:=TJSBitwiseXOrExpression; // no logical xor in JS. bitwise works for boolean too
  8821. end;
  8822. eopPower:
  8823. // convert pascal ** to js **
  8824. C:=TJSPowerExpression;
  8825. else
  8826. if C=nil then
  8827. DoError(20161024191244,nBinaryOpcodeNotSupported,sBinaryOpcodeNotSupported,[OpcodeStrings[El.OpCode]],El);
  8828. end;
  8829. if (Result=Nil) and (C<>Nil) then
  8830. begin
  8831. R:=TJSBinary(CreateElement(C,El));
  8832. R.A:=A; A:=nil;
  8833. R.B:=B; B:=nil;
  8834. Result:=R;
  8835. case El.OpCode of
  8836. eopDiv:
  8837. begin
  8838. // convert "a div b" to "rtl.trunc(a/b)"
  8839. Result:=CreateTruncFloor(El,Result,true);
  8840. end;
  8841. end;
  8842. if (bsOverflowChecks in AContext.ScannerBoolSwitches) and (aResolver<>nil) then
  8843. case El.OpCode of
  8844. eopAdd,eopSubtract:
  8845. if (LeftResolved.BaseType in btAllJSOverflowAddSubType)
  8846. or (RightResolved.BaseType in btAllJSOverflowAddSubType) then
  8847. Result:=CreateOverflowCheckCall(Result,El);
  8848. eopMultiply:
  8849. if (LeftResolved.BaseType in btAllJSOverflowMultType)
  8850. or (RightResolved.BaseType in btAllJSOverflowMultType) then
  8851. Result:=CreateOverflowCheckCall(Result,El);
  8852. end;
  8853. end;
  8854. finally
  8855. AContext.Access:=OldAccess;
  8856. if Result=nil then
  8857. begin
  8858. A.Free;
  8859. B.Free;
  8860. end;
  8861. end;
  8862. end;
  8863. function TPasToJSConverter.ConvertBinaryExpressionRes(El: TBinaryExpr;
  8864. AContext: TConvertContext; const LeftResolved,
  8865. RightResolved: TPasResolverResult; var A, B: TJSElement): TJSElement;
  8866. var
  8867. aResolver: TPas2JSResolver;
  8868. procedure NotSupported(id: TMaxPrecInt);
  8869. begin
  8870. {$IFDEF VerbosePas2JS}
  8871. writeln('TPasToJSConverter.ConvertBinaryExpressionRes.NotSupported',
  8872. ' Left=',GetResolverResultDbg(LeftResolved),
  8873. ' Op=',ExprKindNames[El.Kind],
  8874. ' Right=',GetResolverResultDbg(RightResolved));
  8875. {$ENDIF}
  8876. RaiseNotSupported(El,AContext,id,
  8877. GetResolverResultDbg(LeftResolved)+ExprKindNames[El.Kind]
  8878. +GetResolverResultDbg(RightResolved));
  8879. end;
  8880. function CreateEqualCallback: TJSElement;
  8881. var
  8882. Call: TJSCallExpression;
  8883. begin
  8884. // convert "proctypeA = proctypeB" to "rtl.eqCallback(proctypeA,proctypeB)"
  8885. Call:=CreateCallExpression(El);
  8886. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnProcType_Equal)]);
  8887. Call.AddArg(A);
  8888. A:=nil;
  8889. Call.AddArg(B);
  8890. B:=nil;
  8891. if El.OpCode=eopNotEqual then
  8892. begin
  8893. // convert "proctypeA <> proctypeB" to "!rtl.eqCallback(proctypeA,proctypeB)"
  8894. Result:=CreateUnaryNot(Call,El);
  8895. end
  8896. else
  8897. Result:=Call;
  8898. end;
  8899. procedure ConcatArray(ArrayType: TPasArrayType);
  8900. var
  8901. Call: TJSCallExpression;
  8902. begin
  8903. Call:=CreateArrayConcat(ArrayType,El,AContext);
  8904. Result:=Call;
  8905. Call.AddArg(A); A:=nil;
  8906. Call.AddArg(B); B:=nil;
  8907. if aResolver.IsManagedJSType(ArrayType) then
  8908. Result:=CreateIntfRef(Result,AContext,El);
  8909. end;
  8910. var
  8911. FunName: String;
  8912. Call: TJSCallExpression;
  8913. InOp: TJSRelationalExpressionIn;
  8914. TypeEl, LeftTypeEl, RightTypeEl: TPasType;
  8915. SNE: TJSEqualityExpressionSNE;
  8916. JSBinClass: TJSBinaryClass;
  8917. ResolvedEl: TPasResolverResult;
  8918. AInt, BInt: TMaxPrecInt;
  8919. LArrType: TPasArrayType;
  8920. begin
  8921. {$IFDEF VerbosePas2JS}
  8922. writeln('TPasToJSConverter.ConvertBinaryExpressionRes OpCode="',OpcodeStrings[El.OpCode],'" Left=',GetResolverResultDbg(LeftResolved),' Right=',GetResolverResultDbg(RightResolved));
  8923. {$ENDIF}
  8924. Result:=nil;
  8925. aResolver:=AContext.Resolver;
  8926. LeftTypeEl:=LeftResolved.LoTypeEl;
  8927. RightTypeEl:=RightResolved.LoTypeEl;
  8928. if (LeftResolved.BaseType in [btSet,btArrayOrSet])
  8929. and (RightResolved.BaseType in [btSet,btArrayOrSet]) then
  8930. begin
  8931. // set operators -> rtl.operatorfunction(a,b)
  8932. case El.OpCode of
  8933. eopAdd: FunName:=GetBIName(pbifnSet_Union);
  8934. eopSubtract: FunName:=GetBIName(pbifnSet_Difference);
  8935. eopMultiply: FunName:=GetBIName(pbifnSet_Intersect);
  8936. eopSymmetricaldifference: FunName:=GetBIName(pbifnSet_SymDiffSet);
  8937. eopEqual: FunName:=GetBIName(pbifnSet_Equal);
  8938. eopNotEqual: FunName:=GetBIName(pbifnSet_NotEqual);
  8939. eopGreaterThanEqual: FunName:=GetBIName(pbifnSet_GreaterEqual);
  8940. eopLessthanEqual: FunName:=GetBIName(pbifnSet_LowerEqual);
  8941. else
  8942. DoError(20170209151300,nBinaryOpcodeNotSupported,sBinaryOpcodeNotSupported,[OpcodeStrings[El.OpCode]],El);
  8943. end;
  8944. Call:=CreateCallExpression(El);
  8945. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),FunName]);
  8946. Call.AddArg(A); A:=nil;
  8947. Call.AddArg(B); B:=nil;
  8948. Result:=Call;
  8949. exit;
  8950. end
  8951. else if (El.OpCode=eopIn) and (RightResolved.BaseType in [btSet,btArrayOrSet]) then
  8952. begin
  8953. // a in b -> a in b
  8954. if not (A is TJSLiteral) or (TJSLiteral(A).Value.ValueType<>jstNumber) then
  8955. begin
  8956. FreeAndNil(A);
  8957. A:=CreateSetLiteralElement(El.left,AContext);
  8958. end;
  8959. InOp:=TJSRelationalExpressionIn(CreateElement(TJSRelationalExpressionIn,El));
  8960. InOp.A:=A; A:=nil;
  8961. InOp.B:=B; B:=nil;
  8962. Result:=InOp;
  8963. exit;
  8964. end
  8965. else if (El.OpCode=eopAdd)
  8966. and ((LeftResolved.BaseType=btContext) and (LeftResolved.LoTypeEl.ClassType=TPasArrayType)) then
  8967. begin
  8968. // Arr+Arr Arr+[] Arr+[...]
  8969. ConcatArray(TPasArrayType(LeftResolved.LoTypeEl));
  8970. exit;
  8971. end
  8972. else if (El.OpCode=eopAdd)
  8973. and ((RightResolved.BaseType=btContext) and (RightResolved.LoTypeEl.ClassType=TPasArrayType)) then
  8974. begin
  8975. // []+Arr [...]+Arr
  8976. ConcatArray(TPasArrayType(RightResolved.LoTypeEl));
  8977. exit;
  8978. end
  8979. else if (El.OpCode=eopAdd)
  8980. and (LeftResolved.BaseType=btArrayLit) then
  8981. begin
  8982. // [...]+[] [...]+[...]
  8983. SetResolverValueExpr(ResolvedEl,LeftResolved.SubType,LeftResolved.LoTypeEl,
  8984. LeftResolved.HiTypeEl,El.left,LeftResolved.Flags);
  8985. Call:=CreateArrayConcat(ResolvedEl,El,AContext);
  8986. Result:=Call;
  8987. if aResolver.IsManagedJSType(LeftResolved.LoTypeEl) then
  8988. Result:=CreateIntfRef(Result,AContext,El);
  8989. Call.AddArg(A); A:=nil;
  8990. Call.AddArg(B); B:=nil;
  8991. exit;
  8992. end
  8993. else if El.OpCode in [eopShl,eopShr] then
  8994. begin
  8995. if LeftResolved.BaseType in [btIntDouble,btUIntDouble] then
  8996. begin
  8997. // BigInt shl/shr JavaScript bitwise operators only supports 32bit
  8998. if IsLiteralInteger(B,BInt) then
  8999. begin
  9000. // BigInt shl/shr const
  9001. if BInt>=54 then
  9002. begin
  9003. // A shl 54 -> 0
  9004. // A shr 54 -> 0
  9005. Result:=CreateLiteralNumber(El,0);
  9006. FreeAndNil(A);
  9007. FreeAndNil(B);
  9008. exit;
  9009. end
  9010. else if BInt<=0 then
  9011. begin
  9012. // A shl 0 -> A
  9013. // A shr 0 -> A
  9014. Result:=A;
  9015. A:=nil;
  9016. FreeAndNil(B);
  9017. exit;
  9018. end
  9019. else if IsLiteralInteger(A,AInt) then
  9020. begin
  9021. // const shl const -> const
  9022. if El.OpCode=eopShl then
  9023. AInt:=AInt shl BInt
  9024. else
  9025. AInt:=AInt shr BInt;
  9026. if (AInt>=0) and (AInt<=MaxSafeIntDouble) then
  9027. begin
  9028. TJSLiteral(A).Value.AsNumber:=AInt;
  9029. Result:=A;
  9030. FreeAndNil(B);
  9031. exit;
  9032. end;
  9033. end
  9034. else if El.OpCode=eopShr then
  9035. begin
  9036. // BigInt shr const -> Math.floor(A/otherconst)
  9037. Result:=CreateTruncFloor(El,CreateDivideNumber(El,A,TMaxPrecInt(1) shl BInt),false);
  9038. A:=nil;
  9039. FreeAndNil(B);
  9040. exit;
  9041. end;
  9042. end;
  9043. // use rtl.shl(a,b)
  9044. Call:=CreateCallExpression(El);
  9045. Result:=Call;
  9046. if El.OpCode=eopShl then
  9047. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnBitwiseNativeIntShl)])
  9048. else
  9049. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnBitwiseNativeIntShr)]);
  9050. Call.AddArg(A); A:=nil;
  9051. Call.AddArg(B); B:=nil;
  9052. exit;
  9053. end
  9054. else if LeftResolved.BaseType=btLongWord then
  9055. begin
  9056. // aLongWord shl b -> rtl.lw(a << b)
  9057. if El.OpCode=eopShl then
  9058. JSBinClass:=TJSLShiftExpression
  9059. else
  9060. JSBinClass:=TJSURShiftExpression;
  9061. Result:=TJSBinaryExpression(CreateElement(JSBinClass,El));
  9062. TJSBinaryExpression(Result).A:=A; A:=nil;
  9063. TJSBinaryExpression(Result).B:=B; B:=nil;
  9064. Result:=CreateBitWiseLongword(El,Result);
  9065. exit;
  9066. end;
  9067. end
  9068. else if (LeftResolved.BaseType=btCurrency) or (RightResolved.BaseType=btCurrency) then
  9069. begin
  9070. case El.OpCode of
  9071. eopAdd,eopSubtract,
  9072. eopEqual, eopNotEqual, // Logical
  9073. eopLessThan,eopGreaterThan, eopLessthanEqual,eopGreaterThanEqual: // ordering
  9074. begin
  9075. // currency + currency -> currency + currency
  9076. // currency + number -> currency + number*10000
  9077. // number + currency -> number*10000 + currency
  9078. case El.OpCode of
  9079. eopAdd: JSBinClass:=TJSAdditiveExpressionPlus;
  9080. eopSubtract: JSBinClass:=TJSAdditiveExpressionMinus;
  9081. eopEqual: JSBinClass:=TJSEqualityExpressionSEQ;
  9082. eopNotEqual: JSBinClass:=TJSEqualityExpressionSNE;
  9083. eopLessThan: JSBinClass:=TJSRelationalExpressionLT;
  9084. eopGreaterThan: JSBinClass:=TJSRelationalExpressionGT;
  9085. eopLessthanEqual: JSBinClass:=TJSRelationalExpressionLE;
  9086. eopGreaterThanEqual: JSBinClass:=TJSRelationalExpressionGE;
  9087. end;
  9088. Result:=TJSBinary(CreateElement(JSBinClass,El));
  9089. if LeftResolved.BaseType<>btCurrency then
  9090. A:=CreateMulNumber(El,A,10000);
  9091. TJSBinary(Result).A:=A; A:=nil;
  9092. if RightResolved.BaseType<>btCurrency then
  9093. B:=CreateMulNumber(El,B,10000);
  9094. TJSBinary(Result).B:=B; B:=nil;
  9095. if (bsOverflowChecks in AContext.ScannerBoolSwitches)
  9096. and (El.OpCode in [eopAdd,eopSubtract]) then
  9097. Result:=CreateOverflowCheckCall(Result,El);
  9098. exit;
  9099. end;
  9100. eopMultiply:
  9101. begin
  9102. // currency * currency -> (currency * currency)/10000
  9103. // currency * number -> currency * number
  9104. // number * currency -> number * currency
  9105. Result:=TJSMultiplicativeExpressionMul(CreateElement(TJSMultiplicativeExpressionMul,El));
  9106. TJSBinaryExpression(Result).A:=A; A:=nil;
  9107. TJSBinaryExpression(Result).B:=B; B:=nil;
  9108. if (LeftResolved.BaseType=btCurrency) and (RightResolved.BaseType=btCurrency) then
  9109. Result:=CreateDivideNumber(El,Result,10000);
  9110. if (bsOverflowChecks in AContext.ScannerBoolSwitches) then
  9111. Result:=CreateOverflowCheckCall(Result,El);
  9112. exit;
  9113. end;
  9114. eopDivide:
  9115. begin
  9116. // currency / currency -> rtl.trunc((currency/currency)*10000)
  9117. // currency / number -> rtl.trunc(currency/number)
  9118. // number / currency -> rtl.trunc(number/currency)
  9119. Result:=TJSMultiplicativeExpressionDiv(CreateElement(TJSMultiplicativeExpressionDiv,El));
  9120. TJSBinaryExpression(Result).A:=A; A:=nil;
  9121. TJSBinaryExpression(Result).B:=B; B:=nil;
  9122. if (LeftResolved.BaseType=btCurrency) and (RightResolved.BaseType=btCurrency) then
  9123. Result:=CreateMulNumber(El,Result,10000);
  9124. Result:=CreateTruncFloor(El,Result,true);
  9125. exit;
  9126. end;
  9127. eopPower:
  9128. begin
  9129. // currency^^currency -> rtl.trunc(Math.pow(currency/10000,currency/10000)*10000)
  9130. // currency^^number -> rtl.trunc(Math.pow(currency/10000,number)*10000)
  9131. // number^^currency -> rtl.trunc(Math.pow(number,currency/10000)*10000)
  9132. if LeftResolved.BaseType=btCurrency then
  9133. A:=CreateDivideNumber(El,A,10000);
  9134. if RightResolved.BaseType=btCurrency then
  9135. B:=CreateDivideNumber(El,B,10000);
  9136. Call:=CreateCallExpression(El);
  9137. Call.Expr:=CreatePrimitiveDotExpr('Math.pow',El);
  9138. Call.AddArg(A); A:=nil;
  9139. Call.AddArg(B); B:=nil;
  9140. Result:=CreateMulNumber(El,Call,10000);
  9141. Result:=CreateTruncFloor(El,Result,true);
  9142. end
  9143. else
  9144. RaiseNotSupported(El,AContext,20180422104215);
  9145. end;
  9146. end
  9147. else if (LeftResolved.BaseType=btPointer)
  9148. or ((LeftResolved.BaseType=btContext) and (LeftTypeEl.ClassType=TPasPointerType)) then
  9149. case El.OpCode of
  9150. eopEqual,eopNotEqual: ;
  9151. else
  9152. DoError(20180423114054,nIllegalQualifierAfter,sIllegalQualifierAfter,
  9153. [OpcodeStrings[El.OpCode],aResolver.GetResolverResultDescription(LeftResolved,true)],El);
  9154. end
  9155. else if (RightResolved.BaseType=btPointer)
  9156. or ((RightResolved.BaseType=btContext) and (RightTypeEl.ClassType=TPasPointerType)) then
  9157. case El.OpCode of
  9158. eopEqual,eopNotEqual: ;
  9159. else
  9160. DoError(20180423114246,nIllegalQualifierInFrontOf,sIllegalQualifierInFrontOf,
  9161. [OpcodeStrings[El.OpCode],aResolver.GetResolverResultDescription(RightResolved,true)],El);
  9162. end
  9163. else if (El.OpCode=eopIs) then
  9164. begin
  9165. // "A is B"
  9166. Call:=CreateCallExpression(El);
  9167. Result:=Call;
  9168. Call.AddArg(A); A:=nil;
  9169. if (RightResolved.IdentEl is TPasType) then
  9170. TypeEl:=aResolver.ResolveAliasType(TPasType(RightResolved.IdentEl))
  9171. else
  9172. TypeEl:=nil;
  9173. if (TypeEl is TPasClassOfType) then
  9174. begin
  9175. // "A is class-of-type" -> use the class
  9176. FreeAndNil(B);
  9177. TypeEl:=aResolver.ResolveAliasType(TPasClassOfType(TypeEl).DestType);
  9178. B:=CreateReferencePathExpr(TypeEl,AContext);
  9179. end;
  9180. if (LeftResolved.BaseType=btCustom) then
  9181. begin
  9182. // aJSValue is ... -> "rtl.isExt(A,B,mode)"
  9183. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnIsExt)]);
  9184. Call.AddArg(B); B:=nil;
  9185. if RightTypeEl is TPasClassType then
  9186. Call.AddArg(CreateLiteralNumber(El.right,IsExtModePasClassInstance))
  9187. else if RightTypeEl is TPasClassOfType then
  9188. Call.AddArg(CreateLiteralNumber(El.right,IsExtModePasClass))
  9189. else
  9190. NotSupported(20180119005904);
  9191. end
  9192. else if (RightTypeEl is TPasClassType) and TPasClassType(RightTypeEl).IsExternal then
  9193. begin
  9194. // B is an external class -> "rtl.isExt(A,B)"
  9195. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnIsExt)]);
  9196. Call.AddArg(B); B:=nil;
  9197. end
  9198. else if LeftTypeEl is TPasClassOfType then
  9199. begin
  9200. // A is a TPasClassOfType -> "rtl.is(A,B)"
  9201. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnIs)]);
  9202. Call.AddArg(B); B:=nil;
  9203. end
  9204. else
  9205. begin
  9206. if LeftTypeEl is TPasClassType then
  9207. begin
  9208. if RightTypeEl is TPasClassType then
  9209. case TPasClassType(LeftTypeEl).ObjKind of
  9210. okClass:
  9211. case TPasClassType(RightTypeEl).ObjKind of
  9212. okClass: ;
  9213. okInterface:
  9214. begin
  9215. // ClassInstVar is IntfType
  9216. case TPasClassType(RightTypeEl).InterfaceType of
  9217. citCom:
  9218. begin
  9219. // COM: rtl.queryIntfIsT(A,B)
  9220. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnIntfQueryIntfIsT)]);
  9221. Call.AddArg(B); B:=nil;
  9222. end;
  9223. citCorba:
  9224. begin
  9225. // CORBA: rtl.getIntfT(A,B)!==null
  9226. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnIntfGetIntfT)]);
  9227. Call.AddArg(B); B:=nil;
  9228. SNE:=TJSEqualityExpressionSNE(CreateElement(TJSEqualityExpressionSNE,El));
  9229. Result:=SNE;
  9230. SNE.A:=Call;
  9231. SNE.B:=CreateLiteralNull(El);
  9232. end;
  9233. else
  9234. RaiseNotSupported(El,AContext,20180401225502,InterfaceTypeNames[TPasClassType(RightTypeEl).InterfaceType]){%H-};
  9235. end;
  9236. exit;
  9237. end;
  9238. else
  9239. NotSupported(20180327210501);
  9240. end;
  9241. okInterface:
  9242. case TPasClassType(RightTypeEl).ObjKind of
  9243. okClass:
  9244. begin
  9245. // IntfVar is ClassType -> rtl.intfIsClass(A,B)
  9246. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnIntfIsClass)]);
  9247. Call.AddArg(B); B:=nil;
  9248. exit;
  9249. end;
  9250. okInterface:
  9251. if TPasClassType(LeftTypeEl).InterfaceType=citCom then
  9252. begin
  9253. // COM: IntfVar is IntfType -> rtl.intfIsIntfT(A,B)
  9254. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnIntfIsIntf)]);
  9255. Call.AddArg(B); B:=nil;
  9256. exit;
  9257. end;
  9258. else
  9259. NotSupported(20180327210741);
  9260. end;
  9261. else
  9262. NotSupported(20180327210251);
  9263. end;
  9264. end;
  9265. // use directly "B.isPrototypeOf(A)"
  9266. Call.Expr:=CreateDotNameExpr(El,B,'isPrototypeOf');
  9267. B:=nil;
  9268. end;
  9269. exit;
  9270. end
  9271. else if (El.OpCode in [eopEqual,eopNotEqual]) then
  9272. begin
  9273. if aResolver.IsProcedureType(LeftResolved,true) then
  9274. begin
  9275. if RightResolved.BaseType=btNil then
  9276. else if aResolver.IsProcedureType(RightResolved,true)
  9277. or aResolver.IsJSBaseType(RightResolved,pbtJSValue,true) then
  9278. exit(CreateEqualCallback);
  9279. end
  9280. else if aResolver.IsProcedureType(RightResolved,true) then
  9281. begin
  9282. if LeftResolved.BaseType=btNil then
  9283. else if aResolver.IsJSBaseType(LeftResolved,pbtJSValue,true) then
  9284. exit(CreateEqualCallback);
  9285. end
  9286. else if LeftResolved.BaseType=btNil then
  9287. begin
  9288. if RightResolved.BaseType=btContext then
  9289. begin
  9290. RightTypeEl:=RightResolved.LoTypeEl;
  9291. if RightTypeEl.ClassType=TPasArrayType then
  9292. begin
  9293. // convert "nil = array" to "rtl.length(array) > 0"
  9294. FreeAndNil(A);
  9295. Result:=CreateCmpArrayWithNil(El,B,El.OpCode);
  9296. B:=nil;
  9297. exit;
  9298. end;
  9299. end;
  9300. end
  9301. else if LeftResolved.BaseType in btAllStrings then
  9302. begin
  9303. if RightResolved.BaseType=btContext then
  9304. begin
  9305. RightTypeEl:=RightResolved.LoTypeEl;
  9306. if RightTypeEl.ClassType=TPasRecordType then
  9307. begin
  9308. if aResolver.IsTGUID(TPasRecordType(RightTypeEl)) then
  9309. begin
  9310. // "aString=GuidVar" -> "GuidVar.$eq(rtl.createTGUID(aString))"
  9311. Call:=CreateCallExpression(El);
  9312. Call.Expr:=CreatePrimitiveDotExpr(GetBIName(pbivnRTL)+'.'+GetBIName(pbifnIntfCreateTGUID),El);
  9313. Call.AddArg(A);
  9314. A:=Call;
  9315. Call:=CreateCallExpression(El);
  9316. Call.Expr:=CreateDotNameExpr(El,B,TJSString(GetBIName(pbifnRecordEqual)));
  9317. B:=nil;
  9318. Call.AddArg(A);
  9319. A:=nil;
  9320. if El.OpCode=eopNotEqual then
  9321. Result:=CreateUnaryNot(Call,El)
  9322. else
  9323. Result:=Call;
  9324. exit;
  9325. end;
  9326. end
  9327. else if RightTypeEl.ClassType=TPasClassType then
  9328. begin
  9329. if TPasClassType(RightTypeEl).ObjKind=okInterface then
  9330. begin
  9331. // "aString=IntfTypeOrVar" -> "aString===IntfTypeOrVar.$guid"
  9332. B:=CreateDotNameExpr(El.left,B,TJSString(GetBIName(pbivnIntfGUID)));
  9333. end;
  9334. end;
  9335. end;
  9336. end
  9337. else if LeftResolved.BaseType=btContext then
  9338. begin
  9339. LeftTypeEl:=LeftResolved.LoTypeEl;
  9340. if LeftTypeEl.ClassType=TPasRecordType then
  9341. begin
  9342. // LHS is a record
  9343. if RightResolved.BaseType=btContext then
  9344. begin
  9345. RightTypeEl:=RightResolved.LoTypeEl;
  9346. if RightTypeEl.ClassType=TPasRecordType then
  9347. begin
  9348. // convert "recordA = recordB" to "recordA.$eq(recordB)"
  9349. Call:=CreateCallExpression(El);
  9350. Call.Expr:=CreateDotNameExpr(El,A,TJSString(GetBIName(pbifnRecordEqual)));
  9351. A:=nil;
  9352. Call.AddArg(B);
  9353. B:=nil;
  9354. if El.OpCode=eopNotEqual then
  9355. begin
  9356. // convert "recordA <> recordB" to "!recordA.$eq(recordB)"
  9357. Result:=CreateUnaryNot(Call,El);
  9358. end
  9359. else
  9360. Result:=Call;
  9361. exit;
  9362. end
  9363. else if (RightTypeEl.ClassType=TPasClassType)
  9364. and (TPasClassType(RightTypeEl).ObjKind=okInterface)
  9365. and aResolver.IsTGUID(TPasRecordType(LeftTypeEl)) then
  9366. begin
  9367. // "GuidVar = intfTypeOrVar" -> "GuidVar.$eq(rtl.getIntfGUIDR(intfTypeOrVar))"
  9368. Call:=CreateCallExpression(El);
  9369. Call.Expr:=CreatePrimitiveDotExpr(GetBIName(pbivnRTL)+'.'+GetBIName(pbifnIntfGetGUIDR),El);
  9370. Call.AddArg(B);
  9371. B:=Call;
  9372. Call:=CreateCallExpression(El);
  9373. Call.Expr:=CreateDotNameExpr(El,A,TJSString(GetBIName(pbifnRecordEqual)));
  9374. A:=nil;
  9375. Call.AddArg(B);
  9376. B:=nil;
  9377. if El.OpCode=eopNotEqual then
  9378. Result:=CreateUnaryNot(Call,El)
  9379. else
  9380. Result:=Call;
  9381. exit;
  9382. end;
  9383. end
  9384. else if (RightResolved.BaseType in btAllStrings)
  9385. and aResolver.IsTGUID(TPasRecordType(LeftTypeEl)) then
  9386. begin
  9387. // "GuidVar = aString" -> "GuidVar.$eq(rtl.createTGUID(aString))"
  9388. Call:=CreateCallExpression(El);
  9389. Call.Expr:=CreatePrimitiveDotExpr(GetBIName(pbivnRTL)+'.'+GetBIName(pbifnIntfCreateTGUID),El);
  9390. Call.AddArg(B);
  9391. B:=Call;
  9392. Call:=CreateCallExpression(El);
  9393. Call.Expr:=CreateDotNameExpr(El,A,TJSString(GetBIName(pbifnRecordEqual)));
  9394. A:=nil;
  9395. Call.AddArg(B);
  9396. B:=nil;
  9397. if El.OpCode=eopNotEqual then
  9398. Result:=CreateUnaryNot(Call,El)
  9399. else
  9400. Result:=Call;
  9401. exit;
  9402. end;
  9403. end
  9404. else if LeftTypeEl.ClassType=TPasClassType then
  9405. begin
  9406. if RightResolved.BaseType in btAllStrings then
  9407. begin
  9408. if (TPasClassType(LeftTypeEl).ObjKind=okInterface) then
  9409. begin
  9410. // "IntfTypeOrVar=aString" -> "IntfTypeOrVar.$guid === aString"
  9411. A:=CreateDotNameExpr(El.left,A,TJSString(GetBIName(pbivnIntfGUID)));
  9412. end;
  9413. end
  9414. else if RightResolved.BaseType=btContext then
  9415. begin
  9416. RightTypeEl:=RightResolved.LoTypeEl;
  9417. if RightTypeEl.ClassType=TPasRecordType then
  9418. begin
  9419. if (TPasClassType(LeftTypeEl).ObjKind=okInterface)
  9420. and aResolver.IsTGUID(TPasRecordType(RightTypeEl)) then
  9421. begin
  9422. // "IntfTypeOrVar=GuidVar" -> "GuidVar.$eq(rtl.getIntfGUIDR(intfTypeOrVar))"
  9423. Call:=CreateCallExpression(El);
  9424. Call.Expr:=CreatePrimitiveDotExpr(GetBIName(pbivnRTL)+'.'+GetBIName(pbifnIntfGetGUIDR),El);
  9425. Call.AddArg(A);
  9426. A:=Call;
  9427. Call:=CreateCallExpression(El);
  9428. Call.Expr:=CreateDotNameExpr(El,B,TJSString(GetBIName(pbifnRecordEqual)));
  9429. B:=nil;
  9430. Call.AddArg(A);
  9431. A:=nil;
  9432. if El.OpCode=eopNotEqual then
  9433. Result:=CreateUnaryNot(Call,El)
  9434. else
  9435. Result:=Call;
  9436. exit;
  9437. end;
  9438. end;
  9439. end;
  9440. end
  9441. else if LeftTypeEl.ClassType=TPasArrayType then
  9442. begin
  9443. LArrType:=TPasArrayType(LeftTypeEl);
  9444. if RightResolved.BaseType=btNil then
  9445. begin
  9446. // convert "array = nil" to "rtl.length(array) === 0"
  9447. FreeAndNil(B);
  9448. Result:=CreateCmpArrayWithNil(El,A,El.OpCode);
  9449. A:=nil;
  9450. exit;
  9451. end
  9452. else if length(LArrType.Ranges)>0 then
  9453. begin
  9454. // LHS is static array
  9455. aResolver.RaiseMsg(20200508102656,nXIsNotSupported,sXIsNotSupported,['compare static array'],TPasElement(El));
  9456. end;
  9457. end;
  9458. end;
  9459. if aResolver.IsJSBaseType(LeftResolved,pbtJSValue)
  9460. or aResolver.IsJSBaseType(RightResolved,pbtJSValue) then
  9461. begin
  9462. // convert "jsvalue = something" to "jsvalue == something" (not strict)
  9463. // Note: default "=" is converted to "===" (strict equal)
  9464. if El.OpCode=eopEqual then
  9465. Result:=TJSEqualityExpressionEQ(CreateElement(TJSEqualityExpressionEQ,El))
  9466. else
  9467. Result:=TJSEqualityExpressionNE(CreateElement(TJSEqualityExpressionNE,El));
  9468. TJSBinaryExpression(Result).A:=A; A:=nil;
  9469. TJSBinaryExpression(Result).B:=B; B:=nil;
  9470. exit;
  9471. end;
  9472. end;
  9473. end;
  9474. function TPasToJSConverter.ConvertBinaryExpressionMultiAdd(El: TBinaryExpr;
  9475. AContext: TConvertContext): TJSElement;
  9476. // handle multi add without stack
  9477. // Note: The parser generates a list of TBinaryExpr.Lefts
  9478. var
  9479. aResolver: TPas2JSResolver;
  9480. Left: TPasExpr;
  9481. SubBin: TBinaryExpr;
  9482. A, B: TJSElement;
  9483. LeftResolved, RightResolved, ResultResolved: TPasResolverResult;
  9484. Flags: TPasResolverComputeFlags;
  9485. R: TJSBinary;
  9486. OldAccess: TCtxAccess;
  9487. begin
  9488. Result:=nil;
  9489. aResolver:=AContext.Resolver;
  9490. Left:=El;
  9491. while Left.ClassType=TBinaryExpr do
  9492. begin
  9493. SubBin:=TBinaryExpr(Left);
  9494. if SubBin.OpCode<>eopAdd then break;
  9495. Left:=SubBin.left;
  9496. if Left.Parent<>SubBin then
  9497. begin
  9498. if aResolver<>nil then
  9499. RaiseNotSupported(SubBin,AContext,20210321220458)
  9500. else if Left.Parent=nil then
  9501. Left.Parent:=SubBin
  9502. else
  9503. RaiseNotSupported(SubBin,AContext,20210321221135);
  9504. end;
  9505. end;
  9506. if Left=El then
  9507. RaiseNotSupported(El,AContext,20210321221047);
  9508. OldAccess:=AContext.Access;
  9509. AContext.Access:=caRead;
  9510. A:=nil;
  9511. B:=nil;
  9512. try
  9513. A:=ConvertExpression(Left,AContext);
  9514. Flags:=[];
  9515. if aResolver<>nil then
  9516. aResolver.ComputeElement(Left,LeftResolved,Flags);
  9517. repeat
  9518. SubBin:=TBinaryExpr(Left.Parent);
  9519. B:=ConvertExpression(SubBin.right,AContext);
  9520. if aResolver<>nil then
  9521. begin
  9522. aResolver.ComputeElement(SubBin.right,RightResolved,Flags);
  9523. Result:=ConvertBinaryExpressionRes(SubBin,AContext,LeftResolved,RightResolved,A,B);
  9524. if (Result<>nil) then
  9525. begin
  9526. A:=nil;
  9527. B:=nil;
  9528. if SubBin=El then exit;
  9529. end;
  9530. aResolver.ComputeBinaryExprRes(SubBin,ResultResolved,Flags,LeftResolved,RightResolved);
  9531. end;
  9532. if Result=nil then
  9533. begin
  9534. // +
  9535. R:=TJSBinary(CreateElement(TJSAdditiveExpressionPlus,SubBin));
  9536. R.A:=A; A:=nil;
  9537. R.B:=B; B:=nil;
  9538. Result:=R;
  9539. if (bsOverflowChecks in AContext.ScannerBoolSwitches) and (aResolver<>nil) then
  9540. case El.OpCode of
  9541. eopAdd,eopSubtract:
  9542. if (LeftResolved.BaseType in btAllJSOverflowAddSubType)
  9543. or (RightResolved.BaseType in btAllJSOverflowAddSubType) then
  9544. Result:=CreateOverflowCheckCall(Result,SubBin);
  9545. eopMultiply:
  9546. if (LeftResolved.BaseType in btAllJSOverflowMultType)
  9547. or (RightResolved.BaseType in btAllJSOverflowMultType) then
  9548. Result:=CreateOverflowCheckCall(Result,SubBin);
  9549. end;
  9550. if SubBin=El then exit;
  9551. end;
  9552. // next
  9553. A:=Result;
  9554. Result:=nil;
  9555. if aResolver<>nil then
  9556. LeftResolved:=ResultResolved;
  9557. Left:=SubBin;
  9558. until false;
  9559. finally
  9560. AContext.Access:=OldAccess;
  9561. if Result=nil then
  9562. begin
  9563. A.Free;
  9564. B.Free;
  9565. end;
  9566. end;
  9567. end;
  9568. function TPasToJSConverter.ConvertSubIdentExpression(El: TBinaryExpr;
  9569. AContext: TConvertContext): TJSElement;
  9570. // connect El.left and El.right with a dot.
  9571. var
  9572. RightRef: TResolvedReference;
  9573. RightEl: TPasExpr;
  9574. RightRefDecl: TPasElement;
  9575. aResolver: TPas2JSResolver;
  9576. begin
  9577. Result:=nil;
  9578. aResolver:=AContext.Resolver;
  9579. // Note: TPasParser guarantees that there is at most one TBinaryExpr
  9580. // and/or one TInlineSpecializeExpr between
  9581. // TParamsExpr and its NameExpr. E.g. a.b.c() = ((a.b).c)()
  9582. RightEl:=El.right;
  9583. if RightEl is TInlineSpecializeExpr then
  9584. RightEl:=TInlineSpecializeExpr(RightEl).NameExpr;
  9585. if (RightEl.ClassType<>TPrimitiveExpr) then
  9586. RaiseNotSupported(RightEl,AContext,20190131162250,'Left='+GetObjName(El.left)+' right='+GetObjName(RightEl));
  9587. if not (RightEl.CustomData is TResolvedReference) then
  9588. RaiseNotSupported(RightEl,AContext,20190131162301);
  9589. RightRef:=TResolvedReference(RightEl.CustomData);
  9590. RightRefDecl:=RightRef.Declaration;
  9591. if aResolver.IsTObjectFreeMethod(RightEl) then
  9592. begin
  9593. // e.g. Obj.Free;
  9594. Result:=ConvertTObjectFree_Bin(El,RightEl,AContext);
  9595. exit;
  9596. end
  9597. else if aResolver.IsExternalClassConstructor(RightRefDecl) then
  9598. begin
  9599. // e.g. mod.ExtClass.new;
  9600. if (El.Parent is TParamsExpr) and (TParamsExpr(El.Parent).Value=El) then
  9601. // Note: ExtClass.new() is handled in ConvertFuncParams
  9602. RaiseNotSupported(El,AContext,20190116135818);
  9603. Result:=ConvertExternalConstructor(El.left,RightRef,nil,AContext);
  9604. exit;
  9605. end;
  9606. Result:=ConvertSubIdentExprCustom(El,AContext);
  9607. end;
  9608. function TPasToJSConverter.ConvertSubIdentExprCustom(El: TBinaryExpr;
  9609. AContext: TConvertContext; const OnConvertRight: TConvertJSEvent;
  9610. Data: Pointer): TJSElement;
  9611. var
  9612. OldAccess: TCtxAccess;
  9613. LeftJS, RightJS: TJSElement;
  9614. DotContext: TDotContext;
  9615. aResolver: TPas2JSResolver;
  9616. LeftResolved: TPasResolverResult;
  9617. RightEl: TPasExpr;
  9618. RightRef: TResolvedReference;
  9619. RightRefDecl: TPasElement;
  9620. Proc: TPasProcedure;
  9621. begin
  9622. aResolver:=AContext.Resolver;
  9623. // Note: TPasParser guarantees that there is at most one TBinaryExpr
  9624. // and/or one TInlineSpecializeExpr between
  9625. // TParamsExpr and its NameExpr. E.g. a.b.c() = ((a.b).c)()
  9626. RightEl:=El.right;
  9627. if RightEl is TInlineSpecializeExpr then
  9628. RightEl:=TInlineSpecializeExpr(RightEl).NameExpr;
  9629. if (RightEl.ClassType<>TPrimitiveExpr) then
  9630. begin
  9631. {$IFDEF VerbosePas2JS}
  9632. writeln('TPasToJSConverter.ConvertSubIdentExprCustom Bin=',El.OpCode,' El.Right=',GetObjName(RightEl));
  9633. {$ENDIF}
  9634. RaiseNotSupported(RightEl,AContext,20190131164529);
  9635. end;
  9636. if not (RightEl.CustomData is TResolvedReference) then
  9637. RaiseNotSupported(RightEl,AContext,20190131164530);
  9638. RightRef:=TResolvedReference(RightEl.CustomData);
  9639. RightRefDecl:=RightRef.Declaration;
  9640. if RightRefDecl.ClassType=TPasProperty then
  9641. begin
  9642. // redirect to Getter/Setter
  9643. case AContext.Access of
  9644. caAssign:
  9645. begin
  9646. RightRefDecl:=aResolver.GetPasPropertySetter(TPasProperty(RightRefDecl));
  9647. if RightRefDecl=nil then
  9648. DoError(20190211111137,nNoMemberIsProvidedToAccessProperty,sNoMemberIsProvidedToAccessProperty,[],RightEl);
  9649. end;
  9650. caRead:
  9651. begin
  9652. RightRefDecl:=aResolver.GetPasPropertyGetter(TPasProperty(RightRefDecl));
  9653. if RightRefDecl=nil then
  9654. DoError(20190211111038,nNoMemberIsProvidedToAccessProperty,sNoMemberIsProvidedToAccessProperty,[],RightEl);
  9655. end;
  9656. end;
  9657. end
  9658. else if RightRefDecl.ClassType=TPasEnumValue then
  9659. begin
  9660. // enum value
  9661. Result:=ConvertIdentifierExpr(RightEl,'',aContext);
  9662. exit;
  9663. end;
  9664. if (AContext.Access=caAssign)
  9665. and aResolver.IsClassField(RightRefDecl) then
  9666. begin
  9667. // e.g. "Something.aClassVar:=" -> "aClass.aClassVar:="
  9668. LeftJS:=CreateReferencePathExpr(RightRefDecl.Parent,AContext);
  9669. Result:=CreateDotNameExpr(El,LeftJS,TJSString(TransformElToJSName(RightRefDecl,AContext)));
  9670. exit;
  9671. end;
  9672. if RightRefDecl is TPasProcedure then
  9673. begin
  9674. Proc:=TPasProcedure(RightRefDecl);
  9675. if not aResolver.ProcHasSelf(Proc) then
  9676. begin
  9677. // a.StaticProc -> pas.unit1.aclass.StaticProc(defaultargs)
  9678. // ToDo: check if left side has only types (no call nor field)
  9679. if Assigned(OnConvertRight) then
  9680. Result:=OnConvertRight(RightEl,AContext,Data)
  9681. else
  9682. Result:=ConvertIdentifierExpr(RightEl,TPrimitiveExpr(RightEl).Value,AContext);
  9683. exit;
  9684. end;
  9685. end;
  9686. LeftJS:=nil;
  9687. if aResolver.IsHelper(RightRefDecl.Parent) then
  9688. begin
  9689. // LeftJS.HelperMember
  9690. if (RightRefDecl is TPasVariable)
  9691. and not (vmExternal in TPasVariable(RightRefDecl).VarModifiers) then
  9692. begin
  9693. // LeftJS.HelperField -> HelperType.HelperField
  9694. if Assigned(OnConvertRight) then
  9695. Result:=OnConvertRight(RightEl,AContext,Data)
  9696. else
  9697. Result:=ConvertIdentifierExpr(RightEl,TPrimitiveExpr(RightEl).Value,AContext);
  9698. exit;
  9699. end
  9700. else if RightRefDecl is TPasProcedure then
  9701. begin
  9702. Proc:=TPasProcedure(RightRefDecl);
  9703. if Proc.IsExternal then
  9704. // normal call
  9705. else if rrfNoImplicitCallWithoutParams in RightRef.Flags then
  9706. begin
  9707. Result:=CreateReferencePathExpr(RightRefDecl,AContext);
  9708. exit;
  9709. end
  9710. else
  9711. begin
  9712. // call helper method
  9713. Result:=CreateCallHelperMethod(Proc,El,AContext);
  9714. exit;
  9715. end;
  9716. end
  9717. else
  9718. RaiseNotSupported(El,AContext,20190131170119,GetObjName(RightRefDecl));
  9719. end;
  9720. if LeftJS=nil then
  9721. begin
  9722. // check Left
  9723. if aResolver<>nil then
  9724. aResolver.ComputeElement(El.left,LeftResolved,[])
  9725. else
  9726. LeftResolved:=Default(TPasResolverResult);
  9727. if LeftResolved.BaseType=btModule then
  9728. begin
  9729. // e.g. system.inttostr()
  9730. // module path is created automatically
  9731. if Assigned(OnConvertRight) then
  9732. Result:=OnConvertRight(RightEl,AContext,Data)
  9733. else
  9734. Result:=ConvertIdentifierExpr(RightEl,TPrimitiveExpr(RightEl).Value,AContext);
  9735. exit;
  9736. end;
  9737. // convert LeftJS side
  9738. OldAccess:=AContext.Access;
  9739. AContext.Access:=caRead;
  9740. LeftJS:=ConvertExpression(El.left,AContext);
  9741. if LeftJS=nil then
  9742. RaiseNotSupported(El,AContext,20190116110446);
  9743. AContext.Access:=OldAccess;
  9744. end;
  9745. // convert RightJS side
  9746. DotContext:=TDotContext.Create(El,LeftJS,AContext);
  9747. RightJS:=nil;
  9748. try
  9749. DotContext.LeftResolved:=LeftResolved;
  9750. if Assigned(OnConvertRight) then
  9751. RightJS:=OnConvertRight(RightEl,DotContext,Data)
  9752. else
  9753. RightJS:=ConvertIdentifierExpr(RightEl,TPrimitiveExpr(RightEl).Value,DotContext);
  9754. if DotContext.JS<>nil then
  9755. begin
  9756. LeftJS:=nil;
  9757. RightJS:=nil;
  9758. exit(DotContext.JS);
  9759. end;
  9760. finally
  9761. if (RightJS=nil) and (DotContext.JSElement=LeftJS) then
  9762. LeftJS.Free;
  9763. DotContext.Free;
  9764. end;
  9765. if RightJS is TJSLiteral then
  9766. begin
  9767. LeftJS.Free;
  9768. exit(RightJS);
  9769. end;
  9770. // connect via dot
  9771. Result:=CreateDotExpression(El,LeftJS,RightJS,true);
  9772. end;
  9773. function TPasToJSConverter.CreateIdentifierExpr(El: TPasElement;
  9774. AContext: TConvertContext): TJSElement;
  9775. begin
  9776. Result:=CreatePrimitiveDotExpr(TransformElToJSName(El,AContext),El);
  9777. end;
  9778. function TPasToJSConverter.CreateIdentifierExpr(AName: string;
  9779. CheckGlobal: boolean; PosEl: TPasElement; AContext: TConvertContext
  9780. ): TJSElement;
  9781. // CheckGlobal: check name clashes with global identifiers too
  9782. begin
  9783. Result:=CreatePrimitiveDotExpr(TransformToJSName(PosEl,AName,CheckGlobal,AContext),PosEl);
  9784. end;
  9785. function TPasToJSConverter.CreateSubDeclJSNameExpr(El: TPasElement;
  9786. JSName: string; AContext: TConvertContext; PosEl: TPasElement): TJSElement;
  9787. var
  9788. C: TClass;
  9789. VarKinds: TCtxVarKinds;
  9790. ParentName: String;
  9791. begin
  9792. C:=El.ClassType;
  9793. if C.InheritsFrom(TPasType) or (C=TPasConst) then
  9794. VarKinds:=[cvkGlobal]
  9795. else if C.InheritsFrom(TPasVariable) then
  9796. begin
  9797. VarKinds:=[cvkCurType];
  9798. if ([vmClass, vmStatic]*TPasVariable(El).VarModifiers<>[]) then
  9799. VarKinds:=[cvkGlobal]
  9800. else if El.Parent is TPasMembersType then
  9801. VarKinds:=[cvkCurType]
  9802. else
  9803. VarKinds:=[cvkGlobal];
  9804. end
  9805. else if (El.Parent is TProcedureBody) then
  9806. VarKinds:=[]
  9807. else
  9808. VarKinds:=[cvkGlobal];
  9809. if VarKinds<>[] then
  9810. begin
  9811. ParentName:=GetLocalName(El.Parent,VarKinds,AContext);
  9812. if ParentName='' then
  9813. ParentName:='this';
  9814. if JSName[1]='[' then
  9815. JSName:=ParentName+JSName
  9816. else
  9817. JSName:=ParentName+'.'+JSName;
  9818. end;
  9819. Result:=CreatePrimitiveDotExpr(JSName,PosEl);
  9820. end;
  9821. function TPasToJSConverter.CreateSubDeclPasNameExpr(El: TPasElement;
  9822. const PasName: string; AContext: TConvertContext; PosEl: TPasElement
  9823. ): TJSElement;
  9824. var
  9825. JSName: String;
  9826. begin
  9827. JSName:=TransformToJSName(El,PasName,false,AContext);
  9828. Result:=CreateSubDeclJSNameExpr(El,JSName,AContext,PosEl);
  9829. end;
  9830. function TPasToJSConverter.CreateSubDeclNameExpr(El: TPasElement;
  9831. AContext: TConvertContext; PosEl: TPasElement): TJSElement;
  9832. var
  9833. JSName: String;
  9834. begin
  9835. JSName:=TransformElToJSName(El,AContext);
  9836. Result:=CreateSubDeclJSNameExpr(El,JSName,AContext,PosEl);
  9837. end;
  9838. function TPasToJSConverter.ConvertPrimitiveExpression(El: TPrimitiveExpr;
  9839. AContext: TConvertContext): TJSElement;
  9840. function DeleteLeadingZeroes(const s: string): string;
  9841. // Note: 01 is in JS octal, and in strict mode forbidden
  9842. // $00ff00 -> $ff00
  9843. // 00E001 -> 0E1
  9844. // 0.001 -> 0.001
  9845. // 0.00E1 -> 0.00E1
  9846. var
  9847. i: Integer;
  9848. begin
  9849. Result:=s;
  9850. i:=1;
  9851. if Result[1]='$' then
  9852. // hexadecimal -> can not be a float, 'E' is a hexdigit
  9853. while i<length(Result) do
  9854. begin
  9855. if (Result[i]='0') and (Result[i+1] in ['0'..'9','A'..'F','a'..'f'])
  9856. and ((i=1) or not (Result[i-1] in ['0'..'9','A'..'F','a'..'f'])) then
  9857. Delete(Result,i,1)
  9858. else
  9859. inc(i);
  9860. end
  9861. else
  9862. // decimal, can be a float, 'E' is a start of a new number
  9863. while i<length(Result) do
  9864. begin
  9865. if (Result[i]='0') and (Result[i+1] in ['0'..'9'])
  9866. and ((i=1) or not (Result[i-1] in ['.','0'..'9'])) then
  9867. Delete(Result,i,1)
  9868. else
  9869. inc(i);
  9870. end;
  9871. end;
  9872. Var
  9873. L : TJSLiteral;
  9874. Number : TJSNumber;
  9875. ConversionError , Code: Integer;
  9876. i: TMaxPrecInt;
  9877. S: String;
  9878. begin
  9879. {$IFDEF VerbosePas2JS}
  9880. str(El.Kind,S);
  9881. writeln('TPasToJSConverter.ConvertPrimitiveExpression El=',GetObjName(El),' Context=',GetObjName(AContext),' El.Kind=',S);
  9882. {$ENDIF}
  9883. Result:=Nil;
  9884. case El.Kind of
  9885. pekString:
  9886. begin
  9887. if AContext.Resolver<>nil then
  9888. Result:=CreateLiteralJSString(El,
  9889. AContext.Resolver.ExtractPasStringLiteral(El,El.Value))
  9890. else
  9891. begin
  9892. S:={$IFDEF pas2js}DeQuoteString{$ELSE}AnsiDequotedStr{$ENDIF}(El.Value,'''');
  9893. Result:=CreateLiteralString(El,S);
  9894. end;
  9895. //writeln('TPasToJSConverter.ConvertPrimitiveExpression Result="',TJSLiteral(Result).Value.AsString,'" ',GetObjName(AContext.Resolver));
  9896. end;
  9897. pekStringMultiLine:
  9898. begin
  9899. Result:=CreateLiteralJSString(El,StrToJSString(El.Value));
  9900. //writeln('TPasToJSConverter.ConvertPrimitiveExpression Result="',TJSLiteral(Result).Value.AsString,'" ',GetObjName(AContext.Resolver));
  9901. end;
  9902. pekNumber:
  9903. begin
  9904. case El.Value[1] of
  9905. '0'..'9':
  9906. begin
  9907. Val(El.Value,Number,ConversionError);
  9908. if ConversionError<>0 then
  9909. DoError(20161024191248,nInvalidNumber,sInvalidNumber,[El.Value],El);
  9910. L:=CreateLiteralNumber(El,Number);
  9911. L.Value.CustomValue:=TJSString(DeleteLeadingZeroes(El.Value));
  9912. end;
  9913. '$','&','%':
  9914. begin
  9915. val(El.Value,i,Code);
  9916. if Code<>0 then
  9917. DoError(20161024224442,nInvalidNumber,sInvalidNumber,[El.Value],El);
  9918. Number:=i;
  9919. if Number<>i then
  9920. // number was rounded -> we lost precision
  9921. DoError(20161024230812,nInvalidNumber,sInvalidNumber,[El.Value],El);
  9922. L:=CreateLiteralNumber(El,Number);
  9923. S:=DeleteLeadingZeroes(El.Value);
  9924. S:=copy(S,2,length(S));
  9925. case El.Value[1] of
  9926. '$': S:='0x'+S;
  9927. '&': if FGlobals.TargetProcessor=ProcessorECMAScript5 then
  9928. S:='' // in strict mode 01 is forbidden
  9929. else
  9930. S:='0o'+S;
  9931. '%': if FGlobals.TargetProcessor=ProcessorECMAScript5 then
  9932. S:='' // use decimal
  9933. else
  9934. S:='0b'+S;
  9935. end;
  9936. L.Value.CustomValue:=TJSString(S);
  9937. end;
  9938. else
  9939. DoError(20161024223232,nInvalidNumber,sInvalidNumber,[El.Value],El);
  9940. end;
  9941. Result:=L;
  9942. end;
  9943. pekIdent:
  9944. Result:=ConvertIdentifierExpr(El,El.Value,AContext);
  9945. else
  9946. RaiseNotSupported(El,AContext,20161024222543);
  9947. end;
  9948. end;
  9949. function TPasToJSConverter.ConvertIdentifierExpr(El: TPasExpr;
  9950. const aName: string; AContext: TConvertContext): TJSElement;
  9951. var
  9952. AssignContext: TAssignContext;
  9953. ApplyParam: TJSElement;
  9954. procedure CallImplicit(Decl: TPasElement);
  9955. var
  9956. ProcType: TPasProcedureType;
  9957. ResolvedEl: TPasResolverResult;
  9958. Call: TJSCallExpression;
  9959. NeedIntfRef: Boolean;
  9960. begin
  9961. // create a call with default parameters
  9962. ProcType:=nil;
  9963. if Decl is TPasProcedure then
  9964. ProcType:=TPasProcedure(Decl).ProcType
  9965. else
  9966. begin
  9967. AContext.Resolver.ComputeElement(El,ResolvedEl,[rcNoImplicitProc]);
  9968. if ResolvedEl.LoTypeEl is TPasProcedureType then
  9969. ProcType:=TPasProcedureType(ResolvedEl.LoTypeEl)
  9970. else
  9971. RaiseNotSupported(El,AContext,20170217005025);
  9972. end;
  9973. NeedIntfRef:=false;
  9974. if (ProcType is TPasFunctionType)
  9975. and not ProcType.IsAsync
  9976. and AContext.Resolver.IsManagedJSType(
  9977. TPasFunctionType(ProcType).ResultEl.ResultType)
  9978. then
  9979. NeedIntfRef:=true;
  9980. Call:=nil;
  9981. try
  9982. CreateProcedureCall(Call,nil,ProcType,AContext);
  9983. if ApplyParam<>nil then
  9984. begin
  9985. if Call.Args=nil then
  9986. Call.Args:=TJSArguments(CreateElement(TJSArguments,ProcType));
  9987. Call.InsertArg(0,ApplyParam);
  9988. ApplyParam:=nil;
  9989. if AContext is TDotContext then
  9990. TDotContext(AContext).JS:=Call;
  9991. end;
  9992. Call.Expr:=Result;
  9993. if NeedIntfRef then
  9994. // $ir.ref(id,fnname())
  9995. Call:=CreateIntfRef(Call,AContext,El);
  9996. Result:=Call;
  9997. finally
  9998. if Result<>Call then
  9999. begin
  10000. Call.Free;
  10001. ApplyParam.Free;
  10002. end;
  10003. end;
  10004. end;
  10005. function CreateShortRefImplictCall_Apply(TargetProc: TPasProcedure;
  10006. Ref: TResolvedReference): string;
  10007. var
  10008. ApplyPath: String;
  10009. begin
  10010. // ProcName; -> "$lp.apply(this,args);" or "$lp.apply($with,args);"
  10011. Result:=CreateStaticProcPath(TargetProc,AContext)+'.apply';
  10012. ApplyPath:=CreateReferencePath(TargetProc,AContext,rpkPath,false,Ref);
  10013. if AContext is TDotContext then
  10014. begin
  10015. ApplyParam:=AContext.JSElement;
  10016. AContext.JSElement:=nil;
  10017. if ApplyPath<>'' then
  10018. // e.g. "$class"
  10019. ApplyParam:=CreateDotNameExpr(El,ApplyParam,TJSString(ApplyPath));
  10020. end
  10021. else
  10022. begin
  10023. if ApplyPath='' then
  10024. RaiseNotSupported(El,AContext,20201101022637);
  10025. ApplyParam:=CreatePrimitiveDotExpr(ApplyPath,El);
  10026. end;
  10027. if ApplyParam=nil then
  10028. RaiseNotSupported(El,AContext,20201101021136);
  10029. end;
  10030. procedure CallTypeSetter;
  10031. var
  10032. Call: TJSCallExpression;
  10033. begin
  10034. if AssignContext<>nil then
  10035. begin
  10036. if AssignContext.LeftResolved.LoTypeEl is TPasRecordType then
  10037. begin
  10038. // aRecord:=right -> aRecord.$assign(right)
  10039. Call:=CreateCallExpression(El);
  10040. AssignContext.Call:=Call;
  10041. Call.Expr:=CreateDotNameExpr(El,Result,TJSString(GetBIName(pbifnRecordAssign)));
  10042. Call.AddArg(AssignContext.RightSide);
  10043. AssignContext.RightSide:=nil;
  10044. Result:=Call;
  10045. end;
  10046. end;
  10047. end;
  10048. var
  10049. Decl: TPasElement;
  10050. Name: String;
  10051. Ref: TResolvedReference;
  10052. Call: TJSCallExpression;
  10053. BuiltInProc: TResElDataBuiltInProc;
  10054. Prop: TPasProperty;
  10055. IsImplicitCall: Boolean;
  10056. TargetProcType: TPasProcedureType;
  10057. ArrLit: TJSArrayLiteral;
  10058. FuncScope: TPas2JSProcedureScope;
  10059. Value: TResEvalValue;
  10060. aResolver: TPas2JSResolver;
  10061. BracketExpr: TJSBracketMemberExpression;
  10062. PathExpr: TJSElement;
  10063. Proc: TPasProcedure;
  10064. begin
  10065. Result:=nil;
  10066. if not (El.CustomData is TResolvedReference) then
  10067. begin
  10068. if AContext.Resolver<>nil then
  10069. RaiseIdentifierNotFound(aName,El,20161024191306)
  10070. else
  10071. // simple mode
  10072. Result:=CreateIdentifierExpr(aName,true,El,AContext);
  10073. exit;
  10074. end;
  10075. aResolver:=AContext.Resolver;
  10076. Ref:=TResolvedReference(El.CustomData);
  10077. Decl:=Ref.Declaration;
  10078. if aResolver.IsExternalClassConstructor(Decl) then
  10079. begin
  10080. // create external object/function
  10081. Result:=ConvertExternalConstructor(nil,Ref,nil,AContext);
  10082. exit;
  10083. end;
  10084. if aResolver.IsExternalBracketAccessor(Decl) then
  10085. DoError(20180511154132,nCantCallExtBracketAccessor,sCantCallExtBracketAccessor,[],El);
  10086. if [rrfNewInstance,rrfFreeInstance]*Ref.Flags<>[] then
  10087. begin
  10088. Call:=CreateFreeOrNewInstanceExpr(Ref,AContext);
  10089. Result:=Call;
  10090. TargetProcType:=TPasProcedure(Decl).ProcType;
  10091. if TargetProcType.Args.Count>0 then
  10092. begin
  10093. // add default parameters:
  10094. if Decl.Parent.ClassType=TPasRecordType then
  10095. // insert default parameters, e.g. TRecord.$new().create(1,2,3)
  10096. CreateProcedureCallArgs(Call.Args.Elements,nil,TargetProcType,AContext)
  10097. else
  10098. begin
  10099. // insert array parameter [], e.g. TObject.$create("create",[])
  10100. ArrLit:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,El));
  10101. CreateProcedureCallArgs(ArrLit.Elements,nil,TargetProcType,AContext);
  10102. Call.AddArg(ArrLit);
  10103. end;
  10104. end;
  10105. exit;
  10106. end;
  10107. if (Ref.WithExprScope<>nil) and aResolver.IsTObjectFreeMethod(El) then
  10108. begin
  10109. Result:=ConvertTObjectFree_With(El,AContext);
  10110. exit;
  10111. end;
  10112. Prop:=nil;
  10113. AssignContext:=nil;
  10114. ApplyParam:=nil;
  10115. IsImplicitCall:=rrfImplicitCallWithoutParams in Ref.Flags;
  10116. if AContext.Access=caAssign then
  10117. AssignContext:=AContext.AccessContext as TAssignContext;
  10118. if Decl.ClassType=TPasArgument then
  10119. begin
  10120. Result:=CreateArgumentAccess(TPasArgument(Decl),AContext,El);
  10121. if IsImplicitCall then
  10122. CallImplicit(Decl);
  10123. exit;
  10124. end;
  10125. if Decl.ClassType=TPasProperty then
  10126. begin
  10127. // Decl is a property -> redirect to getter/setter
  10128. Prop:=TPasProperty(Decl);
  10129. case AContext.Access of
  10130. caAssign:
  10131. begin
  10132. if AssignContext.Call<>nil then
  10133. RaiseNotSupported(El,AContext,20170206000310);
  10134. Decl:=aResolver.GetPasPropertySetter(Prop);
  10135. if Decl is TPasProcedure then
  10136. begin
  10137. if aResolver.IsHelperMethod(Decl) then
  10138. begin
  10139. Result:=CreateCallHelperMethod(TPasProcedure(Decl),El,AContext);
  10140. exit;
  10141. end;
  10142. // Setter
  10143. Call:=CreateCallExpression(El);
  10144. Call.Expr:=CreateReferencePathExpr(Decl,AContext,false,Ref);
  10145. Result:=AppendPropertyAssignArgs(Call,Prop,AssignContext,El);
  10146. exit;
  10147. end;
  10148. end;
  10149. caRead:
  10150. begin
  10151. Result:=CreatePropertyGet(Prop,El,AContext,El);
  10152. if Result is TJSCallExpression then exit;
  10153. if not IsImplicitCall then exit;
  10154. end;
  10155. else
  10156. RaiseNotSupported(El,AContext,20170213212623);
  10157. end;
  10158. end; // property redirect
  10159. if aResolver.IsClassField(Decl)
  10160. and (AContext.Access in [caAssign,caByReference]) then
  10161. begin
  10162. // writing a class var -> aClass.VarName
  10163. PathExpr:=CreateReferencePathExpr(Decl.Parent,AContext);
  10164. Result:=CreateDotNameExpr(El,PathExpr,TJSString(TransformElToJSName(Decl,AContext)));
  10165. CallTypeSetter;
  10166. exit;
  10167. end
  10168. else if Decl.ClassType=TPasConst then
  10169. begin
  10170. if TPasConst(Decl).IsConst and (TPasConst(Decl).Expr<>nil) then
  10171. begin
  10172. // const with expression
  10173. Value:=aResolver.Eval(TPasConst(Decl).Expr,[refConst]);
  10174. if Value<>nil then
  10175. try
  10176. if Value.Kind in [revkNil,revkBool,revkInt,revkUInt,revkFloat,revkEnum] then
  10177. begin
  10178. Result:=ConvertConstValue(Value,AContext,El);
  10179. exit;
  10180. end;
  10181. finally
  10182. ReleaseEvalValue(Value);
  10183. end;
  10184. if vmExternal in TPasConst(Decl).VarModifiers then
  10185. begin
  10186. // external constant with expression is always added by value, not by reference
  10187. Result:=ConvertExpression(TPasConst(Decl).Expr,AContext);
  10188. CallTypeSetter;
  10189. exit;
  10190. end;
  10191. end;
  10192. end
  10193. else if Decl.ClassType=TPasResString then
  10194. begin
  10195. // read resourcestring -> rtl.getResStr(pas.modulename,"name")
  10196. Call:=CreateCallExpression(El);
  10197. Result:=Call;
  10198. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnGetResourcestring)]);
  10199. Call.AddArg(CreatePrimitiveDotExpr(TransformModuleName(Decl.GetModule,true,AContext),El));
  10200. Call.AddArg(CreateLiteralString(El,TransformElToJSName(Decl,AContext)));
  10201. exit;
  10202. end
  10203. else if aResolver.IsHelperMethod(Decl)
  10204. and not (rrfNoImplicitCallWithoutParams in Ref.Flags) then
  10205. begin
  10206. Result:=CreateCallHelperMethod(TPasProcedure(Decl),El,AContext);
  10207. exit;
  10208. end
  10209. else if Decl.CustomData is TResElDataBuiltInProc then
  10210. begin
  10211. BuiltInProc:=TResElDataBuiltInProc(Decl.CustomData);
  10212. {$IFDEF VerbosePas2JS}
  10213. writeln('TPasToJSConverter.ConvertIdentifierExpr ',Decl.Name,' ',ResolverBuiltInProcNames[BuiltInProc.BuiltIn]);
  10214. {$ENDIF}
  10215. case BuiltInProc.BuiltIn of
  10216. bfBreak: Result:=ConvertBuiltInBreak(El,AContext);
  10217. bfContinue: Result:=ConvertBuiltInContinue(El,AContext);
  10218. bfExit: Result:=ConvertBuiltIn_Exit(El,AContext);
  10219. bfCustom:
  10220. case BuiltInProc.Element.Name of
  10221. 'Debugger': Result:=ConvertBuiltIn_Debugger(El,AContext);
  10222. else
  10223. RaiseNotSupported(El,AContext,20181126102554,'built in custom proc '+BuiltInProc.Element.Name);
  10224. end
  10225. else
  10226. RaiseNotSupported(El,AContext,20161130164955,'built in proc '+ResolverBuiltInProcNames[BuiltInProc.BuiltIn]);
  10227. end;
  10228. if Result=nil then
  10229. RaiseInconsistency(20170214120048,Decl);
  10230. exit;
  10231. end;
  10232. {$IFDEF VerbosePas2JS}
  10233. writeln('TPasToJSConverter.ConvertIdentifierExpr ',GetObjName(El),' Decl=',GetObjName(Decl),' Decl.Parent=',GetObjName(Decl.Parent));
  10234. //if CompareText(aName,'Self')=0 then
  10235. // begin
  10236. // writeln('TPasToJSConverter.ConvertIdentifierExpr AContext=',GetObjName(AContext),' SelfContext=',GetObjName(AContext.GetSelfContext),' LocalVar=',AContext.GetLocalName(Decl),' ',GetObjName(Decl));
  10237. // AContext.WriteStack;
  10238. // end;
  10239. {$ENDIF}
  10240. try
  10241. if Decl is TPasModule then
  10242. Name:=TransformModuleName(TPasModule(Decl),true,AContext)
  10243. else if (Decl is TPasResultElement) then
  10244. begin
  10245. Name:=ResolverResultVar;
  10246. Proc:=Decl.Parent.Parent as TPasProcedure;
  10247. FuncScope:=Proc.CustomData as TPas2JSProcedureScope;
  10248. if FuncScope.ImplProc<>nil then
  10249. FuncScope:=FuncScope.ImplProc.CustomData as TPas2JSProcedureScope;
  10250. if FuncScope.ResultVarName<>'' then
  10251. Name:=FuncScope.ResultVarName;
  10252. end
  10253. else if Decl.ClassType=TPasEnumValue then
  10254. begin
  10255. if UseEnumNumbers then
  10256. begin
  10257. Result:=CreateLiteralNumber(El,(Decl.Parent as TPasEnumType).Values.IndexOf(Decl));
  10258. exit;
  10259. end
  10260. else
  10261. begin
  10262. // enums always need the full path
  10263. Name:=CreateReferencePath(Decl,AContext,rpkPathAndName,true);
  10264. end;
  10265. end
  10266. else if Decl.ClassType=TPasArgument then
  10267. Name:=TransformArgName(TPasArgument(Decl),AContext)
  10268. else if Decl is TPasProcedure then
  10269. begin
  10270. Proc:=TPasProcedure(Decl);
  10271. if (coShortRefGlobals in Options)
  10272. and aResolver.IsSpecializedNonStaticMethod(Proc.ProcType) then
  10273. Name:=CreateShortRefImplictCall_Apply(Proc,Ref)
  10274. else
  10275. Name:=CreateReferencePath(Decl,AContext,rpkPathAndName,false,Ref);
  10276. end
  10277. else
  10278. Name:=CreateReferencePath(Decl,AContext,rpkPathAndName,false,Ref);
  10279. if Name='' then
  10280. RaiseNotSupported(El,AContext,20180509134804,GetObjName(Decl));
  10281. if Result=nil then
  10282. begin
  10283. if (Name[1]='[') and (Name[length(Name)]=']')
  10284. and (AContext is TDotContext)
  10285. and (AContext.JSElement<>nil) then
  10286. begin
  10287. // e.g. Obj.A with A having an external name '["name"]';
  10288. // -> Obj["name"]
  10289. if IsImplicitCall then
  10290. RaiseNotSupported(El,AContext,20180509134951,Name);
  10291. BracketExpr:=TJSBracketMemberExpression(CreateElement(TJSBracketMemberExpression,El));
  10292. TDotContext(AContext).JS:=BracketExpr;
  10293. BracketExpr.MExpr:=AContext.JSElement;
  10294. Result:=CreateLiteralCustomValue(El,TJSString(copy(Name,2,length(Name)-2)));
  10295. BracketExpr.Name:=Result;
  10296. exit;
  10297. end;
  10298. Result:=CreatePrimitiveDotExpr(Name,El);
  10299. end;
  10300. if IsImplicitCall then
  10301. CallImplicit(Decl);
  10302. CallTypeSetter;
  10303. finally
  10304. ApplyParam.Free;
  10305. end;
  10306. end;
  10307. function TPasToJSConverter.ConvertBoolConstExpression(El: TBoolConstExpr;
  10308. AContext: TConvertContext): TJSElement;
  10309. begin
  10310. if AContext=nil then ;
  10311. Result:=CreateLiteralBoolean(El,El.Value);
  10312. end;
  10313. function TPasToJSConverter.ConvertNilExpr(El: TNilExpr;
  10314. AContext: TConvertContext): TJSElement;
  10315. begin
  10316. if AContext=nil then ;
  10317. Result:=CreateLiteralNull(El);
  10318. end;
  10319. function TPasToJSConverter.ConvertCharToInt(Arg: TJSElement;
  10320. PosEl: TPasElement; ArgContext: TConvertContext): TJSElement;
  10321. begin
  10322. if (Arg is TJSLiteral) and (TJSLiteral(Arg).Value.ValueType=jstString) then
  10323. begin
  10324. // convert char literal to int
  10325. ConvertCharLiteralToInt(TJSLiteral(Arg),PosEl,ArgContext);
  10326. Result:=Arg;
  10327. end
  10328. else
  10329. begin
  10330. // convert char to int -> Arg.charCodeAt(0)
  10331. Result:=CreateCallCharCodeAt(Arg,0,PosEl);
  10332. end;
  10333. end;
  10334. function TPasToJSConverter.ConvertIntToInt(Arg: TJSElement; FromBT,
  10335. ToBT: TResolverBaseType; PosEl: TPasElement; ArgContext: TConvertContext
  10336. ): TJSElement;
  10337. var
  10338. aResolver: TPas2JSResolver;
  10339. MinVal, MaxVal: TMaxPrecInt;
  10340. Call: TJSCallExpression;
  10341. ShiftEx: TJSURShiftExpression;
  10342. begin
  10343. Result:=Arg;
  10344. aResolver:=ArgContext.Resolver;
  10345. if FromBT=btCurrency then
  10346. begin
  10347. if ToBT<>btCurrency then
  10348. // currency to integer -> rtl.trunc(value/10000)
  10349. Result:=CreateTruncFloor(PosEl,CreateDivideNumber(PosEl,Result,10000),true);
  10350. end
  10351. else if ToBT=btCurrency then
  10352. // integer to currency -> value*10000
  10353. Result:=CreateMulNumber(PosEl,Result,10000);
  10354. if (ToBT<>btIntDouble) and not (Result is TJSLiteral) then
  10355. begin
  10356. if bsRangeChecks in ArgContext.ScannerBoolSwitches then
  10357. begin
  10358. // rtl.rc(param,MinInt,MaxInt)
  10359. if not aResolver.GetIntegerRange(ToBT,MinVal,MaxVal) then
  10360. RaiseNotSupported(PosEl,ArgContext,20180425131839);
  10361. Call:=CreateCallExpression(PosEl);
  10362. Call.Expr:=CreatePrimitiveDotExpr(GetBIName(pbivnRTL)+'.'+GetBIName(pbifnRangeCheckInt),PosEl);
  10363. Call.AddArg(Result);
  10364. Result:=Call;
  10365. Call.AddArg(CreateLiteralNumber(PosEl,MinVal));
  10366. Call.AddArg(CreateLiteralNumber(PosEl,MaxVal));
  10367. end
  10368. else
  10369. case ToBT of
  10370. btByte:
  10371. // value to byte -> value & 255
  10372. if FromBT<>btByte then
  10373. Result:=CreateBitWiseAnd(PosEl,Result,255,0);
  10374. btShortInt:
  10375. // value to shortint -> value & 255 << 24 >> 24
  10376. if FromBT<>btShortInt then
  10377. Result:=CreateBitWiseAnd(PosEl,Result,255,24);
  10378. btWord:
  10379. // value to word -> value & 65535
  10380. if not (FromBT in [btByte,btWord]) then
  10381. Result:=CreateBitWiseAnd(PosEl,Result,65535,0);
  10382. btSmallInt:
  10383. // value to smallint -> value & 65535 << 16 >> 16
  10384. if not (FromBT in [btShortInt,btSmallInt]) then
  10385. Result:=CreateBitWiseAnd(PosEl,Result,65535,16);
  10386. btLongWord:
  10387. // value to longword -> value >>> 0
  10388. if not (FromBT in [btByte,btWord,btLongWord,btUIntSingle]) then
  10389. begin
  10390. ShiftEx:=TJSURShiftExpression(CreateElement(TJSURShiftExpression,PosEl));
  10391. ShiftEx.A:=Result;
  10392. ShiftEx.B:=CreateLiteralNumber(PosEl,0);
  10393. Result:=ShiftEx;
  10394. end;
  10395. btLongint:
  10396. // value to longint -> value & 0xffffffff
  10397. if not (FromBT in [btShortInt,btSmallInt,btLongint,btIntSingle]) then
  10398. Result:=CreateBitWiseAnd(PosEl,Result,$ffffffff,0);
  10399. end;
  10400. end;
  10401. end;
  10402. function TPasToJSConverter.CreateBitWiseAnd(El: TPasElement; Value: TJSElement;
  10403. const Mask: TMaxPrecInt; Shift: integer): TJSElement;
  10404. // if sign=false: Value & Mask
  10405. // if sign=true: Value & Mask << ZeroBits >> ZeroBits
  10406. var
  10407. AndEx: TJSBitwiseAndExpression;
  10408. Hex: String;
  10409. i: Integer;
  10410. ShiftEx: TJSShiftExpression;
  10411. begin
  10412. AndEx:=TJSBitwiseAndExpression(CreateElement(TJSBitwiseAndExpression,El));
  10413. Result:=AndEx;
  10414. AndEx.A:=Value;
  10415. AndEx.B:=CreateLiteralNumber(El,Mask);
  10416. if Mask>999999 then
  10417. begin
  10418. Hex:=HexStr(Mask,8);
  10419. i:=1;
  10420. while i<8 do
  10421. if Hex[i]='0' then
  10422. inc(i)
  10423. else
  10424. break;
  10425. Hex:=Copy(Hex,i,8);
  10426. TJSLiteral(AndEx.B).Value.CustomValue:=TJSString('0x'+Hex);
  10427. end;
  10428. if Shift>0 then
  10429. begin
  10430. // value << ZeroBits
  10431. ShiftEx:=TJSLShiftExpression(CreateElement(TJSLShiftExpression,El));
  10432. ShiftEx.A:=Result;
  10433. Result:=ShiftEx;
  10434. ShiftEx.B:=CreateLiteralNumber(El,Shift);
  10435. // value << ZeroBits >> ZeroBits
  10436. ShiftEx:=TJSRShiftExpression(CreateElement(TJSRShiftExpression,El));
  10437. ShiftEx.A:=Result;
  10438. Result:=ShiftEx;
  10439. ShiftEx.B:=CreateLiteralNumber(El,Shift);
  10440. end;
  10441. end;
  10442. function TPasToJSConverter.CreateBitWiseLongword(El: TPasElement;
  10443. Value: TJSElement): TJSElement;
  10444. var
  10445. Call: TJSCallExpression;
  10446. begin
  10447. Call:=CreateCallExpression(El);
  10448. Call.Expr:=CreatePrimitiveDotExpr(GetBIName(pbivnRTL)+'.'+GetBIName(pbifnBitwiseLongwordFix),El);
  10449. Call.AddArg(Value);
  10450. Result:=Call;
  10451. end;
  10452. function TPasToJSConverter.ConvertInheritedExpr(El: TInheritedExpr;
  10453. AContext: TConvertContext): TJSElement;
  10454. function CreateAncestorCall(ParentEl: TPasElement; Apply: boolean;
  10455. AncestorProc: TPasProcedure; ParamsExpr: TParamsExpr): TJSElement;
  10456. var
  10457. FunName, SelfName: String;
  10458. Call: TJSCallExpression;
  10459. SelfContext: TFunctionContext;
  10460. ClassScope, AncestorScope: TPasClassScope;
  10461. AncestorClass, aClass: TPasClassType;
  10462. begin
  10463. Result:=nil;
  10464. SelfContext:=AContext.GetSelfContext;
  10465. if SelfContext=nil then
  10466. RaiseInconsistency(20170418114702,El);
  10467. SelfName:=GetLocalName(SelfContext.ThisVar.Element,[cvkCurType,cvkInstance],AContext);
  10468. if Apply and (SelfContext<>AContext) then
  10469. DoError(20170418204325,nNestedInheritedNeedsParameters,sNestedInheritedNeedsParameters,
  10470. [],El);
  10471. Call:=nil;
  10472. try
  10473. Call:=CreateCallExpression(ParentEl);
  10474. if (AncestorProc.Parent is TPasClassType)
  10475. and TPasClassType(AncestorProc.Parent).IsExternal then
  10476. begin
  10477. // ancestor is in an external class
  10478. // They could be overriden, without a Pascal declaration
  10479. // -> use the direct ancestor class of the current proc
  10480. aClass:=SelfContext.ThisVar.Element as TPasClassType;
  10481. if aClass.CustomData=nil then
  10482. RaiseInconsistency(20170323111252,aClass);
  10483. ClassScope:=TPasClassScope(aClass.CustomData);
  10484. AncestorScope:=ClassScope.AncestorScope;
  10485. if AncestorScope=nil then
  10486. RaiseInconsistency(20170323111306,aClass);
  10487. AncestorClass:=AncestorScope.Element as TPasClassType;
  10488. if (AncestorProc.ClassType=TPasConstructor) and SameText(AncestorProc.Name,'new')
  10489. and AContext.Resolver.IsExternalClass_Name(TPasClassType(AncestorProc.Parent),'Function') then
  10490. begin
  10491. // calling ancestor new constructor
  10492. // this.$func(param1,param2,...)
  10493. FunName:='this.'+GetBIName(pbifnClassAncestorFunc);
  10494. Call.Expr:=CreatePrimitiveDotExpr(FunName,ParentEl);
  10495. CreateProcedureCall(Call,ParamsExpr,AncestorProc.ProcType,AContext);
  10496. Result:=Call;
  10497. exit;
  10498. end
  10499. else
  10500. FunName:=CreateReferencePath(AncestorClass,AContext,rpkPathAndName,true)
  10501. +'.'+TransformElToJSName(AncestorProc,AContext);
  10502. end
  10503. else
  10504. FunName:=CreateReferencePath(AncestorProc,AContext,rpkPathAndName,true);
  10505. if AncestorProc.ProcType.Args.Count=0 then
  10506. Apply:=false;
  10507. if Apply and (SelfContext=AContext) then
  10508. // create "ancestor.funcname.apply(this,arguments)"
  10509. FunName:=FunName+'.apply'
  10510. else
  10511. // create "ancestor.funcname.call(this,param1,param2,...)"
  10512. FunName:=FunName+'.call';
  10513. Call.Expr:=CreatePrimitiveDotExpr(FunName,ParentEl);
  10514. Call.AddArg(CreatePrimitiveDotExpr(SelfName,ParentEl));
  10515. if Apply then
  10516. // "inherited;" -> pass the arguments
  10517. Call.AddArg(CreatePrimitiveDotExpr('arguments',ParentEl))
  10518. else
  10519. // "inherited Name(...)" -> pass the user arguments
  10520. CreateProcedureCall(Call,ParamsExpr,AncestorProc.ProcType,AContext);
  10521. if (AncestorProc is TPasFunction)
  10522. and not AncestorProc.IsAsync
  10523. and AContext.Resolver.IsManagedJSType(
  10524. TPasFunction(AncestorProc).FuncType.ResultEl.ResultType) then
  10525. Call:=CreateIntfRef(Call,AContext,El);
  10526. Result:=Call;
  10527. finally
  10528. if Result=nil then
  10529. Call.Free;
  10530. end;
  10531. end;
  10532. var
  10533. Right: TPasExpr;
  10534. Ref: TResolvedReference;
  10535. PrimExpr: TPrimitiveExpr;
  10536. AncestorProc: TPasProcedure;
  10537. ParamsExpr: TParamsExpr;
  10538. begin
  10539. Result:=nil;
  10540. if (El.Parent is TBinaryExpr) and (TBinaryExpr(El.Parent).OpCode=eopNone)
  10541. and (TBinaryExpr(El.Parent).left=El) then
  10542. begin
  10543. // "inherited <name>"
  10544. AncestorProc:=nil;
  10545. ParamsExpr:=nil;
  10546. Right:=TBinaryExpr(El.Parent).right;
  10547. if Right.ClassType=TPrimitiveExpr then
  10548. begin
  10549. PrimExpr:=TPrimitiveExpr(Right);
  10550. Ref:=PrimExpr.CustomData as TResolvedReference;
  10551. if rrfImplicitCallWithoutParams in Ref.Flags then
  10552. begin
  10553. // inherited <function>
  10554. // -> create "AncestorProc.call(this,defaultargs)"
  10555. AncestorProc:=Ref.Declaration as TPasProcedure;
  10556. end
  10557. else
  10558. begin
  10559. // inherited <varname>
  10560. // all variables have unique names -> simply access it
  10561. Result:=ConvertPrimitiveExpression(PrimExpr,AContext);
  10562. exit;
  10563. end;
  10564. end
  10565. else if Right.ClassType=TParamsExpr then
  10566. begin
  10567. ParamsExpr:=TParamsExpr(Right);
  10568. if ParamsExpr.Kind=pekFuncParams then
  10569. begin
  10570. if ParamsExpr.Value is TPrimitiveExpr then
  10571. begin
  10572. // inherited <function>(args)
  10573. // -> create "AncestorProc.call(this,args,defaultargs)"
  10574. PrimExpr:=TPrimitiveExpr(ParamsExpr.Value);
  10575. Ref:=PrimExpr.CustomData as TResolvedReference;
  10576. AncestorProc:=Ref.Declaration as TPasProcedure;
  10577. end
  10578. else
  10579. DoError(20170418205802,nXExpectedButYFound,sXExpectedButYFound,
  10580. ['inherited name()',ParamsExpr.Value.ElementTypeName],ParamsExpr.Value);
  10581. end
  10582. else
  10583. begin
  10584. // inherited <varname>[]
  10585. // all variables have unique names -> simply access it
  10586. Result:=ConvertExpression(Right,AContext);
  10587. exit;
  10588. end;
  10589. end
  10590. else
  10591. begin
  10592. {$IFDEF VerbosePas2JS}
  10593. writeln('TPasToJSConverter.ConvertInheritedExpression Parent=',GetTreeDbg(El.Parent,2));
  10594. {$ENDIF}
  10595. DoError(20170418205955,nXExpectedButYFound,sXExpectedButYFound,
  10596. ['inherited name()',Right.ElementTypeName],Right);
  10597. end;
  10598. if AncestorProc=nil then
  10599. begin
  10600. {$IFDEF VerbosePas2JS}
  10601. writeln('TPasToJSConverter.ConvertInheritedExpression Right=',GetObjName(Right));
  10602. {$ENDIF}
  10603. RaiseNotSupported(El,AContext,20170201190824);
  10604. end;
  10605. //writeln('TPasToJSConverter.ConvertInheritedExpression Func=',GetObjName(FuncContext.PasElement));
  10606. Result:=CreateAncestorCall(Right,false,AncestorProc,ParamsExpr);
  10607. end
  10608. else
  10609. begin
  10610. // "inherited;"
  10611. if El.CustomData=nil then
  10612. exit; // "inherited;" when there is no AncestorProc proc -> silently ignore
  10613. // create "AncestorProc.apply(this,arguments)"
  10614. Ref:=TResolvedReference(El.CustomData);
  10615. AncestorProc:=Ref.Declaration as TPasProcedure;
  10616. Result:=CreateAncestorCall(El,true,AncestorProc,nil);
  10617. end;
  10618. end;
  10619. function TPasToJSConverter.ConvertSelfExpression(El: TSelfExpr;
  10620. AContext: TConvertContext): TJSElement;
  10621. begin
  10622. Result:=ConvertIdentifierExpr(El,'Self',AContext);
  10623. end;
  10624. function TPasToJSConverter.ConvertParamsExpr(El: TParamsExpr;
  10625. AContext: TConvertContext): TJSElement;
  10626. begin
  10627. Result:=Nil;
  10628. {$IFDEF VerbosePas2JS}
  10629. writeln('TPasToJSConverter.ConvertParamsExpression ',GetObjName(El),' El.Kind=',ExprKindNames[El.Kind]);
  10630. {$ENDIF}
  10631. Case El.Kind of
  10632. pekFuncParams:
  10633. Result:=ConvertFuncParams(El,AContext);
  10634. pekArrayParams:
  10635. Result:=ConvertArrayParams(El,AContext);
  10636. pekSet:
  10637. Result:=ConvertArrayOrSetLiteral(El,AContext);
  10638. else
  10639. RaiseNotSupported(El,AContext,20170209103235,ExprKindNames[El.Kind]);
  10640. end;
  10641. end;
  10642. function TPasToJSConverter.ConvertArrayParams(El: TParamsExpr;
  10643. AContext: TConvertContext): TJSElement;
  10644. var
  10645. ArgContext: TConvertContext;
  10646. procedure RaiseIllegalBrackets(id: TMaxPrecInt; const ResolvedEl: TPasResolverResult);
  10647. begin
  10648. DoError(id,nIllegalQualifierAfter,sIllegalQualifierAfter,
  10649. ['[',AContext.Resolver.GetResolverResultDescription(ResolvedEl,true)],El);
  10650. end;
  10651. function GetValueReference: TResolvedReference;
  10652. var
  10653. Value: TPasExpr;
  10654. begin
  10655. Result:=nil;
  10656. Value:=El.Value;
  10657. if (Value.ClassType=TPrimitiveExpr)
  10658. and (Value.CustomData is TResolvedReference) then
  10659. exit(TResolvedReference(Value.CustomData));
  10660. end;
  10661. function ConvertIndexMinus1(Param: TPasExpr): TJSElement;
  10662. var
  10663. NeedMinus1: Boolean;
  10664. JSVal: TJSValue;
  10665. MinusJS: TJSAdditiveExpressionMinus;
  10666. begin
  10667. Result:=ConvertExpression(Param,ArgContext);
  10668. NeedMinus1:=true;
  10669. if Result is TJSLiteral then
  10670. begin
  10671. JSVal:=TJSLiteral(Result).Value;
  10672. if (JSVal.ValueType=jstNumber) then
  10673. begin
  10674. // simply subtract 1 from constant
  10675. JSVal.AsNumber:=JSVal.AsNumber-1;
  10676. NeedMinus1:=false;
  10677. end;
  10678. end;
  10679. if NeedMinus1 then
  10680. begin
  10681. // index-1
  10682. MinusJS:=TJSAdditiveExpressionMinus(CreateElement(TJSAdditiveExpressionMinus,Param));
  10683. MinusJS.A:=Result;
  10684. MinusJS.B:=CreateLiteralNumber(Param,1);
  10685. Result:=MinusJS;
  10686. end;
  10687. end;
  10688. procedure ConvertStringBracket(const ResolvedValue: TPasResolverResult);
  10689. var
  10690. CallEx, SetStrCall: TJSCallExpression;
  10691. Param: TPasExpr;
  10692. DotExpr: TJSDotMemberExpression;
  10693. AssignContext: TAssignContext;
  10694. AssignSt: TJSSimpleAssignStatement;
  10695. OldAccess: TCtxAccess;
  10696. IndexExpr: TJSElement;
  10697. Arg: TPasArgument;
  10698. IsRangeCheck: Boolean;
  10699. begin
  10700. Result:=nil;
  10701. IsRangeCheck:=(bsRangeChecks in AContext.ScannerBoolSwitches)
  10702. and (AContext.Access in [caRead,caAssign]);
  10703. Param:=El.Params[0];
  10704. case AContext.Access of
  10705. caAssign:
  10706. begin
  10707. // s[index] := value
  10708. AssignContext:=AContext.AccessContext as TAssignContext;
  10709. if AssignContext.RightSide=nil then
  10710. RaiseInconsistency(20180123192020,El);
  10711. AssignSt:=nil;
  10712. SetStrCall:=nil;
  10713. CallEx:=nil;
  10714. try
  10715. // CallEx: rtl.setCharAt(s,index,value)
  10716. // rtl.setCharAt
  10717. CallEx:=CreateCallExpression(El);
  10718. if IsRangeCheck then
  10719. CallEx.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnRangeCheckSetCharAt)])
  10720. else
  10721. CallEx.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnSetCharAt)]);
  10722. // first param s
  10723. OldAccess:=AContext.Access;
  10724. AContext.Access:=caRead;
  10725. CallEx.AddArg(ConvertExpression(El.Value,AContext));
  10726. // second param index-1
  10727. CallEx.AddArg(ConvertIndexMinus1(Param));
  10728. AContext.Access:=OldAccess;
  10729. // third param value
  10730. CallEx.AddArg(AssignContext.RightSide);
  10731. AssignContext.RightSide:=nil;
  10732. if ResolvedValue.IdentEl is TPasArgument then
  10733. begin
  10734. Arg:=TPasArgument(ResolvedValue.IdentEl);
  10735. if Arg.Access in [argVar,argOut] then
  10736. begin
  10737. // call by reference
  10738. // s[index] := value -> s.set(CallEx)
  10739. SetStrCall:=CreateCallExpression(El.Value);
  10740. SetStrCall.Expr:=CreateMemberExpression([TransformArgName(Arg,AContext),TempRefObjSetterName]);
  10741. SetStrCall.AddArg(CallEx);
  10742. AssignContext.Call:=CallEx;
  10743. CallEx:=nil;
  10744. Result:=SetStrCall;
  10745. end;
  10746. end
  10747. else if ResolvedValue.IdentEl is TPasProperty then
  10748. RaiseNotSupported(El,AContext,20180124115924);
  10749. if Result=nil then
  10750. begin
  10751. // s[index] := value -> s = CallEx
  10752. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  10753. AssignSt.Expr:=CallEx;
  10754. AssignContext.Call:=CallEx;
  10755. CallEx:=nil;
  10756. OldAccess:=AContext.Access;
  10757. AContext.Access:=caRead;
  10758. AssignSt.LHS:=ConvertExpression(El.Value,AContext);
  10759. Result:=AssignSt;
  10760. end;
  10761. finally
  10762. if Result=nil then
  10763. begin
  10764. CallEx.Free;
  10765. SetStrCall.Free;
  10766. AssignSt.Free;
  10767. end;
  10768. end;
  10769. end;
  10770. caRead:
  10771. begin
  10772. CallEx:=CreateCallExpression(El);
  10773. try
  10774. if IsRangeCheck and not TBinaryExpr.IsRightSubIdent(El) then
  10775. begin
  10776. // read s[index] -> rtl.rcCharAt(s,index-1)
  10777. CallEx.Expr:=CreatePrimitiveDotExpr(GetBIName(pbivnRTL)+'.'+GetBIName(pbifnRangeCheckGetCharAt),El);
  10778. CallEx.AddArg(ConvertExpression(El.Value,AContext));
  10779. end
  10780. else
  10781. begin
  10782. // s[index] -> s.charAt(index-1)
  10783. // add string accessor
  10784. DotExpr:=TJSDotMemberExpression(CreateElement(TJSDotMemberExpression,El));
  10785. CallEx.Expr:=DotExpr;
  10786. DotExpr.MExpr:=ConvertExpression(El.Value,AContext);
  10787. DotExpr.Name:='charAt';
  10788. end;
  10789. // add parameter "index-1"
  10790. IndexExpr:=ConvertIndexMinus1(Param);
  10791. CallEx.AddArg(IndexExpr);
  10792. Result:=CallEx;
  10793. finally
  10794. if Result=nil then
  10795. CallEx.Free;
  10796. end;
  10797. end;
  10798. else
  10799. RaiseNotSupported(El,AContext,20170213213101);
  10800. end;
  10801. end;
  10802. procedure ConvertArrayBracket(ArrayEl: TPasArrayType);
  10803. var
  10804. BracketEx, Sub: TJSBracketMemberExpression;
  10805. i, ArgNo: Integer;
  10806. Arg, ArrJS: TJSElement;
  10807. OldAccess: TCtxAccess;
  10808. Ranges: TPasExprArray;
  10809. Int: TMaxPrecInt;
  10810. Param: TPasExpr;
  10811. JSAdd: TJSAdditiveExpression;
  10812. LowRg: TResEvalValue;
  10813. IsRangeCheck, ok, NeedRangeCheck: Boolean;
  10814. CallEx, CallAssign: TJSCallExpression;
  10815. AssignContext: TAssignContext;
  10816. ArgList: TFPList;
  10817. IsAssignRecord: boolean;
  10818. {$IFDEF FPC_HAS_CPSTRING}
  10819. w: WideChar;
  10820. {$ENDIF}
  10821. begin
  10822. Result:=nil;
  10823. Arg:=nil;
  10824. ArrJS:=nil;
  10825. ArgList:=TFPList.Create;
  10826. NeedRangeCheck:=false;
  10827. ok:=false;
  10828. try
  10829. // add read accessor
  10830. OldAccess:=AContext.Access;
  10831. AContext.Access:=caRead;
  10832. ArrJS:=ConvertExpression(El.Value,AContext);
  10833. AContext.Access:=OldAccess;
  10834. ArgNo:=0;
  10835. repeat
  10836. // Note: dynamic array has length(ArrayEl.Ranges)=0
  10837. Ranges:=ArrayEl.Ranges;
  10838. for i:=1 to Max(length(Ranges),1) do
  10839. begin
  10840. // add parameter
  10841. Param:=El.Params[ArgNo];
  10842. ArgContext.Access:=caRead;
  10843. Arg:=ConvertExpression(Param,ArgContext);
  10844. ArgContext.Access:=OldAccess;
  10845. if not (Arg is TJSLiteral) then
  10846. NeedRangeCheck:=true;
  10847. if i<=length(Ranges) then
  10848. begin
  10849. // static array
  10850. LowRg:=ArgContext.Resolver.EvalRangeLimit(Ranges[i-1],[refConst],true,El);
  10851. if LowRg=nil then
  10852. RaiseNotSupported(Param,ArgContext,20170910163341);
  10853. try
  10854. Int:=0;
  10855. case LowRg.Kind of
  10856. revkBool:
  10857. if TResEvalBool(LowRg).B=false then
  10858. begin
  10859. // array starts at 'false'
  10860. if (Arg is TJSLiteral) and (TJSLiteral(Arg).Value.ValueType=jstBoolean) then
  10861. begin
  10862. // convert Pascal boolean literal to JS number
  10863. if TJSLiteral(Arg).Value.AsBoolean then
  10864. TJSLiteral(Arg).Value.AsNumber:=1
  10865. else
  10866. TJSLiteral(Arg).Value.AsNumber:=0;
  10867. end
  10868. else
  10869. begin
  10870. // -> convert bool to int with unary plus: +bool
  10871. Arg:=CreateUnaryPlus(Arg,Param);
  10872. end;
  10873. end
  10874. else
  10875. begin
  10876. // array starts at 'true'
  10877. if (Arg is TJSLiteral) and (TJSLiteral(Arg).Value.ValueType=jstBoolean) then
  10878. begin
  10879. if TJSLiteral(Arg).Value.AsBoolean then
  10880. TJSLiteral(Arg).Value.AsNumber:=0
  10881. else
  10882. ArgContext.Resolver.ExprEvaluator.EmitRangeCheckConst(
  10883. 20170910203312,'false','true','true',Param,mtError);
  10884. end
  10885. else
  10886. begin
  10887. // convert bool to int with offset: 1-bool
  10888. JSAdd:=TJSAdditiveExpressionMinus(CreateElement(TJSAdditiveExpressionMinus,Param));
  10889. JSAdd.A:=CreateLiteralNumber(Param,1);
  10890. JSAdd.B:=Arg;
  10891. Arg:=JSAdd;
  10892. end;
  10893. end;
  10894. revkEnum:
  10895. Int:=TResEvalEnum(LowRg).Index;
  10896. revkInt:
  10897. Int:=TResEvalInt(LowRg).Int;
  10898. {$IFDEF FPC_HAS_CPSTRING}
  10899. revkString:
  10900. begin
  10901. if length(TResEvalString(LowRg).S)<>1 then
  10902. begin
  10903. if ArgContext.Resolver.ExprEvaluator.GetWideChar(TResEvalString(LowRg).S,w) then
  10904. Int:=ord(w)
  10905. else
  10906. ArgContext.Resolver.RaiseXExpectedButYFound(20170910213203,'char','string',Param);
  10907. end
  10908. else
  10909. Int:=ord(TResEvalString(LowRg).S[1]);
  10910. Arg:=ConvertCharToInt(Arg,Param,ArgContext);
  10911. end;
  10912. {$ENDIF}
  10913. revkUnicodeString:
  10914. begin
  10915. if length(TResEvalUTF16(LowRg).S)<>1 then
  10916. ArgContext.Resolver.RaiseXExpectedButYFound(20170910213247,'char','string',Param)
  10917. else
  10918. Int:=ord(TResEvalUTF16(LowRg).S[1]);
  10919. Arg:=ConvertCharToInt(Arg,Param,ArgContext);
  10920. end
  10921. else
  10922. RaiseNotSupported(Param,ArgContext,20170910170446);
  10923. end;
  10924. if Int<>0 then
  10925. begin
  10926. if (Arg is TJSLiteral) and (TJSLiteral(Arg).Value.ValueType=jstNumber) then
  10927. // parameter is single number -> simply subtract the offset
  10928. TJSLiteral(Arg).Value.AsNumber:=TJSLiteral(Arg).Value.AsNumber-Int
  10929. else
  10930. begin
  10931. // parameter is an expression -> add offset
  10932. if Int>0 then
  10933. begin
  10934. // Arg-Offset
  10935. JSAdd:=TJSAdditiveExpressionMinus(CreateElement(TJSAdditiveExpressionMinus,Param));
  10936. JSAdd.A:=Arg;
  10937. JSAdd.B:=CreateLiteralNumber(Param,Int);
  10938. Arg:=JSAdd;
  10939. end
  10940. else
  10941. begin
  10942. // Arg+Offset
  10943. JSAdd:=TJSAdditiveExpressionPlus(CreateElement(TJSAdditiveExpressionPlus,Param));
  10944. JSAdd.A:=Arg;
  10945. JSAdd.B:=CreateLiteralNumber(Param,-Int);
  10946. Arg:=JSAdd;
  10947. end;
  10948. end;
  10949. end;
  10950. finally
  10951. ReleaseEvalValue(LowRg);
  10952. end;
  10953. end;
  10954. ArgList.Add(Arg);
  10955. Arg:=nil;
  10956. inc(ArgNo);
  10957. if ArgNo>length(El.Params) then
  10958. RaiseInconsistency(20170206180553,El);
  10959. end;
  10960. if ArgNo=length(El.Params) then
  10961. break;
  10962. // continue in sub array
  10963. ArrayEl:=AContext.Resolver.ResolveAliasType(ArrayEl.ElType) as TPasArrayType;
  10964. until ArrayEl=nil;
  10965. IsRangeCheck:=NeedRangeCheck
  10966. and (bsRangeChecks in AContext.ScannerBoolSwitches)
  10967. and (AContext.Access in [caRead,caAssign]);
  10968. AssignContext:=nil;
  10969. IsAssignRecord:=false;
  10970. if AContext.Access=caAssign then
  10971. begin
  10972. AssignContext:=AContext.AccessContext as TAssignContext;
  10973. if AssignContext.Call<>nil then
  10974. RaiseNotSupported(El,AContext,20180424192155);
  10975. IsAssignRecord:=AssignContext.LeftResolved.LoTypeEl is TPasRecordType;
  10976. end;
  10977. if IsRangeCheck and not TBinaryExpr.IsRightSubIdent(El) then
  10978. begin
  10979. // read a[i,j,k] -> rtl.rcArrR(a,i,j,k)
  10980. // assign a[i,j,k]:=RHS -> rtl.rcArrW(a,i,j,k,RHS)
  10981. // assign ArrOfRecord[i,j]:=RHS -> rtl.rcArrR(a,i,j,k).$assign(RHS)
  10982. CallEx:=CreateCallExpression(El);
  10983. Result:=CallEx;
  10984. if (AContext.Access=caRead) or IsAssignRecord then
  10985. CallEx.Expr:=CreatePrimitiveDotExpr(GetBIName(pbivnRTL)+'.'+GetBIName(pbifnRangeCheckArrayRead),El)
  10986. else
  10987. CallEx.Expr:=CreatePrimitiveDotExpr(GetBIName(pbivnRTL)+'.'+GetBIName(pbifnRangeCheckArrayWrite),El);
  10988. CallEx.AddArg(ArrJS); ArrJS:=nil;
  10989. for i:=0 to ArgList.Count-1 do
  10990. CallEx.AddArg(TJSElement(ArgList[i]));
  10991. ArgList.Clear;
  10992. if AContext.Access=caAssign then
  10993. begin
  10994. // a[i,j,k]:=
  10995. if IsAssignRecord then
  10996. begin
  10997. // rtl.rcArrR(a,i,j,k).$assign(RHS)
  10998. CallAssign:=CreateCallExpression(El);
  10999. CallAssign.Expr:=CreateDotNameExpr(El,CallEx,
  11000. TJSString(GetBIName(pbifnRecordAssign)));
  11001. CallEx:=CallAssign;
  11002. end;
  11003. CallEx.AddArg(AssignContext.RightSide);
  11004. AssignContext.RightSide:=nil;
  11005. AssignContext.Call:=CallEx;
  11006. // ToDo: range check value
  11007. Result:=CallEx;
  11008. end;
  11009. end
  11010. else
  11011. begin
  11012. BracketEx:=TJSBracketMemberExpression(CreateElement(TJSBracketMemberExpression,El));
  11013. BracketEx.MExpr:=ArrJS; ArrJS:=nil;
  11014. for i:=0 to ArgList.Count-1 do
  11015. begin
  11016. if BracketEx.Name<>nil then
  11017. begin
  11018. // nested [][]
  11019. Sub:=BracketEx;
  11020. BracketEx:=TJSBracketMemberExpression(CreateElement(TJSBracketMemberExpression,El));
  11021. BracketEx.MExpr:=Sub;
  11022. end;
  11023. BracketEx.Name:=TJSElement(ArgList[i]);
  11024. end;
  11025. Result:=BracketEx;
  11026. ArgList.Clear;
  11027. if IsAssignRecord then
  11028. begin
  11029. // assign ArrOfRecord[i,j]:=RHS -> a[i][j].$assign(RHS)
  11030. CallAssign:=CreateCallExpression(El);
  11031. CallAssign.Expr:=CreateDotNameExpr(El,Result,
  11032. TJSString(GetBIName(pbifnRecordAssign)));
  11033. Result:=CallAssign;
  11034. CallAssign.AddArg(AssignContext.RightSide);
  11035. AssignContext.RightSide:=nil;
  11036. AssignContext.Call:=CallAssign;
  11037. end;
  11038. end;
  11039. ok:=true;
  11040. finally
  11041. if not ok then
  11042. begin
  11043. ArrJS.Free;
  11044. for i:=0 to ArgList.Count-1 do
  11045. TJSElement(ArgList[i]).{$IFDEF pas2js}Destroy{$ELSE}Free{$ENDIF};
  11046. Arg.Free;
  11047. Result.Free;
  11048. end;
  11049. ArgList.Free;
  11050. end;
  11051. end;
  11052. function IsJSBracketAccessorAndConvert(Prop: TPasProperty;
  11053. AccessEl: TPasElement;
  11054. AContext: TConvertContext; ChompPropName: boolean): boolean;
  11055. // If El.Value contains property name set ChompPropName = true
  11056. var
  11057. Bracket: TJSBracketMemberExpression;
  11058. OldAccess: TCtxAccess;
  11059. PathEl: TPasExpr;
  11060. Ref: TResolvedReference;
  11061. Path: String;
  11062. begin
  11063. if not AContext.Resolver.IsExternalBracketAccessor(AccessEl) then
  11064. exit(false);
  11065. Result:=true;
  11066. // bracket accessor of external class
  11067. if AContext.Resolver.GetPasPropertyArgs(Prop).Count<>1 then
  11068. RaiseInconsistency(20170403003753,Prop);
  11069. // bracket accessor of external class -> create PathEl[param]
  11070. Bracket:=TJSBracketMemberExpression(CreateElement(TJSBracketMemberExpression,El.Params[0]));
  11071. try
  11072. PathEl:=El.Value;
  11073. if ChompPropName then
  11074. begin
  11075. if (PathEl is TPrimitiveExpr)
  11076. and (TPrimitiveExpr(PathEl).Kind=pekIdent)
  11077. and (PathEl.CustomData is TResolvedReference) then
  11078. begin
  11079. // propname without path, e.g. propname[param]
  11080. Ref:=TResolvedReference(PathEl.CustomData);
  11081. Path:=CreateReferencePath(Prop,AContext,rpkPath,false,Ref);
  11082. if Path<>'' then
  11083. Bracket.MExpr:=CreatePrimitiveDotExpr(Path,PathEl);
  11084. PathEl:=nil;
  11085. end
  11086. else if (PathEl is TBinaryExpr)
  11087. and (TBinaryExpr(PathEl).OpCode=eopSubIdent)
  11088. and (TBinaryExpr(PathEl).right is TPrimitiveExpr)
  11089. and (TPrimitiveExpr(TBinaryExpr(PathEl).right).Kind=pekIdent) then
  11090. begin
  11091. // instance.propname[param] -> instance[param]
  11092. PathEl:=TBinaryExpr(PathEl).left;
  11093. end
  11094. else
  11095. RaiseNotSupported(El.Value,AContext,20170402225050);
  11096. end;
  11097. if (PathEl<>nil) and (Bracket.MExpr=nil) then
  11098. begin
  11099. OldAccess:=AContext.Access;
  11100. AContext.Access:=caRead;
  11101. Bracket.MExpr:=ConvertExpression(PathEl,AContext);
  11102. AContext.Access:=OldAccess;
  11103. end;
  11104. OldAccess:=ArgContext.Access;
  11105. ArgContext.Access:=caRead;
  11106. Bracket.Name:=ConvertExpression(El.Params[0],ArgContext);
  11107. ArgContext.Access:=OldAccess;
  11108. ConvertArrayParams:=Bracket;
  11109. Bracket:=nil;
  11110. finally
  11111. Bracket.Free;
  11112. end;
  11113. end;
  11114. procedure ConvertIndexedProperty(Prop: TPasProperty; AContext: TConvertContext;
  11115. CheckPath: boolean);
  11116. var
  11117. Call: TJSCallExpression;
  11118. i: Integer;
  11119. TargetArg: TPasArgument;
  11120. Elements: TJSArrayLiteralElements;
  11121. Arg: TJSElement;
  11122. AccessEl: TPasElement;
  11123. AssignContext: TAssignContext;
  11124. OldAccess: TCtxAccess;
  11125. IndexExpr: TPasExpr;
  11126. Value: TResEvalValue;
  11127. PropArgs: TFPList;
  11128. aResolver: TPas2JSResolver;
  11129. TypeEl: TPasType;
  11130. Bin: TBinaryExpr;
  11131. CreateRefPathData: TCreateRefPathData;
  11132. begin
  11133. Result:=nil;
  11134. AssignContext:=nil;
  11135. aResolver:=AContext.Resolver;
  11136. Call:=nil;
  11137. try
  11138. // find getter/setter
  11139. case AContext.Access of
  11140. caAssign:
  11141. AccessEl:=aResolver.GetPasPropertySetter(Prop);
  11142. caRead:
  11143. AccessEl:=aResolver.GetPasPropertyGetter(Prop);
  11144. else
  11145. RaiseNotSupported(El,AContext,20170213213317);
  11146. end;
  11147. if IsJSBracketAccessorAndConvert(Prop,AccessEl,AContext,true) then
  11148. exit;
  11149. // create call
  11150. if aResolver.IsHelperMethod(AccessEl) then
  11151. begin
  11152. if CheckPath then
  11153. Call:=CreateCallHelperMethod(TPasProcedure(AccessEl),El.Value,AContext)
  11154. else
  11155. Call:=CreateCallHelperMethod(TPasProcedure(AccessEl),El,AContext)
  11156. end
  11157. else
  11158. Call:=CreateCallExpression(El);
  11159. if AContext.Access=caAssign then
  11160. begin
  11161. AssignContext:=AContext.AccessContext as TAssignContext;
  11162. AssignContext.PropertyEl:=Prop;
  11163. AssignContext.Call:=Call;
  11164. end;
  11165. if CheckPath and (Call.Expr=nil) then
  11166. if aResolver.IsNameExpr(El.Value) then
  11167. // no special context
  11168. else if El.Value is TBinaryExpr then
  11169. begin
  11170. // convert left
  11171. Bin:=TBinaryExpr(El.Value);
  11172. if Bin.OpCode<>eopSubIdent then
  11173. RaiseNotSupported(El,AContext,20190116100510);
  11174. CreateRefPathData.El:=AccessEl;
  11175. CreateRefPathData.Full:=false;
  11176. CreateRefPathData.Ref:=GetValueReference;
  11177. Call.Expr:=ConvertSubIdentExprCustom(Bin,AContext,
  11178. @OnCreateReferencePathExpr,@CreateRefPathData);
  11179. end
  11180. else
  11181. begin
  11182. {$IFDEF VerbosePas2JS}
  11183. writeln('ConvertFuncParams.ConvertIndexedProperty ',GetObjName(El.Value));
  11184. {$ENDIF}
  11185. RaiseNotSupported(El,AContext,20190116100431);
  11186. end;
  11187. if Call.Expr=nil then
  11188. Call.Expr:=CreateReferencePathExpr(AccessEl,AContext,false,GetValueReference);
  11189. Elements:=Call.Args.Elements;
  11190. OldAccess:=ArgContext.Access;
  11191. // add params
  11192. PropArgs:=aResolver.GetPasPropertyArgs(Prop);
  11193. i:=0;
  11194. while i<PropArgs.Count do
  11195. begin
  11196. TargetArg:=TPasArgument(PropArgs[i]);
  11197. Arg:=CreateProcCallArg(El.Params[i],TargetArg,ArgContext);
  11198. Elements.AddElement.Expr:=Arg;
  11199. inc(i);
  11200. end;
  11201. // fill up default values
  11202. while i<PropArgs.Count do
  11203. begin
  11204. TargetArg:=TPasArgument(PropArgs[i]);
  11205. if TargetArg.ValueExpr=nil then
  11206. begin
  11207. {$IFDEF VerbosePas2JS}
  11208. writeln('TPasToJSConverter.ConvertArrayParams.ConvertIndexedProperty missing default value: Prop=',Prop.Name,' i=',i);
  11209. {$ENDIF}
  11210. RaiseInconsistency(20170206185126,TargetArg);
  11211. end;
  11212. AContext.Access:=caRead;
  11213. Arg:=ConvertExpression(TargetArg.ValueExpr,ArgContext);
  11214. Elements.AddElement.Expr:=Arg;
  11215. inc(i);
  11216. end;
  11217. // add index specifier
  11218. IndexExpr:=aResolver.GetPasPropertyIndex(Prop);
  11219. if IndexExpr<>nil then
  11220. begin
  11221. Value:=aResolver.Eval(IndexExpr,[refConst]);
  11222. try
  11223. Elements.AddElement.Expr:=ConvertConstValue(Value,ArgContext,El);
  11224. finally
  11225. ReleaseEvalValue(Value);
  11226. end;
  11227. end;
  11228. // finally add as last parameter the value
  11229. if AssignContext<>nil then
  11230. begin
  11231. Elements.AddElement.Expr:=AssignContext.RightSide;
  11232. AssignContext.RightSide:=nil;
  11233. end;
  11234. ArgContext.Access:=OldAccess;
  11235. // add interface reference
  11236. if AContext.Access=caRead then
  11237. begin
  11238. TypeEl:=aResolver.GetPasPropertyType(Prop);
  11239. if aResolver.IsManagedJSType(TypeEl) then
  11240. Call:=CreateIntfRef(Call,AContext,El);
  11241. end;
  11242. Result:=Call;
  11243. finally
  11244. if Result=nil then
  11245. begin
  11246. if (AssignContext<>nil) and (AssignContext.Call=Call) then
  11247. AssignContext.Call:=nil;
  11248. Call.Free;
  11249. end;
  11250. end;
  11251. end;
  11252. procedure ConvertDefaultProperty(const ResolvedEl: TPasResolverResult;
  11253. Prop: TPasProperty);
  11254. var
  11255. DotContext: TDotContext;
  11256. Left, Right: TJSElement;
  11257. OldAccess: TCtxAccess;
  11258. AccessEl, SetAccessEl: TPasElement;
  11259. aResolver: TPas2JSResolver;
  11260. begin
  11261. aResolver:=AContext.Resolver;
  11262. case AContext.Access of
  11263. caAssign:
  11264. begin
  11265. AccessEl:=aResolver.GetPasPropertySetter(Prop);
  11266. if IsJSBracketAccessorAndConvert(Prop,AccessEl,AContext,false) then
  11267. exit;
  11268. end;
  11269. caRead:
  11270. begin
  11271. AccessEl:=aResolver.GetPasPropertyGetter(Prop);
  11272. if IsJSBracketAccessorAndConvert(Prop,AccessEl,AContext,false) then
  11273. exit;
  11274. end;
  11275. caByReference:
  11276. begin
  11277. AccessEl:=aResolver.GetPasPropertyGetter(Prop);
  11278. SetAccessEl:=aResolver.GetPasPropertySetter(Prop);
  11279. if aResolver.IsExternalBracketAccessor(AccessEl) then
  11280. begin
  11281. if aResolver.IsExternalBracketAccessor(SetAccessEl) then
  11282. begin
  11283. // read and write are brackets -> easy
  11284. if not IsJSBracketAccessorAndConvert(Prop,AccessEl,AContext,false) then
  11285. RaiseNotSupported(El,AContext,20170405090845);
  11286. exit;
  11287. end;
  11288. end;
  11289. RaiseNotSupported(El,AContext,20170403000550);
  11290. end;
  11291. else
  11292. RaiseNotSupported(El,AContext,20170402233834){%H-};
  11293. end;
  11294. if aResolver.IsHelperMethod(AccessEl) then
  11295. begin
  11296. ConvertIndexedProperty(Prop,AContext,false);
  11297. exit;
  11298. end;
  11299. DotContext:=nil;
  11300. Left:=nil;
  11301. Right:=nil;
  11302. try
  11303. OldAccess:=AContext.Access;
  11304. AContext.Access:=caRead;
  11305. Left:=ConvertExpression(El.Value,AContext);
  11306. AContext.Access:=OldAccess;
  11307. DotContext:=TDotContext.Create(El.Value,Left,AContext);
  11308. DotContext.LeftResolved:=ResolvedEl;
  11309. ConvertIndexedProperty(Prop,DotContext,false);
  11310. if DotContext.JS<>nil then
  11311. RaiseNotSupported(El,AContext,20180509134226,GetObjName(DotContext.JS));
  11312. Right:=Result;
  11313. Result:=nil;
  11314. finally
  11315. DotContext.Free;
  11316. if Right=nil then
  11317. Left.Free;
  11318. end;
  11319. Result:=CreateDotExpression(El,Left,Right,true);
  11320. end;
  11321. Var
  11322. ResolvedEl: TPasResolverResult;
  11323. TypeEl: TPasType;
  11324. B: TJSBracketMemberExpression;
  11325. OldAccess: TCtxAccess;
  11326. aResolver: TPas2JSResolver;
  11327. Ref: TResolvedReference;
  11328. begin
  11329. if El.Kind<>pekArrayParams then
  11330. RaiseInconsistency(20170209113713,El);
  11331. ArgContext:=AContext.GetNonDotContext;
  11332. aResolver:=AContext.Resolver;
  11333. if aResolver=nil then
  11334. begin
  11335. // without Resolver
  11336. if Length(El.Params)>1 then
  11337. RaiseNotSupported(El,AContext,20170207151325,'Cannot convert 2-dim arrays');
  11338. B:=TJSBracketMemberExpression(CreateElement(TJSBracketMemberExpression,El));
  11339. try
  11340. // add reference
  11341. OldAccess:=AContext.Access;
  11342. AContext.Access:=caRead;
  11343. B.MExpr:=ConvertExpression(El.Value,AContext);
  11344. // add parameter
  11345. OldAccess:=ArgContext.Access;
  11346. ArgContext.Access:=caRead;
  11347. B.Name:=ConvertExpression(El.Params[0],ArgContext);
  11348. ArgContext.Access:=OldAccess;
  11349. Result:=B;
  11350. finally
  11351. if Result=nil then
  11352. B.Free;
  11353. end;
  11354. exit;
  11355. end;
  11356. // has Resolver
  11357. aResolver.ComputeElement(El.Value,ResolvedEl,[]);
  11358. if El.CustomData is TResolvedReference then
  11359. begin
  11360. Ref:=TResolvedReference(El.CustomData);
  11361. if Ref.Declaration is TPasProperty then
  11362. begin
  11363. ConvertDefaultProperty(ResolvedEl,TPasProperty(Ref.Declaration));
  11364. exit;
  11365. end;
  11366. end;
  11367. {$IFDEF VerbosePas2JS}
  11368. writeln('TPasToJSConverter.ConvertArrayParams Value=',GetResolverResultDbg(ResolvedEl));
  11369. {$ENDIF}
  11370. if ResolvedEl.BaseType in btAllJSStrings then
  11371. // aString[]
  11372. ConvertStringBracket(ResolvedEl)
  11373. else if (ResolvedEl.IdentEl is TPasProperty)
  11374. and (aResolver.GetPasPropertyArgs(TPasProperty(ResolvedEl.IdentEl)).Count>0) then
  11375. // aProperty[]
  11376. ConvertIndexedProperty(TPasProperty(ResolvedEl.IdentEl),AContext,true)
  11377. else if ResolvedEl.BaseType=btContext then
  11378. begin
  11379. TypeEl:=ResolvedEl.LoTypeEl;
  11380. if TypeEl.ClassType=TPasArrayType then
  11381. // anArray[]
  11382. ConvertArrayBracket(TPasArrayType(TypeEl))
  11383. else
  11384. RaiseIllegalBrackets(20170206181220,ResolvedEl);
  11385. end
  11386. else
  11387. RaiseIllegalBrackets(20170206180222,ResolvedEl);
  11388. end;
  11389. function TPasToJSConverter.ConvertFuncParams(El: TParamsExpr;
  11390. AContext: TConvertContext): TJSElement;
  11391. var
  11392. aResolver: TPas2JSResolver;
  11393. DotBin: TBinaryExpr;
  11394. Call: TJSCallExpression;
  11395. Elements: TJSArrayLiteralElements;
  11396. procedure CreateFreeOrNewInstanceCall(Ref: TResolvedReference);
  11397. var
  11398. JsArrLit: TJSArrayLiteral;
  11399. LeftResolved: TPasResolverResult;
  11400. OldAccess: TCtxAccess;
  11401. Left, DotExpr: TJSElement;
  11402. DotContext: TDotContext;
  11403. begin
  11404. if DotBin<>nil then
  11405. begin
  11406. aResolver.ComputeElement(DotBin.left,LeftResolved,[]);
  11407. // convert left side
  11408. OldAccess:=AContext.Access;
  11409. AContext.Access:=caRead;
  11410. Left:=ConvertExpression(DotBin.left,AContext);
  11411. if Left=nil then
  11412. RaiseInconsistency(20190116132530,El);
  11413. AContext.Access:=OldAccess;
  11414. DotContext:=TDotContext.Create(DotBin,Left,AContext);
  11415. try
  11416. DotContext.LeftResolved:=LeftResolved;
  11417. Call:=CreateFreeOrNewInstanceExpr(Ref,DotContext);
  11418. if DotContext.JS<>nil then
  11419. RaiseNotSupported(El,AContext,20190116132748);
  11420. finally
  11421. DotContext.Free;
  11422. if Call=nil then
  11423. Left.Free;
  11424. end;
  11425. // connect via dot
  11426. DotExpr:=CreateDotExpression(DotBin,Left,Call,true);
  11427. if DotExpr<>Call then
  11428. RaiseNotSupported(El,AContext,20190116133841);
  11429. end;
  11430. if Call=nil then
  11431. Call:=CreateFreeOrNewInstanceExpr(Ref,AContext);
  11432. if (rrfNewInstance in Ref.Flags)
  11433. and (Ref.Declaration.Parent.ClassType=TPasClassType) then
  11434. begin
  11435. // insert array parameter [], e.g. this.TObject.$create("create",[])
  11436. JsArrLit:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,El));
  11437. Call.AddArg(JsArrLit);
  11438. Elements:=JsArrLit.Elements;
  11439. end
  11440. else
  11441. Elements:=Call.Args.Elements;
  11442. end;
  11443. procedure CreateShortRefApply(Value: TPasExpr; TargetProcType: TPasProcedureType);
  11444. var
  11445. TargetProc: TPasProcedure;
  11446. aName: String;
  11447. LeftJS: TJSElement;
  11448. Ref: TResolvedReference;
  11449. begin
  11450. // create "$lp.apply(LeftJS,args);"
  11451. TargetProc:=TPasProcedure(TargetProcType.Parent);
  11452. aName:=CreateStaticProcPath(TargetProc,AContext);
  11453. Call.Expr:=CreatePrimitiveDotExpr(aName+'.apply',Value);
  11454. if DotBin<>nil then
  11455. begin
  11456. // a.b() -> "$lp.apply(a,args);"
  11457. LeftJS:=ConvertExpression(DotBin.left,AContext);
  11458. if LeftJS=nil then
  11459. RaiseNotSupported(DotBin,AContext,20201030235816);
  11460. end
  11461. else if Value.CustomData is TResolvedReference then
  11462. begin
  11463. // a() -> "$lp.apply(this,args);" or "$lp.apply($with,args);"
  11464. Ref:=TResolvedReference(Value.CustomData);
  11465. aName:=CreateReferencePath(TargetProc,AContext,rpkPath,false,Ref);
  11466. LeftJS:=CreatePrimitiveDotExpr(aName,Value);
  11467. if LeftJS=nil then
  11468. RaiseNotSupported(DotBin,AContext,20201031003202);
  11469. end
  11470. else
  11471. RaiseNotSupported(DotBin,AContext,202010310032046);
  11472. Elements.AddElement.Expr:=LeftJS;
  11473. end;
  11474. function ConvertJSArrayLit(Param: TPasExpr; const ParamResolved: TPasResolverResult): TJSElement;
  11475. // TJSArray(Param)
  11476. var
  11477. ParamExpr: TParamsExpr;
  11478. ArrayType: TPasArrayType;
  11479. i: Integer;
  11480. JS: TJSElement;
  11481. SubParam: TPasExpr;
  11482. ArrLit: TJSArrayLiteral;
  11483. begin
  11484. Result:=nil;
  11485. if not (Param is TParamsExpr) then exit;
  11486. ParamExpr:=TParamsExpr(Param);
  11487. if ParamExpr.Kind<>pekSet then exit;
  11488. ArrayType:=aResolver.IsArrayExpr(ParamExpr);
  11489. if ArrayType<>nil then
  11490. begin
  11491. Result:=CreateArrayInit(ArrayType,Param,Param,AContext);
  11492. exit;
  11493. end
  11494. else if ParamResolved.BaseType=btArrayLit then
  11495. begin
  11496. ArrLit:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,Param));
  11497. try
  11498. for i:=0 to length(ParamExpr.Params)-1 do
  11499. begin
  11500. SubParam:=ParamExpr.Params[i];
  11501. JS:=ConvertExpression(SubParam,AContext);
  11502. ArrLit.AddElement(JS);
  11503. end;
  11504. Result:=ArrLit;
  11505. finally
  11506. if Result=nil then
  11507. ArrLit.Free;
  11508. end;
  11509. end
  11510. else
  11511. RaiseNotSupported(El,AContext,20220331114026);
  11512. end;
  11513. var
  11514. Decl: TPasElement;
  11515. Ref: TResolvedReference;
  11516. BuiltInProc: TResElDataBuiltInProc;
  11517. TargetProc: TPasProcedure;
  11518. TargetProcType: TPasProcedureType;
  11519. JsArrLit: TJSArrayLiteral;
  11520. OldAccess: TCtxAccess;
  11521. DeclResolved, ParamResolved, ValueResolved: TPasResolverResult;
  11522. Param, Value: TPasExpr;
  11523. JSBaseType: TPas2jsBaseType;
  11524. C: TClass;
  11525. aName, ArgName: String;
  11526. aClassTypeEl: TPasClassType;
  11527. ParamTypeEl: TPasType;
  11528. NeedIntfRef: Boolean;
  11529. DestRange, SrcRange: TResEvalValue;
  11530. LastArg: TJSArrayLiteralElement;
  11531. CallArgs: TJSArguments;
  11532. begin
  11533. Result:=nil;
  11534. if El.Kind<>pekFuncParams then
  11535. RaiseInconsistency(20170209113515,El);
  11536. aResolver:=AContext.Resolver;
  11537. //writeln('TPasToJSConverter.ConvertFuncParams START pekFuncParams ',GetObjName(El.CustomData),' ',GetObjName(El.Value.CustomData));
  11538. Call:=nil;
  11539. Elements:=nil;
  11540. TargetProcType:=nil;
  11541. DotBin:=nil;
  11542. Value:=El.Value;
  11543. if (not (Value.CustomData is TResolvedReference))
  11544. and (aResolver<>nil)
  11545. and (Value is TBinaryExpr) and (TBinaryExpr(Value).OpCode=eopSubIdent) then
  11546. begin
  11547. // path.Value()
  11548. DotBin:=TBinaryExpr(Value);
  11549. Value:=DotBin.right;
  11550. end;
  11551. if (not (Value.CustomData is TResolvedReference))
  11552. and (aResolver<>nil)
  11553. and (Value is TInlineSpecializeExpr) then
  11554. begin
  11555. // Value<>()
  11556. Value:=TInlineSpecializeExpr(Value).NameExpr;
  11557. end;
  11558. if Value.CustomData is TResolvedReference then
  11559. begin
  11560. Ref:=TResolvedReference(Value.CustomData);
  11561. Decl:=Ref.Declaration;
  11562. if Decl is TPasType then
  11563. Decl:=aResolver.ResolveAliasType(TPasType(Decl));
  11564. //writeln('TPasToJSConverter.ConvertFuncParams pekFuncParams TResolvedReference ',GetObjName(Ref.Declaration),' ',GetObjName(Ref.Declaration.CustomData));
  11565. C:=Decl.ClassType;
  11566. if C=TPasUnresolvedSymbolRef then
  11567. begin
  11568. if Decl.CustomData is TResElDataBuiltInProc then
  11569. begin
  11570. BuiltInProc:=TResElDataBuiltInProc(Decl.CustomData);
  11571. {$IFDEF VerbosePas2JS}
  11572. writeln('TPasToJSConverter.ConvertFuncParams BuiltInProc ',Decl.Name,' ',ResolverBuiltInProcNames[BuiltInProc.BuiltIn]);
  11573. {$ENDIF}
  11574. case BuiltInProc.BuiltIn of
  11575. bfLength: Result:=ConvertBuiltIn_Length(El,AContext);
  11576. bfSetLength: Result:=ConvertBuiltIn_SetLength(El,AContext);
  11577. bfInclude: Result:=ConvertBuiltIn_ExcludeInclude(El,AContext,true);
  11578. bfExclude: Result:=ConvertBuiltIn_ExcludeInclude(El,AContext,false);
  11579. bfExit: Result:=ConvertBuiltIn_Exit(El,AContext);
  11580. bfInc,
  11581. bfDec: Result:=ConvertBuiltIn_IncDec(El,AContext);
  11582. bfAssigned: Result:=ConvertBuiltIn_Assigned(El,AContext);
  11583. bfChr: Result:=ConvertBuiltIn_Chr(El,AContext);
  11584. bfOrd: Result:=ConvertBuiltIn_Ord(El,AContext);
  11585. bfLow: Result:=ConvertBuiltIn_LowHigh(El,AContext,true);
  11586. bfHigh: Result:=ConvertBuiltIn_LowHigh(El,AContext,false);
  11587. bfPred: Result:=ConvertBuiltIn_PredSucc(El,AContext,true);
  11588. bfSucc: Result:=ConvertBuiltIn_PredSucc(El,AContext,false);
  11589. bfStrProc: Result:=ConvertBuiltIn_StrProc(El,AContext);
  11590. bfStrFunc: Result:=ConvertBuiltIn_StrFunc(El,AContext);
  11591. bfWriteStr: Result:=ConvertBuiltIn_WriteStr(El,AContext);
  11592. bfVal: Result:=ConvertBuiltIn_Val(El,AContext);
  11593. bfLo: Result := ConvertBuiltIn_LoHi(El,AContext,True);
  11594. bfHi: Result := ConvertBuiltIn_LoHi(El,AContext,False);
  11595. bfConcatArray: Result:=ConvertBuiltIn_ConcatArray(El,AContext);
  11596. bfConcatString: Result:=ConvertBuiltIn_ConcatString(El,AContext);
  11597. bfCopyArray: Result:=ConvertBuiltIn_CopyArray(El,AContext);
  11598. bfInsertArray: Result:=ConvertBuiltIn_InsertArray(El,AContext);
  11599. bfDeleteArray: Result:=ConvertBuiltIn_DeleteArray(El,AContext);
  11600. bfTypeInfo: Result:=ConvertBuiltIn_TypeInfo(El,AContext);
  11601. bfGetTypeKind: Result:=ConvertBuiltIn_GetTypeKind(El,AContext);
  11602. bfAssert:
  11603. begin
  11604. Result:=ConvertBuiltIn_Assert(El,AContext);
  11605. if Result=nil then exit;
  11606. end;
  11607. bfNew: Result:=ConvertBuiltIn_New(El,AContext);
  11608. bfDispose:
  11609. begin
  11610. Result:=ConvertBuiltIn_Dispose(El,AContext);
  11611. if Result=nil then exit;
  11612. end;
  11613. bfDefault: Result:=ConvertBuiltIn_Default(El,AContext);
  11614. bfCustom:
  11615. case BuiltInProc.Element.Name of
  11616. 'Debugger': Result:=ConvertBuiltIn_Debugger(El,AContext);
  11617. 'AWait': Result:=ConvertBuiltIn_AWait(El,AContext);
  11618. else
  11619. RaiseNotSupported(El,AContext,20181126101801,'built in custom proc '+BuiltInProc.Element.Name);
  11620. end;
  11621. else
  11622. RaiseNotSupported(El,AContext,20161130164955,'built in proc '+ResolverBuiltInProcNames[BuiltInProc.BuiltIn]);
  11623. end;
  11624. if Result=nil then
  11625. RaiseInconsistency(20170210121932,El);
  11626. exit;
  11627. end
  11628. else if Decl.CustomData is TResElDataBaseType then
  11629. begin
  11630. // typecast to base type
  11631. Result:=ConvertTypeCastToBaseType(El,AContext,TResElDataBaseType(Decl.CustomData));
  11632. exit;
  11633. end
  11634. else
  11635. RaiseNotSupported(El,AContext,20170325160624);
  11636. end
  11637. else if aResolver.IsExternalClassConstructor(Decl) then
  11638. begin
  11639. // create external object/function
  11640. if DotBin<>nil then
  11641. Param:=DotBin.left
  11642. else
  11643. Param:=nil;
  11644. Result:=ConvertExternalConstructor(Param,Ref,El,AContext);
  11645. exit;
  11646. end
  11647. else if aResolver.IsTObjectFreeMethod(Value) then
  11648. begin
  11649. if DotBin<>nil then
  11650. Result:=ConvertTObjectFree_Bin(DotBin,Value,AContext)
  11651. else
  11652. RaiseNotSupported(El,AContext,20190115215224);
  11653. exit;
  11654. end
  11655. else if C.InheritsFrom(TPasProcedure) then
  11656. begin
  11657. TargetProc:=TPasProcedure(Decl);
  11658. if aResolver.IsHelperMethod(TargetProc) then
  11659. begin
  11660. // calling a helper method
  11661. Result:=CreateCallHelperMethod(TargetProc,El.Value,AContext);
  11662. exit;
  11663. end;
  11664. if aResolver.IsExternalBracketAccessor(TargetProc) then
  11665. exit(CreateExternalBracketAccessorCall(El,AContext));
  11666. TargetProcType:=TargetProc.ProcType;
  11667. end
  11668. else if (C=TPasClassType)
  11669. or (C=TPasClassOfType)
  11670. or (C=TPasRecordType)
  11671. or (C=TPasEnumType)
  11672. or (C=TPasRangeType)
  11673. or (C=TPasArrayType)
  11674. or (C=TPasPointerType) then
  11675. begin
  11676. // typecast
  11677. // default is to simply replace "aType(param)" with "param"
  11678. Param:=El.Params[0];
  11679. aResolver.ComputeElement(Param,ParamResolved,[]);
  11680. ParamTypeEl:=ParamResolved.LoTypeEl;
  11681. if (C=TPasRecordType) and (ParamResolved.BaseType=btUntyped)
  11682. and (ParamResolved.IdentEl is TPasArgument) then
  11683. begin
  11684. // RecordType(UntypedArg) -> UntypedArg
  11685. ArgName:=TransformArgName(TPasArgument(ParamResolved.IdentEl),AContext);
  11686. Result:=CreatePrimitiveDotExpr(ArgName,El);
  11687. exit;
  11688. end
  11689. else if (C=TPasClassType) then
  11690. begin
  11691. if aResolver.IsExternalClass_Name(TPasClassType(Decl),'Function') then
  11692. begin
  11693. // TJSFunction(param)
  11694. if (Param is TPasExpr) and (TPasExpr(Param).OpCode=eopAddress) then
  11695. begin
  11696. aResolver.ComputeElement(TUnaryExpr(Param).Operand,ValueResolved,[rcNoImplicitProc]);
  11697. if (ValueResolved.BaseType=btProc)
  11698. and (ValueResolved.IdentEl is TPasProcedure) then
  11699. begin
  11700. // TJSFunction(@procname) -> procname
  11701. Result:=CreateReferencePathExpr(TPasProcedure(ValueResolved.IdentEl),AContext);
  11702. exit;
  11703. end;
  11704. end;
  11705. end
  11706. else if aResolver.IsExternalClass_Name(TPasClassType(Decl),'Array') then
  11707. begin
  11708. // TJSArray(param)
  11709. Result:=ConvertJSArrayLit(Param,ParamResolved);
  11710. if Result<>nil then exit;
  11711. end;
  11712. end;
  11713. Result:=ConvertExpression(Param,AContext);
  11714. if C=TPasRangeType then
  11715. begin
  11716. DestRange:=aResolver.EvalTypeRange(TPasRangeType(Decl),[refConst]);
  11717. SrcRange:=nil;
  11718. try
  11719. if DestRange=nil then
  11720. RaiseNotSupported(El,AContext,20180424124708);
  11721. SrcRange:=aResolver.EvalTypeRange(ParamResolved.LoTypeEl,[]);
  11722. if SrcRange=nil then
  11723. RaiseNotSupported(El,AContext,20180424125331);
  11724. case DestRange.Kind of
  11725. revkRangeInt:
  11726. case TResEvalRangeInt(DestRange).ElKind of
  11727. revskEnum, revskInt:
  11728. // type cast to integer-range
  11729. case SrcRange.Kind of
  11730. revkRangeInt:
  11731. case TResEvalRangeInt(SrcRange).ElKind of
  11732. revskEnum, revskInt:
  11733. ; // ToDo: higher precision to lower precision -> modulo
  11734. else
  11735. RaiseNotSupported(El,AContext,20180424130705);
  11736. end;
  11737. revkRangeUInt: ;
  11738. else
  11739. RaiseNotSupported(El,AContext,20180424125608);
  11740. end;
  11741. else
  11742. RaiseNotSupported(El,AContext,20180424125419);
  11743. end;
  11744. else
  11745. RaiseNotSupported(El,AContext,20180424124814);
  11746. end;
  11747. finally
  11748. ReleaseEvalValue(SrcRange);
  11749. ReleaseEvalValue(DestRange);
  11750. end;
  11751. end
  11752. else if C=TPasClassType then
  11753. begin
  11754. if ParamTypeEl is TPasClassType then
  11755. case TPasClassType(Decl).ObjKind of
  11756. okClass:
  11757. case TPasClassType(ParamTypeEl).ObjKind of
  11758. okClass:;
  11759. okInterface:
  11760. if not TPasClassType(Decl).IsExternal then
  11761. begin
  11762. // classtype(intfvar) -> rtl.intfToClass(intfvar,classtype)
  11763. Call:=CreateCallExpression(El);
  11764. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnIntfToClass)]);
  11765. Call.AddArg(Result);
  11766. Result:=Call;
  11767. Call.AddArg(CreateReferencePathExpr(Decl,AContext));
  11768. exit; // bsObjectChecks not needed
  11769. end;
  11770. else
  11771. RaiseNotSupported(El,AContext,20180327221211,ObjKindNames[TPasClassType(ParamTypeEl).ObjKind]);
  11772. end;
  11773. okInterface:
  11774. case TPasClassType(ParamTypeEl).ObjKind of
  11775. okClass:
  11776. begin
  11777. case TPasClassType(Decl).InterfaceType of
  11778. citCom:
  11779. // IntfType(ClassInstVar) -> queryIntfT(ClassInstVar,IntfType)
  11780. begin
  11781. Call:=CreateCallExpression(El);
  11782. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnIntfQueryIntfT)]);
  11783. Call.AddArg(Result);
  11784. Result:=Call;
  11785. Call.AddArg(CreateReferencePathExpr(Decl,AContext));
  11786. Result:=CreateIntfRef(Result,AContext,El);
  11787. end;
  11788. citCorba:
  11789. // IntfType(ClassInstVar) -> getIntfT(ClassInstVar,IntfType)
  11790. begin
  11791. Call:=CreateCallExpression(El);
  11792. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnIntfGetIntfT)]);
  11793. Call.AddArg(Result);
  11794. Result:=Call;
  11795. Call.AddArg(CreateReferencePathExpr(Decl,AContext));
  11796. end;
  11797. else
  11798. RaiseNotSupported(El,AContext,20180416102614,InterfaceTypeNames[TPasClassType(Decl).InterfaceType]){%H-};
  11799. end;
  11800. exit; // bsObjectChecks not needed
  11801. end;
  11802. okInterface:;
  11803. else
  11804. RaiseNotSupported(El,AContext,20180327221233,ObjKindNames[TPasClassType(ParamTypeEl).ObjKind]);
  11805. end;
  11806. else
  11807. RaiseNotSupported(El,AContext,20180327221130,ObjKindNames[TPasClassType(Decl).ObjKind]);
  11808. end;
  11809. end;
  11810. if bsObjectChecks in AContext.ScannerBoolSwitches then
  11811. begin
  11812. if (C=TPasClassType)
  11813. or (C=TPasClassOfType) then
  11814. begin
  11815. // TObject(param) -> rtl.asExt(param,type,mode)
  11816. if C=TPasClassOfType then
  11817. aClassTypeEl:=aResolver.ResolveAliasType(TPasClassOfType(Decl).DestType) as TPasClassType
  11818. else
  11819. aClassTypeEl:=TPasClassType(Decl);
  11820. aName:=CreateReferencePath(aClassTypeEl,AContext,rpkPathAndName);
  11821. Call:=CreateCallExpression(El);
  11822. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnAsExt)]);
  11823. Call.AddArg(Result);
  11824. Call.AddArg(CreatePrimitiveDotExpr(aName,Value));
  11825. if aClassTypeEl.IsExternal then
  11826. else if C=TPasClassOfType then
  11827. Call.AddArg(CreateLiteralNumber(Value,IsExtModePasClass))
  11828. else
  11829. Call.AddArg(CreateLiteralNumber(Value,IsExtModePasClassInstance));
  11830. Result:=Call;
  11831. end;
  11832. end
  11833. else if (ParamResolved.BaseType=btCustom)
  11834. and (ParamTypeEl.CustomData is TResElDataPas2JSBaseType) then
  11835. begin
  11836. JSBaseType:=TResElDataPas2JSBaseType(ParamTypeEl.CustomData).JSBaseType;
  11837. if JSBaseType=pbtJSValue then
  11838. begin
  11839. if ((C=TPasClassType) and not TPasClassType(Decl).IsExternal)
  11840. or (C=TPasClassOfType)
  11841. or (C=TPasRecordType) then
  11842. begin
  11843. // TObject(jsvalue) -> rtl.getObject(jsvalue)
  11844. Call:=CreateCallExpression(El);
  11845. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnGetObject)]);
  11846. Call.AddArg(Result);
  11847. Result:=Call;
  11848. end;
  11849. end;
  11850. end;
  11851. exit;
  11852. end
  11853. else if C.InheritsFrom(TPasVariable) then
  11854. begin
  11855. aResolver.ComputeElement(Decl,DeclResolved,[rcType]);
  11856. if DeclResolved.LoTypeEl is TPasProcedureType then
  11857. // e.g. OnClick()
  11858. TargetProcType:=TPasProcedureType(DeclResolved.LoTypeEl)
  11859. else
  11860. RaiseNotSupported(El,AContext,20170217115244);
  11861. end
  11862. else if (C=TPasArgument) then
  11863. begin
  11864. aResolver.ComputeElement(Decl,DeclResolved,[rcType]);
  11865. if DeclResolved.LoTypeEl is TPasProcedureType then
  11866. TargetProcType:=TPasProcedureType(DeclResolved.LoTypeEl)
  11867. else
  11868. RaiseNotSupported(El,AContext,20170328224020);
  11869. end
  11870. else if (C=TPasProcedureType)
  11871. or (C=TPasFunctionType) then
  11872. begin
  11873. aResolver.ComputeElement(Value,ValueResolved,[rcNoImplicitProc]);
  11874. if (ValueResolved.IdentEl is TPasType)
  11875. and (aResolver.ResolveAliasType(TPasType(ValueResolved.IdentEl)) is TPasProcedureType) then
  11876. begin
  11877. // type cast to proc type
  11878. Param:=El.Params[0];
  11879. Result:=ConvertExpression(Param,AContext);
  11880. exit;
  11881. end
  11882. else
  11883. begin
  11884. // calling proc var
  11885. TargetProcType:=TPasProcedureType(Decl);
  11886. end;
  11887. end
  11888. else
  11889. begin
  11890. {$IFDEF VerbosePas2JS}
  11891. writeln('TPasToJSConverter.ConvertFuncParams El=',GetObjName(El),' Decl=',GetObjName(Decl));
  11892. {$ENDIF}
  11893. RaiseNotSupported(El,AContext,20170215114337);
  11894. end;
  11895. if [rrfNewInstance,rrfFreeInstance]*Ref.Flags<>[] then
  11896. begin
  11897. // call constructor, destructor
  11898. CreateFreeOrNewInstanceCall(Ref);
  11899. end;
  11900. end;
  11901. // BEWARE: TargetProcType can be nil, if called without resolver
  11902. NeedIntfRef:=false;
  11903. if (TargetProcType is TPasFunctionType) and (aResolver<>nil) then
  11904. begin
  11905. if aResolver.IsManagedJSType(TPasFunctionType(TargetProcType).ResultEl.ResultType)
  11906. and not TargetProcType.IsAsync then
  11907. begin
  11908. // when part of an expression use $ir.ref
  11909. // ToDo: if proc call, i.e. result is not used, use rtl._release()
  11910. NeedIntfRef:=true;
  11911. end;
  11912. end;
  11913. if Call=nil then
  11914. begin
  11915. Call:=CreateCallExpression(El);
  11916. Elements:=Call.Args.Elements;
  11917. end;
  11918. OldAccess:=AContext.Access;
  11919. try
  11920. AContext.Access:=caRead;
  11921. if Call.Args=nil then
  11922. begin
  11923. // append ()
  11924. Call.Args:=TJSArguments(CreateElement(TJSArguments,El));
  11925. Elements:=Call.Args.Elements;
  11926. end
  11927. else if Elements=nil then
  11928. RaiseInconsistency(20180720154413,El);
  11929. if Call.Expr=nil then
  11930. begin
  11931. if (coShortRefGlobals in Options)
  11932. and aResolver.IsSpecializedNonStaticMethod(TargetProcType) then
  11933. CreateShortRefApply(Value,TargetProcType)
  11934. else if DotBin<>nil then
  11935. Call.Expr:=ConvertSubIdentExprCustom(DotBin,AContext)
  11936. else
  11937. Call.Expr:=ConvertExpression(Value,AContext);
  11938. end;
  11939. //if Call.Expr is TPrimitiveExpr then
  11940. // writeln('TPasToJSConverter.ConvertFuncParams ',TPrimitiveExpr(Call.Expr).GetDeclaration(true));
  11941. CreateProcedureCallArgs(Elements,El,TargetProcType,AContext);
  11942. CallArgs:=Call.Args;
  11943. if (Elements.Count=0)
  11944. and (CallArgs.Elements.Count>0) then
  11945. begin
  11946. // for example: rrfNewInstance
  11947. LastArg:=CallArgs.Elements[CallArgs.Elements.Count-1];
  11948. if not (LastArg.Expr is TJSArrayLiteral) then
  11949. RaiseNotSupported(El,AContext,20180720161317);
  11950. JsArrLit:=TJSArrayLiteral(LastArg.Expr);
  11951. if JsArrLit.Elements<>Elements then
  11952. RaiseNotSupported(El,AContext,20180720161324);
  11953. LastArg.Free;
  11954. end;
  11955. if CallArgs.Elements.Count=0 then
  11956. begin
  11957. CallArgs.Free;
  11958. Call.Args:=nil;
  11959. end;
  11960. if NeedIntfRef then
  11961. // $ir.ref(id,path.fnname())
  11962. Call:=CreateIntfRef(Call,AContext,El);
  11963. Result:=Call;
  11964. finally
  11965. AContext.Access:=OldAccess;
  11966. if Result=nil then
  11967. Call.Free;
  11968. end;
  11969. end;
  11970. function TPasToJSConverter.ConvertExternalConstructor(Left: TPasExpr;
  11971. Ref: TResolvedReference; ParamsExpr: TParamsExpr; AContext: TConvertContext
  11972. ): TJSElement;
  11973. var
  11974. Proc: TPasConstructor;
  11975. ExtName: String;
  11976. NewExpr: TJSNewMemberExpression;
  11977. LeftResolved: TPasResolverResult;
  11978. OldAccess: TCtxAccess;
  11979. ExtNameEl: TJSElement;
  11980. WithData: TPas2JSWithExprScope;
  11981. PosEl: TPasElement;
  11982. aResolver: TPas2JSResolver;
  11983. begin
  11984. Result:=nil;
  11985. aResolver:=AContext.Resolver;
  11986. NewExpr:=nil;
  11987. ExtName:='';
  11988. ExtNameEl:=nil;
  11989. try
  11990. Proc:=Ref.Declaration as TPasConstructor;
  11991. PosEl:=Ref.Element;
  11992. if CompareText(Proc.Name,'new')=0 then
  11993. begin
  11994. if Proc.LibrarySymbolName<>nil then
  11995. begin
  11996. ExtName:=ComputeConstString(Proc.LibrarySymbolName,AContext,true);
  11997. if not SameText(ExtName,'new') then
  11998. ExtNameEl:=CreatePrimitiveDotExpr(ExtName,PosEl);
  11999. end;
  12000. if (ExtNameEl=nil) and (Left<>nil) then
  12001. begin
  12002. if aResolver<>nil then
  12003. begin
  12004. aResolver.ComputeElement(Left,LeftResolved,[]);
  12005. if LeftResolved.BaseType=btModule then
  12006. begin
  12007. // e.g. Unit.TExtA
  12008. // ExtName is global -> omit unit
  12009. Left:=nil;
  12010. end
  12011. else ;
  12012. end;
  12013. if Left<>nil then
  12014. begin
  12015. // convert left side
  12016. OldAccess:=AContext.Access;
  12017. AContext.Access:=caRead;
  12018. ExtNameEl:=ConvertExpression(Left,AContext);
  12019. AContext.Access:=OldAccess;
  12020. end;
  12021. end;
  12022. if ExtNameEl=nil then
  12023. begin
  12024. if Ref.WithExprScope<>nil then
  12025. begin
  12026. // using local WITH var
  12027. WithData:=Ref.WithExprScope as TPas2JSWithExprScope;
  12028. ExtName:=WithData.WithVarName;
  12029. if ExtName='' then
  12030. RaiseNotSupported(ParamsExpr,AContext,20190209092049);
  12031. end
  12032. else
  12033. // use external class name
  12034. ExtName:=(Proc.Parent as TPasClassType).ExternalName;
  12035. if ExtName='' then
  12036. DoError(20180511163944,nJSNewNotSupported,sJSNewNotSupported,[],ParamsExpr);
  12037. ExtNameEl:=CreatePrimitiveDotExpr(ExtName,PosEl);
  12038. end;
  12039. end
  12040. else
  12041. begin
  12042. // external constructor ProcName
  12043. ExtName:='';
  12044. if aResolver<>nil then
  12045. ExtName:=aResolver.ComputeConstString(Proc.LibrarySymbolName,true,true);
  12046. if ExtName='{}' then
  12047. begin
  12048. // external constructor {} -> "{}"
  12049. Result:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,PosEl));
  12050. exit;
  12051. end;
  12052. // external constructor ProcName -> "new ExtA.ProcName()"
  12053. ExtNameEl:=CreateReferencePathExpr(Proc,AContext,true);
  12054. end;
  12055. NewExpr:=TJSNewMemberExpression(CreateElement(TJSNewMemberExpression,PosEl));
  12056. NewExpr.MExpr:=ExtNameEl;
  12057. ExtNameEl:=nil;
  12058. NewExpr.Args:=TJSArguments(CreateElement(TJSArguments,PosEl));
  12059. if ParamsExpr<>nil then
  12060. CreateProcedureCallArgs(NewExpr.Args.Elements,ParamsExpr,Proc.ProcType,AContext);
  12061. Result:=NewExpr;
  12062. NewExpr:=nil;
  12063. finally
  12064. ExtNameEl.Free;
  12065. NewExpr.Free;
  12066. end;
  12067. end;
  12068. function TPasToJSConverter.ConvertTObjectFree_Bin(Bin: TBinaryExpr;
  12069. NameExpr: TPasExpr; AContext: TConvertContext): TJSElement;
  12070. function CreateCallRTLFree(Obj, Prop: TJSElement): TJSElement;
  12071. // create "rtl.free(obj,prop)"
  12072. var
  12073. Call: TJSCallExpression;
  12074. begin
  12075. Call:=CreateCallExpression(Bin.right);
  12076. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnFreeVar)]);
  12077. Call.Args.AddElement(Obj);
  12078. Call.Args.AddElement(Prop);
  12079. Result:=Call;
  12080. end;
  12081. var
  12082. LeftJS, Obj, Prop, Getter, Setter: TJSElement;
  12083. DotExpr: TJSDotMemberExpression;
  12084. BracketJS: TJSBracketMemberExpression;
  12085. aName: TJSString;
  12086. Call: TJSCallExpression;
  12087. AssignContext: TAssignContext;
  12088. begin
  12089. Result:=nil;
  12090. LeftJS:=ConvertExpression(Bin.left,AContext);
  12091. try
  12092. {$IFDEF VerbosePas2JS}
  12093. writeln('TPasToJSConverter.ConvertTObjectFree_Bin ',GetObjName(LeftJS));
  12094. {$ENDIF}
  12095. if LeftJS is TJSPrimaryExpressionIdent then
  12096. begin
  12097. aName:=TJSPrimaryExpressionIdent(LeftJS).Name;
  12098. if Pos('.',aName)>0 then
  12099. RaiseInconsistency(20170516173832,Bin.left);
  12100. // v.free
  12101. // -> v=rtl.freeLoc(v);
  12102. Getter:=LeftJS;
  12103. Setter:=ClonePrimaryExpression(TJSPrimaryExpressionIdent(LeftJS),Bin.left);
  12104. Result:=CreateCallRTLFreeLoc(Setter,Getter,NameExpr);
  12105. end
  12106. else if LeftJS is TJSDotMemberExpression then
  12107. begin
  12108. // obj.prop.free
  12109. // -> rtl.free(obj,"prop");
  12110. DotExpr:=TJSDotMemberExpression(LeftJS);
  12111. Obj:=DotExpr.MExpr;
  12112. DotExpr.MExpr:=nil;
  12113. Prop:=CreateLiteralJSString(Bin.right,DotExpr.Name);
  12114. FreeAndNil(LeftJS);
  12115. Result:=CreateCallRTLFree(Obj,Prop);
  12116. end
  12117. else if LeftJS is TJSBracketMemberExpression then
  12118. begin
  12119. // obj[prop].free
  12120. // -> rtl.free(obj,prop);
  12121. BracketJS:=TJSBracketMemberExpression(LeftJS);
  12122. Obj:=BracketJS.MExpr;
  12123. BracketJS.MExpr:=nil;
  12124. Prop:=BracketJS.Name;
  12125. BracketJS.Name:=nil;
  12126. FreeAndNil(LeftJS);
  12127. Result:=CreateCallRTLFree(Obj,Prop);
  12128. end
  12129. else if LeftJS is TJSCallExpression then
  12130. begin
  12131. // getter().free
  12132. // -> setter(rtl.freeLoc(getter()))
  12133. AssignContext:=TAssignContext.Create(Bin.Left,nil,AContext);
  12134. try
  12135. Call:=CreateCallExpression(Bin.Left);
  12136. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnFreeLocalVar)]);
  12137. Call.Args.AddElement(LeftJS);
  12138. LeftJS:=nil;
  12139. AssignContext.RightSide:=Call;
  12140. AContext.Resolver.ComputeElement(Bin.Left,AssignContext.LeftResolved,[rcNoImplicitProc]);
  12141. AssignContext.RightResolved:=AssignContext.LeftResolved;
  12142. Result:=CreateAssignStatement(Bin.Left,AssignContext);
  12143. finally
  12144. AssignContext.RightSide.Free;
  12145. AssignContext.Free;
  12146. end;
  12147. end
  12148. else
  12149. begin
  12150. {$IFDEF VerbosePas2JS}
  12151. writeln('TPasToJSConverter.ConvertTObjectFree_Bin ',GetObjName(LeftJS));
  12152. {$ENDIF}
  12153. RaiseNotSupported(Bin.left,AContext,20170516164659,'invalid scope for Free');
  12154. end;
  12155. finally
  12156. if Result=nil then
  12157. LeftJS.Free;
  12158. end;
  12159. end;
  12160. function TPasToJSConverter.ConvertTObjectFree_With(NameExpr: TPasExpr;
  12161. AContext: TConvertContext): TJSElement;
  12162. var
  12163. WithExprScope: TPas2JSWithExprScope;
  12164. Getter, Setter: TJSElement;
  12165. begin
  12166. Result:=nil;
  12167. WithExprScope:=TResolvedReference(NameExpr.CustomData).WithExprScope as TPas2JSWithExprScope;
  12168. if WithExprScope=nil then
  12169. RaiseInconsistency(20181027133210,NameExpr);
  12170. if AContext.Resolver.GetNewInstanceExpr(WithExprScope.Expr)<>nil then
  12171. begin
  12172. // "with TSomeClass.Create do Free"
  12173. // -> "$with1=rtl.freeLoc($with1);
  12174. if WithExprScope.WithVarName='' then
  12175. RaiseNotSupported(NameExpr,AContext,20190209092220);
  12176. Getter:=CreatePrimitiveDotExpr(WithExprScope.WithVarName,WithExprScope.Expr);
  12177. Setter:=CreatePrimitiveDotExpr(WithExprScope.WithVarName,WithExprScope.Expr);
  12178. Result:=CreateCallRTLFreeLoc(Setter,Getter,NameExpr);
  12179. exit;
  12180. end;
  12181. {$IFDEF VerbosePas2JS}
  12182. writeln('TPasToJSConverter.ConvertTObjectFree_With With=',GetObjName(WithExprScope.Expr));
  12183. {$ENDIF}
  12184. RaiseInconsistency(20170517092248,NameExpr);
  12185. end;
  12186. function TPasToJSConverter.ConvertTypeCastToBaseType(El: TParamsExpr;
  12187. AContext: TConvertContext; ToBaseTypeData: TResElDataBaseType): TJSElement;
  12188. var
  12189. to_bt: TResolverBaseType;
  12190. Param: TPasExpr;
  12191. ParamResolved: TPasResolverResult;
  12192. JSBaseType: TPas2jsBaseType;
  12193. JSBaseTypeData: TResElDataPas2JSBaseType;
  12194. function IsParamPas2JSBaseType: boolean;
  12195. var
  12196. TypeEl: TPasType;
  12197. begin
  12198. if ParamResolved.BaseType<>btCustom then exit(false);
  12199. TypeEl:=ParamResolved.LoTypeEl;
  12200. if TypeEl.ClassType<>TPasUnresolvedSymbolRef then exit(false);
  12201. if not (TypeEl.CustomData is TResElDataPas2JSBaseType) then exit(false);
  12202. Result:=true;
  12203. JSBaseTypeData:=TResElDataPas2JSBaseType(TypeEl.CustomData);
  12204. JSBaseType:=JSBaseTypeData.JSBaseType;
  12205. end;
  12206. var
  12207. NotEqual: TJSEqualityExpressionNE;
  12208. CondExpr: TJSConditionalExpression;
  12209. Call: TJSCallExpression;
  12210. NotExpr: TJSUnaryNotExpression;
  12211. AddExpr: TJSAdditiveExpressionPlus;
  12212. Int: TMaxPrecInt;
  12213. aResolver: TPas2JSResolver;
  12214. from_bt: TResolverBaseType;
  12215. FromTypeEl: TPasType;
  12216. ElTypeResolved: TPasResolverResult;
  12217. begin
  12218. Result:=nil;
  12219. Param:=El.Params[0];
  12220. aResolver:=AContext.Resolver;
  12221. aResolver.ComputeElement(Param,ParamResolved,[]);
  12222. JSBaseTypeData:=nil;
  12223. JSBaseType:=pbtNone;
  12224. from_bt:=ParamResolved.BaseType;
  12225. FromTypeEl:=ParamResolved.LoTypeEl;
  12226. if from_bt=btRange then
  12227. begin
  12228. from_bt:=ParamResolved.SubType;
  12229. aResolver.ComputeElement(TPasRangeType(FromTypeEl).RangeExpr.left,ElTypeResolved,[rcConstant]);
  12230. FromTypeEl:=ElTypeResolved.LoTypeEl;
  12231. end;
  12232. to_bt:=ToBaseTypeData.BaseType;
  12233. if from_bt=to_bt then
  12234. begin
  12235. Result:=ConvertExpression(Param,AContext);
  12236. exit;
  12237. end;
  12238. if to_bt in btAllJSInteger then
  12239. begin
  12240. if from_bt in btAllJSInteger then
  12241. begin
  12242. // integer to integer -> value
  12243. Result:=ConvertExpression(Param,AContext);
  12244. Result:=ConvertIntToInt(Result,from_bt,to_bt,El,AContext);
  12245. exit;
  12246. end
  12247. else if from_bt in btAllJSBooleans then
  12248. begin
  12249. // boolean to integer -> value?1:0
  12250. Result:=ConvertExpression(Param,AContext);
  12251. // Note: convert Param first in case it raises an exception
  12252. CondExpr:=TJSConditionalExpression(CreateElement(TJSConditionalExpression,El));
  12253. CondExpr.A:=Result;
  12254. if to_bt=btCurrency then
  12255. CondExpr.B:=CreateLiteralNumber(El,10000)
  12256. else
  12257. CondExpr.B:=CreateLiteralNumber(El,1);
  12258. CondExpr.C:=CreateLiteralNumber(El,0);
  12259. Result:=CondExpr;
  12260. exit;
  12261. end
  12262. else if from_bt in btAllJSChars then
  12263. begin
  12264. // char to integer
  12265. Result:=ConvertExpression(Param,AContext);
  12266. Result:=ConvertCharToInt(Result,El,AContext);
  12267. Result:=ConvertIntToInt(Result,btWord,to_bt,El,AContext);
  12268. exit;
  12269. end
  12270. else if from_bt=btContext then
  12271. begin
  12272. if FromTypeEl.ClassType=TPasEnumType then
  12273. begin
  12274. // e.g. longint(TEnum) -> value
  12275. Result:=ConvertExpression(Param,AContext);
  12276. if to_bt=btCurrency then
  12277. // value*10000
  12278. Result:=CreateMulNumber(Param,Result,10000);
  12279. exit;
  12280. end;
  12281. end
  12282. else if IsParamPas2JSBaseType then
  12283. begin
  12284. if JSBaseType=pbtJSValue then
  12285. begin
  12286. // convert jsvalue to integer -> rtl.trunc(value)
  12287. Result:=ConvertExpression(Param,AContext);
  12288. // Note: convert Param first in case it raises an exception
  12289. if to_bt=btCurrency then
  12290. // jsvalue to currency -> rtl.trunc(value*10000)
  12291. Result:=CreateMulNumber(Param,Result,10000);
  12292. Result:=CreateTruncFloor(El,Result,true);
  12293. exit;
  12294. end;
  12295. end
  12296. else if (to_bt=btCurrency) and (from_bt in btAllJSFloats) then
  12297. begin
  12298. // currency(double) -> double*10000
  12299. Result:=ConvertExpression(Param,AContext);
  12300. Result:=CreateMulNumber(Param,Result,10000);
  12301. exit;
  12302. end;
  12303. end
  12304. else if to_bt in btAllJSBooleans then
  12305. begin
  12306. if from_bt in btAllJSBooleans then
  12307. begin
  12308. // boolean to boolean -> value
  12309. Result:=ConvertExpression(Param,AContext);
  12310. exit;
  12311. end
  12312. else if from_bt in btAllJSInteger then
  12313. begin
  12314. // integer to boolean -> value!=0
  12315. Result:=ConvertExpression(Param,AContext);
  12316. // Note: convert Param first in case it raises an exception
  12317. NotEqual:=TJSEqualityExpressionNE(CreateElement(TJSEqualityExpressionNE,El));
  12318. NotEqual.A:=Result;
  12319. NotEqual.B:=CreateLiteralNumber(El,0);
  12320. Result:=NotEqual;
  12321. exit;
  12322. end
  12323. else if IsParamPas2JSBaseType then
  12324. begin
  12325. if JSBaseType=pbtJSValue then
  12326. begin
  12327. // convert jsvalue to boolean -> !(value==false)
  12328. Result:=ConvertExpression(Param,AContext);
  12329. // Note: convert Param first in case it raises an exception
  12330. NotExpr:=TJSUnaryNotExpression(CreateElement(TJSUnaryNotExpression,El));
  12331. NotExpr.A:=TJSEqualityExpressionEQ(CreateElement(TJSEqualityExpressionEQ,El));
  12332. TJSEqualityExpressionEQ(NotExpr.A).A:=Result;
  12333. TJSEqualityExpressionEQ(NotExpr.A).B:=CreateLiteralBoolean(El,false);
  12334. Result:=NotExpr;
  12335. exit;
  12336. end;
  12337. end;
  12338. end
  12339. else if to_bt in btAllJSFloats then
  12340. begin
  12341. if from_bt in (btAllJSFloats+btAllJSInteger) then
  12342. begin
  12343. // int to double -> value
  12344. Result:=ConvertExpression(Param,AContext);
  12345. if ParamResolved.BaseType=btCurrency then
  12346. // currency to double -> value/10000
  12347. Result:=CreateDivideNumber(El,Result,10000);
  12348. exit;
  12349. end
  12350. else if IsParamPas2JSBaseType then
  12351. begin
  12352. if JSBaseType=pbtJSValue then
  12353. begin
  12354. // convert jsvalue to double -> rtl.getNumber(value)
  12355. Result:=ConvertExpression(Param,AContext);
  12356. // Note: convert Param first in case it raises an exception
  12357. Call:=CreateCallExpression(El);
  12358. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnGetNumber)]);
  12359. Call.AddArg(Result);
  12360. Result:=Call;
  12361. exit;
  12362. end;
  12363. end;
  12364. end
  12365. else if to_bt in btAllJSStrings then
  12366. begin
  12367. if from_bt in btAllJSStringAndChars then
  12368. begin
  12369. // string or char to string -> value
  12370. Result:=ConvertExpression(Param,AContext);
  12371. exit;
  12372. end
  12373. else if from_bt=btPointer then
  12374. begin
  12375. // string(aPointer) -> value
  12376. Result:=ConvertExpression(Param,AContext);
  12377. exit;
  12378. end
  12379. else if IsParamPas2JSBaseType then
  12380. begin
  12381. if JSBaseType=pbtJSValue then
  12382. begin
  12383. // convert jsvalue to string -> ""+value
  12384. Result:=ConvertExpression(Param,AContext);
  12385. // Note: convert value first in case it raises an exception
  12386. AddExpr:=TJSAdditiveExpressionPlus(CreateElement(TJSAdditiveExpressionPlus,El));
  12387. AddExpr.A:=CreateLiteralString(El,'');
  12388. AddExpr.B:=Result;
  12389. Result:=AddExpr;
  12390. exit;
  12391. end;
  12392. end;
  12393. end
  12394. else if to_bt in [btChar,btWideChar] then
  12395. begin
  12396. if from_bt in [btChar,btWideChar] then
  12397. begin
  12398. // char to char
  12399. Result:=ConvertExpression(Param,AContext);
  12400. exit;
  12401. end
  12402. else if (from_bt in btAllJSInteger)
  12403. or ((from_bt=btContext)
  12404. and (FromTypeEl.ClassType=TPasEnumType))
  12405. then
  12406. begin
  12407. // Note: convert value first in case it raises an exception
  12408. Result:=ConvertExpression(Param,AContext);
  12409. if IsLiteralInteger(Result,Int)
  12410. and (Int>=0) and (Int<=$ffff) then
  12411. begin
  12412. FreeAndNil(Result);
  12413. Result:=CreateLiteralJSString(Param,WideChar(Int));
  12414. end
  12415. else
  12416. begin
  12417. // char(integer) -> String.fromCharCode(integer)
  12418. Result:=CreateCallFromCharCode(Result,El);
  12419. end;
  12420. exit;
  12421. end
  12422. else if (from_bt in (btArrayRangeTypes+[btRange]))
  12423. or (IsParamPas2JSBaseType and (JSBaseType=pbtJSValue)) then
  12424. begin
  12425. // convert value to char -> rtl.getChar(value)
  12426. // Note: convert value first in case it raises an exception
  12427. Result:=ConvertExpression(Param,AContext);
  12428. if IsLiteralInteger(Result,Int) then
  12429. begin
  12430. if (Int>=0) and (Int<=$ffff) then
  12431. begin
  12432. FreeAndNil(Result);
  12433. Result:=CreateLiteralJSString(Param,WideChar(Int));
  12434. end
  12435. else
  12436. begin
  12437. // char(integer) -> String.fromCharCode(integer)
  12438. Result:=CreateCallFromCharCode(Result,El);
  12439. end;
  12440. end
  12441. else
  12442. begin
  12443. // convert value to char -> rtl.getChar(value)
  12444. Call:=CreateCallExpression(El);
  12445. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnGetChar)]);
  12446. Call.AddArg(Result);
  12447. Result:=Call;
  12448. end;
  12449. exit;
  12450. end;
  12451. end
  12452. else if to_bt=btPointer then
  12453. begin
  12454. if IsParamPas2JSBaseType then
  12455. begin
  12456. if JSBaseType=pbtJSValue then
  12457. begin
  12458. // convert jsvalue to pointer -> value
  12459. Result:=ConvertExpression(Param,AContext);
  12460. exit;
  12461. end;
  12462. end
  12463. else if from_bt in btAllJSStrings then
  12464. begin
  12465. // pointer(aString) -> value
  12466. Result:=ConvertExpression(Param,AContext);
  12467. exit;
  12468. end
  12469. else if from_bt=btContext then
  12470. begin
  12471. // convert user type/value to pointer -> value
  12472. Result:=ConvertExpression(Param,AContext);
  12473. exit;
  12474. end;
  12475. end
  12476. else if (to_bt=btCustom) and (ToBaseTypeData is TResElDataPas2JSBaseType) then
  12477. begin
  12478. JSBaseType:=TResElDataPas2JSBaseType(ToBaseTypeData).JSBaseType;
  12479. if JSBaseType=pbtJSValue then
  12480. begin
  12481. // type cast to jsvalue
  12482. Result:=ConvertExpression(Param,AContext);
  12483. exit;
  12484. end;
  12485. end;
  12486. {$IFDEF VerbosePas2JS}
  12487. writeln('TPasToJSConverter.ConvertTypeCastToBaseType BaseTypeData=',aResolver.BaseTypeNames[to_bt],' ParamResolved=',GetResolverResultDbg(ParamResolved));
  12488. {$ENDIF}
  12489. RaiseNotSupported(El,AContext,20170325161150);
  12490. end;
  12491. function TPasToJSConverter.ConvertArrayOrSetLiteral(El: TParamsExpr;
  12492. AContext: TConvertContext): TJSElement;
  12493. var
  12494. Call: TJSCallExpression;
  12495. ArgContext: TConvertContext;
  12496. procedure AddArg(Expr: TPasExpr);
  12497. begin
  12498. Call.AddArg(CreateSetLiteralElement(Expr,ArgContext));
  12499. end;
  12500. var
  12501. i: Integer;
  12502. ArgEl: TPasExpr;
  12503. aResolver: TPas2JSResolver;
  12504. ArrayType: TPasArrayType;
  12505. begin
  12506. if El.Kind<>pekSet then
  12507. RaiseInconsistency(20170209112737,El);
  12508. if AContext.Access<>caRead then
  12509. DoError(20170209112926,nCantWriteSetLiteral,sCantWriteSetLiteral,[],El);
  12510. aResolver:=AContext.Resolver;
  12511. if aResolver<>nil then
  12512. begin
  12513. ArrayType:=aResolver.IsArrayExpr(El);
  12514. if ArrayType<>nil then
  12515. begin
  12516. // array literal
  12517. Result:=CreateArrayInit(ArrayType,El,El,AContext);
  12518. exit;
  12519. end;
  12520. end;
  12521. // create set literal
  12522. if length(El.Params)=0 then
  12523. Result:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,El))
  12524. else
  12525. begin
  12526. Result:=nil;
  12527. ArgContext:=AContext.GetNonDotContext;
  12528. Call:=CreateCallExpression(El);
  12529. try
  12530. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnSet_Create)]);
  12531. for i:=0 to length(El.Params)-1 do
  12532. begin
  12533. ArgEl:=El.Params[i];
  12534. {$IFDEF VerbosePas2JS}
  12535. writeln('TPasToJSConverter.ConvertSetLiteral ',i,' El.Params[i]=',GetObjName(ArgEl));
  12536. {$ENDIF}
  12537. if (ArgEl.ClassType=TBinaryExpr) and (TBinaryExpr(ArgEl).Kind=pekRange) then
  12538. begin
  12539. // range -> add three parameters: null,left,right
  12540. Call.AddArg(CreateLiteralNull(ArgEl));
  12541. AddArg(TBinaryExpr(ArgEl).left);
  12542. AddArg(TBinaryExpr(ArgEl).right);
  12543. end
  12544. else
  12545. AddArg(ArgEl);
  12546. end;
  12547. Result:=Call;
  12548. finally
  12549. if Result=nil then
  12550. Call.Free;
  12551. end;
  12552. end;
  12553. end;
  12554. function TPasToJSConverter.ConvertBuiltIn_Length(El: TParamsExpr;
  12555. AContext: TConvertContext): TJSElement;
  12556. var
  12557. Arg: TJSElement;
  12558. Param, RangeEl: TPasExpr;
  12559. ParamResolved: TPasResolverResult;
  12560. Ranges: TPasExprArray;
  12561. Call: TJSCallExpression;
  12562. RgLen: TMaxPrecInt;
  12563. begin
  12564. Result:=nil;
  12565. Param:=El.Params[0];
  12566. AContext.Resolver.ComputeElement(Param,ParamResolved,[]);
  12567. if ParamResolved.BaseType=btContext then
  12568. begin
  12569. if ParamResolved.LoTypeEl is TPasArrayType then
  12570. begin
  12571. Ranges:=TPasArrayType(ParamResolved.LoTypeEl).Ranges;
  12572. if length(Ranges)>0 then
  12573. begin
  12574. // static array -> number literal
  12575. if length(Ranges)>1 then
  12576. RaiseNotSupported(El,AContext,20170223131042);
  12577. RangeEl:=Ranges[0];
  12578. RgLen:=AContext.Resolver.GetRangeLength(RangeEl);
  12579. Result:=CreateLiteralNumber(El,RgLen);
  12580. exit;
  12581. end
  12582. else
  12583. begin
  12584. // dynamic array -> rtl.length(array)
  12585. Result:=ConvertExpression(El.Params[0],AContext);
  12586. // Note: convert param first, it may raise an exception
  12587. Call:=CreateCallExpression(El);
  12588. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnArray_Length)]);
  12589. Call.AddArg(Result);
  12590. Result:=Call;
  12591. exit;
  12592. end;
  12593. end;
  12594. end;
  12595. // default: Param.length
  12596. Arg:=ConvertExpression(Param,AContext);
  12597. Result:=CreateDotNameExpr(El,Arg,'length');
  12598. end;
  12599. function TPasToJSConverter.ConvertBuiltIn_SetLength(El: TParamsExpr;
  12600. AContext: TConvertContext): TJSElement;
  12601. // convert "SetLength(a,Len)" to "a = rtl.arraySetLength(a,Len)"
  12602. var
  12603. Param0, Range: TPasExpr;
  12604. ResolvedParam0, RangeResolved: TPasResolverResult;
  12605. ArrayType: TPasArrayType;
  12606. Call: TJSCallExpression;
  12607. ValInit: TJSElement;
  12608. AssignContext: TAssignContext;
  12609. ElType, TypeEl: TPasType;
  12610. i: Integer;
  12611. aResolver: TPas2JSResolver;
  12612. DimSize: TMaxPrecInt;
  12613. StaticDims: TObjectList;
  12614. Lit: TJSLiteral;
  12615. ArrScope: TPas2JSArrayScope;
  12616. aManaged: Boolean;
  12617. begin
  12618. Result:=nil;
  12619. Param0:=El.Params[0];
  12620. if AContext.Access<>caRead then
  12621. RaiseInconsistency(20170213213621,El);
  12622. aResolver:=AContext.Resolver;
  12623. aResolver.ComputeElement(Param0,ResolvedParam0,[rcNoImplicitProc]);
  12624. {$IFDEF VerbosePasResolver}
  12625. writeln('TPasToJSConverter.ConvertBuiltInSetLength ',GetResolverResultDbg(ResolvedParam0));
  12626. {$ENDIF}
  12627. TypeEl:=ResolvedParam0.LoTypeEl;
  12628. if TypeEl is TPasArrayType then
  12629. begin
  12630. // SetLength(AnArray,dim1,dim2,...)
  12631. ArrayType:=TPasArrayType(TypeEl);
  12632. {$IFDEF VerbosePasResolver}
  12633. writeln('TPasToJSConverter.ConvertBuiltInSetLength array');
  12634. {$ENDIF}
  12635. // -> AnArray = rtl.setArrayLength(AnArray,defaultvalue,dim1,dim2,...)
  12636. AssignContext:=TAssignContext.Create(El,nil,AContext);
  12637. StaticDims:=nil;
  12638. try
  12639. aResolver.ComputeElement(Param0,AssignContext.LeftResolved,[rcNoImplicitProc]);
  12640. AssignContext.RightResolved:=ResolvedParam0;
  12641. // create right side
  12642. // rtl.setArrayLength()
  12643. Call:=CreateCallExpression(El);
  12644. AssignContext.RightSide:=Call;
  12645. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnArray_SetLength)]);
  12646. // 1st param: AnArray
  12647. Call.AddArg(ConvertExpression(Param0,AContext));
  12648. // 2nd param: default value
  12649. for i:=3 to length(El.Params) do
  12650. begin
  12651. ElType:=aResolver.ResolveAliasType(aResolver.GetArrayElType(ArrayType));
  12652. ArrayType:=ElType as TPasArrayType;
  12653. end;
  12654. ArrScope:=ArrayType.CustomData as TPas2JSArrayScope;
  12655. aManaged:=(ArrScope<>nil) and ArrScope.Managed;
  12656. ElType:=aResolver.ResolveAliasType(aResolver.GetArrayElType(ArrayType));
  12657. while (ElType.ClassType=TPasArrayType) and (length(TPasArrayType(ElType).Ranges)>0) do
  12658. begin
  12659. // array of static array, Note: setlength reallocs static arrays
  12660. ArrayType:=ElType as TPasArrayType;
  12661. for i:=0 to length(ArrayType.Ranges)-1 do
  12662. begin
  12663. Range:=ArrayType.Ranges[i];
  12664. // compute size of this dimension
  12665. DimSize:=aResolver.GetRangeLength(Range);
  12666. if DimSize=0 then
  12667. begin
  12668. aResolver.ComputeElement(Range,RangeResolved,[rcConstant]);
  12669. RaiseNotSupported(Range,AContext,20190614171520,GetResolverResultDbg(RangeResolved));
  12670. end;
  12671. Lit:=CreateLiteralNumber(El,DimSize);
  12672. if StaticDims=nil then
  12673. StaticDims:=TObjectList.Create(true);
  12674. StaticDims.Add(Lit);
  12675. end;
  12676. ElType:=aResolver.ResolveAliasType(aResolver.GetArrayElType(ArrayType));
  12677. end;
  12678. if ElType.ClassType=TPasRecordType then
  12679. ValInit:=CreateReferencePathExpr(ElType,AContext)
  12680. else if aManaged then
  12681. ValInit:=CreateLiteralJSString(Param0,TJSString(GetBIName(pbivnIntfRefCnt)))
  12682. else
  12683. ValInit:=CreateValInit(ElType,nil,Param0,AContext);
  12684. Call.AddArg(ValInit);
  12685. // add params: dim1, dim2, ...
  12686. for i:=1 to length(El.Params)-1 do
  12687. Call.AddArg(ConvertExpression(El.Params[i],AContext));
  12688. if StaticDims<>nil then
  12689. begin
  12690. Call.AddArg(CreateLiteralJSString(El,'s'));
  12691. for i:=0 to StaticDims.Count-1 do
  12692. Call.AddArg(TJSElement(StaticDims[i]));
  12693. StaticDims.OwnsObjects:=false;
  12694. end;
  12695. // create left side: array =
  12696. Result:=CreateAssignStatement(Param0,AssignContext);
  12697. finally
  12698. AssignContext.RightSide.Free;
  12699. AssignContext.Free;
  12700. StaticDims.Free;
  12701. end;
  12702. end
  12703. else if ResolvedParam0.BaseType in btAllJSStrings then
  12704. begin
  12705. // convert "SetLength(astring,NewLen);" to "astring = rtl.strSetLength(astring,NewLen);"
  12706. {$IFDEF VerbosePasResolver}
  12707. writeln('TPasToJSConverter.ConvertBuiltInSetLength string');
  12708. {$ENDIF}
  12709. AssignContext:=TAssignContext.Create(El,nil,AContext);
  12710. try
  12711. aResolver.ComputeElement(Param0,AssignContext.LeftResolved,[rcNoImplicitProc]);
  12712. AssignContext.RightResolved:=AssignContext.LeftResolved;
  12713. // create right side rtl.strSetLength(aString,NewLen)
  12714. Call:=CreateCallExpression(El);
  12715. AssignContext.RightSide:=Call;
  12716. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnStringSetLength)]);
  12717. Call.AddArg(ConvertExpression(Param0,AContext));
  12718. Call.AddArg(ConvertExpression(El.Params[1],AContext));
  12719. Result:=CreateAssignStatement(Param0,AssignContext);
  12720. finally
  12721. AssignContext.RightSide.Free;
  12722. AssignContext.Free;
  12723. end;
  12724. end
  12725. else
  12726. RaiseNotSupported(El.Value,AContext,20170130141026,'setlength '+GetResolverResultDbg(ResolvedParam0));
  12727. end;
  12728. function TPasToJSConverter.ConvertBuiltIn_ExcludeInclude(El: TParamsExpr;
  12729. AContext: TConvertContext; IsInclude: boolean): TJSElement;
  12730. // convert "Include(aSet,Enum)" to "aSet=rtl.includeSet(aSet,Enum)"
  12731. var
  12732. Call: TJSCallExpression;
  12733. Param0: TPasExpr;
  12734. AssignContext: TAssignContext;
  12735. FunName: String;
  12736. begin
  12737. Result:=nil;
  12738. Param0:=El.Params[0];
  12739. AssignContext:=TAssignContext.Create(El,nil,AContext);
  12740. try
  12741. AContext.Resolver.ComputeElement(Param0,AssignContext.LeftResolved,[rcNoImplicitProc]);
  12742. AssignContext.RightResolved:=AssignContext.LeftResolved;
  12743. // create right side rtl.includeSet(aSet,Enum)
  12744. Call:=CreateCallExpression(El);
  12745. AssignContext.RightSide:=Call;
  12746. if IsInclude then
  12747. FunName:=GetBIName(pbifnSet_Include)
  12748. else
  12749. FunName:=GetBIName(pbifnSet_Exclude);
  12750. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),FunName]);
  12751. Call.AddArg(ConvertExpression(Param0,AContext));
  12752. Call.AddArg(ConvertExpression(El.Params[1],AContext));
  12753. Result:=CreateAssignStatement(Param0,AssignContext);
  12754. finally
  12755. AssignContext.RightSide.Free;
  12756. AssignContext.Free;
  12757. end;
  12758. end;
  12759. function TPasToJSConverter.ConvertBuiltInContinue(El: TPasExpr;
  12760. AContext: TConvertContext): TJSElement;
  12761. begin
  12762. if AContext=nil then;
  12763. Result:=TJSContinueStatement(CreateElement(TJSContinueStatement,El));
  12764. end;
  12765. function TPasToJSConverter.ConvertBuiltInBreak(El: TPasExpr;
  12766. AContext: TConvertContext): TJSElement;
  12767. begin
  12768. if AContext=nil then;
  12769. Result:=TJSBreakStatement(CreateElement(TJSBreakStatement,El));
  12770. end;
  12771. function TPasToJSConverter.ConvertBuiltIn_Exit(El: TPasExpr;
  12772. AContext: TConvertContext): TJSElement;
  12773. // convert "exit;" -> in a function: "return result;" in a procedure: "return;"
  12774. // convert "exit(param);" -> "return param;"
  12775. var
  12776. ParentEl: TPasElement;
  12777. ImplProcScope: TPas2JSProcedureScope;
  12778. ResultVarName: String;
  12779. FuncContext: TFunctionContext;
  12780. AssignSt: TJSSimpleAssignStatement;
  12781. St: TJSStatementList;
  12782. ImplProc, DeclProc: TPasProcedure;
  12783. ImplTry: TPasImplTry;
  12784. ResultIsRead, aManaged: Boolean;
  12785. ResultEl: TPasResultElement;
  12786. TypeEl: TPasType;
  12787. Call: TJSCallExpression;
  12788. begin
  12789. {$IFDEF VerbosePas2JS}
  12790. writeln('TPasToJSConverter.ConvertBuiltIn_Exit ',GetObjName(El));
  12791. {$ENDIF}
  12792. ParentEl:=El.Parent;
  12793. while (ParentEl<>nil) and not (ParentEl is TPasProcedure) do
  12794. ParentEl:=ParentEl.Parent;
  12795. // ParentEl can be nil, when exit is in program begin block
  12796. ImplProc:=TPasProcedure(ParentEl);
  12797. ResultVarName:='';
  12798. ResultEl:=nil;
  12799. aManaged:=false;
  12800. if ImplProc<>nil then
  12801. begin
  12802. ImplProcScope:=ImplProc.CustomData as TPas2JSProcedureScope;
  12803. DeclProc:=ImplProcScope.DeclarationProc;
  12804. if DeclProc=nil then
  12805. DeclProc:=ImplProc; // Note: references refer to ResultEl of DeclProc
  12806. if DeclProc.ProcType is TPasFunctionType then
  12807. begin
  12808. ResultVarName:=ImplProcScope.ResultVarName; // ResultVarName needs ImplProc
  12809. if ResultVarName='' then
  12810. ResultVarName:=ResolverResultVar;
  12811. ResultEl:=TPasFunctionType(DeclProc.ProcType).ResultEl;
  12812. TypeEl:=AContext.Resolver.ResolveAliasType(ResultEl.ResultType);
  12813. aManaged:=AContext.Resolver.IsManagedJSType(TypeEl);
  12814. end;
  12815. end
  12816. else
  12817. DeclProc:=nil;
  12818. FuncContext:=AContext.GetFunctionContext;
  12819. Result:=TJSReturnStatement(CreateElement(TJSReturnStatement,El));
  12820. if (El is TParamsExpr) and (length(TParamsExpr(El).Params)>0) then
  12821. begin
  12822. // with parameter, e.g. "exit(param);"
  12823. ResultIsRead:=false;
  12824. if (ResultVarName<>'') then
  12825. begin
  12826. ParentEl:=El.Parent;
  12827. while (ParentEl<>ImplProc) do
  12828. begin
  12829. if ParentEl is TPasImplTry then
  12830. begin
  12831. ImplTry:=TPasImplTry(ParentEl);
  12832. if ImplTry.FinallyExcept is TPasImplTryFinally then
  12833. begin
  12834. if AContext.Resolver.ImplBlockReadsDecl(ImplTry.FinallyExcept,ResultEl) then
  12835. begin
  12836. ResultIsRead:=true;
  12837. break;
  12838. end;
  12839. end;
  12840. end;
  12841. ParentEl:=ParentEl.Parent;
  12842. end;
  12843. end;
  12844. if aManaged then
  12845. begin
  12846. FuncContext.ResultNeedsIntfRelease:=true;
  12847. // create "Result = rtl.setIntfL(Result,param); return Result;"
  12848. Call:=CreateCallExpression(El);
  12849. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnIntfSetIntfL)]);
  12850. Call.AddArg(CreatePrimitiveDotExpr(ResultVarName,El));
  12851. Call.AddArg(ConvertExpression(TParamsExpr(El).Params[0],AContext));
  12852. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  12853. AssignSt.LHS:=CreatePrimitiveDotExpr(ResultVarName,El);
  12854. AssignSt.Expr:=Call;
  12855. TJSReturnStatement(Result).Expr:=CreatePrimitiveDotExpr(ResultVarName,El);
  12856. St:=TJSStatementList(CreateElement(TJSStatementList,El));
  12857. St.A:=AssignSt;
  12858. St.B:=Result;
  12859. Result:=St;
  12860. end
  12861. else if ResultIsRead then
  12862. begin
  12863. // create "Result = param; return Result;"
  12864. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  12865. AssignSt.LHS:=CreatePrimitiveDotExpr(ResultVarName,El);
  12866. AssignSt.Expr:=ConvertExpression(TParamsExpr(El).Params[0],AContext);
  12867. TJSReturnStatement(Result).Expr:=CreatePrimitiveDotExpr(ResultVarName,El);
  12868. St:=TJSStatementList(CreateElement(TJSStatementList,El));
  12869. St.A:=AssignSt;
  12870. St.B:=Result;
  12871. Result:=St;
  12872. end
  12873. else
  12874. begin
  12875. // create "return param;"
  12876. TJSReturnStatement(Result).Expr:=ConvertExpression(TParamsExpr(El).Params[0],AContext);
  12877. end;
  12878. end
  12879. else
  12880. begin
  12881. // without parameter
  12882. if (ResultVarName<>'') then
  12883. begin
  12884. // in a function, "return Result;"
  12885. TJSReturnStatement(Result).Expr:=CreatePrimitiveDotExpr(ResultVarName,El);
  12886. end
  12887. else
  12888. ; // in a procedure, "return;" which means "return undefined;"
  12889. end;
  12890. if (FuncContext<>nil) and FuncContext.ResultNeedsIntfRelease then
  12891. begin
  12892. // add "$ok = true;"
  12893. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  12894. AssignSt.LHS:=CreatePrimitiveDotExpr(GetBIName(pbivnProcOk),El);
  12895. AssignSt.Expr:=CreateLiteralBoolean(El,true);
  12896. St:=TJSStatementList(CreateElement(TJSStatementList,El));
  12897. St.A:=AssignSt;
  12898. St.B:=Result;
  12899. Result:=St;
  12900. end;
  12901. end;
  12902. function TPasToJSConverter.ConvertBuiltIn_IncDec(El: TParamsExpr;
  12903. AContext: TConvertContext): TJSElement;
  12904. { inc(a) or inc(a,b)
  12905. if a is a variable:
  12906. convert inc(a,b) to a+=b
  12907. if a is a var/out arg:
  12908. convert inc(a,b) to a.set(a.get+b)
  12909. if a is a property
  12910. Getter: field, procedure
  12911. if a is an indexed-property
  12912. Getter: field, procedure
  12913. if a is a property with index-specifier
  12914. Getter: field, procedure
  12915. }
  12916. var
  12917. AssignSt: TJSAssignStatement;
  12918. Expr, SrcEl: TPasExpr;
  12919. ExprResolved: TPasResolverResult;
  12920. ExprArg: TPasArgument;
  12921. LHS, ValueJS: TJSElement;
  12922. Call: TJSCallExpression;
  12923. IsInc: Boolean;
  12924. AddJS: TJSAdditiveExpression;
  12925. AssignContext: TAssignContext;
  12926. aResolver: TPas2JSResolver;
  12927. begin
  12928. Result:=nil;
  12929. aResolver:=AContext.Resolver;
  12930. Expr:=aResolver.GetRightMostExpr(El.Value);
  12931. if not (Expr is TPrimitiveExpr) then
  12932. RaiseNotSupported(Expr,AContext,20200620113218);
  12933. IsInc:=CompareText(TPrimitiveExpr(Expr).Value,'inc')=0;
  12934. Expr:=El.Params[0];
  12935. aResolver.ComputeElement(Expr,ExprResolved,[]);
  12936. // convert value
  12937. if length(El.Params)=1 then
  12938. ValueJS:=CreateLiteralNumber(El,1)
  12939. else
  12940. ValueJS:=ConvertExpression(El.Params[1],AContext);
  12941. SrcEl:=El.Value;
  12942. // check target variable
  12943. AssignSt:=nil;
  12944. Call:=nil;
  12945. AssignContext:=nil;
  12946. LHS:=nil;
  12947. try
  12948. if ExprResolved.IdentEl is TPasArgument then
  12949. begin
  12950. ExprArg:=TPasArgument(ExprResolved.IdentEl);
  12951. if ExprArg.Access in [argVar,argOut] then
  12952. begin
  12953. // target variable is a reference
  12954. // -> convert inc(ref,b) to ref.set(ref.get()+b)
  12955. Call:=CreateCallExpression(SrcEl);
  12956. // create "ref.set"
  12957. Call.Expr:=CreateDotNameExpr(SrcEl,
  12958. CreateIdentifierExpr(ExprResolved.IdentEl,AContext),
  12959. TempRefObjSetterName);
  12960. // create "+"
  12961. if IsInc then
  12962. AddJS:=TJSAdditiveExpressionPlus(CreateElement(TJSAdditiveExpressionPlus,SrcEl))
  12963. else
  12964. AddJS:=TJSAdditiveExpressionMinus(CreateElement(TJSAdditiveExpressionMinus,SrcEl));
  12965. Call.AddArg(AddJS);
  12966. // create "ref.get()"
  12967. AddJS.A:=TJSCallExpression(CreateElement(TJSCallExpression,SrcEl));
  12968. TJSCallExpression(AddJS.A).Expr:=CreateDotNameExpr(SrcEl,
  12969. CreateIdentifierExpr(ExprResolved.IdentEl,AContext),
  12970. TJSString(TempRefObjGetterName));
  12971. // add "b"
  12972. AddJS.B:=ValueJS;
  12973. ValueJS:=nil;
  12974. Result:=Call;
  12975. exit;
  12976. end;
  12977. end
  12978. else if ExprResolved.IdentEl is TPasProperty then
  12979. begin
  12980. RaiseNotSupported(Expr,AContext,20170501151316);
  12981. end;
  12982. // inc(a,b) -> a = a+b or setter(getter()+b)
  12983. AssignContext:=TAssignContext.Create(Expr,nil,AContext);
  12984. aResolver.ComputeElement(Expr,AssignContext.LeftResolved,[rcNoImplicitProc]);
  12985. SetResolverValueExpr(AssignContext.RightResolved,
  12986. AssignContext.LeftResolved.BaseType,AssignContext.LeftResolved.LoTypeEl,
  12987. AssignContext.LeftResolved.HiTypeEl,Expr,[rrfReadable]);
  12988. AssignContext.RightSide:=ValueJS;
  12989. ValueJS:=nil;
  12990. LHS:=ConvertExpression(Expr,AssignContext);
  12991. if AssignContext.Call<>nil then
  12992. begin
  12993. // left side is a Setter -> RightSide was already inserted as parameter
  12994. RaiseNotSupported(El,AContext,20181101154351);
  12995. end
  12996. else
  12997. begin
  12998. // left side is a variable
  12999. if AssignContext.RightSide=nil then
  13000. RaiseInconsistency(20180622211919,El);
  13001. end;
  13002. // convert inc(avar,b) to a+=b
  13003. if IsInc then
  13004. AssignSt:=TJSAddEqAssignStatement(CreateElement(TJSAddEqAssignStatement,SrcEl))
  13005. else
  13006. AssignSt:=TJSSubEqAssignStatement(CreateElement(TJSSubEqAssignStatement,SrcEl));
  13007. AssignSt.LHS:=LHS;
  13008. LHS:=nil;
  13009. AssignSt.Expr:=AssignContext.RightSide;
  13010. AssignContext.RightSide:=nil;
  13011. Result:=AssignSt;
  13012. finally
  13013. ValueJS.Free;
  13014. if Result=nil then
  13015. begin
  13016. AssignSt.Free;
  13017. Call.Free;
  13018. LHS.Free;
  13019. end;
  13020. if AssignContext<>nil then
  13021. begin
  13022. AssignContext.RightSide.Free;
  13023. AssignContext.Free;
  13024. end;
  13025. end;
  13026. end;
  13027. function TPasToJSConverter.ConvertBuiltIn_Assigned(El: TParamsExpr;
  13028. AContext: TConvertContext): TJSElement;
  13029. var
  13030. NE: TJSEqualityExpressionNE;
  13031. Param: TPasExpr;
  13032. ParamResolved: TPasResolverResult;
  13033. C: TClass;
  13034. GT: TJSRelationalExpressionGT;
  13035. Call: TJSCallExpression;
  13036. begin
  13037. Result:=nil;
  13038. if AContext.Resolver=nil then
  13039. RaiseInconsistency(20170210105235,El);
  13040. Param:=El.Params[0];
  13041. AContext.Resolver.ComputeElement(Param,ParamResolved,[rcNoImplicitProcType]);
  13042. {$IFDEF VerbosePas2JS}
  13043. writeln('TPasToJSConverter.ConvertBuiltInAssigned ParamResolved=',GetResolverResultDbg(ParamResolved));
  13044. {$ENDIF}
  13045. if ParamResolved.BaseType=btPointer then
  13046. begin
  13047. // convert Assigned(value) -> value!=null
  13048. Result:=ConvertExpression(Param,AContext);
  13049. // Note: convert Param first, it may raise an exception
  13050. NE:=TJSEqualityExpressionNE(CreateElement(TJSEqualityExpressionNE,El));
  13051. NE.A:=Result;
  13052. NE.B:=CreateLiteralNull(El);
  13053. Result:=NE;
  13054. end
  13055. else if ParamResolved.BaseType=btContext then
  13056. begin
  13057. C:=ParamResolved.LoTypeEl.ClassType;
  13058. if (C=TPasClassType)
  13059. or (C=TPasClassOfType)
  13060. or C.InheritsFrom(TPasProcedureType) then
  13061. begin
  13062. // convert Assigned(value) -> value!=null
  13063. Result:=ConvertExpression(Param,AContext);
  13064. // Note: convert Param first, it may raise an exception
  13065. NE:=TJSEqualityExpressionNE(CreateElement(TJSEqualityExpressionNE,El));
  13066. NE.A:=Result;
  13067. NE.B:=CreateLiteralNull(El);
  13068. Result:=NE;
  13069. end
  13070. else if C=TPasArrayType then
  13071. begin
  13072. // convert Assigned(value) -> rtl.length(value)>0
  13073. Result:=ConvertExpression(Param,AContext);
  13074. // Note: convert Param first, it may raise an exception
  13075. GT:=TJSRelationalExpressionGT(CreateElement(TJSRelationalExpressionGT,El));
  13076. Call:=CreateCallExpression(El);
  13077. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnArray_Length)]);
  13078. Call.AddArg(Result);
  13079. GT.A:=Call;
  13080. GT.B:=CreateLiteralNumber(El,0);
  13081. Result:=GT;
  13082. end
  13083. else
  13084. RaiseNotSupported(El,AContext,20170328124606);
  13085. end;
  13086. end;
  13087. function TPasToJSConverter.ConvertBuiltIn_Chr(El: TParamsExpr;
  13088. AContext: TConvertContext): TJSElement;
  13089. var
  13090. ParamResolved: TPasResolverResult;
  13091. Param: TPasExpr;
  13092. begin
  13093. Result:=nil;
  13094. if AContext.Resolver=nil then
  13095. RaiseInconsistency(20170325185847,El);
  13096. Param:=El.Params[0];
  13097. AContext.Resolver.ComputeElement(Param,ParamResolved,[]);
  13098. if ParamResolved.BaseType in btAllJSInteger then
  13099. begin
  13100. // chr(integer) -> String.fromCharCode(integer)
  13101. Result:=ConvertExpression(Param,AContext);
  13102. // Note: convert Param first, as it might raise an exception
  13103. Result:=CreateCallFromCharCode(Result,El);
  13104. exit;
  13105. end;
  13106. DoError(20170325185906,nXExpectedButYFound,sXExpectedButYFound,['integer',
  13107. AContext.Resolver.GetResolverResultDescription(ParamResolved)],Param);
  13108. end;
  13109. function TPasToJSConverter.ConvertBuiltIn_Ord(El: TParamsExpr;
  13110. AContext: TConvertContext): TJSElement;
  13111. function CheckOrdConstant(aResolver: TPas2JSResolver; Param: TPasExpr): TJSElement;
  13112. var
  13113. ParamValue, OrdValue: TResEvalValue;
  13114. begin
  13115. Result:=nil;
  13116. OrdValue:=nil;
  13117. ParamValue:=aResolver.Eval(Param,[]);
  13118. if ParamValue=nil then exit;
  13119. try
  13120. OrdValue:=aResolver.ExprEvaluator.OrdValue(ParamValue,El);
  13121. if OrdValue=ParamValue then
  13122. ParamValue:=nil;
  13123. if OrdValue<>nil then
  13124. begin
  13125. // ord(constant) -> constant
  13126. Result:=ConvertConstValue(OrdValue,AContext,El);
  13127. exit;
  13128. end;
  13129. finally
  13130. ReleaseEvalValue(ParamValue);
  13131. ReleaseEvalValue(OrdValue);
  13132. end;
  13133. end;
  13134. var
  13135. ParamResolved, SubParamResolved: TPasResolverResult;
  13136. Param, SubParam: TPasExpr;
  13137. Call: TJSCallExpression;
  13138. SubParams: TParamsExpr;
  13139. SubParamJS: TJSElement;
  13140. Minus: TJSAdditiveExpressionMinus;
  13141. Add: TJSAdditiveExpressionPlus;
  13142. aResolver: TPas2JSResolver;
  13143. bt: TResolverBaseType;
  13144. C: TClass;
  13145. begin
  13146. Result:=nil;
  13147. aResolver:=AContext.Resolver;
  13148. if aResolver=nil then
  13149. RaiseInconsistency(20170210105235,El);
  13150. Param:=El.Params[0];
  13151. aResolver.ComputeElement(Param,ParamResolved,[]);
  13152. bt:=ParamResolved.BaseType;
  13153. if bt=btRange then
  13154. bt:=ParamResolved.SubType;
  13155. if bt in [btChar,btWideChar] then
  13156. begin
  13157. if Param is TParamsExpr then
  13158. begin
  13159. SubParams:=TParamsExpr(Param);
  13160. if SubParams.Kind=pekArrayParams then
  13161. begin
  13162. // e.g. ord(something[index])
  13163. SubParam:=SubParams.Value;
  13164. AContext.Resolver.ComputeElement(SubParam,SubParamResolved,[]);
  13165. if SubParamResolved.BaseType in btAllJSStrings then
  13166. begin
  13167. // e.g. ord(aString[index]) -> aString.charCodeAt(index-1)
  13168. SubParamJS:=ConvertExpression(SubParam,AContext);
  13169. // Note: convert SubParam first, as it might raise an exception
  13170. Call:=nil;
  13171. try
  13172. Call:=CreateCallExpression(El);
  13173. Call.Expr:=CreateDotNameExpr(El,SubParamJS,'charCodeAt');
  13174. Minus:=TJSAdditiveExpressionMinus(CreateElement(TJSAdditiveExpressionMinus,Param));
  13175. Call.AddArg(Minus);
  13176. if length(SubParams.Params)<>1 then
  13177. RaiseInconsistency(20170405231706,El);
  13178. Minus.A:=ConvertExpression(SubParams.Params[0],AContext);
  13179. Minus.B:=CreateLiteralNumber(Param,1);
  13180. Result:=Call;
  13181. finally
  13182. if Result=nil then
  13183. Call.Free;
  13184. end;
  13185. exit;
  13186. end;
  13187. end;
  13188. end
  13189. else
  13190. begin
  13191. Result:=CheckOrdConstant(aResolver,Param);
  13192. if Result<>nil then exit;
  13193. end;
  13194. // ord(aChar) -> aChar.charCodeAt()
  13195. Result:=ConvertExpression(Param,AContext);
  13196. // Note: convert Param first, as it might raise an exception
  13197. Result:=CreateCallCharCodeAt(Result,0,El);
  13198. exit;
  13199. end
  13200. else if bt in btAllJSBooleans then
  13201. begin
  13202. // ord(bool)
  13203. Result:=CheckOrdConstant(aResolver,Param);
  13204. if Result<>nil then exit;
  13205. // ord(bool) -> bool+0
  13206. Result:=ConvertExpression(Param,AContext);
  13207. // Note: convert Param first, as it might raise an exception
  13208. Add:=TJSAdditiveExpressionPlus(CreateElement(TJSAdditiveExpressionPlus,El));
  13209. Add.A:=Result;
  13210. Add.B:=CreateLiteralNumber(El,0);
  13211. Result:=Add;
  13212. exit;
  13213. end
  13214. else if bt in btAllJSInteger then
  13215. begin
  13216. // ord(integer)
  13217. Result:=CheckOrdConstant(aResolver,Param);
  13218. if Result<>nil then exit;
  13219. // ord(integer) -> integer
  13220. Result:=ConvertExpression(Param,AContext);
  13221. exit;
  13222. end
  13223. else if bt=btContext then
  13224. begin
  13225. C:=ParamResolved.LoTypeEl.ClassType;
  13226. if (C=TPasEnumType) or (C=TPasRangeType) then
  13227. begin
  13228. // ord(enum) -> enum
  13229. Result:=ConvertExpression(Param,AContext);
  13230. exit;
  13231. end;
  13232. end;
  13233. DoError(20170210105339,nXExpectedButYFound,sXExpectedButYFound,['enum',
  13234. AContext.Resolver.GetResolverResultDescription(ParamResolved)],Param);
  13235. end;
  13236. function TPasToJSConverter.ConvertBuiltIn_LowHigh(El: TParamsExpr;
  13237. AContext: TConvertContext; IsLow: boolean): TJSElement;
  13238. // low(enumtype) -> first enumvalue
  13239. // high(enumtype) -> last enumvalue
  13240. // low(set var) -> first enumvalue
  13241. // high(set var) -> last enumvalue
  13242. // low(settype) -> first enumvalue
  13243. // high(settype) -> last enumvalue
  13244. // low(array var) -> first index
  13245. // high(dynamic array) -> array.length-1
  13246. // high(static array) -> last index
  13247. procedure CreateEnumValue(TypeEl: TPasEnumType);
  13248. var
  13249. EnumValue: TPasEnumValue;
  13250. begin
  13251. if IsLow then
  13252. EnumValue:=TPasEnumValue(TypeEl.Values[0])
  13253. else
  13254. EnumValue:=TPasEnumValue(TypeEl.Values[TypeEl.Values.Count-1]);
  13255. Result:=CreateReferencePathExpr(EnumValue,AContext);
  13256. end;
  13257. var
  13258. Param: TPasExpr;
  13259. aResolver: TPas2JSResolver;
  13260. ResolvedEl: TPasResolverResult;
  13261. TypeEl: TPasType;
  13262. Ranges: TPasExprArray;
  13263. Value: TResEvalValue;
  13264. Call: TJSCallExpression;
  13265. MinusExpr: TJSAdditiveExpressionMinus;
  13266. MinVal, MaxVal: TMaxPrecInt;
  13267. bt: TResolverBaseType;
  13268. begin
  13269. Result:=nil;
  13270. if AContext.Resolver=nil then
  13271. RaiseInconsistency(20170210120659,El);
  13272. Param:=El.Params[0];
  13273. aResolver:=AContext.Resolver;
  13274. aResolver.ComputeElement(Param,ResolvedEl,[]);
  13275. bt:=ResolvedEl.BaseType;
  13276. if bt=btRange then
  13277. bt:=ResolvedEl.SubType;
  13278. case bt of
  13279. btContext:
  13280. begin
  13281. TypeEl:=ResolvedEl.LoTypeEl;
  13282. if TypeEl.ClassType=TPasRangeType then
  13283. begin
  13284. if IsLow then
  13285. Result:=ConvertElement(TPasRangeType(TypeEl).RangeExpr.left,AContext)
  13286. else
  13287. Result:=ConvertElement(TPasRangeType(TypeEl).RangeExpr.right,AContext);
  13288. exit;
  13289. end
  13290. else if TypeEl.ClassType=TPasEnumType then
  13291. begin
  13292. CreateEnumValue(TPasEnumType(TypeEl));
  13293. exit;
  13294. end
  13295. else if (TypeEl.ClassType=TPasSetType) then
  13296. begin
  13297. if TPasSetType(TypeEl).EnumType<>nil then
  13298. begin
  13299. TypeEl:=TPasSetType(TypeEl).EnumType;
  13300. CreateEnumValue(TPasEnumType(TypeEl));
  13301. exit;
  13302. end;
  13303. end
  13304. else if TypeEl.ClassType=TPasArrayType then
  13305. begin
  13306. Ranges:=TPasArrayType(TypeEl).Ranges;
  13307. if IsLow then
  13308. begin
  13309. // low(arr)
  13310. if length(Ranges)=0 then
  13311. begin
  13312. // dynamic array starts at 0
  13313. Result:=CreateLiteralNumber(El,0);
  13314. exit;
  13315. end
  13316. else
  13317. begin
  13318. // static array
  13319. Value:=AContext.Resolver.EvalRangeLimit(Ranges[0],[refConst],true,El);
  13320. if Value=nil then
  13321. RaiseNotSupported(El,AContext,20170910160817);
  13322. try
  13323. Result:=ConvertConstValue(Value,AContext,Param);
  13324. finally
  13325. ReleaseEvalValue(Value);
  13326. end;
  13327. exit;
  13328. end;
  13329. end
  13330. else
  13331. begin
  13332. // high(arr)
  13333. if length(Ranges)=0 then
  13334. begin
  13335. // dynamic array -> rtl.length(Param)-1
  13336. Result:=ConvertExpression(Param,AContext);
  13337. // Note: convert Param first, it may raise an exception
  13338. Call:=CreateCallExpression(El);
  13339. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnArray_Length)]);
  13340. Call.AddArg(Result);
  13341. MinusExpr:=TJSAdditiveExpressionMinus(CreateElement(TJSAdditiveExpressionMinus,El));
  13342. MinusExpr.A:=Call;
  13343. MinusExpr.B:=CreateLiteralNumber(El,1);
  13344. Result:=MinusExpr;
  13345. exit;
  13346. end
  13347. else
  13348. begin
  13349. // static array
  13350. Value:=AContext.Resolver.EvalRangeLimit(Ranges[0],[refConst],false,El);
  13351. if Value=nil then
  13352. RaiseNotSupported(El,AContext,20170910161555);
  13353. try
  13354. Result:=ConvertConstValue(Value,AContext,Param);
  13355. finally
  13356. ReleaseEvalValue(Value);
  13357. end;
  13358. exit;
  13359. end;
  13360. end;
  13361. end;
  13362. end;
  13363. btBoolean,btByteBool,btWordBool,btLongBool:
  13364. begin
  13365. if IsLow then
  13366. Result:=CreateLiteralBoolean(El,LowJSBoolean)
  13367. else
  13368. Result:=CreateLiteralBoolean(El,HighJSBoolean);
  13369. exit;
  13370. end;
  13371. btChar,
  13372. btWideChar:
  13373. begin
  13374. if IsLow then
  13375. Result:=CreateLiteralJSString(El,#0)
  13376. else
  13377. Result:=CreateLiteralJSString(El,#$ffff);
  13378. exit;
  13379. end;
  13380. btByte..btIntMax:
  13381. begin
  13382. TypeEl:=ResolvedEl.LoTypeEl;
  13383. if TypeEl.ClassType=TPasUnresolvedSymbolRef then
  13384. begin
  13385. if TypeEl.CustomData is TResElDataBaseType then
  13386. begin
  13387. AContext.Resolver.GetIntegerRange(ResolvedEl.BaseType,MinVal,MaxVal);
  13388. if IsLow then
  13389. Result:=CreateLiteralNumber(El,MinVal)
  13390. else
  13391. Result:=CreateLiteralNumber(El,MaxVal);
  13392. exit;
  13393. end;
  13394. end
  13395. else if TypeEl.ClassType=TPasRangeType then
  13396. begin
  13397. Value:=AContext.Resolver.EvalRangeLimit(TPasRangeType(TypeEl).RangeExpr,
  13398. [refConst],IsLow,El);
  13399. try
  13400. case Value.Kind of
  13401. revkInt:
  13402. Result:=CreateLiteralNumber(El,TResEvalInt(Value).Int);
  13403. revkUInt:
  13404. Result:=CreateLiteralNumber(El,TResEvalUInt(Value).UInt);
  13405. else
  13406. RaiseNotSupported(El,AContext,20170925214317);
  13407. end;
  13408. exit;
  13409. finally
  13410. ReleaseEvalValue(Value);
  13411. end;
  13412. end;
  13413. {$IFDEF VerbosePas2JS}
  13414. writeln('TPasToJSConverter.ConvertBuiltIn_LowHigh ',GetResolverResultDbg(ResolvedEl));
  13415. {$ENDIF}
  13416. RaiseNotSupported(El,AContext,20170925214351);
  13417. end;
  13418. btSet,btArrayOrSet:
  13419. begin
  13420. TypeEl:=ResolvedEl.LoTypeEl;
  13421. if TypeEl.ClassType=TPasEnumType then
  13422. begin
  13423. CreateEnumValue(TPasEnumType(TypeEl));
  13424. exit;
  13425. end;
  13426. end;
  13427. btString:
  13428. begin
  13429. if isLow then
  13430. // low(aString) -> 1
  13431. Result:=CreateLiteralNumber(El,1)
  13432. else
  13433. begin
  13434. // high(aString) -> aString.length
  13435. Result:=ConvertExpression(Param,AContext);
  13436. Result:=CreateDotNameExpr(El,Result,'length');
  13437. end;
  13438. exit;
  13439. end;
  13440. end;
  13441. DoError(20170210110717,nXExpectedButYFound,sXExpectedButYFound,['enum or array',
  13442. AContext.Resolver.GetResolverResultDescription(ResolvedEl)],Param);
  13443. end;
  13444. function TPasToJSConverter.ConvertBuiltIn_PredSucc(El: TParamsExpr;
  13445. AContext: TConvertContext; IsPred: boolean): TJSElement;
  13446. // pred(enumvalue) -> enumvalue-1
  13447. // succ(enumvalue) -> enumvalue+1
  13448. var
  13449. ResolvedEl: TPasResolverResult;
  13450. TypeEl: TPasType;
  13451. procedure EnumExpected(Id: TMaxPrecInt);
  13452. begin
  13453. {$IFDEF VerbosePas2JS}
  13454. writeln('TPasToJSConverter.ConvertBuiltIn_PredSucc ',ResolvedEl.BaseType,' ',ResolvedEl.SubType,' ',GetObjName(TypeEl));
  13455. {$ENDIF}
  13456. DoError(Id,nXExpectedButYFound,sXExpectedButYFound,['enum',
  13457. AContext.Resolver.GetResolverResultDescription(ResolvedEl)],El.Params[0]);
  13458. end;
  13459. procedure CreateAdd(Param: TPasExpr);
  13460. var
  13461. V: TJSElement;
  13462. Expr: TJSAdditiveExpression;
  13463. begin
  13464. V:=ConvertExpression(Param,AContext);
  13465. if IsPred then
  13466. // pred(int) -> Param-1
  13467. Expr:=TJSAdditiveExpressionMinus(CreateElement(TJSAdditiveExpressionMinus,El))
  13468. else
  13469. // succ(int) -> Param+1
  13470. Expr:=TJSAdditiveExpressionPlus(CreateElement(TJSAdditiveExpressionPlus,El));
  13471. Expr.A:=V;
  13472. Expr.B:=CreateLiteralNumber(El,1);
  13473. ConvertBuiltIn_PredSucc:=Expr;
  13474. end;
  13475. procedure CreateSwitchBool;
  13476. begin
  13477. if IsPred then
  13478. // pred(bool) -> false
  13479. ConvertBuiltIn_PredSucc:=CreateLiteralBoolean(El,false)
  13480. else
  13481. // succ(bool) -> true
  13482. ConvertBuiltIn_PredSucc:=CreateLiteralBoolean(El,true);
  13483. end;
  13484. procedure CreateCharPredSucc(Param: TPasExpr);
  13485. var
  13486. V: TJSElement;
  13487. Call: TJSCallExpression;
  13488. Expr: TJSAdditiveExpression;
  13489. begin
  13490. V:=ConvertExpression(Param,AContext);
  13491. // V.charCodeAt()
  13492. Call:=CreateCallCharCodeAt(V,0,El);
  13493. if IsPred then
  13494. // pred(V) -> V.charCodeAt-1
  13495. Expr:=TJSAdditiveExpressionMinus(CreateElement(TJSAdditiveExpressionMinus,El))
  13496. else
  13497. // succ(V) -> V.charCodeAt+1
  13498. Expr:=TJSAdditiveExpressionPlus(CreateElement(TJSAdditiveExpressionPlus,El));
  13499. Expr.A:=Call;
  13500. Expr.B:=CreateLiteralNumber(El,1);
  13501. // String.fromCharCode(V.charCodeAt+1)
  13502. Call:=CreateCallFromCharCode(Expr,El);
  13503. ConvertBuiltIn_PredSucc:=Call;
  13504. end;
  13505. var
  13506. Param: TPasExpr;
  13507. Value: TResEvalValue;
  13508. begin
  13509. Result:=nil;
  13510. if AContext.Resolver=nil then
  13511. RaiseInconsistency(20170210120648,El);
  13512. Param:=El.Params[0];
  13513. AContext.Resolver.ComputeElement(Param,ResolvedEl,[]);
  13514. TypeEl:=ResolvedEl.LoTypeEl;
  13515. if ResolvedEl.BaseType in btAllJSInteger then
  13516. begin
  13517. CreateAdd(Param);
  13518. exit;
  13519. end
  13520. else if ResolvedEl.BaseType in btAllJSBooleans then
  13521. begin
  13522. CreateSwitchBool;
  13523. exit;
  13524. end
  13525. else if ResolvedEl.BaseType in btAllJSChars then
  13526. begin
  13527. CreateCharPredSucc(Param);
  13528. exit;
  13529. end
  13530. else if ResolvedEl.BaseType=btContext then
  13531. begin
  13532. if TypeEl.ClassType=TPasEnumType then
  13533. begin
  13534. CreateAdd(Param);
  13535. exit;
  13536. end
  13537. else
  13538. EnumExpected(20180424115902);
  13539. end
  13540. else if ResolvedEl.BaseType=btRange then
  13541. begin
  13542. if ResolvedEl.SubType in btAllJSInteger then
  13543. begin
  13544. CreateAdd(Param);
  13545. exit;
  13546. end
  13547. else if ResolvedEl.SubType in btAllJSBooleans then
  13548. begin
  13549. CreateAdd(Param);
  13550. exit;
  13551. end
  13552. else if ResolvedEl.SubType=btContext then
  13553. begin
  13554. if TypeEl.ClassType=TPasRangeType then
  13555. begin
  13556. Value:=AContext.Resolver.EvalTypeRange(TypeEl,[refConst]);
  13557. if Value<>nil then
  13558. try
  13559. case Value.Kind of
  13560. revkRangeInt:
  13561. case TResEvalRangeInt(Value).ElKind of
  13562. revskEnum, revskInt:
  13563. begin
  13564. CreateAdd(Param);
  13565. exit;
  13566. end;
  13567. revskChar:
  13568. EnumExpected(20180424115736);
  13569. revskBool:
  13570. begin
  13571. CreateSwitchBool;
  13572. exit;
  13573. end;
  13574. else
  13575. EnumExpected(20180424115959);
  13576. end;
  13577. revkRangeUInt:
  13578. begin
  13579. CreateAdd(Param);
  13580. exit;
  13581. end;
  13582. else
  13583. EnumExpected(20180424115757);
  13584. end;
  13585. finally
  13586. ReleaseEvalValue(Value);
  13587. end;
  13588. end
  13589. else
  13590. EnumExpected(20180424115934);
  13591. end;
  13592. end;
  13593. EnumExpected(20170210120039);
  13594. end;
  13595. function TPasToJSConverter.ConvertBuiltIn_StrProc(El: TParamsExpr;
  13596. AContext: TConvertContext): TJSElement;
  13597. // convert 'str(value,aString)' to 'aString = <string>'
  13598. // for the conversion see ConvertBuiltInStrParam
  13599. var
  13600. AssignContext: TAssignContext;
  13601. StrVar: TPasExpr;
  13602. TypeEl: TPasType;
  13603. begin
  13604. Result:=nil;
  13605. AssignContext:=TAssignContext.Create(El,nil,AContext);
  13606. try
  13607. StrVar:=El.Params[1];
  13608. AContext.Resolver.ComputeElement(StrVar,AssignContext.LeftResolved,[rcNoImplicitProc]);
  13609. // create right side
  13610. AssignContext.RightSide:=ConvertBuiltInStrParam(El.Params[0],AContext,false,true);
  13611. TypeEl:=AContext.Resolver.BaseTypes[btString];
  13612. SetResolverValueExpr(AssignContext.RightResolved,btString,
  13613. TypeEl,TypeEl,El,[rrfReadable]);
  13614. // create 'StrVar = rightside'
  13615. Result:=CreateAssignStatement(StrVar,AssignContext);
  13616. finally
  13617. AssignContext.RightSide.Free;
  13618. AssignContext.Free;
  13619. end;
  13620. end;
  13621. function TPasToJSConverter.ConvertBuiltIn_StrFunc(El: TParamsExpr;
  13622. AContext: TConvertContext): TJSElement;
  13623. // convert 'str(boolean)' to '""+boolean'
  13624. // convert 'str(integer)' to '""+integer'
  13625. // convert 'str(float)' to '""+float'
  13626. // convert 'str(float:width)' to rtl.spaceLeft('""+float,width)'
  13627. // convert 'str(float:width:precision)' to 'rtl.spaceLeft(float.toFixed(precision),width)'
  13628. var
  13629. i: Integer;
  13630. Param: TPasExpr;
  13631. Sum, Add: TJSElement;
  13632. AddEl: TJSAdditiveExpressionPlus;
  13633. begin
  13634. {$IFDEF VerbosePas2JS}
  13635. writeln('TPasToJSConverter.ConvertBuiltInStrFunc Count=',length(El.Params));
  13636. {$ENDIF}
  13637. Result:=nil;
  13638. Sum:=nil;
  13639. Add:=nil;
  13640. try
  13641. for i:=0 to length(El.Params)-1 do
  13642. begin
  13643. Param:=El.Params[i];
  13644. Add:=ConvertBuiltInStrParam(Param,AContext,true,i=0);
  13645. if Sum=nil then
  13646. Sum:=Add
  13647. else
  13648. begin
  13649. AddEl:=TJSAdditiveExpressionPlus(CreateElement(TJSAdditiveExpressionPlus,Param));
  13650. AddEl.A:=Sum;
  13651. AddEl.B:=Add;
  13652. Sum:=AddEl;
  13653. end;
  13654. Add:=nil;
  13655. end;
  13656. Result:=Sum;
  13657. finally
  13658. Add.Free;
  13659. if Result=nil then
  13660. Sum.Free;
  13661. end;
  13662. end;
  13663. function TPasToJSConverter.ConvertBuiltInStrParam(El: TPasExpr;
  13664. AContext: TConvertContext; IsStrFunc, IsFirst: boolean): TJSElement;
  13665. var
  13666. Add: TJSElement;
  13667. procedure PrependStrLit;
  13668. var
  13669. PlusEl: TJSAdditiveExpressionPlus;
  13670. begin
  13671. PlusEl:=TJSAdditiveExpressionPlus(CreateElement(TJSAdditiveExpressionPlus,El));
  13672. PlusEl.A:=CreateLiteralString(El,'');
  13673. PlusEl.B:=Add;
  13674. Add:=PlusEl;
  13675. end;
  13676. var
  13677. aResolver: TPas2JSResolver;
  13678. ResolvedEl, ElTypeResolved: TPasResolverResult;
  13679. NeedStrLit: Boolean;
  13680. Call: TJSCallExpression;
  13681. Bracket: TJSBracketMemberExpression;
  13682. Arg: TJSElement;
  13683. bt: TResolverBaseType;
  13684. TypeEl: TPasType;
  13685. begin
  13686. Result:=nil;
  13687. aResolver:=AContext.Resolver;
  13688. aResolver.ComputeElement(El,ResolvedEl,[]);
  13689. Add:=nil;
  13690. Call:=nil;
  13691. Bracket:=nil;
  13692. try
  13693. NeedStrLit:=false;
  13694. bt:=ResolvedEl.BaseType;
  13695. if bt=btRange then
  13696. bt:=ResolvedEl.SubType;
  13697. if bt in (btAllJSBooleans+btAllJSInteger-[btCurrency]) then
  13698. begin
  13699. NeedStrLit:=true;
  13700. Add:=ConvertExpression(El,AContext);
  13701. end
  13702. else if bt in (btAllJSFloats+[btCurrency]) then
  13703. begin
  13704. // convert to rtl.floatToStr(El,width,precision)
  13705. Call:=CreateCallExpression(El);
  13706. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnFloatToStr)]);
  13707. Arg:=ConvertExpression(El,AContext);
  13708. if ResolvedEl.BaseType=btCurrency then
  13709. Arg:=CreateDivideNumber(El,Arg,10000);
  13710. Call.AddArg(Arg);
  13711. if El.format1<>nil then
  13712. Call.AddArg(ConvertExpression(El.format1,AContext));
  13713. if El.format2<>nil then
  13714. Call.AddArg(ConvertExpression(El.format2,AContext));
  13715. Result:=Call;
  13716. Call:=nil;
  13717. exit;
  13718. end
  13719. else if IsStrFunc and (bt in btAllJSStringAndChars) then
  13720. Add:=ConvertExpression(El,AContext)
  13721. else if bt=btContext then
  13722. begin
  13723. TypeEl:=ResolvedEl.LoTypeEl;
  13724. if TypeEl.ClassType=TPasRangeType then
  13725. begin
  13726. aResolver.ComputeElement(TPasRangeType(TypeEl).RangeExpr.left,ElTypeResolved,[rcConstant]);
  13727. TypeEl:=ElTypeResolved.LoTypeEl;
  13728. end;
  13729. if TypeEl.ClassType=TPasEnumType then
  13730. begin
  13731. // create enumtype[enumvalue]
  13732. Bracket:=TJSBracketMemberExpression(CreateElement(TJSBracketMemberExpression,El));
  13733. Bracket.MExpr:=CreateReferencePathExpr(TPasEnumType(TypeEl),AContext);
  13734. Bracket.Name:=ConvertExpression(El,AContext);
  13735. Add:=Bracket;
  13736. Bracket:=nil;
  13737. end
  13738. else
  13739. RaiseNotSupported(El,AContext,20170320123827);
  13740. end
  13741. else
  13742. RaiseNotSupported(El,AContext,20170320093001);
  13743. if El.format1<>nil then
  13744. begin
  13745. // width -> leading spaces
  13746. if NeedStrLit then
  13747. PrependStrLit;
  13748. // create 'rtl.spaceLeft(add,width)'
  13749. Call:=CreateCallExpression(El);
  13750. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnSpaceLeft)]);
  13751. Call.AddArg(Add);
  13752. Add:=nil;
  13753. Call.AddArg(ConvertExpression(El.format1,AContext));
  13754. Add:=Call;
  13755. Call:=nil;
  13756. end
  13757. else if IsFirst and NeedStrLit then
  13758. PrependStrLit;
  13759. Result:=Add;
  13760. finally
  13761. Call.Free;
  13762. Bracket.Free;
  13763. if Result=nil then
  13764. Add.Free;
  13765. end;
  13766. end;
  13767. function TPasToJSConverter.ConvertBuiltIn_WriteStr(El: TParamsExpr;
  13768. AContext: TConvertContext): TJSElement;
  13769. // convert 'writestr(aString,v:width,p)' to 'aString = <string of v> + (<string of p>+"")'
  13770. // for the conversion see ConvertBuiltInStrParam
  13771. var
  13772. AssignContext: TAssignContext;
  13773. StrVar: TPasExpr;
  13774. TypeEl: TPasType;
  13775. JS: TJSElement;
  13776. AddJS: TJSAdditiveExpressionPlus;
  13777. i: Integer;
  13778. begin
  13779. Result:=nil;
  13780. AssignContext:=TAssignContext.Create(El,nil,AContext);
  13781. try
  13782. StrVar:=El.Params[0];
  13783. AContext.Resolver.ComputeElement(StrVar,AssignContext.LeftResolved,[rcNoImplicitProc]);
  13784. // create right side
  13785. for i:=1 to length(El.Params)-1 do
  13786. begin
  13787. JS:=ConvertBuiltInStrParam(El.Params[i],AContext,false,true);
  13788. if AssignContext.RightSide=nil then
  13789. AssignContext.RightSide:=JS
  13790. else
  13791. begin
  13792. AddJS:=TJSAdditiveExpressionPlus(CreateElement(TJSAdditiveExpressionPlus,El));
  13793. AddJS.A:=AssignContext.RightSide;
  13794. AssignContext.RightSide:=AddJS;
  13795. AddJS.B:=JS;
  13796. end;
  13797. end;
  13798. TypeEl:=AContext.Resolver.BaseTypes[btString];
  13799. SetResolverValueExpr(AssignContext.RightResolved,btString,
  13800. TypeEl,TypeEl,El,[rrfReadable]);
  13801. // create 'StrVar = rightside'
  13802. Result:=CreateAssignStatement(StrVar,AssignContext);
  13803. finally
  13804. AssignContext.RightSide.Free;
  13805. AssignContext.Free;
  13806. end;
  13807. end;
  13808. function TPasToJSConverter.ConvertBuiltIn_Val(El: TParamsExpr;
  13809. AContext: TConvertContext): TJSElement;
  13810. // val(const s: string; out value: valuetype; out Code: integertype)
  13811. // for enum it is converted to
  13812. // value = rtl.valEnum(s,enumType,function(c){ Code=c; })
  13813. var
  13814. aResolver: TPas2JSResolver;
  13815. AssignContext: TAssignContext;
  13816. ValueExpr, CodeExpr: TPasExpr;
  13817. Call: TJSCallExpression;
  13818. Params: TPasExprArray;
  13819. EnumType: TPasEnumType;
  13820. Fun: TJSFunctionDeclarationStatement;
  13821. ExprResolved, ElTypeResolved: TPasResolverResult;
  13822. ExprArg: TPasArgument;
  13823. AssignSt: TJSSimpleAssignStatement;
  13824. SetterArgName: String;
  13825. ArgJS, SetExpr: TJSElement;
  13826. bt: TResolverBaseType;
  13827. LoTypeEl: TPasType;
  13828. begin
  13829. Result:=nil;
  13830. aResolver:=AContext.Resolver;
  13831. Params:=El.Params;
  13832. Call:=nil;
  13833. AssignContext:=TAssignContext.Create(El,nil,AContext);
  13834. try
  13835. //
  13836. ValueExpr:=Params[1];
  13837. aResolver.ComputeElement(ValueExpr,AssignContext.LeftResolved,[rcNoImplicitProc]);
  13838. // rtl.valEnum()
  13839. Call:=CreateCallExpression(El);
  13840. AssignContext.RightSide:=Call;
  13841. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnValEnum)]);
  13842. // add arg string
  13843. Call.AddArg(ConvertExpression(Params[0],AContext));
  13844. // add arg enumtype
  13845. bt:=AssignContext.LeftResolved.BaseType;
  13846. if bt=btRange then
  13847. bt:=AssignContext.LeftResolved.SubType;
  13848. if bt=btContext then
  13849. begin
  13850. LoTypeEl:=AssignContext.LeftResolved.LoTypeEl;
  13851. if LoTypeEl.ClassType=TPasRangeType then
  13852. begin
  13853. aResolver.ComputeElement(TPasRangeType(LoTypeEl).RangeExpr.left,ElTypeResolved,[rcConstant]);
  13854. LoTypeEl:=ElTypeResolved.LoTypeEl;
  13855. end;
  13856. if LoTypeEl.ClassType=TPasEnumType then
  13857. begin
  13858. EnumType:=TPasEnumType(LoTypeEl);
  13859. Call.AddArg(CreateReferencePathExpr(EnumType,AContext));
  13860. end else
  13861. RaiseNotSupported(Params[1],AContext,20181214145226,GetResolverResultDbg(AssignContext.LeftResolved));
  13862. end
  13863. else
  13864. RaiseNotSupported(Params[1],AContext,20181214145125,GetResolverResultDbg(AssignContext.LeftResolved));
  13865. // add arg setter for Code
  13866. CodeExpr:=Params[2];
  13867. AContext.Resolver.ComputeElement(CodeExpr,ExprResolved,[rcNoImplicitProc]);
  13868. ArgJS:=nil;
  13869. if ExprResolved.IdentEl is TPasArgument then
  13870. begin
  13871. ExprArg:=TPasArgument(ExprResolved.IdentEl);
  13872. if ExprArg.Access in [argVar,argOut] then
  13873. begin
  13874. // add arg setter for Code: Code.set
  13875. ArgJS:=CreateDotNameExpr(CodeExpr,
  13876. CreateIdentifierExpr(ExprResolved.IdentEl,AContext),
  13877. TempRefObjSetterName);
  13878. Call.AddArg(ArgJS);
  13879. end;
  13880. end;
  13881. if ArgJS=nil then
  13882. begin
  13883. // add arg setter for Code: function(v){ Code=v; }
  13884. if (ExprResolved.IdentEl=nil) or (ExprResolved.IdentEl is TPasProperty) then
  13885. RaiseNotSupported(CodeExpr,AContext,20181214154031,'property');
  13886. Fun:=CreateFunctionSt(CodeExpr);
  13887. ArgJS:=Fun;
  13888. Call.AddArg(ArgJS);
  13889. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,CodeExpr));
  13890. Fun.AFunction.Body.A:=AssignSt;
  13891. SetExpr:=ConvertExpression(CodeExpr,AContext);
  13892. AssignSt.LHS:=SetExpr;
  13893. SetterArgName:=TempRefObjSetterArgName;
  13894. FindAvailableLocalName(SetterArgName,SetExpr);
  13895. Fun.AFunction.TypedParams.AddParam(TJSString(SetterArgName));
  13896. AssignSt.Expr:=CreatePrimitiveDotExpr(SetterArgName,CodeExpr);
  13897. end;
  13898. // create 'ValueVar = rightside'
  13899. Result:=CreateAssignStatement(ValueExpr,AssignContext);
  13900. finally
  13901. if TAssignContext<>nil then
  13902. begin
  13903. AssignContext.RightSide.Free;
  13904. AssignContext.Free;
  13905. end;
  13906. end;
  13907. end;
  13908. function TPasToJSConverter.ConvertBuiltIn_LoHi(El: TParamsExpr;
  13909. AContext: TConvertContext; IsLoFunc: Boolean): TJSElement;
  13910. var
  13911. ResolvedParam: TPasResolverResult;
  13912. Param: TPasExpr;
  13913. Mask: LongWord;
  13914. Shift, Digits: Integer;
  13915. ShiftEx: TJSShiftExpression;
  13916. AndEx: TJSBitwiseAndExpression;
  13917. begin
  13918. Result := nil;
  13919. if AContext.Resolver=nil then
  13920. RaiseInconsistency(20190129102200,El);
  13921. Param := El.Params[0];
  13922. AContext.Resolver.ComputeElement(Param,ResolvedParam,[]);
  13923. if not (ResolvedParam.BaseType in btAllJSInteger) then
  13924. DoError(20190129121100,nXExpectedButYFound,sXExpectedButYFound,['integer type',
  13925. AContext.Resolver.GetResolverResultDescription(ResolvedParam)],Param);
  13926. Shift := AContext.Resolver.GetShiftAndMaskForLoHiFunc(ResolvedParam.BaseType,IsLoFunc,Mask);
  13927. Result := ConvertExpression(Param,AContext);
  13928. // Note: convert Param first, as it might raise an exception
  13929. if Shift > 0 then
  13930. begin
  13931. if Shift=32 then
  13932. begin
  13933. // JS bitwise operations work only 32bit -> use division for bigger shifts
  13934. Result:=CreateTruncFloor(El,CreateDivideNumber(El,Result,$100000000),false);
  13935. end
  13936. else
  13937. begin
  13938. ShiftEx := TJSRShiftExpression(CreateElement(TJSRShiftExpression,El));
  13939. ShiftEx.A := Result;
  13940. ShiftEx.B := CreateLiteralNumber(El, Shift);
  13941. Result := ShiftEx;
  13942. end;
  13943. end;
  13944. case Mask of
  13945. $FF: Digits := 2;
  13946. $FFFF: Digits := 4;
  13947. $FFFFFFFF: Digits := 8;
  13948. else { $F } Digits := 1;
  13949. end;
  13950. if Digits<8 then
  13951. begin
  13952. // & Mask
  13953. AndEx := TJSBitwiseAndExpression(CreateElement(TJSBitwiseAndExpression,El));
  13954. AndEx.A := Result;
  13955. AndEx.B := CreateLiteralHexNumber(El,Mask,Digits);
  13956. Result := AndEx;
  13957. end
  13958. else
  13959. begin
  13960. // mask to longword -> >>> 0
  13961. ShiftEx:=TJSURShiftExpression(CreateElement(TJSURShiftExpression,El));
  13962. ShiftEx.A:=Result;
  13963. ShiftEx.B:=CreateLiteralNumber(El,0);
  13964. Result:=ShiftEx;
  13965. end;
  13966. end;
  13967. function TPasToJSConverter.ConvertBuiltIn_ConcatArray(El: TParamsExpr;
  13968. AContext: TConvertContext): TJSElement;
  13969. // concat(array1, array2)
  13970. var
  13971. Params: TPasExprArray;
  13972. ParamResolved: TPasResolverResult;
  13973. Param0: TPasExpr;
  13974. ArrayType: TPasArrayType;
  13975. i: Integer;
  13976. Call: TJSCallExpression;
  13977. JS: TJSElement;
  13978. aResolver: TPas2JSResolver;
  13979. aManaged: Boolean;
  13980. begin
  13981. Result:=nil;
  13982. Params:=El.Params;
  13983. if length(Params)<1 then
  13984. RaiseInconsistency(20170331000332,El);
  13985. Param0:=El.Params[0];
  13986. aResolver:=AContext.Resolver;
  13987. aResolver.ComputeElement(Param0,ParamResolved,[]);
  13988. if length(Params)=1 then
  13989. begin
  13990. // concat(array1) -> array1
  13991. {$IFDEF VerbosePas2JS}
  13992. writeln('TPasToJSConverter.ConvertBuiltInConcatArray Count=',length(El.Params));
  13993. {$ENDIF}
  13994. Result:=ConvertExpression(Param0,AContext);
  13995. if not aResolver.IsManagedJSType(ParamResolved.LoTypeEl) then
  13996. Result:=CreateArrayRef(El,Result);
  13997. end
  13998. else
  13999. begin
  14000. // concat(array1,array2,...)
  14001. Call:=nil;
  14002. aManaged:=false;
  14003. if ParamResolved.LoTypeEl is TPasArrayType then
  14004. begin
  14005. ArrayType:=TPasArrayType(ParamResolved.LoTypeEl);
  14006. Call:=CreateArrayConcat(ArrayType,El,AContext);
  14007. aManaged:=aResolver.IsManagedJSType(ArrayType);
  14008. end
  14009. else if ParamResolved.BaseType=btArrayLit then
  14010. begin
  14011. ParamResolved.BaseType:=ParamResolved.SubType;
  14012. ParamResolved.SubType:=btNone;
  14013. Call:=CreateArrayConcat(ParamResolved,El,AContext);
  14014. end;
  14015. if Call=nil then
  14016. begin
  14017. {$IFDEF VerbosePas2JS}
  14018. writeln('TPasToJSConverter.ConvertBuiltIn_ConcatArray Param0Resolved=',GetResolverResultDbg(ParamResolved));
  14019. {$ENDIF}
  14020. RaiseNotSupported(Param0,AContext,20170331000846);
  14021. end;
  14022. try
  14023. for i:=0 to length(Params)-1 do
  14024. begin
  14025. JS:=CreateArrayEl(Params[i],AContext);
  14026. Call.AddArg(JS);
  14027. end;
  14028. Result:=Call;
  14029. if aManaged then
  14030. Result:=CreateIntfRef(Result,AContext,El);
  14031. finally
  14032. if Result=nil then
  14033. Call.Free;
  14034. end;
  14035. end;
  14036. end;
  14037. function TPasToJSConverter.ConvertBuiltIn_ConcatString(El: TParamsExpr;
  14038. AContext: TConvertContext): TJSElement;
  14039. var
  14040. Params: TPasExprArray;
  14041. A: TJSElement;
  14042. Call: TJSCallExpression;
  14043. i: Integer;
  14044. begin
  14045. Params:=El.Params;
  14046. if Length(Params)=1 then
  14047. // concat(a) -> a
  14048. Result:=ConvertExpression(Params[0],AContext)
  14049. else
  14050. begin
  14051. // concat(a,b,c) -> a.concat(b,c)
  14052. Result:=nil;
  14053. A:=ConvertExpression(Params[0],AContext); // beware: might fail
  14054. Call:=CreateCallExpression(El);
  14055. try
  14056. Call.Expr:=CreateDotNameExpr(Params[0],A,'concat');
  14057. for i:=1 to length(Params)-1 do
  14058. Call.AddArg(ConvertExpression(Params[i],AContext));
  14059. Result:=Call;
  14060. finally
  14061. if Result=nil then
  14062. Call.Free;
  14063. end;
  14064. end;
  14065. end;
  14066. function TPasToJSConverter.ConvertBuiltIn_CopyArray(El: TParamsExpr;
  14067. AContext: TConvertContext): TJSElement;
  14068. // convert copy(Arr,Start,Count)
  14069. // -> rtl.arrayCopy(type,Arr,Start,Count)
  14070. var
  14071. Param: TPasExpr;
  14072. ParamResolved, ElTypeResolved: TPasResolverResult;
  14073. C: TClass;
  14074. TypeParam: TJSElement;
  14075. Call: TJSCallExpression;
  14076. ArrayType: TPasArrayType;
  14077. aResolver: TPas2JSResolver;
  14078. LoElType: TPasType;
  14079. aManaged: Boolean;
  14080. begin
  14081. Result:=nil;
  14082. aResolver:=AContext.Resolver;
  14083. Call:=nil;
  14084. try
  14085. Param:=El.Params[0];
  14086. aResolver.ComputeElement(El,ParamResolved,[]);
  14087. aManaged:=false;
  14088. if (ParamResolved.BaseType=btContext)
  14089. and (ParamResolved.LoTypeEl.ClassType=TPasArrayType) then
  14090. begin
  14091. ArrayType:=TPasArrayType(ParamResolved.LoTypeEl);
  14092. aResolver.ComputeElement(aResolver.GetArrayElType(ArrayType),ElTypeResolved,[rcType]);
  14093. aManaged:=aResolver.IsManagedJSType(ArrayType);
  14094. end
  14095. else if ParamResolved.BaseType=btArrayLit then
  14096. begin
  14097. ElTypeResolved:=ParamResolved;
  14098. ElTypeResolved.BaseType:=ElTypeResolved.SubType;
  14099. ElTypeResolved.SubType:=btNone;
  14100. end;
  14101. // rtl.arrayCopy(type,src,start,count)
  14102. TypeParam:=nil;
  14103. if ElTypeResolved.BaseType=btContext then
  14104. begin
  14105. LoElType:=ElTypeResolved.LoTypeEl;
  14106. C:=LoElType.ClassType;
  14107. if C=TPasRecordType then
  14108. // copy array of record
  14109. TypeParam:=CreateReferencePathExpr(TPasRecordType(LoElType),AContext)
  14110. else if (C=TPasClassType)
  14111. and (TPasClassType(LoElType).ObjKind=okInterface)
  14112. and (TPasClassType(LoElType).InterfaceType=citCom) then
  14113. begin
  14114. // copy array of COM interface
  14115. TypeParam:=CreateLiteralString(El,GetBIName(pbivnIntfRefCnt));
  14116. end;
  14117. end
  14118. else if ElTypeResolved.BaseType=btSet then
  14119. // copy array of set
  14120. TypeParam:=CreateLiteralString(El,GetBIName(pbifnSet_Reference));
  14121. if TypeParam=nil then
  14122. TypeParam:=CreateLiteralNumber(El,0);
  14123. Call:=CreateCallExpression(El);
  14124. // rtl.arrayCopy
  14125. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnArray_Copy)]);
  14126. // param: type
  14127. Call.AddArg(TypeParam);
  14128. // param: src
  14129. Call.AddArg(ConvertExpression(Param,AContext));
  14130. // param: start
  14131. if length(El.Params)=1 then
  14132. Call.AddArg(CreateLiteralNumber(El,0))
  14133. else
  14134. Call.AddArg(ConvertExpression(El.Params[1],AContext));
  14135. // param: count
  14136. if length(El.Params)>=3 then
  14137. Call.AddArg(ConvertExpression(El.Params[2],AContext));
  14138. Result:=Call;
  14139. if aManaged then
  14140. Result:=CreateIntfRef(Result,AContext,El);
  14141. finally
  14142. if Result=nil then
  14143. Call.Free;
  14144. end;
  14145. if El=nil then ;
  14146. if AContext=nil then;
  14147. end;
  14148. function TPasToJSConverter.ConvertBuiltIn_InsertArray(El: TParamsExpr;
  14149. AContext: TConvertContext): TJSElement;
  14150. // procedure insert(item,var AnArray,const position)
  14151. // -> AnArray=rtl.arrayInsert(item,AnArray,position);
  14152. // for array of COM interface: rtl.arrayInsert(item,AnArray,position,"R");
  14153. var
  14154. Call: TJSCallExpression;
  14155. AssignSt: TJSSimpleAssignStatement;
  14156. aResolver: TPas2JSResolver;
  14157. Param: TPasExpr;
  14158. ParamJS: TJSElement;
  14159. ParamResolved: TPasResolverResult;
  14160. ItemType: TPasType;
  14161. C: TClass;
  14162. aManaged: Boolean;
  14163. begin
  14164. Result:=nil;
  14165. aResolver:=AContext.Resolver;
  14166. AssignSt:=nil;
  14167. try
  14168. // AnArray=
  14169. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  14170. AssignSt.LHS:=ConvertExpression(El.Params[1],AContext);
  14171. Call:=CreateCallExpression(El);
  14172. AssignSt.Expr:=Call;
  14173. // rtl.arrayInsert
  14174. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnArray_Insert)]);
  14175. // param: item
  14176. Param:=El.Params[0];
  14177. ParamJS:=ConvertExpression(Param,AContext);
  14178. aManaged:=false;
  14179. aResolver.ComputeElement(Param,ParamResolved,[]);
  14180. if (ParamResolved.BaseType=btContext) then
  14181. begin
  14182. ItemType:=ParamResolved.LoTypeEl;
  14183. aManaged:=aResolver.IsManagedJSType(ItemType);
  14184. C:=ItemType.ClassType;
  14185. if C=TPasRecordType then
  14186. begin
  14187. // todo: clone
  14188. end
  14189. end;
  14190. Call.AddArg(ParamJS);
  14191. // param: AnArray
  14192. Call.AddArg(ConvertExpression(El.Params[1],AContext));
  14193. // param: position
  14194. Call.AddArg(ConvertExpression(El.Params[2],AContext));
  14195. // optional param: type
  14196. if aManaged then
  14197. Call.AddArg(CreateLiteralJSString(El,TJSString(GetBIName(pbivnIntfRefCnt))));
  14198. Result:=AssignSt;
  14199. finally
  14200. if Result=nil then
  14201. AssignSt.Free;
  14202. end;
  14203. end;
  14204. function TPasToJSConverter.ConvertBuiltIn_DeleteArray(El: TParamsExpr;
  14205. AContext: TConvertContext): TJSElement;
  14206. // proc delete(var array,const start,count)
  14207. var
  14208. ArrEl: TJSElement;
  14209. Call: TJSCallExpression;
  14210. Param: TPasExpr;
  14211. aResolver: TPas2JSResolver;
  14212. ParamResolved: TPasResolverResult;
  14213. AssignSt: TJSSimpleAssignStatement;
  14214. begin
  14215. Result:=nil;
  14216. aResolver:=AContext.Resolver;
  14217. Param:=El.Params[0];
  14218. aResolver.ComputeElement(Param,ParamResolved,[]);
  14219. if aResolver.IsManagedJSType(ParamResolved.LoTypeEl) then
  14220. begin
  14221. // for array of COM interface: array=rtl.arrayDeleteR(array,index,count);
  14222. AssignSt:=nil;
  14223. try
  14224. // AnArray=
  14225. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  14226. AssignSt.LHS:=ConvertExpression(Param,AContext);
  14227. Call:=CreateCallExpression(El);
  14228. AssignSt.Expr:=Call;
  14229. // rtl.arrayInsert
  14230. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnArray_DeleteR)]);
  14231. // param: AnArray
  14232. Call.AddArg(ConvertExpression(Param,AContext));
  14233. // param: position
  14234. Call.AddArg(ConvertExpression(El.Params[1],AContext));
  14235. // param: count
  14236. Call.AddArg(ConvertExpression(El.Params[2],AContext));
  14237. Result:=AssignSt;
  14238. finally
  14239. if Result=nil then
  14240. AssignSt.Free;
  14241. end;
  14242. end
  14243. else
  14244. begin
  14245. // array.splice(start,count)
  14246. Call:=nil;
  14247. try
  14248. Call:=CreateCallExpression(El);
  14249. ArrEl:=ConvertExpression(El.Params[0],AContext);
  14250. Call.Expr:=CreateDotNameExpr(El,ArrEl,'splice');
  14251. Call.AddArg(ConvertExpression(El.Params[1],AContext));
  14252. Call.AddArg(ConvertExpression(El.Params[2],AContext));
  14253. Result:=Call;
  14254. finally
  14255. if Result=nil then
  14256. Call.Free;
  14257. end;
  14258. end;
  14259. end;
  14260. function TPasToJSConverter.ConvertBuiltIn_TypeInfo(El: TParamsExpr;
  14261. AContext: TConvertContext): TJSElement;
  14262. var
  14263. ParamResolved: TPasResolverResult;
  14264. Param: TPasExpr;
  14265. ResultEl: TPasResultElement;
  14266. TypeEl: TPasType;
  14267. aResolver: TPas2JSResolver;
  14268. begin
  14269. Result:=nil;
  14270. Param:=El.Params[0];
  14271. aResolver:=AContext.Resolver;
  14272. aResolver.ComputeElement(Param,ParamResolved,[rcNoImplicitProc]);
  14273. {$IFDEF VerbosePas2JS}
  14274. writeln('TPasToJSConverter.ConvertBuiltIn_TypeInfo ',GetResolverResultDbg(ParamResolved));
  14275. {$ENDIF}
  14276. if (ParamResolved.BaseType=btProc) and (ParamResolved.IdentEl is TPasFunction) then
  14277. begin
  14278. // typeinfo(function) -> typeinfo(resulttype)
  14279. ResultEl:=TPasFunction(ParamResolved.IdentEl).FuncType.ResultEl;
  14280. aResolver.ComputeResultElement(ResultEl,ParamResolved,[]);
  14281. {$IFDEF VerbosePas2JS}
  14282. writeln('TPasToJSConverter.ConvertBuiltIn_TypeInfo FuncResult=',GetResolverResultDbg(ParamResolved));
  14283. {$ENDIF}
  14284. Include(ParamResolved.Flags,rrfReadable);
  14285. ParamResolved.IdentEl:=ResultEl;
  14286. end;
  14287. TypeEl:=ResolveSimpleAliasType(ParamResolved.HiTypeEl);
  14288. if TypeEl=nil then
  14289. RaiseNotSupported(El,AContext,20170413001544)
  14290. else if ParamResolved.IdentEl is TPasType then
  14291. Result:=CreateTypeInfoRef(TPasType(ParamResolved.IdentEl),AContext,Param)
  14292. else if (rrfReadable in ParamResolved.Flags)
  14293. and ((TypeEl.ClassType=TPasClassType)
  14294. or (TypeEl.ClassType=TPasClassOfType))
  14295. and ((ParamResolved.IdentEl is TPasVariable)
  14296. or (ParamResolved.IdentEl.ClassType=TPasArgument)
  14297. or (ParamResolved.IdentEl.ClassType=TPasResultElement)) then
  14298. begin
  14299. // typeinfo(classinstance) -> classinstance.$rtti
  14300. // typeinfo(classof) -> classof.$rtti
  14301. Result:=ConvertExpression(Param,AContext);
  14302. Result:=CreateDotNameExpr(El,Result,TJSString(GetBIName(pbivnRTTI)));
  14303. end
  14304. else
  14305. Result:=CreateTypeInfoRef(TypeEl,AContext,Param);
  14306. end;
  14307. function TPasToJSConverter.ConvertBuiltIn_GetTypeKind(El: TParamsExpr;
  14308. AContext: TConvertContext): TJSElement;
  14309. var
  14310. aResolver: TPas2JSResolver;
  14311. Value: TResEvalValue;
  14312. begin
  14313. Result:=nil;
  14314. aResolver:=AContext.Resolver;
  14315. aResolver.BI_GetTypeKind_OnEval(aResolver.BuiltInProcs[bfGetTypeKind],El,[refConst],Value);
  14316. try
  14317. if not (Value is TResEvalEnum) then
  14318. RaiseNotSupported(El,AContext,20200826222729,GetObjName(Value));
  14319. Result:=CreateLiteralNumber(El,TResEvalEnum(Value).Index);
  14320. finally
  14321. ReleaseEvalValue(Value);
  14322. end;
  14323. end;
  14324. function TPasToJSConverter.ConvertBuiltIn_Assert(El: TParamsExpr;
  14325. AContext: TConvertContext): TJSElement;
  14326. // throw pas.SysUtils.EAssertionFailed.$create("Create");
  14327. // throw pas.SysUtils.EAssertionFailed.$create("Create$1",["text"]);
  14328. // throw "text"
  14329. var
  14330. IfSt: TJSIfStatement;
  14331. ThrowSt: TJSThrowStatement;
  14332. ModScope: TPasModuleScope;
  14333. aConstructor: TPasConstructor;
  14334. Ref: TResolvedReference;
  14335. ArrLit: TJSArrayLiteral;
  14336. Call: TJSCallExpression;
  14337. FunName: String;
  14338. PosEl: TPasExpr;
  14339. begin
  14340. Result:=nil;
  14341. // check if assertions are enabled
  14342. if not (bsAssertions in AContext.ScannerBoolSwitches) then
  14343. exit;
  14344. Ref:=nil;
  14345. IfSt:=TJSIfStatement(CreateElement(TJSIfStatement,El));
  14346. try
  14347. PosEl:=El.Params[0];
  14348. IfSt.Cond:=CreateUnaryNot(ConvertExpression(PosEl,AContext),PosEl);
  14349. ThrowSt:=TJSThrowStatement(CreateElement(TJSThrowStatement,PosEl));
  14350. IfSt.BTrue:=ThrowSt;
  14351. // using sysutils.EAssertionFailed if available
  14352. aConstructor:=nil;
  14353. if El.CustomData is TResolvedReference then
  14354. begin
  14355. Ref:=TResolvedReference(El.CustomData);
  14356. if Ref.Declaration is TPasConstructor then
  14357. aConstructor:=TPasConstructor(Ref.Declaration);
  14358. Ref:=nil;
  14359. end;
  14360. //writeln('TPasToJSConverter.ConvertBuiltIn_Assert ',GetObjName(aConstructor));
  14361. if aConstructor<>nil then
  14362. begin
  14363. Ref:=TResolvedReference.Create;
  14364. ModScope:=El.GetModule.CustomData as TPasModuleScope;
  14365. Ref.Declaration:=ModScope.AssertClass;
  14366. // pas.sysutils.EAssertionFailed
  14367. FunName:=CreateReferencePath(ModScope.AssertClass,AContext,rpkPathAndName,true,Ref);
  14368. // append .$create('Create')
  14369. FunName:=FunName+'.'+GetBIName(pbifnClassInstanceNew);
  14370. Call:=CreateCallExpression(PosEl);
  14371. Call.Expr:=CreatePrimitiveDotExpr(FunName,PosEl);
  14372. // parameter: "Create"
  14373. Call.AddArg(CreateLiteralString(PosEl,TransformElToJSName(aConstructor,AContext)));
  14374. ThrowSt.A:=Call;
  14375. if length(El.Params)>1 then
  14376. begin
  14377. // add [msg]
  14378. ArrLit:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,El.Params[1]));
  14379. Call.AddArg(ArrLit);
  14380. ArrLit.AddElement(ConvertExpression(El.Params[1],AContext));
  14381. end;
  14382. end;
  14383. if ThrowSt.A=nil then
  14384. begin
  14385. // fallback: throw msg
  14386. if length(El.Params)>1 then
  14387. ThrowSt.A:=ConvertExpression(El.Params[1],AContext)
  14388. else
  14389. ThrowSt.A:=CreateLiteralJSString(El.Params[0],'assert failed');
  14390. end;
  14391. Result:=IfSt;
  14392. finally
  14393. Ref.Free;
  14394. if Result=nil then
  14395. IfSt.Free;
  14396. end;
  14397. end;
  14398. function TPasToJSConverter.ConvertBuiltIn_New(El: TParamsExpr;
  14399. AContext: TConvertContext): TJSElement;
  14400. // new(p) -> p=new TRecord();
  14401. var
  14402. Param0: TPasExpr;
  14403. ParamResolved: TPasResolverResult;
  14404. AssignContext: TAssignContext;
  14405. TypeEl, SubTypeEl: TPasType;
  14406. aResolveR: TPas2JSResolver;
  14407. RecType: TPasRecordType;
  14408. begin
  14409. Result:=nil;
  14410. Param0:=El.Params[0];
  14411. aResolveR:=AContext.Resolver;
  14412. aResolveR.ComputeElement(Param0,ParamResolved,[]);
  14413. RecType:=nil;
  14414. if ParamResolved.BaseType=btContext then
  14415. begin
  14416. TypeEl:=ParamResolved.LoTypeEl;
  14417. if TypeEl.ClassType=TPasPointerType then
  14418. begin
  14419. SubTypeEl:=aResolveR.ResolveAliasType(TPasPointerType(TypeEl).DestType);
  14420. if SubTypeEl.ClassType=TPasRecordType then
  14421. RecType:=TPasRecordType(SubTypeEl);
  14422. end;
  14423. end;
  14424. if RecType=nil then
  14425. DoError(20180425011901,nIncompatibleTypesGotExpected,sIncompatibleTypesGotExpected,
  14426. [aResolveR.GetResolverResultDescription(ParamResolved,true),'pointer of record'],Param0);
  14427. AssignContext:=TAssignContext.Create(El,nil,AContext);
  14428. try
  14429. aResolveR.ComputeElement(Param0,AssignContext.LeftResolved,[rcNoImplicitProc]);
  14430. AssignContext.RightResolved:=AssignContext.LeftResolved;
  14431. // create right side new TRecord()
  14432. AssignContext.RightSide:=CreateRecordCallNew(El,RecType,AContext);
  14433. Result:=CreateAssignStatement(Param0,AssignContext);
  14434. finally
  14435. AssignContext.RightSide.Free;
  14436. AssignContext.Free;
  14437. end;
  14438. end;
  14439. function TPasToJSConverter.ConvertBuiltIn_Dispose(El: TParamsExpr;
  14440. AContext: TConvertContext): TJSElement;
  14441. // dispose(p)
  14442. // if p is writable set to null
  14443. var
  14444. Param0: TPasExpr;
  14445. aResolveR: TPas2JSResolver;
  14446. ParamResolved: TPasResolverResult;
  14447. TypeEl, SubTypeEl: TPasType;
  14448. RecType: TPasRecordType;
  14449. AssignContext: TAssignContext;
  14450. begin
  14451. Result:=nil;
  14452. Param0:=El.Params[0];
  14453. aResolveR:=AContext.Resolver;
  14454. aResolveR.ComputeElement(Param0,ParamResolved,[]);
  14455. RecType:=nil;
  14456. if ParamResolved.BaseType=btContext then
  14457. begin
  14458. TypeEl:=ParamResolved.LoTypeEl;
  14459. if TypeEl.ClassType=TPasPointerType then
  14460. begin
  14461. SubTypeEl:=aResolveR.ResolveAliasType(TPasPointerType(TypeEl).DestType);
  14462. if SubTypeEl.ClassType=TPasRecordType then
  14463. RecType:=TPasRecordType(SubTypeEl);
  14464. end;
  14465. end;
  14466. if RecType=nil then
  14467. DoError(20180425012910,nIncompatibleTypesGotExpected,sIncompatibleTypesGotExpected,
  14468. [aResolveR.GetResolverResultDescription(ParamResolved,true),'pointer of record'],Param0);
  14469. if not (rrfWritable in ParamResolved.Flags) then
  14470. // Param0 is no writable
  14471. exit(nil);
  14472. // Param0 is writable -> set to null
  14473. AssignContext:=TAssignContext.Create(El,nil,AContext);
  14474. try
  14475. aResolveR.ComputeElement(Param0,AssignContext.LeftResolved,[rcNoImplicitProc]);
  14476. AssignContext.RightResolved:=AssignContext.LeftResolved;
  14477. // create right side: null
  14478. AssignContext.RightSide:=CreateLiteralNull(El);
  14479. Result:=CreateAssignStatement(Param0,AssignContext);
  14480. finally
  14481. AssignContext.RightSide.Free;
  14482. AssignContext.Free;
  14483. end;
  14484. end;
  14485. function TPasToJSConverter.ConvertBuiltIn_Default(El: TParamsExpr;
  14486. AContext: TConvertContext): TJSElement;
  14487. procedure CreateEnumValue(TypeEl: TPasEnumType);
  14488. var
  14489. EnumValue: TPasEnumValue;
  14490. begin
  14491. EnumValue:=TPasEnumValue(TypeEl.Values[0]);
  14492. Result:=CreateReferencePathExpr(EnumValue,AContext);
  14493. end;
  14494. var
  14495. ResolvedEl: TPasResolverResult;
  14496. Param: TPasExpr;
  14497. TypeEl: TPasType;
  14498. Value: TResEvalValue;
  14499. MinVal, MaxVal: TMaxPrecInt;
  14500. C: TClass;
  14501. begin
  14502. Result:=nil;
  14503. if AContext.Resolver=nil then
  14504. RaiseInconsistency(20180501011029,El);
  14505. Param:=El.Params[0];
  14506. AContext.Resolver.ComputeElement(Param,ResolvedEl,[]);
  14507. case ResolvedEl.BaseType of
  14508. btBoolean,btByteBool,btWordBool,btLongBool:
  14509. begin
  14510. Result:=CreateLiteralBoolean(El,LowJSBoolean);
  14511. exit;
  14512. end;
  14513. btChar,
  14514. btWideChar:
  14515. begin
  14516. Result:=CreateLiteralJSString(El,#0);
  14517. exit;
  14518. end;
  14519. btString,btUnicodeString:
  14520. begin
  14521. Result:=CreateLiteralJSString(El,'');
  14522. exit;
  14523. end;
  14524. btByte..btIntMax:
  14525. begin
  14526. TypeEl:=ResolvedEl.LoTypeEl;
  14527. if TypeEl.ClassType=TPasUnresolvedSymbolRef then
  14528. begin
  14529. if TypeEl.CustomData is TResElDataBaseType then
  14530. begin
  14531. AContext.Resolver.GetIntegerRange(ResolvedEl.BaseType,MinVal,MaxVal);
  14532. Result:=CreateLiteralNumber(El,MinVal);
  14533. exit;
  14534. end;
  14535. end
  14536. else if TypeEl.ClassType=TPasRangeType then
  14537. begin
  14538. Value:=AContext.Resolver.EvalRangeLimit(TPasRangeType(TypeEl).RangeExpr,
  14539. [refConst],true,El);
  14540. try
  14541. case Value.Kind of
  14542. revkInt:
  14543. Result:=CreateLiteralNumber(El,TResEvalInt(Value).Int);
  14544. revkUInt:
  14545. Result:=CreateLiteralNumber(El,TResEvalUInt(Value).UInt);
  14546. else
  14547. RaiseNotSupported(El,AContext,20180501011646);
  14548. end;
  14549. exit;
  14550. finally
  14551. ReleaseEvalValue(Value);
  14552. end;
  14553. end;
  14554. {$IFDEF VerbosePas2JS}
  14555. writeln('TPasToJSConverter.ConvertBuiltIn_Default ',GetResolverResultDbg(ResolvedEl));
  14556. {$ENDIF}
  14557. RaiseNotSupported(El,AContext,20180501011649);
  14558. end;
  14559. btSingle,btDouble:
  14560. begin
  14561. Result:=CreateLiteralNumber(El,0);
  14562. TJSLiteral(Result).Value.CustomValue:='0.0';
  14563. exit;
  14564. end;
  14565. btCurrency:
  14566. begin
  14567. Result:=CreateLiteralNumber(El,0);
  14568. exit;
  14569. end;
  14570. btContext:
  14571. begin
  14572. TypeEl:=ResolvedEl.LoTypeEl;
  14573. C:=TypeEl.ClassType;
  14574. if C=TPasEnumType then
  14575. begin
  14576. CreateEnumValue(TPasEnumType(TypeEl));
  14577. exit;
  14578. end
  14579. else if C=TPasSetType then
  14580. begin
  14581. Result:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,El));
  14582. exit;
  14583. end
  14584. else if C=TPasArrayType then
  14585. begin
  14586. Result:=CreateArrayInit(TPasArrayType(TypeEl),nil,El,AContext);
  14587. exit;
  14588. end
  14589. else if C=TPasRecordType then
  14590. begin
  14591. Result:=CreateRecordInit(TPasRecordType(TypeEl),nil,El,AContext);
  14592. exit;
  14593. end
  14594. else if C=TPasRangeType then
  14595. // a custom range without initial value -> use first value
  14596. begin
  14597. Value:=AContext.Resolver.Eval(TPasRangeType(TypeEl).RangeExpr.left,[refConst]);
  14598. try
  14599. Result:=ConvertConstValue(Value,AContext,El);
  14600. finally
  14601. ReleaseEvalValue(Value);
  14602. end;
  14603. end
  14604. else if (C=TPasClassType) or (C=TPasPointerType) or (C=TPasClassOfType) then
  14605. begin
  14606. Result:=CreateLiteralNull(El);
  14607. exit;
  14608. end;
  14609. end;
  14610. btRange:
  14611. begin
  14612. if ResolvedEl.LoTypeEl is TPasRangeType then
  14613. begin
  14614. Value:=AContext.Resolver.Eval(TPasRangeType(ResolvedEl.LoTypeEl).RangeExpr.left,[refConst]);
  14615. try
  14616. Result:=ConvertConstValue(Value,AContext,El);
  14617. finally
  14618. ReleaseEvalValue(Value);
  14619. end;
  14620. exit;
  14621. end;
  14622. end;
  14623. btSet:
  14624. begin
  14625. Result:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,El));
  14626. exit;
  14627. end;
  14628. end;
  14629. {$IFDEF VerbosePas2JS}
  14630. writeln('TPasToJSConverter.ConvertBuiltIn_Default ',GetResolverResultDbg(ResolvedEl));
  14631. {$ENDIF}
  14632. DoError(20180501011723,nXExpectedButYFound,sXExpectedButYFound,['record',
  14633. AContext.Resolver.GetResolverResultDescription(ResolvedEl)],Param);
  14634. end;
  14635. function TPasToJSConverter.ConvertBuiltIn_Debugger(El: TPasExpr;
  14636. AContext: TConvertContext): TJSElement;
  14637. begin
  14638. Result:=CreateLiteralCustomValue(El,'debugger');
  14639. if AContext=nil then ;
  14640. end;
  14641. function TPasToJSConverter.ConvertBuiltIn_AWait(El: TParamsExpr;
  14642. AContext: TConvertContext): TJSElement;
  14643. var
  14644. Param: TPasExpr;
  14645. JS: TJSElement;
  14646. AWaitJS: TJSAwaitExpression;
  14647. begin
  14648. if length(El.Params)=1 then
  14649. Param:=El.Params[0]
  14650. else if length(El.Params)=2 then
  14651. Param:=El.Params[1]
  14652. else
  14653. RaiseNotSupported(El,AContext,20200519233919);
  14654. JS:=ConvertExpression(Param,AContext);
  14655. AWaitJS:=TJSAwaitExpression(CreateElement(TJSAwaitExpression,El));
  14656. AWaitJS.A:=JS;
  14657. Result:=AWaitJS;
  14658. end;
  14659. function TPasToJSConverter.ConvertRecordValues(El: TRecordValues;
  14660. AContext: TConvertContext): TJSElement;
  14661. var
  14662. aResolver: TPas2JSResolver;
  14663. Vars: TFPList;
  14664. RecType: TPasRecordType;
  14665. Ref: TResolvedReference;
  14666. ResolvedEl: TPasResolverResult;
  14667. ObjLit: TJSObjectLiteral;
  14668. i: Integer;
  14669. RecFields: TRecordValuesItemArray;
  14670. Field: PRecordValuesItem;
  14671. Member: TPasElement;
  14672. PasVar: TPasVariable;
  14673. ok: Boolean;
  14674. ObjLitEl: TJSObjectLiteralElement;
  14675. Call: TJSCallExpression;
  14676. CurName: String;
  14677. begin
  14678. Result:=nil;
  14679. aResolver:=AContext.Resolver;
  14680. Vars:=TFPList.Create;
  14681. ok:=false;
  14682. try
  14683. RecType:=nil;
  14684. if aResolver<>nil then
  14685. begin
  14686. // with resolver: TRecord.$clone({...})
  14687. aResolver.ComputeElement(El,ResolvedEl,[]);
  14688. if (ResolvedEl.BaseType<>btContext)
  14689. or (ResolvedEl.LoTypeEl.ClassType<>TPasRecordType) then
  14690. RaiseNotSupported(El,AContext,20180429210932);
  14691. RecType:=TPasRecordType(ResolvedEl.LoTypeEl);
  14692. Call:=CreateRecordCallClone(El,RecType,nil,AContext);
  14693. Result:=Call;
  14694. ObjLit:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,El));
  14695. Call.AddArg(ObjLit);
  14696. end
  14697. else
  14698. begin
  14699. // without resolver: {...}
  14700. ObjLit:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,El));
  14701. Result:=ObjLit;;
  14702. end;
  14703. RecFields:=El.Fields;
  14704. for i:=0 to length(RecFields)-1 do
  14705. begin
  14706. Field:=@RecFields[i];
  14707. Ref:=Field^.NameExp.CustomData as TResolvedReference;
  14708. PasVar:=Ref.Declaration as TPasVariable;
  14709. Vars.Add(PasVar);
  14710. ObjLitEl:=ObjLit.Elements.AddElement;
  14711. CurName:=TransformElToJSName(PasVar,AContext);
  14712. if CurName[1]='[' then
  14713. begin
  14714. if CurName[length(CurName)]=']' then
  14715. CurName:=copy(CurName,2,length(CurName)-2)
  14716. else
  14717. CurName:=copy(CurName,2,length(CurName)-1);
  14718. end;
  14719. ObjLitEl.Name:=TJSString(CurName);
  14720. ObjLitEl.Expr:=CreateValInit(PasVar.VarType,Field^.ValueExp,Field^.NameExp,AContext);
  14721. end;
  14722. // add missing fields
  14723. if RecType<>nil then
  14724. for i:=0 to RecType.Members.Count-1 do
  14725. begin
  14726. Member:=TPasElement(RecType.Members[i]);
  14727. if Member.ClassType<>TPasVariable then continue;
  14728. PasVar:=TPasVariable(Member);
  14729. if [vmClass,vmStatic]*PasVar.VarModifiers<>[] then continue;
  14730. if Vars.IndexOf(PasVar)>=0 then continue;
  14731. if not IsElementUsed(PasVar) then continue;
  14732. // missing instance field in constant -> add default value
  14733. ObjLitEl:=ObjLit.Elements.AddElement;
  14734. ObjLitEl.Name:=TJSString(TransformElToJSName(PasVar,AContext));
  14735. ObjLitEl.Expr:=CreateValInit(PasVar.VarType,PasVar.Expr,PasVar,AContext);
  14736. end;
  14737. ok:=true;
  14738. finally
  14739. Vars.Free;
  14740. if not ok then
  14741. Result.Free;
  14742. end;
  14743. end;
  14744. function TPasToJSConverter.ConvertArrayValues(El: TArrayValues;
  14745. AContext: TConvertContext): TJSElement;
  14746. Var
  14747. ArrLit : TJSArrayLiteral;
  14748. I : Integer;
  14749. begin
  14750. ArrLit:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,El));
  14751. For I:=0 to Length(El.Values)-1 do
  14752. begin
  14753. ArrLit.AddElement(ConvertExpression(El.Values[i],AContext));
  14754. end;
  14755. Result:=ArrLit;
  14756. end;
  14757. function TPasToJSConverter.ConvertExpression(El: TPasExpr;
  14758. AContext: TConvertContext): TJSElement;
  14759. var
  14760. C: TClass;
  14761. begin
  14762. {$IFDEF VerbosePas2JS}
  14763. writeln('TPasToJSConverter.ConvertExpression El=',GetObjName(El),' Context=',GetObjName(AContext));
  14764. {$ENDIF}
  14765. Result:=Nil;
  14766. C:=El.ClassType;
  14767. if C=TUnaryExpr then
  14768. Result:=ConvertUnaryExpression(TUnaryExpr(El),AContext)
  14769. else if C=TBinaryExpr then
  14770. Result:=ConvertBinaryExpression(TBinaryExpr(El),AContext)
  14771. else if C=TPrimitiveExpr then
  14772. Result:=ConvertPrimitiveExpression(TPrimitiveExpr(El),AContext)
  14773. else if C=TBoolConstExpr then
  14774. Result:=ConvertBoolConstExpression(TBoolConstExpr(El),AContext)
  14775. else if C=TNilExpr then
  14776. Result:=ConvertNilExpr(TNilExpr(El),AContext)
  14777. else if C=TInheritedExpr then
  14778. Result:=ConvertInheritedExpr(TInheritedExpr(El),AContext)
  14779. else if C=TParamsExpr then
  14780. Result:=ConvertParamsExpr(TParamsExpr(El),AContext)
  14781. else if C=TProcedureExpr then
  14782. Result:=ConvertProcedure(TProcedureExpr(El).Proc,AContext)
  14783. else if C=TRecordValues then
  14784. Result:=ConvertRecordValues(TRecordValues(El),AContext)
  14785. else if C=TArrayValues then
  14786. Result:=ConvertArrayValues(TArrayValues(El),AContext)
  14787. else if C=TInlineSpecializeExpr then
  14788. Result:=ConvertInlineSpecializeExpr(TInlineSpecializeExpr(El),AContext)
  14789. else
  14790. RaiseNotSupported(El,AContext,20161024191314);
  14791. end;
  14792. function TPasToJSConverter.CreatePrimitiveDotExpr(Path: string;
  14793. PosEl: TPasElement): TJSElement;
  14794. var
  14795. p: Integer;
  14796. DotExpr: TJSDotMemberExpression;
  14797. Ident: TJSPrimaryExpressionIdent;
  14798. begin
  14799. if Path='' then
  14800. RaiseInconsistency(20170402230134,PosEl);
  14801. p:=PosLast('.',Path);
  14802. if p>0 then
  14803. begin
  14804. if PosEl<>nil then
  14805. DotExpr:=TJSDotMemberExpression(CreateElement(TJSDotMemberExpression,PosEl))
  14806. else
  14807. DotExpr:=TJSDotMemberExpression.Create(0,0);
  14808. DotExpr.Name:=TJSString(copy(Path,p+1,length(Path))); // do not lowercase
  14809. DotExpr.MExpr:=CreatePrimitiveDotExpr(LeftStr(Path,p-1),PosEl);
  14810. Result:=DotExpr;
  14811. end
  14812. else
  14813. begin
  14814. if PosEl<>nil then
  14815. Ident:=TJSPrimaryExpressionIdent(CreateElement(TJSPrimaryExpressionIdent,PosEl))
  14816. else
  14817. Ident:=TJSPrimaryExpressionIdent.Create(0,0);
  14818. Ident.Name:=TJSString(Path); // do not lowercase
  14819. Result:=Ident;
  14820. end;
  14821. end;
  14822. function TPasToJSConverter.CreateTypeDecl(El: TPasType;
  14823. AContext: TConvertContext): TJSElement;
  14824. var
  14825. C: TClass;
  14826. GlobalCtx: TConvertContext;
  14827. begin
  14828. Result:=Nil;
  14829. GlobalCtx:=AContext;
  14830. if El.Parent is TProcedureBody then
  14831. GlobalCtx:=AContext.GetGlobalFunc;
  14832. C:=El.ClassType;
  14833. if C=TPasClassType then
  14834. Result := ConvertClassType(TPasClassType(El), GlobalCtx)
  14835. else if (C=TPasClassOfType) then
  14836. Result := ConvertClassOfType(TPasClassOfType(El), GlobalCtx)
  14837. else if C=TPasRecordType then
  14838. Result := ConvertRecordType(TPasRecordType(El), GlobalCtx)
  14839. else if C=TPasEnumType then
  14840. Result := ConvertEnumType(TPasEnumType(El), GlobalCtx)
  14841. else if (C=TPasSetType) then
  14842. Result := ConvertSetType(TPasSetType(El), GlobalCtx)
  14843. else if (C=TPasRangeType) then
  14844. Result:=ConvertRangeType(TPasRangeType(El),GlobalCtx)
  14845. else if (C=TPasAliasType) then
  14846. else if (C=TPasTypeAliasType) then
  14847. Result:=ConvertTypeAliasType(TPasTypeAliasType(El),GlobalCtx)
  14848. else if (C=TPasPointerType) then
  14849. Result:=ConvertPointerType(TPasPointerType(El),GlobalCtx)
  14850. else if (C=TPasProcedureType)
  14851. or (C=TPasFunctionType) then
  14852. Result:=ConvertProcedureType(TPasProcedureType(El),GlobalCtx)
  14853. else if (C=TPasArrayType) then
  14854. Result:=ConvertArrayType(TPasArrayType(El),GlobalCtx)
  14855. else if (C=TPasSpecializeType) then
  14856. // specialize type is converted at the generic type
  14857. else
  14858. begin
  14859. {$IFDEF VerbosePas2JS}
  14860. writeln('TPasToJSConverter.CreateTypeDecl El=',GetObjName(El));
  14861. {$ENDIF}
  14862. RaiseNotSupported(El,AContext,20170208144053);
  14863. end;
  14864. end;
  14865. function TPasToJSConverter.CreateVarDecl(El: TPasVariable;
  14866. AContext: TConvertContext): TJSElement;
  14867. Var
  14868. C : TJSElement;
  14869. V : TJSVariableStatement;
  14870. AssignSt: TJSSimpleAssignStatement;
  14871. Obj: TJSObjectLiteral;
  14872. ObjLit: TJSObjectLiteralElement;
  14873. begin
  14874. Result:=nil;
  14875. if El.AbsoluteExpr<>nil then
  14876. exit; // absolute: do not add a declaration
  14877. if vmExternal in El.VarModifiers then
  14878. exit; // external: do not add a declaration
  14879. if AContext is TObjectContext then
  14880. begin
  14881. // create 'A: initvalue'
  14882. Obj:=TObjectContext(AContext).JSElement as TJSObjectLiteral;
  14883. ObjLit:=Obj.Elements.AddElement;
  14884. ObjLit.Name:=TJSString(TransformElToJSName(El,AContext));
  14885. ObjLit.Expr:=CreateVarInit(El,AContext);
  14886. end
  14887. else if AContext.IsGlobal or (El.Parent is TPasMembersType) then
  14888. begin
  14889. // create 'this.A=initvalue'
  14890. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  14891. Result:=AssignSt;
  14892. AssignSt.LHS:=CreateSubDeclNameExpr(El,AContext);
  14893. AssignSt.Expr:=CreateVarInit(El,AContext);
  14894. end
  14895. else
  14896. begin
  14897. // create 'var A=initvalue'
  14898. C:=ConvertVariable(El,AContext);
  14899. if C=nil then
  14900. RaiseInconsistency(20180501114300,El);
  14901. V:=TJSVariableStatement(CreateElement(TJSVariableStatement,El));
  14902. V.VarDecl:=C;
  14903. Result:=V;
  14904. end;
  14905. end;
  14906. function TPasToJSConverter.CreateSwitchStatement(El: TPasImplCaseOf;
  14907. AContext: TConvertContext): TJSElement;
  14908. var
  14909. SwitchEl: TJSSwitchStatement;
  14910. JSCaseEl: TJSCaseElement;
  14911. SubEl: TPasImplElement;
  14912. St: TPasImplCaseStatement;
  14913. ok: Boolean;
  14914. i, j: Integer;
  14915. BreakSt: TJSBreakStatement;
  14916. BodySt: TJSElement;
  14917. StList: TJSStatementList;
  14918. Expr: TPasExpr;
  14919. begin
  14920. Result:=nil;
  14921. SwitchEl:=TJSSwitchStatement(CreateElement(TJSSwitchStatement,El));
  14922. ok:=false;
  14923. try
  14924. SwitchEl.Cond:=ConvertExpression(El.CaseExpr,AContext);
  14925. for i:=0 to El.Elements.Count-1 do
  14926. begin
  14927. SubEl:=TPasImplElement(El.Elements[i]);
  14928. if not (SubEl is TPasImplCaseStatement) then
  14929. continue;
  14930. St:=TPasImplCaseStatement(SubEl);
  14931. JSCaseEl:=nil;
  14932. for j:=0 to St.Expressions.Count-1 do
  14933. begin
  14934. Expr:=TPasExpr(St.Expressions[j]);
  14935. JSCaseEl:=SwitchEl.Cases.AddCase;
  14936. JSCaseEl.Expr:=ConvertExpression(Expr,AContext);
  14937. end;
  14938. BodySt:=nil;
  14939. if St.Body<>nil then
  14940. BodySt:=ConvertElement(St.Body,AContext);
  14941. // add break
  14942. BreakSt:=TJSBreakStatement(CreateElement(TJSBreakStatement,St));
  14943. if BodySt=nil then
  14944. // no Pascal statement -> add only one 'break;'
  14945. BodySt:=BreakSt
  14946. else
  14947. begin
  14948. if (BodySt is TJSStatementList) then
  14949. begin
  14950. // list of statements -> append 'break;' to end
  14951. StList:=TJSStatementList(BodySt);
  14952. AddToStatementList(TJSStatementList(BodySt),StList,BreakSt,St);
  14953. end
  14954. else
  14955. begin
  14956. // single statement -> create list of old and 'break;'
  14957. StList:=TJSStatementList(CreateElement(TJSStatementList,St));
  14958. StList.A:=BodySt;
  14959. StList.B:=BreakSt;
  14960. BodySt:=StList;
  14961. end;
  14962. end;
  14963. JSCaseEl.Body:=BodySt;
  14964. end;
  14965. if El.ElseBranch<>nil then
  14966. begin
  14967. JSCaseEl:=SwitchEl.Cases.AddCase;
  14968. JSCaseEl.Body:=ConvertImplBlockElements(El.ElseBranch,AContext,false);
  14969. SwitchEl.TheDefault:=JSCaseEl;
  14970. end;
  14971. ok:=true;
  14972. finally
  14973. if not ok then
  14974. SwitchEl.Free;
  14975. end;
  14976. Result:=SwitchEl;
  14977. end;
  14978. function TPasToJSConverter.ConvertDeclarations(El: TPasDeclarations;
  14979. AContext: TConvertContext): TJSElement;
  14980. Var
  14981. SLFirst, SLLast: TJSStatementList;
  14982. IsProcBody, IsFunction, IsAssembler, IsConstructor, HasResult: boolean;
  14983. PasProc: TPasProcedure;
  14984. ProcScope: TPasProcedureScope;
  14985. ProcBody: TPasImplBlock;
  14986. ResultEl: TPasResultElement;
  14987. ResultVarName: String;
  14988. ResStrVarEl: TJSVarDeclaration;
  14989. ResStrVarElAdd: boolean;
  14990. Procedure Add(NewEl: TJSElement; PosEl: TPasElement);
  14991. begin
  14992. if AContext is TObjectContext then
  14993. begin
  14994. // NewEl is already added
  14995. end
  14996. else if AContext.IsGlobal and (AContext.JSElement is TJSSourceElements) then
  14997. AddToSourceElements(TJSSourceElements(AContext.JSElement),NewEl)
  14998. else
  14999. begin
  15000. AddToStatementList(SLFirst,SLLast,NewEl,PosEl);
  15001. ConvertDeclarations:=SLFirst;
  15002. end;
  15003. end;
  15004. Procedure AddFunctionResultInit;
  15005. var
  15006. Proc: TPasProcedure;
  15007. FunType: TPasFunctionType;
  15008. VarSt: TJSVariableStatement;
  15009. ImplScope: TPas2JSProcedureScope;
  15010. begin
  15011. Proc:=El.Parent as TPasProcedure;
  15012. FunType:=Proc.ProcType as TPasFunctionType;
  15013. ResultEl:=FunType.ResultEl;
  15014. ImplScope:=Proc.CustomData as TPas2JSProcedureScope;
  15015. if (ResultEl=nil) or (ResultEl.ResultType=nil) then
  15016. begin
  15017. Proc:=ImplScope.DeclarationProc;
  15018. FunType:=Proc.ProcType as TPasFunctionType;
  15019. ResultEl:=FunType.ResultEl;
  15020. end;
  15021. if ImplScope.ResultVarName<>'' then
  15022. ResultVarName:=ImplScope.ResultVarName
  15023. else
  15024. ResultVarName:=ResolverResultVar;
  15025. // add 'var result=initvalue'
  15026. VarSt:=CreateVarStatement(ResultVarName,
  15027. CreateValInit(ResultEl.ResultType,nil,ResultEl,aContext),ResultEl);
  15028. Add(VarSt,ResultEl);
  15029. Result:=SLFirst;
  15030. end;
  15031. Procedure AddFunctionResultReturn;
  15032. var
  15033. RetSt: TJSReturnStatement;
  15034. begin
  15035. RetSt:=TJSReturnStatement(CreateElement(TJSReturnStatement,ResultEl));
  15036. RetSt.Expr:=CreatePrimitiveDotExpr(ResultVarName,ResultEl);
  15037. Add(RetSt,ResultEl);
  15038. end;
  15039. Procedure AddReturnThis;
  15040. var
  15041. RetSt: TJSReturnStatement;
  15042. HelperForType: TPasType;
  15043. Call: TJSCallExpression;
  15044. Proc: TPasProcedure;
  15045. aResolver: TPas2JSResolver;
  15046. ClassOrRec: TPasMembersType;
  15047. begin
  15048. // "return this"
  15049. RetSt:=TJSReturnStatement(CreateElement(TJSReturnStatement,El));
  15050. RetSt.Expr:=TJSPrimaryExpressionThis(CreateElement(TJSPrimaryExpressionThis,El));
  15051. aResolver:=AContext.Resolver;
  15052. if aResolver<>nil then
  15053. begin
  15054. Proc:=TPasProcedure(El.Parent);
  15055. ProcScope:=Proc.CustomData as TPas2JSProcedureScope;
  15056. ClassOrRec:=ProcScope.ClassRecScope.Element as TPasMembersType;
  15057. if (ClassOrRec.ClassType=TPasClassType)
  15058. and (TPasClassType(ClassOrRec).HelperForType<>nil) then
  15059. begin
  15060. HelperForType:=AContext.Resolver.ResolveAliasType(TPasClassType(ClassOrRec).HelperForType);
  15061. if HelperForType is TPasMembersType then
  15062. // helper constructor for class or record -> "this" is the class/record
  15063. else
  15064. begin
  15065. // helper constructor for a simpletype -> "this" is a reference
  15066. // -> return this.get()
  15067. Call:=CreateCallExpression(El);
  15068. Call.Expr:=CreateDotExpression(El,RetSt.Expr,
  15069. CreatePrimitiveDotExpr(TempRefObjGetterName,El));
  15070. RetSt.Expr:=Call;
  15071. end;
  15072. end;
  15073. end;
  15074. Add(RetSt,El);
  15075. end;
  15076. procedure AddResourceString(ResStr: TPasResString);
  15077. // $mod.$resourcestrings = {
  15078. // name1 : { org: "value" },
  15079. // name2 : { org: "value" },
  15080. // ...
  15081. // }
  15082. var
  15083. Value: TResEvalValue;
  15084. ObjLit: TJSObjectLiteral;
  15085. Lit: TJSObjectLiteralElement;
  15086. RootContext: TRootContext;
  15087. begin
  15088. // first convert expression, it might fail
  15089. Value:=AContext.Resolver.Eval(ResStr.Expr,[refConst]);
  15090. //writeln('AddResourceString ',GetObjName(ResStr),' Value=',Value.AsDebugString);
  15091. // create table
  15092. if (ResStrVarEl=nil) and (El.ClassType=TImplementationSection) then
  15093. begin
  15094. RootContext:=AContext.GetRootContext as TRootContext;
  15095. ResStrVarEl:=RootContext.ResourceStrings;
  15096. end;
  15097. if ResStrVarEl=nil then
  15098. begin
  15099. ResStrVarEl:=TJSVarDeclaration(CreateElement(TJSVarDeclaration,El));
  15100. ResStrVarEl.Name:=TJSString(GetBIName(pbivnModule)+'.'+GetBIName(pbivnResourceStrings));
  15101. ResStrVarElAdd:=true;
  15102. ObjLit:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,El));
  15103. ResStrVarEl.Init:=ObjLit;
  15104. RootContext:=TRootContext(AContext.GetContextOfType(TRootContext));
  15105. RootContext.ResourceStrings:=ResStrVarEl;
  15106. end;
  15107. // add element: name : { ... }
  15108. Lit:=TJSObjectLiteral(ResStrVarEl.Init).Elements.AddElement;
  15109. Lit.Name:=TJSString(TransformElToJSName(ResStr,AContext));
  15110. ObjLit:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,ResStr));
  15111. Lit.Expr:=ObjLit;
  15112. // add sub element: org: value
  15113. Lit:=ObjLit.Elements.AddElement;
  15114. Lit.Name:=TJSString(GetBIName(pbivnResourceStringOrig));
  15115. Lit.Expr:=ConvertConstValue(Value,AContext,ResStr);
  15116. ReleaseEvalValue(Value);
  15117. end;
  15118. procedure InitForwards(Decls: TFPList; SectionContext: TSectionContext);
  15119. var
  15120. i: Integer;
  15121. P: TPasElement;
  15122. C: TClass;
  15123. Proc: TPasProcedure;
  15124. aResolver: TPas2JSResolver;
  15125. begin
  15126. aResolver:=AContext.Resolver;
  15127. For i:=0 to Decls.Count-1 do
  15128. begin
  15129. P:=TPasElement(Decls[i]);
  15130. if not IsElementUsed(P) then continue;
  15131. C:=P.ClassType;
  15132. if (C=TPasClassType) or (C=TPasRecordType) or (C=TPasEnumType) then
  15133. begin
  15134. if (C=TPasClassType) then
  15135. begin
  15136. if TPasClassType(P).IsForward then
  15137. continue;
  15138. if not aResolver.IsFullySpecialized(TPasClassType(P)) then
  15139. continue;
  15140. end
  15141. else if C=TPasRecordType then
  15142. begin
  15143. if not aResolver.IsFullySpecialized(TPasRecordType(P)) then
  15144. continue;
  15145. end;
  15146. // add var $lt = null;
  15147. CreateGlobalAliasNull(P,pbivnLocalTypeRef,SectionContext);
  15148. if (C=TPasClassType) or (C=TPasRecordType) then
  15149. InitForwards(TPasMembersType(P).Members,SectionContext);
  15150. end
  15151. else if C.InheritsFrom(TPasProcedure) then
  15152. begin
  15153. Proc:=TPasProcedure(P);
  15154. if Proc.IsForward or Proc.IsAbstract or Proc.IsExternal then
  15155. continue;
  15156. if TPas2JSProcedureScope(Proc.CustomData).SpecializedFromItem=nil then
  15157. continue;
  15158. if not aResolver.IsFullySpecialized(Proc) then
  15159. continue; // skip non specialized generics
  15160. // specialized proc: add var $lp = null;
  15161. CreateGlobalAliasNull(P,pbivnLocalProcRef,SectionContext);
  15162. end;
  15163. end;
  15164. end;
  15165. procedure InitSection(Section: TPasSection);
  15166. var
  15167. SectionScope: TPas2JSSectionScope;
  15168. SectionCtx: TSectionContext;
  15169. Src: TJSSourceElements;
  15170. ImplSect: TImplementationSection;
  15171. begin
  15172. SectionScope:=Section.CustomData as TPas2JSSectionScope;
  15173. AContext.ScannerBoolSwitches:=SectionScope.BoolSwitches;
  15174. AContext.ScannerModeSwitches:=SectionScope.ModeSwitches;
  15175. if not (AContext is TSectionContext) then
  15176. RaiseNotSupported(Section,AContext,20200606142828,GetObjName(AContext));
  15177. SectionCtx:=TSectionContext(AContext);
  15178. Src:=SectionCtx.JSElement as TJSSourceElements;
  15179. SectionCtx.HeaderIndex:=Src.Statements.Count;
  15180. // add local vars for forward declarations
  15181. if (coShortRefGlobals in Options)
  15182. and (Section.ClassType<>TImplementationSection) then
  15183. begin
  15184. InitForwards(Section.Declarations,TSectionContext(AContext));
  15185. if Section is TInterfaceSection then
  15186. begin
  15187. ImplSect:=TPasModule(Section.Parent).ImplementationSection;
  15188. if ImplSect<>nil then
  15189. InitForwards(ImplSect.Declarations,TSectionContext(AContext));
  15190. end;
  15191. end;
  15192. end;
  15193. var
  15194. E, BodySt: TJSElement;
  15195. I : Integer;
  15196. P: TPasElement;
  15197. C: TClass;
  15198. FuncContext: TFunctionContext;
  15199. begin
  15200. Result:=nil;
  15201. {
  15202. TPasDeclarations = class(TPasElement)
  15203. TPasSection = class(TPasDeclarations)
  15204. TInterfaceSection = class(TPasSection)
  15205. TImplementationSection = class(TPasSection)
  15206. TProgramSection = class(TImplementationSection)
  15207. TLibrarySection = class(TImplementationSection)
  15208. TProcedureBody = class(TPasDeclarations)
  15209. }
  15210. IsProcBody:=(El is TProcedureBody) and (TProcedureBody(El).Body<>nil);
  15211. IsFunction:=IsProcBody and (TPasProcedure(El.Parent).ProcType is TPasFunctionType);
  15212. IsAssembler:=IsProcBody and (TProcedureBody(El).Body is TPasImplAsmStatement);
  15213. IsConstructor:=IsProcBody and (El.Parent.ClassType=TPasConstructor);
  15214. HasResult:=IsFunction and not IsAssembler;
  15215. if (AContext.Resolver<>nil) and (El is TPasSection) then
  15216. InitSection(TPasSection(El));
  15217. SLFirst:=nil;
  15218. SLLast:=nil;
  15219. ResultEl:=nil;
  15220. ResultVarName:='';
  15221. ResStrVarEl:=nil;
  15222. ResStrVarElAdd:=false;
  15223. try
  15224. if HasResult then
  15225. AddFunctionResultInit;
  15226. For I:=0 to El.Declarations.Count-1 do
  15227. begin
  15228. P:=TPasElement(El.Declarations[i]);
  15229. {$IFDEF VerbosePas2JS}
  15230. writeln('TPasToJSConverter.ConvertDeclarations El[',i,']=',GetObjName(P));
  15231. {$ENDIF}
  15232. if not IsElementUsed(P) then continue;
  15233. E:=Nil;
  15234. C:=P.ClassType;
  15235. if C=TPasConst then
  15236. E:=ConvertConst(TPasConst(P),aContext) // can be nil
  15237. else if C=TPasVariable then
  15238. E:=CreateVarDecl(TPasVariable(P),aContext) // can be nil
  15239. else if C.InheritsFrom(TPasType) then
  15240. E:=CreateTypeDecl(TPasType(P),aContext) // can be nil
  15241. else if C.InheritsFrom(TPasProcedure) then
  15242. begin
  15243. PasProc:=TPasProcedure(P);
  15244. if PasProc.IsForward then continue; // JavaScript does not need the forward
  15245. ProcScope:=TPasProcedureScope(PasProc.CustomData);
  15246. if (ProcScope.DeclarationProc<>nil)
  15247. and (not ProcScope.DeclarationProc.IsForward) then
  15248. continue; // this proc was already converted in interface or class
  15249. if ProcScope.DeclarationProc<>nil then
  15250. PasProc:=ProcScope.DeclarationProc;
  15251. E:=ConvertProcedure(PasProc,aContext);
  15252. end
  15253. else if C=TPasResString then
  15254. begin
  15255. if not (El is TPasSection) then
  15256. RaiseNotSupported(P,AContext,20171004185348);
  15257. AddResourceString(TPasResString(P));
  15258. continue;
  15259. end
  15260. else if C=TPasAttributes then
  15261. continue
  15262. else if C=TPasExportSymbol then
  15263. continue
  15264. else
  15265. RaiseNotSupported(P as TPasElement,AContext,20161024191434);
  15266. Add(E,P);
  15267. end;
  15268. if IsProcBody then
  15269. begin
  15270. ProcBody:=TProcedureBody(El).Body;
  15271. if (ProcBody.Elements.Count>0) or IsAssembler then
  15272. begin
  15273. // convert body (creates a TJSStatementList)
  15274. BodySt:=ConvertElement(ProcBody,aContext);
  15275. if AContext is TFunctionContext then
  15276. begin
  15277. FuncContext:=TFunctionContext(AContext);
  15278. FuncContext.BodySt:=BodySt;
  15279. // if needed add try..finally for COM interfaces
  15280. AddInterfaceReleases(FuncContext,ProcBody);
  15281. if FuncContext.ResultNeedsIntfRelease then
  15282. AddInterfaceRelease_Result(FuncContext,ResultVarName,ProcBody);
  15283. BodySt:=FuncContext.BodySt;
  15284. end;
  15285. Add(BodySt,ProcBody);
  15286. end;
  15287. end;
  15288. if HasResult then
  15289. AddFunctionResultReturn
  15290. else if IsConstructor then
  15291. AddReturnThis;
  15292. if ResStrVarEl<>nil then
  15293. begin
  15294. if ResStrVarElAdd then
  15295. Add(ResStrVarEl,El);
  15296. ResStrVarEl:=nil;
  15297. end;
  15298. finally
  15299. ResStrVarEl.Free;
  15300. end;
  15301. end;
  15302. function TPasToJSConverter.ConvertClassType(El: TPasClassType;
  15303. AContext: TConvertContext): TJSElement;
  15304. (*
  15305. type
  15306. TMyClass = class(Ancestor)
  15307. i: longint;
  15308. end;
  15309. rtl.createClass(this,"TMyClass",Ancestor,function(){
  15310. this.i = 0;
  15311. });
  15312. *)
  15313. var
  15314. IsTObject, AncestorIsExternal: boolean;
  15315. function IsMemberNeeded(aMember: TPasElement): boolean;
  15316. begin
  15317. if IsElementUsed(aMember) then exit(true);
  15318. if IsTObject then
  15319. begin
  15320. if aMember.ClassType=TPasProcedure then
  15321. begin
  15322. if (CompareText(aMember.Name,'AfterConstruction')=0)
  15323. or (CompareText(aMember.Name,'BeforeDestruction')=0) then
  15324. exit(true);
  15325. end;
  15326. end;
  15327. Result:=false;
  15328. end;
  15329. procedure AddInterfaceProcNames(Call: TJSCallExpression);
  15330. var
  15331. Arr: TJSArrayLiteral;
  15332. i: Integer;
  15333. Member: TPasElement;
  15334. begin
  15335. Arr:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,El));
  15336. Call.AddArg(Arr);
  15337. for i:=0 to El.Members.Count-1 do
  15338. begin
  15339. Member:=TPasElement(El.Members[i]);
  15340. if not (Member is TPasProcedure) then continue;
  15341. if not IsMemberNeeded(Member) then continue;
  15342. if (Member.ClassType=TPasClassConstructor)
  15343. or (Member.ClassType=TPasClassDestructor) then
  15344. continue;
  15345. Arr.AddElement(CreateLiteralString(Member,TransformElToJSName(Member,AContext)));
  15346. end;
  15347. end;
  15348. var
  15349. aResolver: TPas2JSResolver;
  15350. DelaySrc: TJSSourceElements;
  15351. DelayFuncContext: TFunctionContext;
  15352. Call: TJSCallExpression;
  15353. FunDecl: TJSFunctionDeclarationStatement;
  15354. Src: TJSSourceElements;
  15355. ArgEx: TJSLiteral;
  15356. FuncContext: TFunctionContext;
  15357. i: Integer;
  15358. NewEl: TJSElement;
  15359. P: TPasElement;
  15360. Scope: TPas2JSClassScope;
  15361. Ancestor: TPasType;
  15362. AncestorPath, OwnerName, DestructorName, FnName, IntfKind, JSName: String;
  15363. C: TClass;
  15364. AssignSt: TJSSimpleAssignStatement;
  15365. NeedInitFunction, HasConstructor, IsJSFunction, NeedClassExt,
  15366. SpecializeDelay, NeedTypeInfo: Boolean;
  15367. Proc: TPasProcedure;
  15368. begin
  15369. Result:=nil;
  15370. aResolver:=AContext.Resolver;
  15371. {$IFDEF VerbosePas2JS}
  15372. writeln('TPasToJSConverter.ConvertClassType START ',GetObjName(El));
  15373. {$ENDIF}
  15374. if not (El.ObjKind in [okClass,okInterface,okClassHelper,okRecordHelper,okTypeHelper]) then
  15375. RaiseNotSupported(El,AContext,20170927183645);
  15376. if El.Parent is TProcedureBody then
  15377. RaiseNotSupported(El,AContext,20181231004355);
  15378. if not aResolver.IsFullySpecialized(El) then exit;
  15379. if El.IsForward then
  15380. exit(ConvertClassForwardType(El,AContext))
  15381. else if El.IsExternal then
  15382. exit(ConvertExtClassType(El,AContext));
  15383. IsTObject:=false;
  15384. if El.CustomData is TPas2JSClassScope then
  15385. begin
  15386. Scope:=TPas2JSClassScope(El.CustomData);
  15387. if Scope.AncestorScope<>nil then
  15388. Ancestor:=Scope.AncestorScope.Element as TPasType
  15389. else
  15390. begin
  15391. Ancestor:=nil;
  15392. IsTObject:=(El.ObjKind=okClass) and SameText(El.Name,'TObject');
  15393. end;
  15394. // clear Msg lists, they recreated only for the needed procs
  15395. FreeAndNil(Scope.MsgIntToProc);
  15396. FreeAndNil(Scope.MsgStrToProc);
  15397. SpecializeDelay:=SpecializeNeedsDelay(El,AContext);
  15398. end
  15399. else
  15400. begin
  15401. Scope:=nil;
  15402. IsTObject:=(El.AncestorType=nil) and (El.ObjKind=okClass) and SameText(El.Name,'TObject');
  15403. Ancestor:=El.AncestorType;
  15404. SpecializeDelay:=false;
  15405. end;
  15406. // create call 'rtl.createClass(' or 'rtl.createInterface('
  15407. FuncContext:=nil;
  15408. DelaySrc:=nil;
  15409. DelayFuncContext:=nil;
  15410. Call:=CreateCallExpression(El);
  15411. try
  15412. AncestorIsExternal:=(Ancestor is TPasClassType) and TPasClassType(Ancestor).IsExternal;
  15413. IsJSFunction:=aResolver.IsExternalClass_Name(El,'Function');
  15414. NeedClassExt:=AncestorIsExternal or IsJSFunction;
  15415. if NeedClassExt and (El.ObjKind<>okClass) then
  15416. RaiseNotSupported(El,AContext,20200627083750);
  15417. if El.ObjKind=okInterface then
  15418. FnName:=GetBIName(pbifnIntfCreate)
  15419. else if El.ObjKind in okAllHelpers then
  15420. FnName:=GetBIName(pbifnCreateHelper)
  15421. else if NeedClassExt then
  15422. FnName:=GetBIName(pbifnCreateClassExt)
  15423. else
  15424. FnName:=GetBIName(pbifnCreateClass);
  15425. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),FnName]);
  15426. // add parameter: owner. For top level class, the module is the owner.
  15427. if (El.Parent=nil)
  15428. or ((El.Parent is TPasSection)
  15429. and (El.Parent.ClassType<>TImplementationSection)) then
  15430. OwnerName:=AContext.GetLocalName(El.GetModule,[cvkGlobal])
  15431. else
  15432. OwnerName:=AContext.GetLocalName(El.Parent,[cvkGlobal]);
  15433. if OwnerName='' then
  15434. OwnerName:='this';
  15435. Call.AddArg(CreatePrimitiveDotExpr(OwnerName,El));
  15436. // add parameter: string constant '"classname"'
  15437. JSName:=TransformElToJSName(El,AContext);
  15438. ArgEx:=CreateLiteralString(El,JSName);
  15439. Call.AddArg(ArgEx);
  15440. if El.ObjKind=okInterface then
  15441. begin
  15442. // add parameter: string constant guid
  15443. Call.AddArg(CreateLiteralString(El,uppercase(Scope.GUID)));
  15444. // add parameter: array of function names
  15445. AddInterfaceProcNames(Call);
  15446. end;
  15447. // add parameter: ancestor
  15448. if Ancestor=nil then
  15449. AncestorPath:='null'
  15450. else if AncestorIsExternal then
  15451. AncestorPath:=TPasClassType(Ancestor).ExternalName
  15452. else
  15453. AncestorPath:=CreateReferencePath(Ancestor,AContext,rpkPathAndName);
  15454. Call.AddArg(CreatePrimitiveDotExpr(AncestorPath,El));
  15455. // for external class: add name of NewInstance function
  15456. if NeedClassExt then
  15457. begin
  15458. if Scope.NewInstanceFunction<>nil then
  15459. Call.AddArg(CreateLiteralString(
  15460. Scope.NewInstanceFunction,Scope.NewInstanceFunction.Name))
  15461. else
  15462. Call.AddArg(CreateLiteralString(El,''));
  15463. end;
  15464. NeedInitFunction:=true;
  15465. NeedTypeInfo:=(pcsfPublished in Scope.Flags) or HasTypeInfo(El,AContext)
  15466. or aResolver.HasExtRTTI(El);
  15467. IntfKind:='';
  15468. if El.ObjKind=okInterface then
  15469. begin
  15470. if (Scope.AncestorScope=nil) and (not (coNoTypeInfo in Options)) then
  15471. case El.InterfaceType of
  15472. citCom: IntfKind:='com';
  15473. citCorba: ; // default
  15474. else
  15475. RaiseNotSupported(El,AContext,20180405093512){%H-};
  15476. end;
  15477. NeedInitFunction:=NeedTypeInfo or (IntfKind<>'') or (coShortRefGlobals in Options);
  15478. end;
  15479. if NeedInitFunction then
  15480. begin
  15481. // add parameter: class initialize function 'function(){...}'
  15482. FunDecl:=CreateFunctionSt(El,true,true);
  15483. Call.AddArg(FunDecl);
  15484. Src:=TJSSourceElements(FunDecl.AFunction.Body.A);
  15485. // create context
  15486. FuncContext:=TFunctionContext.Create(El,Src,AContext);
  15487. FuncContext.IsGlobal:=true;
  15488. FuncContext.ThisVar.Element:=El;
  15489. FuncContext.ThisVar.Kind:=cvkGlobal;
  15490. if coShortRefGlobals in Options then
  15491. begin
  15492. // $lt = this;
  15493. JSName:=AContext.GetLocalName(El,[cvkGlobal]);
  15494. if JSName='' then
  15495. RaiseNotSupported(El,AContext,20200926232402);
  15496. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  15497. AssignSt.LHS:=CreatePrimitiveDotExpr(JSName,El);
  15498. AssignSt.Expr:=CreatePrimitiveDotExpr('this',El);
  15499. AddToSourceElements(Src,AssignSt);
  15500. end;
  15501. if IntfKind<>'' then
  15502. begin
  15503. // add this.$kind="com";
  15504. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  15505. AssignSt.LHS:=CreatePrimitiveDotExpr('this.'+GetBIName(pbivnIntfKind),El);
  15506. AssignSt.Expr:=CreateLiteralString(El,IntfKind);
  15507. AddToSourceElements(Src,AssignSt);
  15508. end;
  15509. // add class members: types and class vars
  15510. if SpecializeDelay then
  15511. DelayFuncContext:=CreateDelayedInitMembersFunction(El,Src,FuncContext,DelaySrc);
  15512. if El.ObjKind in ([okClass]+okAllHelpers) then
  15513. begin
  15514. For i:=0 to El.Members.Count-1 do
  15515. begin
  15516. P:=TPasElement(El.Members[i]);
  15517. //writeln('TPasToJSConverter.ConvertClassType class vars El[',i,']=',GetObjName(P));
  15518. if not IsMemberNeeded(P) then continue;
  15519. C:=P.ClassType;
  15520. NewEl:=nil;
  15521. if C=TPasVariable then
  15522. begin
  15523. if ClassVarModifiersType*TPasVariable(P).VarModifiers*[vmClass, vmStatic]<>[] then
  15524. begin
  15525. NewEl:=CreateVarDecl(TPasVariable(P),FuncContext); // can be nil
  15526. if NewEl=nil then continue;
  15527. end
  15528. else
  15529. continue;
  15530. end
  15531. else if C=TPasConst then
  15532. NewEl:=ConvertConst(TPasConst(P),FuncContext)
  15533. else if C=TPasProperty then
  15534. NewEl:=ConvertProperty(TPasProperty(P),FuncContext)
  15535. else if C.InheritsFrom(TPasType) then
  15536. NewEl:=CreateTypeDecl(TPasType(P),FuncContext)
  15537. else if C.InheritsFrom(TPasProcedure) then
  15538. continue
  15539. else if C=TPasMethodResolution then
  15540. continue
  15541. else if C=TPasAttributes then
  15542. continue
  15543. else
  15544. RaiseNotSupported(P,FuncContext,20161221233338);
  15545. if NewEl<>nil then
  15546. begin
  15547. if SpecializeDelay and not (P is TPasProcedure) then
  15548. AddToSourceElements(DelaySrc,NewEl)
  15549. else
  15550. AddToSourceElements(Src,NewEl);
  15551. end;
  15552. end;
  15553. end;
  15554. if El.ObjKind in [okClass] then
  15555. begin
  15556. // instance initialization function
  15557. AddClassConDestructorFunction(El,Src,FuncContext,IsTObject,Ancestor,mfInit);
  15558. // instance finalization function
  15559. AddClassConDestructorFunction(El,Src,FuncContext,IsTObject,Ancestor,mfFinalize);
  15560. end;
  15561. if El.ObjKind in ([okClass]+okAllHelpers) then
  15562. begin
  15563. HasConstructor:=false;
  15564. // add method implementations
  15565. For i:=0 to El.Members.Count-1 do
  15566. begin
  15567. P:=TPasElement(El.Members[i]);
  15568. //writeln('TPasToJSConverter.ConvertClassType methods El[',i,']=',GetObjName(P));
  15569. if not IsMemberNeeded(P) then continue;
  15570. NewEl:=nil;
  15571. C:=P.ClassType;
  15572. if not (P is TPasProcedure) then continue;
  15573. Proc:=TPasProcedure(P);
  15574. if IsTObject and (C=TPasDestructor) then
  15575. begin
  15576. DestructorName:=TransformElToJSName(P,AContext);
  15577. if DestructorName<>'Destroy' then
  15578. begin
  15579. // add 'rtl.tObjectDestroy="destroy";'
  15580. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,P));
  15581. AssignSt.LHS:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbivnTObjectDestroy)]);
  15582. AssignSt.Expr:=CreateLiteralString(P,DestructorName);
  15583. AddToSourceElements(Src,AssignSt);
  15584. end;
  15585. end
  15586. else if C=TPasConstructor then
  15587. HasConstructor:=true
  15588. else if (C=TPasClassConstructor)
  15589. or (C=TPasClassDestructor) then
  15590. begin
  15591. AddGlobalClassMethod(AContext,Proc);
  15592. continue;
  15593. end
  15594. else if (Proc.MessageExpr<>nil) and (aResolver<>nil) then
  15595. aResolver.AddMessageIdToClassScope(Proc,false);
  15596. NewEl:=ConvertProcedure(Proc,FuncContext);
  15597. if NewEl=nil then
  15598. continue; // e.g. abstract or external proc
  15599. AddToSourceElements(Src,NewEl);
  15600. end;
  15601. if HasConstructor and (El.HelperForType<>nil) then
  15602. AddHelperConstructor(El,Src,FuncContext);
  15603. end;
  15604. if aResolver<>nil then
  15605. begin
  15606. // add interfaces
  15607. if (El.ObjKind=okClass) then
  15608. AddClassSupportedInterfaces(El,Src,FuncContext);
  15609. AddClassMessageIds(El,Src,FuncContext,pbivnMessageInt);
  15610. AddClassMessageIds(El,Src,FuncContext,pbivnMessageStr);
  15611. if NeedTypeInfo then
  15612. begin
  15613. // add RTTI init function
  15614. if SpecializeDelay then
  15615. AddClassRTTI(El,DelaySrc,DelayFuncContext)
  15616. else
  15617. AddClassRTTI(El,Src,FuncContext);
  15618. end;
  15619. end;
  15620. end;// end of init function
  15621. // for specialization: add RTTI name
  15622. if ((Scope.JSName<>'') and (Scope.JSName<>El.Name))
  15623. or (El.Parent is TPasMembersType) then
  15624. begin
  15625. Call.AddArg(CreateLiteralString(El,GetTypeInfoName(El,AContext,El)));
  15626. end;
  15627. Result:=Call;
  15628. finally
  15629. FuncContext.Free;
  15630. DelayFuncContext.Free;
  15631. if Result<>Call then
  15632. Call.Free;
  15633. end;
  15634. end;
  15635. function TPasToJSConverter.ConvertClassForwardType(El: TPasClassType;
  15636. AContext: TConvertContext): TJSElement;
  15637. // module.$rtti.$Class("classname");
  15638. var
  15639. Ref: TResolvedReference;
  15640. aClass: TPasClassType;
  15641. Creator: String;
  15642. ObjLit: TJSObjectLiteral;
  15643. begin
  15644. Result:=nil;
  15645. if El.Parent is TProcedureBody then
  15646. RaiseNotSupported(El,AContext,20181231004420);
  15647. if (El.GenericTemplateTypes<>nil) and (El.GenericTemplateTypes.Count>0) then
  15648. exit;
  15649. if (AContext.Resolver=nil) or not (El.CustomData is TResolvedReference) then
  15650. exit;
  15651. Ref:=TResolvedReference(El.CustomData);
  15652. aClass:=Ref.Declaration as TPasClassType;
  15653. if IsClassRTTICreatedBefore(aClass,El,AContext) then
  15654. exit; // there is a class-of in front, which already created the class RTTI
  15655. if not HasTypeInfo(aClass,AContext) then exit;
  15656. // module.$rtti.$Class("classname");
  15657. Creator:=GetClassBIName(aClass,AContext);
  15658. Result:=CreateRTTINewType(aClass,Creator,true,AContext,ObjLit);
  15659. if ObjLit<>nil then
  15660. RaiseInconsistency(20170412093427,El);
  15661. end;
  15662. function TPasToJSConverter.ConvertClassOfType(El: TPasClassOfType;
  15663. AContext: TConvertContext): TJSElement;
  15664. // create
  15665. // module.$rtti.$ClassRef("typename",{
  15666. // instancetype: module.$rtti["classname"])
  15667. // }
  15668. // if class is defined later add a forward define for the class
  15669. var
  15670. ObjLit: TJSObjectLiteral;
  15671. Prop: TJSObjectLiteralElement;
  15672. Call: TJSCallExpression;
  15673. ok: Boolean;
  15674. List: TJSStatementList;
  15675. DestType: TPasClassType;
  15676. begin
  15677. Result:=nil;
  15678. if not HasTypeInfo(El,AContext) then exit;
  15679. if El.Parent is TProcedureBody then
  15680. RaiseNotSupported(El,AContext,20181231004435);
  15681. ok:=false;
  15682. Call:=CreateRTTINewType(El,GetBIName(pbifnRTTINewClassRef),false,AContext,ObjLit);
  15683. Result:=Call;
  15684. try
  15685. Prop:=ObjLit.Elements.AddElement;
  15686. Prop.Name:=TJSString(GetBIName(pbivnRTTIClassRef_InstanceType));
  15687. DestType:=AContext.Resolver.ResolveAliasType(El.DestType) as TPasClassType;
  15688. Prop.Expr:=CreateTypeInfoRef(DestType,AContext,El);
  15689. if IsClassRTTICreatedBefore(DestType,El,AContext) then
  15690. // there is a forward class in front, which already created the class RTTI
  15691. else
  15692. begin
  15693. // class rtti must be forward registered
  15694. if not (AContext is TFunctionContext) then
  15695. RaiseNotSupported(El,AContext,20170412102916);
  15696. // prepend module.$rtti.$Class("classname");
  15697. Call:=CreateRTTINewType(DestType,GetClassBIName(DestType,AContext),true,
  15698. AContext,ObjLit);
  15699. if ObjLit<>nil then
  15700. RaiseInconsistency(20170412102654,El);
  15701. List:=TJSStatementList(CreateElement(TJSStatementList,El));
  15702. List.A:=Call;
  15703. List.B:=Result;
  15704. Result:=List;
  15705. end;
  15706. ok:=true;
  15707. finally
  15708. if not ok then
  15709. FreeAndNil(Result);
  15710. end;
  15711. end;
  15712. function TPasToJSConverter.ConvertExtClassType(El: TPasClassType;
  15713. AContext: TConvertContext): TJSElement;
  15714. // module.$rtti.$ExtClass("TJSObject",{
  15715. // ancestor: ancestortypeinfo,
  15716. // jsclass: "Object"
  15717. // });
  15718. var
  15719. A: Integer;
  15720. TIObj: TJSObjectLiteral;
  15721. Call: TJSCallExpression;
  15722. TIProp: TJSObjectLiteralElement;
  15723. ClassScope: TPas2JSClassScope;
  15724. AncestorType: TPasClassType;
  15725. aResolver: TPas2JSResolver;
  15726. St: TJSStatementList;
  15727. MemberElement: TPasElement;
  15728. begin
  15729. Result:=nil;
  15730. if not El.IsExternal then
  15731. RaiseNotSupported(El,AContext,20191027183236);
  15732. aResolver:=AContext.Resolver;
  15733. if not aResolver.IsFullySpecialized(El) then
  15734. exit;
  15735. if not HasTypeInfo(El,AContext) then
  15736. exit;
  15737. // create typeinfo
  15738. if not (AContext is TFunctionContext) then
  15739. RaiseNotSupported(El,AContext,20191027182023,'typeinfo');
  15740. if El.Parent is TProcedureBody then
  15741. RaiseNotSupported(El,AContext,20191027182019);
  15742. ClassScope:=El.CustomData as TPas2JSClassScope;
  15743. if ClassScope.AncestorScope<>nil then
  15744. AncestorType:=ClassScope.AncestorScope.Element as TPasClassType
  15745. else
  15746. AncestorType:=nil;
  15747. Call:=nil;
  15748. try
  15749. // module.$rtti.$ExtClass("TMyClass",{...});
  15750. Call:=CreateRTTINewType(El,GetBIName(pbifnRTTINewExtClass),false,AContext,TIObj);
  15751. if AncestorType<>nil then
  15752. begin
  15753. // add ancestor: ancestortypeinfo
  15754. TIProp:=TIObj.Elements.AddElement;
  15755. TIProp.Name:=TJSString(GetBIName(pbivnRTTIExtClass_Ancestor));
  15756. TIProp.Expr:=CreateTypeInfoRef(AncestorType,AContext,El);
  15757. end;
  15758. // add jsclass: "extname"
  15759. TIProp:=TIObj.Elements.AddElement;
  15760. TIProp.Name:=TJSString(GetBIName(pbivnRTTIExtClass_JSClass));
  15761. TIProp.Expr:=CreateLiteralString(El,TPasClassType(El).ExternalName);
  15762. St:=TJSStatementList(CreateElement(TJSStatementList,El));
  15763. St.A := Call;
  15764. Result:=St;
  15765. for A := 0 to Pred(El.Members.Count) do
  15766. begin
  15767. MemberElement := TPasElement(El.Members[A]);
  15768. if (MemberElement is TPasClassType) and not (TPasClassType(MemberElement).IsForward) then
  15769. begin
  15770. St.B := ConvertExtClassType(TPasClassType(MemberElement), AContext);
  15771. St := St.B as TJSStatementList;
  15772. end;
  15773. end;
  15774. finally
  15775. if Result=nil then
  15776. Call.Free;
  15777. end;
  15778. end;
  15779. function TPasToJSConverter.ConvertEnumType(El: TPasEnumType;
  15780. AContext: TConvertContext): TJSElement;
  15781. // TMyEnum = (red, green)
  15782. // convert to
  15783. // this.TMyEnum = {
  15784. // "0":"red",
  15785. // "red":0,
  15786. // "0":"green",
  15787. // "green":0,
  15788. // };
  15789. // module.$rtti.$Enum("TMyEnum",{
  15790. // enumtype: this.TMyEnum,
  15791. // minvalue: 0,
  15792. // maxvalue: 1
  15793. // });
  15794. // coShortRefGlobals:
  15795. // $lt = this.TMyEnum ...
  15796. var
  15797. ObjectContect: TObjectContext;
  15798. i: Integer;
  15799. EnumValue: TPasEnumValue;
  15800. ParentObj, Obj, TIObj: TJSObjectLiteral;
  15801. ObjLit, TIProp: TJSObjectLiteralElement;
  15802. AssignSt: TJSSimpleAssignStatement;
  15803. JSName: string;
  15804. Call: TJSCallExpression;
  15805. List: TJSStatementList;
  15806. ok: Boolean;
  15807. OrdType: TOrdType;
  15808. Src: TJSSourceElements;
  15809. ProcScope: TPas2JSProcedureScope;
  15810. VarSt: TJSVariableStatement;
  15811. SectionContext: TSectionContext;
  15812. begin
  15813. Result:=nil;
  15814. for i:=0 to El.Values.Count-1 do
  15815. begin
  15816. EnumValue:=TPasEnumValue(El.Values[i]);
  15817. if EnumValue.Value<>nil then
  15818. RaiseNotSupported(EnumValue.Value,AContext,20170208145221,'enum constant');
  15819. end;
  15820. ok:=false;
  15821. ObjectContect:=nil;
  15822. Src:=nil;
  15823. Call:=nil;
  15824. VarSt:=nil;
  15825. ProcScope:=nil;
  15826. try
  15827. Obj:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,El));
  15828. if AContext is TObjectContext then
  15829. begin
  15830. // add 'TypeName: {}'
  15831. ParentObj:=TObjectContext(AContext).JSElement as TJSObjectLiteral;
  15832. ObjLit:=ParentObj.Elements.AddElement;
  15833. ObjLit.Name:=TJSString(TransformElToJSName(El,AContext));
  15834. ObjLit.Expr:=Obj;
  15835. Result:=Obj;
  15836. end
  15837. else if El.Parent is TProcedureBody then
  15838. begin
  15839. // add 'var TypeName = {}'
  15840. JSName:=TransformElToJSName(El,AContext);
  15841. VarSt:=CreateVarStatement(JSName,Obj,El);
  15842. if AContext.JSElement is TJSSourceElements then
  15843. begin
  15844. Src:=TJSSourceElements(AContext.JSElement);
  15845. AddToSourceElements(Src,VarSt); // keep Result=nil
  15846. if AContext is TFunctionContext then
  15847. TFunctionContext(AContext).AddLocalVar(JSName,El,cvkGlobal,false);
  15848. end
  15849. else
  15850. Result:=VarSt;
  15851. end
  15852. else
  15853. begin
  15854. // add 'this.TypeName = {}'
  15855. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  15856. AssignSt.LHS:=CreateSubDeclNameExpr(El,AContext);
  15857. AssignSt.Expr:=Obj;
  15858. Result:=AssignSt;
  15859. if coShortRefGlobals in Options then
  15860. begin
  15861. SectionContext:=TSectionContext(AContext.GetMainSectionContext);
  15862. JSName:=SectionContext.GetLocalName(El,[cvkGlobal]);
  15863. if JSName='' then
  15864. RaiseNotSupported(El,AContext,20200926232620);
  15865. if coStoreImplJS in Options then
  15866. StoreImplJSLocal(El,AContext);
  15867. // $lt = this.TypeName = {}
  15868. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  15869. AssignSt.LHS:=CreatePrimitiveDotExpr(JSName,El);
  15870. AssignSt.Expr:=Result;
  15871. Result:=AssignSt;
  15872. end;
  15873. end;
  15874. ObjectContect:=TObjectContext.Create(El,Obj,AContext);
  15875. for i:=0 to El.Values.Count-1 do
  15876. begin
  15877. EnumValue:=TPasEnumValue(El.Values[i]);
  15878. JSName:=TransformElToJSName(EnumValue,AContext);
  15879. // add "0":"value"
  15880. ObjLit:=Obj.Elements.AddElement;
  15881. ObjLit.Name:=TJSString(IntToStr(i));
  15882. ObjLit.Expr:=CreateLiteralJSString(El,TJSString(JSName));
  15883. // add value:0
  15884. ObjLit:=Obj.Elements.AddElement;
  15885. ObjLit.Name:=TJSString(JSName);
  15886. ObjLit.Expr:=CreateLiteralNumber(El,i);
  15887. end;
  15888. if Src<>nil then
  15889. begin
  15890. // store precompiled enum type in proc
  15891. ProcScope:=GetImplJSProcScope(El,Src,AContext);
  15892. if ProcScope<>nil then
  15893. ProcScope.AddGlobalJS(CreatePrecompiledJS(VarSt));
  15894. end;
  15895. if HasTypeInfo(El,AContext) then
  15896. begin
  15897. // create typeinfo
  15898. if not (AContext is TFunctionContext) then
  15899. RaiseNotSupported(El,AContext,20170411210045,'typeinfo');
  15900. OrdType:=GetOrdType(0,TMaxPrecInt(El.Values.Count)-1,El);
  15901. // module.$rtti.$TIEnum("TMyEnum",{...});
  15902. Call:=CreateRTTINewType(El,GetBIName(pbifnRTTINewEnum),false,AContext,TIObj);
  15903. // add minvalue: number
  15904. TIProp:=TIObj.Elements.AddElement;
  15905. TIProp.Name:=TJSString(GetBIName(pbivnRTTIInt_MinValue));
  15906. TIProp.Expr:=CreateLiteralNumber(El,0);
  15907. // add maxvalue: number
  15908. TIProp:=TIObj.Elements.AddElement;
  15909. TIProp.Name:=TJSString(GetBIName(pbivnRTTIInt_MaxValue));
  15910. TIProp.Expr:=CreateLiteralNumber(El,El.Values.Count-1);
  15911. // add ordtype: number
  15912. TIProp:=TIObj.Elements.AddElement;
  15913. TIProp.Name:=TJSString(GetBIName(pbivnRTTIInt_OrdType));
  15914. TIProp.Expr:=CreateLiteralNumber(El,ord(OrdType));
  15915. // add enumtype: this.TypeName
  15916. TIProp:=TIObj.Elements.AddElement;
  15917. TIProp.Name:=TJSString(GetBIName(pbivnRTTIEnum_EnumType));
  15918. TIProp.Expr:=CreateSubDeclNameExpr(El,AContext);
  15919. if Src<>nil then
  15920. begin
  15921. // add to source elements
  15922. AddToSourceElements(Src,Call);
  15923. if ProcScope<>nil then
  15924. ProcScope.AddGlobalJS(CreatePrecompiledJS(Call));
  15925. end
  15926. else if Result=nil then
  15927. RaiseNotSupported(El,AContext,20190101130432)
  15928. else
  15929. begin
  15930. // create statement list
  15931. List:=TJSStatementList(CreateElement(TJSStatementList,El));
  15932. List.A:=Result;
  15933. Result:=List;
  15934. List.B:=Call;
  15935. end;
  15936. Call:=nil;
  15937. end;
  15938. ok:=true;
  15939. finally
  15940. Call.Free;
  15941. ObjectContect.Free;
  15942. if not ok then
  15943. FreeAndNil(Result);
  15944. end;
  15945. end;
  15946. function TPasToJSConverter.ConvertSetType(El: TPasSetType;
  15947. AContext: TConvertContext): TJSElement;
  15948. // create
  15949. // module.$rtti.$Set("name",{
  15950. // comptype: module.$rtti["enumtype"]
  15951. // })
  15952. var
  15953. Obj: TJSObjectLiteral;
  15954. Call: TJSCallExpression;
  15955. Prop: TJSObjectLiteralElement;
  15956. begin
  15957. Result:=nil;
  15958. if El.IsPacked then
  15959. DoError(20170222231613,nPasElementNotSupported,sPasElementNotSupported,
  15960. ['packed'],El);
  15961. if not HasTypeInfo(El,AContext) then exit;
  15962. if El.Parent is TProcedureBody then
  15963. RaiseNotSupported(El,AContext,20181231112029);
  15964. // module.$rtti.$Set("name",{...})
  15965. Call:=CreateRTTINewType(El,GetBIName(pbifnRTTINewSet),false,AContext,Obj);
  15966. try
  15967. // "comptype: ref"
  15968. Prop:=Obj.Elements.AddElement;
  15969. Prop.Name:=TJSString(GetBIName(pbivnRTTISet_CompType));
  15970. Prop.Expr:=CreateTypeInfoRef(El.EnumType,AContext,El);
  15971. Result:=Call;
  15972. finally
  15973. if Result=nil then
  15974. Call.Free;
  15975. end;
  15976. end;
  15977. function TPasToJSConverter.ConvertRangeType(El: TPasRangeType;
  15978. AContext: TConvertContext): TJSElement;
  15979. // create
  15980. // module.$rtti.$Int("name",{
  15981. // minvalue: <number>,
  15982. // maxvalue: <number>,
  15983. // ordtype: <number>
  15984. // })
  15985. var
  15986. TIObj: TJSObjectLiteral;
  15987. Call: TJSCallExpression;
  15988. MinVal, MaxVal: TResEvalValue;
  15989. MinInt, MaxInt: TMaxPrecInt;
  15990. OrdType: TOrdType;
  15991. TIProp: TJSObjectLiteralElement;
  15992. fn: TPas2JSBuiltInName;
  15993. begin
  15994. Result:=nil;
  15995. if not HasTypeInfo(El,AContext) then exit;
  15996. if El.Parent is TProcedureBody then
  15997. RaiseNotSupported(El,AContext,20181231112029);
  15998. // module.$rtti.$Int("name",{...})
  15999. MinVal:=nil;
  16000. MaxVal:=nil;
  16001. Call:=nil;
  16002. try
  16003. MinVal:=AContext.Resolver.EvalRangeLimit(El.RangeExpr,[refConst],true,El);
  16004. MaxVal:=AContext.Resolver.EvalRangeLimit(El.RangeExpr,[refConst],false,El);
  16005. if MinVal.Kind=revkInt then
  16006. begin
  16007. fn:=pbifnRTTINewInt;
  16008. MinInt:=TResEvalInt(MinVal).Int;
  16009. MaxInt:=TResEvalInt(MaxVal).Int;
  16010. end
  16011. else if MinVal.Kind=revkEnum then
  16012. begin
  16013. fn:=pbifnRTTINewEnum;
  16014. MinInt:=TResEvalEnum(MinVal).Index;
  16015. MaxInt:=TResEvalEnum(MaxVal).Index;
  16016. end
  16017. else
  16018. begin
  16019. {$IFDEF VerbosePas2JS}
  16020. writeln('TPasToJSConverter.ConvertRangeType type: ',MinVal.AsDebugString,'..',MaxVal.AsDebugString);
  16021. {$ENDIF}
  16022. RaiseNotSupported(El,AContext,20170925201628);
  16023. end;
  16024. OrdType:=GetOrdType(MinInt,MaxInt,El);
  16025. Call:=CreateRTTINewType(El,GetBIName(fn),false,AContext,TIObj);
  16026. // add minvalue: number
  16027. TIProp:=TIObj.Elements.AddElement;
  16028. TIProp.Name:=TJSString(GetBIName(pbivnRTTIInt_MinValue));
  16029. TIProp.Expr:=CreateLiteralNumber(El,MinInt);
  16030. // add maxvalue: number
  16031. TIProp:=TIObj.Elements.AddElement;
  16032. TIProp.Name:=TJSString(GetBIName(pbivnRTTIInt_MaxValue));
  16033. TIProp.Expr:=CreateLiteralNumber(El,MaxInt);
  16034. // add ordtype: number
  16035. TIProp:=TIObj.Elements.AddElement;
  16036. TIProp.Name:=TJSString(GetBIName(pbivnRTTIInt_OrdType));
  16037. TIProp.Expr:=CreateLiteralNumber(El,ord(OrdType));
  16038. if MinVal.Kind=revkEnum then
  16039. begin
  16040. // add enumtype: this.TypeName
  16041. TIProp:=TIObj.Elements.AddElement;
  16042. TIProp.Name:=TJSString(GetBIName(pbivnRTTIEnum_EnumType));
  16043. TIProp.Expr:=CreateSubDeclPasNameExpr(El,TResEvalEnum(MinVal).ElType.Name,AContext); // use Pascal name
  16044. end;
  16045. Result:=Call;
  16046. finally
  16047. ReleaseEvalValue(MinVal);
  16048. ReleaseEvalValue(MaxVal);
  16049. if Result=nil then
  16050. Call.Free;
  16051. end;
  16052. end;
  16053. function TPasToJSConverter.ConvertTypeAliasType(El: TPasTypeAliasType;
  16054. AContext: TConvertContext): TJSElement;
  16055. // create
  16056. // module.$rtti.$inherited(name,desttype,{});
  16057. var
  16058. Obj: TJSObjectLiteral;
  16059. begin
  16060. Result:=nil;
  16061. if not HasTypeInfo(El,AContext) then exit;
  16062. if El.Parent is TProcedureBody then
  16063. RaiseNotSupported(El,AContext,20181231112029);
  16064. Result:=CreateRTTINewType(El,GetBIName(pbifnRTTIInherited),false,AContext,Obj);
  16065. end;
  16066. function TPasToJSConverter.ConvertPointerType(El: TPasPointerType;
  16067. AContext: TConvertContext): TJSElement;
  16068. // create
  16069. // module.$rtti.$Pointer("name",{
  16070. // reftype: module.$rtti["reftype"]
  16071. // })
  16072. var
  16073. Obj: TJSObjectLiteral;
  16074. Call: TJSCallExpression;
  16075. Prop: TJSObjectLiteralElement;
  16076. begin
  16077. Result:=nil;
  16078. if not HasTypeInfo(El,AContext) then exit;
  16079. if El.Parent is TProcedureBody then
  16080. RaiseNotSupported(El,AContext,20181231112029);
  16081. // module.$rtti.$Pointer("name",{...})
  16082. Call:=CreateRTTINewType(El,GetBIName(pbifnRTTINewPointer),false,AContext,Obj);
  16083. try
  16084. // "comptype: ref"
  16085. Prop:=Obj.Elements.AddElement;
  16086. Prop.Name:=TJSString(GetBIName(pbivnRTTIPointer_RefType));
  16087. Prop.Expr:=CreateTypeInfoRef(El.DestType,AContext,El);
  16088. Result:=Call;
  16089. finally
  16090. if Result=nil then
  16091. Call.Free;
  16092. end;
  16093. end;
  16094. function TPasToJSConverter.ConvertProcedureType(El: TPasProcedureType;
  16095. AContext: TConvertContext): TJSElement;
  16096. // create
  16097. // "reference to":
  16098. // module.$rtti.$RefToProcVar("longname",{
  16099. // procsig: rtl.newTIProcSignature([[arg1name,arg1type,arg1flags],[arg2name...],...],resulttype,flags)
  16100. // })
  16101. // "of object":
  16102. // module.$rtti.$MethodVar("longname",{
  16103. // procsig: rtl.newTIProcSignature([[arg1name,arg1type,arg1flags],[arg2name...],...],resulttype,flags),
  16104. // methodkind: 1
  16105. // })
  16106. // "normal":
  16107. // module.$rtti.$ProcVar("longname",{
  16108. // procsig: rtl.newTIProcSignature([[arg1name,arg1type,arg1flags],[arg2name...],...],resulttype,flags)
  16109. // })
  16110. // delayed specialization:
  16111. // module.$rtti.$MethodVar("longname",{
  16112. // init: function()}{ this.procsig = rtl.newTIProcSignature([[arg1name,arg1type,arg1flags],[arg2name...],...],resulttype,flags)},
  16113. // methodkind: 1
  16114. // })
  16115. var
  16116. Call, InnerCall: TJSCallExpression;
  16117. FunName: String;
  16118. ResultEl: TPasResultElement;
  16119. ResultTypeInfo: TJSElement;
  16120. Flags: Integer;
  16121. MethodKind: TMethodKind;
  16122. Obj: TJSObjectLiteral;
  16123. Prop: TJSObjectLiteralElement;
  16124. aResolver: TPas2JSResolver;
  16125. Scope: TPas2JSProcTypeScope;
  16126. SpecializeDelay: Boolean;
  16127. FuncSt: TJSFunctionDeclarationStatement;
  16128. AssignSt: TJSSimpleAssignStatement;
  16129. FuncContext: TFunctionContext;
  16130. CurContext: TConvertContext;
  16131. begin
  16132. Result:=nil;
  16133. aResolver:=AContext.Resolver;
  16134. if not aResolver.IsFullySpecialized(El) then exit;
  16135. if El.IsNested then
  16136. DoError(20170222231636,nPasElementNotSupported,sPasElementNotSupported,
  16137. ['is nested'],El);
  16138. if not (El.CallingConvention in [ccDefault,ccSafeCall]) then
  16139. DoError(20170222231532,nPasElementNotSupported,sPasElementNotSupported,
  16140. ['calling convention '+cCallingConventions[El.CallingConvention]],El);
  16141. if not HasTypeInfo(El,AContext) then
  16142. exit; // no RTTI needed
  16143. if El.Parent is TProcedureBody then
  16144. RaiseNotSupported(El,AContext,20181231112029);
  16145. Scope:=El.CustomData as TPas2JSProcTypeScope;
  16146. SpecializeDelay:=(Scope<>nil) and SpecializeNeedsDelay(El,AContext);
  16147. // module.$rtti.$ProcVar("name",function(){})
  16148. if El.IsReferenceTo then
  16149. FunName:=GetBIName(pbifnRTTINewRefToProcVar)
  16150. else if El.IsOfObject then
  16151. FunName:=GetBIName(pbifnRTTINewMethodVar)
  16152. else
  16153. FunName:=GetBIName(pbifnRTTINewProcVar);
  16154. Call:=CreateRTTINewType(El,FunName,false,AContext,Obj);
  16155. FuncContext:=nil;
  16156. try
  16157. // add "procsig: rtl.newTIProcSignature()"
  16158. Prop:=Obj.Elements.AddElement;
  16159. InnerCall:=CreateCallExpression(El);
  16160. if SpecializeDelay then
  16161. begin
  16162. Prop.Name:=TJSString(GetBIName(pbivnRTTIProc_InitSpec));
  16163. // init: function(){ this.procsig = rtl.newTIProcSignature(...) }
  16164. FuncSt:=CreateFunctionSt(El);
  16165. Prop.Expr:=FuncSt;
  16166. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  16167. AssignSt.LHS:=CreatePrimitiveDotExpr('this.'+GetBIName(pbivnRTTIProcVar_ProcSig),El);
  16168. AssignSt.Expr:=InnerCall;
  16169. FuncSt.AFunction.Body.A:=AssignSt;
  16170. FuncContext:=TFunctionContext.Create(El,AssignSt,AContext);
  16171. CurContext:=FuncContext;
  16172. end
  16173. else
  16174. begin
  16175. CurContext:=AContext;
  16176. Prop.Name:=TJSString(GetBIName(pbivnRTTIProcVar_ProcSig));
  16177. Prop.Expr:=InnerCall;
  16178. end;
  16179. InnerCall.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnRTTINewProcSig)]);
  16180. // add array of arguments
  16181. InnerCall.AddArg(CreateRTTIArgList(El,El.Args,CurContext));
  16182. // add resulttype as typeinfo reference
  16183. if El is TPasFunctionType then
  16184. begin
  16185. ResultEl:=TPasFunctionType(El).ResultEl;
  16186. ResultTypeInfo:=CreateTypeInfoRef(ResultEl.ResultType,CurContext,ResultEl);
  16187. if ResultTypeInfo<>nil then
  16188. InnerCall.AddArg(ResultTypeInfo);
  16189. end;
  16190. // add procedure flags
  16191. Flags:=0;
  16192. if ptmVarargs in El.Modifiers then
  16193. inc(Flags,pfVarargs);
  16194. if ptmAsync in El.Modifiers then
  16195. inc(Flags,pfAsync);
  16196. if El.CallingConvention=ccSafeCall then
  16197. inc(Flags,pfSafeCall);
  16198. if Flags>0 then
  16199. begin
  16200. if not (El is TPasFunctionType) then
  16201. InnerCall.AddArg(CreateLiteralNull(El));
  16202. InnerCall.AddArg(CreateLiteralNumber(El,Flags));
  16203. end;
  16204. if El.IsOfObject then
  16205. begin
  16206. // add "methodkind: number;"
  16207. Prop:=Obj.Elements.AddElement;
  16208. Prop.Name:=TJSString(GetBIName(pbivnRTTIMethodKind));
  16209. if El.ClassType=TPasProcedureType then
  16210. MethodKind:=mkProcedure
  16211. else if El.ClassType=TPasFunctionType then
  16212. MethodKind:=mkFunction
  16213. else
  16214. RaiseNotSupported(El,AContext,20170411180848);
  16215. Prop.Expr:=CreateLiteralNumber(El,ord(MethodKind));
  16216. end;
  16217. Result:=Call;
  16218. finally
  16219. FuncContext.Free;
  16220. if Result=nil then
  16221. Call.Free;
  16222. end;
  16223. end;
  16224. function TPasToJSConverter.ConvertArrayType(El: TPasArrayType;
  16225. AContext: TConvertContext): TJSElement;
  16226. // Static array of static array need clone function:
  16227. // this.TStaticArray$clone = function(a){
  16228. // var r = [];
  16229. // for (var i=0; i<*High(a)*; i++) r.push(a[i].slice(0));
  16230. // return r;
  16231. // };
  16232. //
  16233. // Published array types need:
  16234. // module.$rtti.$StaticArray("name",{
  16235. // dims: [dimsize1,dimsize2,...],
  16236. // eltype: module.$rtti["ElTypeName"]
  16237. // };
  16238. // module.$rtti.$DynArray("name",{
  16239. // eltype: module.$rtti["ElTypeName"]
  16240. // };
  16241. //
  16242. var
  16243. VarIndex: integer;
  16244. ProcScope: TPas2JSProcedureScope;
  16245. Src: TJSSourceElements;
  16246. Index: Integer;
  16247. BodySrc: TJSSourceElements;
  16248. ForLoop: TJSForStatement;
  16249. procedure StorePrecompiledJS(JS: TJSElement);
  16250. begin
  16251. // store precompiled enum type in proc
  16252. if ProcScope=nil then
  16253. ProcScope:=GetImplJSProcScope(El,Src,AContext);
  16254. if ProcScope<>nil then
  16255. ProcScope.AddGlobalJS(CreatePrecompiledJS(JS));
  16256. end;
  16257. function GetNextVarName: string;
  16258. var
  16259. i: integer;
  16260. begin
  16261. i:=VarIndex mod 52;
  16262. if i<26 then
  16263. Result:=chr(ord('a')+i)
  16264. else
  16265. Result:=chr(ord('A')+i);
  16266. if VarIndex>=52 then
  16267. Result:=Result+IntToStr(VarIndex div 52);
  16268. inc(VarIndex);
  16269. end;
  16270. procedure AddLoopSt(JS: TJSElement);
  16271. var
  16272. List: TJSStatementList;
  16273. begin
  16274. if Index=0 then
  16275. AddToSourceElements(BodySrc,JS)
  16276. else
  16277. begin
  16278. if ForLoop.Body=nil then
  16279. ForLoop.Body:=JS
  16280. else
  16281. begin
  16282. List:=TJSStatementList(CreateElement(TJSStatementList,El));
  16283. List.A:=ForLoop.Body;
  16284. List.B:=JS;
  16285. ForLoop.Body:=List;
  16286. end;
  16287. end;
  16288. end;
  16289. var
  16290. aResolver: TPas2JSResolver;
  16291. AssignSt: TJSSimpleAssignStatement;
  16292. ArrName: String;
  16293. ElTypeLo: TPasType;
  16294. RangeEl: TPasExpr;
  16295. Call: TJSCallExpression;
  16296. RangeEnd: TMaxPrecInt;
  16297. List: TJSStatementList;
  16298. Func: TJSFunctionDeclarationStatement;
  16299. VarSt: TJSVariableStatement;
  16300. ExprLT: TJSRelationalExpressionLT;
  16301. PlusPlus: TJSUnaryPostPlusPlusExpression;
  16302. BracketLeftEx, BracketRightEx: TJSBracketMemberExpression;
  16303. ArraySt, CloneEl: TJSElement;
  16304. ReturnSt: TJSReturnStatement;
  16305. FuncContext: TFunctionContext;
  16306. SrcArrName, ResultName, LoopVarName, NewArrName,
  16307. ParentNewArrName, ParentSrcArrName: string;
  16308. VarDecl: TJSVarDeclaration;
  16309. MaxIndex: SizeInt;
  16310. UseSlice: boolean;
  16311. NewLoop: TJSForStatement;
  16312. begin
  16313. Result:=nil;
  16314. aResolver:=AContext.Resolver;
  16315. if not aResolver.IsFullySpecialized(El) then exit;
  16316. if El.PackMode<>pmNone then
  16317. DoError(20170222231648,nPasElementNotSupported,sPasElementNotSupported,
  16318. ['packed'],El);
  16319. {$IFDEF VerbosePas2JS}
  16320. writeln('TPasToJSConverter.ConvertArrayType ',GetObjName(El));
  16321. {$ENDIF}
  16322. ProcScope:=nil;
  16323. Src:=nil;
  16324. if AContext.JSElement is TJSSourceElements then
  16325. Src:=TJSSourceElements(AContext.JSElement);
  16326. if aResolver.HasStaticArrayCloneFunc(El) then
  16327. begin
  16328. // Example1: type TStaticArray = array[1..2] of array[1..2] of longint;
  16329. // this.TStaticArray$clone = function(a){
  16330. // var b = [];
  16331. // b.length = Dim1;
  16332. // for (var c=0; c<Dim1; c++) b[c] = a[c].slice(0);
  16333. // return b;
  16334. // };
  16335. // Example2: type TDim3 = array[1..3,2..4,3..5] of longint;
  16336. // this.TDim3$clone = function(a){
  16337. // var b = [];
  16338. // b.length = Dim1;
  16339. // for (var c=0; c<Dim1; c++){
  16340. // var d = b[c] = [];
  16341. // d.length = Dim2;
  16342. // var e = a[c];
  16343. // for (var f=0; f<Dim2; f++) d[f] = e[f].slice(0);
  16344. // }
  16345. // return b;
  16346. // };
  16347. BracketLeftEx:=nil;
  16348. AssignSt:=nil;
  16349. Func:=nil;
  16350. FuncContext:=nil;
  16351. try
  16352. VarIndex:=0;
  16353. SrcArrName:=GetNextVarName;
  16354. ResultName:=GetNextVarName;
  16355. LoopVarName:='';
  16356. ElTypeLo:=aResolver.ResolveAliasType(El.ElType);
  16357. // function(a){...
  16358. Func:=CreateFunctionSt(El,true,true);
  16359. Func.AFunction.TypedParams.AddParam(TJSString(SrcArrName));
  16360. BodySrc:=Func.AFunction.Body.A as TJSSourceElements;
  16361. FuncContext:=TFunctionContext.Create(El,BodySrc,AContext);
  16362. FuncContext.IsGlobal:=true;
  16363. MaxIndex:=length(El.Ranges)-1;
  16364. UseSlice:=(ElTypeLo is TPasUnresolvedSymbolRef)
  16365. or (ElTypeLo is TPasRangeType)
  16366. or ((ElTypeLo is TPasClassType) and (TPasClassType(ElTypeLo).ObjKind in [okClass]));
  16367. ForLoop:=nil;
  16368. if UseSlice then
  16369. // static array of a base type -> inner loop is replaced with slice(0)
  16370. dec(MaxIndex);
  16371. for Index:=0 to MaxIndex do
  16372. begin
  16373. RangeEl:=El.Ranges[Index];
  16374. RangeEnd:=aResolver.GetRangeLength(RangeEl);
  16375. if Index=0 then
  16376. NewArrName:=ResultName
  16377. else
  16378. begin
  16379. ParentNewArrName:=NewArrName;
  16380. NewArrName:=GetNextVarName;
  16381. end;
  16382. // var NewArr = [];
  16383. VarSt:=TJSVariableStatement(CreateElement(TJSVariableStatement,El));
  16384. VarDecl:=TJSVarDeclaration(CreateElement(TJSVarDeclaration,El));
  16385. VarSt.VarDecl:=VarDecl;
  16386. VarDecl.Name:=TJSString(NewArrName);
  16387. VarDecl.Init:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,El));
  16388. AddLoopSt(VarSt);
  16389. if Index>0 then
  16390. begin
  16391. // var NewArr = ParentNewArrName[LoopVar] = [];
  16392. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  16393. AssignSt.Expr:=VarDecl.Init; // ... = []
  16394. VarDecl.Init:=AssignSt;
  16395. // ... = ParentNewArrName[LoopVar] = ...
  16396. BracketLeftEx:=TJSBracketMemberExpression(CreateElement(TJSBracketMemberExpression,El));
  16397. AssignSt.LHS:=BracketLeftEx;
  16398. BracketLeftEx.MExpr:=CreatePrimitiveDotExpr(ParentNewArrName,El);
  16399. BracketLeftEx.Name:=CreatePrimitiveDotExpr(LoopVarName,El);
  16400. end;
  16401. // NewArr.length = Dim;
  16402. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  16403. AssignSt.LHS:=CreatePrimitiveDotExpr(NewArrName+'.length',El);
  16404. AssignSt.Expr:=CreateLiteralNumber(El,RangeEnd);
  16405. AddLoopSt(AssignSt);
  16406. if Index>0 then
  16407. begin
  16408. // var SrcArrName = ParentSrcArrName[LoopVar];
  16409. ParentSrcArrName:=SrcArrName;
  16410. SrcArrName:=GetNextVarName;
  16411. BracketLeftEx:=TJSBracketMemberExpression(CreateElement(TJSBracketMemberExpression,El));
  16412. VarSt:=CreateVarStatement(SrcArrName,BracketLeftEx,El);
  16413. BracketLeftEx.MExpr:=CreatePrimitiveDotExpr(ParentSrcArrName,El);
  16414. BracketLeftEx.Name:=CreatePrimitiveDotExpr(LoopVarName,El);
  16415. AddLoopSt(VarSt);
  16416. end;
  16417. // for (
  16418. LoopVarName:=GetNextVarName;
  16419. NewLoop:=TJSForStatement(CreateElement(TJSForStatement,El));
  16420. AddLoopSt(NewLoop);
  16421. ForLoop:=NewLoop;
  16422. // var LoopVar=0;
  16423. ForLoop.Init:=CreateVarStatement(LoopVarName,CreateLiteralNumber(El,0),El);
  16424. // LoopVar<Dim
  16425. ExprLT:=TJSRelationalExpressionLT(CreateElement(TJSRelationalExpressionLT,El));
  16426. ForLoop.Cond:=ExprLT;
  16427. ExprLT.A:=CreatePrimitiveDotExpr(LoopVarName,El);
  16428. ExprLT.B:=CreateLiteralNumber(El,RangeEnd);
  16429. // LoopVar++
  16430. PlusPlus:=TJSUnaryPostPlusPlusExpression(CreateElement(TJSUnaryPostPlusPlusExpression,El));
  16431. ForLoop.Incr:=PlusPlus;
  16432. PlusPlus.A:=CreatePrimitiveDotExpr(LoopVarName,El);
  16433. if Index=MaxIndex then
  16434. begin
  16435. // NewArr[LoopVar] = ...
  16436. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  16437. ForLoop.Body:=AssignSt;
  16438. BracketLeftEx:=TJSBracketMemberExpression(CreateElement(TJSBracketMemberExpression,El));
  16439. AssignSt.LHS:=BracketLeftEx;
  16440. BracketLeftEx.MExpr:=CreatePrimitiveDotExpr(NewArrName,El);
  16441. BracketLeftEx.Name:=CreatePrimitiveDotExpr(LoopVarName,El);
  16442. // SrcArr[LoopVar]
  16443. BracketRightEx:=TJSBracketMemberExpression(CreateElement(TJSBracketMemberExpression,El));
  16444. BracketRightEx.MExpr:=CreatePrimitiveDotExpr(SrcArrName,El);
  16445. BracketRightEx.Name:=CreatePrimitiveDotExpr(LoopVarName,El);
  16446. try
  16447. // clone array element
  16448. CloneEl:=nil;
  16449. if UseSlice then
  16450. begin
  16451. // SrcArr[LoopVar].slice(0)
  16452. Call:=CreateCallExpression(El);
  16453. CloneEl:=Call;
  16454. Call.Expr:=CreateDotNameExpr(El,BracketRightEx,'slice');
  16455. Call.AddArg(CreateLiteralNumber(El,0));
  16456. end
  16457. else if ElTypeLo is TPasArrayType then
  16458. begin
  16459. if length(TPasArrayType(ElTypeLo).Ranges)=0 then
  16460. RaiseNotSupported(El,FuncContext,20180218223414,GetObjName(ElTypeLo));
  16461. CloneEl:=CreateCloneStaticArray(El,TPasArrayType(ElTypeLo),BracketRightEx,FuncContext);
  16462. end
  16463. else if ElTypeLo is TPasRecordType then
  16464. CloneEl:=CreateRecordCallClone(El,TPasRecordType(ElTypeLo),BracketRightEx,FuncContext)
  16465. else if ElTypeLo is TPasSetType then
  16466. CloneEl:=CreateReferencedSet(El,BracketRightEx)
  16467. else
  16468. RaiseNotSupported(El,FuncContext,20180218223618,GetObjName(ElTypeLo));
  16469. AssignSt.Expr:=CloneEl;
  16470. BracketRightEx:=nil;
  16471. finally
  16472. BracketRightEx.Free;
  16473. end;
  16474. end;
  16475. end;
  16476. // return ResultName;
  16477. ReturnSt:=TJSReturnStatement(CreateElement(TJSReturnStatement,El));
  16478. AddToSourceElements(BodySrc,ReturnSt);
  16479. ReturnSt.Expr:=CreatePrimitiveDotExpr(ResultName,El);
  16480. ArrName:=GetOverloadName(El,AContext)+GetBIName(pbifnArray_Static_Clone);
  16481. if El.Parent is TProcedureBody then
  16482. begin
  16483. // local array type (elevated to global)
  16484. // -> add 'var TypeName = function(){}'
  16485. ArraySt:=CreateVarStatement(ArrName,Func,El);
  16486. end
  16487. else
  16488. begin
  16489. // global array type
  16490. // -> add 'this.TypeName = function(){}'
  16491. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  16492. ArraySt:=AssignSt;
  16493. AssignSt.LHS:=CreateSubDeclPasNameExpr(El,ArrName,AContext);
  16494. AssignSt.Expr:=Func;
  16495. end;
  16496. Func:=nil;
  16497. if Src<>nil then
  16498. AddToSourceElements(Src,ArraySt)
  16499. else
  16500. Result:=ArraySt;
  16501. // store precompiled array type in proc
  16502. StorePrecompiledJS(ArraySt);
  16503. ArraySt:=nil;
  16504. finally
  16505. Func.Free;
  16506. ArraySt.Free;
  16507. FuncContext.Free;
  16508. end;
  16509. end;
  16510. if (not (AContext.PasElement is TPasMembersType)) // rtti of members is added separate
  16511. and HasTypeInfo(El,AContext) then
  16512. begin
  16513. // writeln('TPasToJSConverter.ConvertArrayType ',GetObjPath(El),' ',GetObjPath(AContext.PasElement));
  16514. Call:=nil;
  16515. try
  16516. Call:=CreateRTTIAnonymousArray(El,AContext);
  16517. if Src<>nil then
  16518. begin
  16519. AddToSourceElements(Src,Call);
  16520. // store precompiled rtti call in proc
  16521. StorePrecompiledJS(Call);
  16522. end
  16523. else if Result=nil then
  16524. Result:=Call
  16525. else
  16526. begin
  16527. List:=TJSStatementList(CreateElement(TJSStatementList,El));
  16528. List.A:=Result;
  16529. List.B:=Call;
  16530. Result:=List;
  16531. end;
  16532. Call:=nil;
  16533. finally
  16534. Call.Free;
  16535. end;
  16536. end;
  16537. end;
  16538. function TPasToJSConverter.GetOrdType(MinValue, MaxValue: TMaxPrecInt;
  16539. ErrorEl: TPasElement): TOrdType;
  16540. var
  16541. V: TMaxPrecInt;
  16542. begin
  16543. if MinValue<0 then
  16544. begin
  16545. if MaxValue<-(MinValue+1) then
  16546. V:=-(MinValue+1)
  16547. else
  16548. V:=MaxValue;
  16549. if V<$8f then
  16550. Result:=otSByte
  16551. else if V<$8fff then
  16552. Result:=otSWord
  16553. else if V<$8fffffff then
  16554. Result:=otSLong
  16555. else if V<=MaxSafeIntDouble then
  16556. Result:=otSIntDouble
  16557. else
  16558. DoError(20170925200802,nRangeCheckError,sRangeCheckError,[],ErrorEl);
  16559. end
  16560. else
  16561. begin
  16562. if MaxValue<$ff then
  16563. Result:=otUByte
  16564. else if MaxValue<$ffff then
  16565. Result:=otUWord
  16566. else if MaxValue<$ffffffff then
  16567. Result:=otULong
  16568. else if MaxValue<=MaxSafeIntDouble then
  16569. Result:=otUIntDouble
  16570. else
  16571. DoError(20170925201002,nRangeCheckError,sRangeCheckError,[],ErrorEl);
  16572. end;
  16573. end;
  16574. {$IFDEF EnableForLoopRunnerCheck}
  16575. procedure TPasToJSConverter.ForLoop_OnProcBodyElement(El: TPasElement;
  16576. arg: pointer);
  16577. // Called by ConvertForStatement on each element of the current proc body
  16578. // Check each element that lies behind the loop if it is reads the LoopVar
  16579. var
  16580. Data: PForLoopFindData absolute arg;
  16581. begin
  16582. if El.HasParent(Data^.ForLoop) then
  16583. Data^.FoundLoop:=true
  16584. else if Data^.FoundLoop and (not Data^.LoopVarWrite) and (not Data^.LoopVarRead) then
  16585. begin
  16586. // El comes after loop and LoopVar was not yet accessed
  16587. if (El.CustomData is TResolvedReference)
  16588. and (TResolvedReference(El.CustomData).Declaration=Data^.LoopVar) then
  16589. begin
  16590. // El refers the LoopVar
  16591. // ToDo: check write only access
  16592. Data^.LoopVarRead:=true;
  16593. end;
  16594. end;
  16595. end;
  16596. {$ENDIF}
  16597. procedure TPasToJSConverter.SetUseEnumNumbers(const AValue: boolean);
  16598. begin
  16599. if AValue then
  16600. Include(FOptions,coEnumNumbers)
  16601. else
  16602. Exclude(FOptions,coEnumNumbers);
  16603. end;
  16604. procedure TPasToJSConverter.SetUseLowerCase(const AValue: boolean);
  16605. begin
  16606. if AValue then
  16607. Include(FOptions,coLowerCase)
  16608. else
  16609. Exclude(FOptions,coLowerCase);
  16610. end;
  16611. procedure TPasToJSConverter.SetUseSwitchStatement(const AValue: boolean);
  16612. begin
  16613. if AValue then
  16614. Include(FOptions,coSwitchStatement)
  16615. else
  16616. Exclude(FOptions,coSwitchStatement);
  16617. end;
  16618. function TPasToJSConverter.OnCreateReferencePathExpr(El: TPasElement;
  16619. AContext: TConvertContext; CreateRefPathData: Pointer): TJSElement;
  16620. var
  16621. Data: PCreateRefPathData absolute CreateRefPathData;
  16622. begin
  16623. Result:=CreateReferencePathExpr(Data^.El,AContext,Data^.Full,Data^.Ref);
  16624. if El=nil then ;
  16625. end;
  16626. constructor TPasToJSConverter.Create;
  16627. begin
  16628. FOptions:=DefaultPasToJSOptions;
  16629. end;
  16630. destructor TPasToJSConverter.Destroy;
  16631. begin
  16632. Globals:=nil;
  16633. inherited Destroy;
  16634. end;
  16635. function TPasToJSConverter.ConvertProcedure(El: TPasProcedure;
  16636. AContext: TConvertContext): TJSElement;
  16637. var
  16638. BodyJS: TJSFunctionBody;
  16639. FirstSt, LastSt: TJSStatementList;
  16640. procedure AddBodyStatement(Add: TJSElement; Src: TPasElement);
  16641. begin
  16642. AddToStatementList(FirstSt,LastSt,Add,Src);
  16643. BodyJS.A:=FirstSt;
  16644. end;
  16645. procedure AddRangeCheckType(Arg: TPasArgument; aType: TPasType;
  16646. AContext: TConvertContext);
  16647. var
  16648. GetExpr: TJSElement;
  16649. begin
  16650. GetExpr:=CreateArgumentAccess(Arg,AContext,Arg);
  16651. AddBodyStatement(CreateRangeCheckCall_TypeRange(aType,GetExpr,AContext,Arg),Arg);
  16652. end;
  16653. Var
  16654. FS : TJSFunctionDeclarationStatement;
  16655. FD : TJSFuncDef;
  16656. n, i, Line, Col:Integer;
  16657. AssignSt, AssignSt2: TJSSimpleAssignStatement;
  16658. FuncContext, ConstContext: TFunctionContext;
  16659. ProcScope, ImplProcScope: TPas2JSProcedureScope;
  16660. Arg, SelfArg: TPasArgument;
  16661. SelfSt: TJSVariableStatement;
  16662. ImplProc: TPasProcedure;
  16663. BodyPas: TProcedureBody;
  16664. PosEl, ThisPas: TPasElement;
  16665. Call: TJSCallExpression;
  16666. ClassPath, aName: String;
  16667. ArgResolved: TPasResolverResult;
  16668. Lit: TJSLiteral;
  16669. ConstSrcElems: TJSSourceElements;
  16670. ArgTypeEl, HelperForType: TPasType;
  16671. aResolver: TPas2JSResolver;
  16672. IsClassConDestructor: Boolean;
  16673. ThisKind: TCtxVarKind;
  16674. ImplJS: TPas2JSPrecompiledJS;
  16675. begin
  16676. Result:=nil;
  16677. if El.IsAbstract then exit;
  16678. if El.IsExternal then exit;
  16679. ProcScope:=TPas2JSProcedureScope(El.CustomData);
  16680. if ProcScope.DeclarationProc<>nil then
  16681. exit;
  16682. IsClassConDestructor:=(El.ClassType=TPasClassConstructor)
  16683. or (El.ClassType=TPasClassDestructor);
  16684. aResolver:=AContext.Resolver;
  16685. if not aResolver.IsFullySpecialized(El) then exit;
  16686. {$IFDEF VerbosePas2JS}
  16687. writeln('TPasToJSConverter.ConvertProcedure "',El.Name,'" Overload="',ProcScope.OverloadName,'" ',El.Parent.ClassName);
  16688. {$ENDIF}
  16689. ImplProc:=El;
  16690. if ProcScope.ImplProc<>nil then
  16691. ImplProc:=ProcScope.ImplProc;
  16692. ImplProcScope:=TPas2JSProcedureScope(ImplProc.CustomData);
  16693. ImplJS:=ImplProcScope.ImplJS;
  16694. if ImplJS<>nil then
  16695. begin
  16696. // using precompiled code
  16697. TPasResolver.UnmangleSourceLineNumber(El.SourceLinenumber,Line,Col);
  16698. if ImplJS.GlobalJS<>nil then
  16699. begin
  16700. ConstContext:=AContext.GetGlobalFunc;
  16701. if not (ConstContext.JSElement is TJSSourceElements) then
  16702. begin
  16703. {$IFDEF VerbosePas2JS}
  16704. writeln('TPasToJSConverter.ConvertProcedure ConstContext=',GetObjName(ConstContext),' JSElement=',GetObjName(ConstContext.JSElement));
  16705. {$ENDIF}
  16706. RaiseNotSupported(El,AContext,20180228231008);
  16707. end;
  16708. ConstSrcElems:=TJSSourceElements(ConstContext.JSElement);
  16709. for i:=0 to ImplJS.GlobalJS.Count-1 do
  16710. begin
  16711. // precompiled global var or type
  16712. Lit:=TJSLiteral.Create(Line,Col,El.SourceFilename);
  16713. Lit.Value.CustomValue:=StrToJSString(ImplJS.GlobalJS[i]);
  16714. AddToSourceElements(ConstSrcElems,Lit);
  16715. end;
  16716. end;
  16717. if coShortRefGlobals in Options then
  16718. CreateGlobalAlias_List(ImplJS.ShortRefs,AContext);
  16719. // precompiled body
  16720. Lit:=TJSLiteral.Create(Line,Col,El.SourceFilename);
  16721. Lit.Value.CustomValue:=StrToJSString(ImplJS.BodyJS);
  16722. Result:=Lit;
  16723. exit;
  16724. end
  16725. else if (coStoreImplJS in Options) and (aResolver<>nil) then
  16726. begin
  16727. if aResolver.ProcCanBePrecompiled(El) then
  16728. begin
  16729. ImplJS:=TPas2JSPrecompiledJS.Create;
  16730. ImplProcScope.ImplJS:=ImplJS;
  16731. end;
  16732. end;
  16733. AssignSt:=nil;
  16734. if AContext.IsGlobal then
  16735. begin
  16736. // add 'this.FuncName = ...'
  16737. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,ImplProc));
  16738. Result:=AssignSt;
  16739. AssignSt.LHS:=CreateSubDeclNameExpr(El,AContext,ImplProc);
  16740. if (coShortRefGlobals in Options) then
  16741. begin
  16742. aName:=AContext.GetLocalName(El,[cvkGlobal]);
  16743. if aName<>'' then
  16744. begin
  16745. // this.FuncName = $lp = ...;
  16746. AssignSt2:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,ImplProc));
  16747. AssignSt.Expr:=AssignSt2;
  16748. AssignSt:=AssignSt2;
  16749. AssignSt.LHS:=CreatePrimitiveDotExpr(aName,El);
  16750. end;
  16751. end;
  16752. end;
  16753. FS:=CreateFunctionSt(ImplProc,ImplProc.Body<>nil);
  16754. FD:=FS.AFunction;
  16755. FD.IsAsync:=El.IsAsync or ImplProc.IsAsync;
  16756. if AssignSt<>nil then
  16757. AssignSt.Expr:=FS
  16758. else
  16759. begin
  16760. // local/nested or anonymous function
  16761. Result:=FS;
  16762. if (El.Name<>'') and not IsClassConDestructor then
  16763. FD.Name:=TJSString(TransformElToJSName(El,AContext));
  16764. end;
  16765. for n := 0 to El.ProcType.Args.Count - 1 do
  16766. begin
  16767. Arg:=TPasArgument(El.ProcType.Args[n]);
  16768. FD.TypedParams.AddParam(TJSString(TransformElToJSName(Arg,AContext)));
  16769. end;
  16770. BodyPas:=ImplProc.Body;
  16771. if BodyPas<>nil then
  16772. begin
  16773. PosEl:=BodyPas;
  16774. if PosEl=nil then
  16775. PosEl:=ImplProc;
  16776. BodyJS:=FD.Body;
  16777. FuncContext:=TFunctionContext.Create(ImplProc,FD.Body,AContext);
  16778. try
  16779. FuncContext.ScannerBoolSwitches:=ImplProcScope.BoolSwitches;
  16780. FirstSt:=nil;
  16781. LastSt:=nil;
  16782. if ProcScope.ClassRecScope<>nil then
  16783. begin
  16784. ThisKind:=cvkNone;
  16785. SelfArg:=nil;
  16786. // method or class method
  16787. //writeln('TPasToJSConverter.ConvertProcedure El=',GetObjPath(El),' IsStatic=',El.IsStatic);
  16788. if not AContext.IsGlobal then
  16789. begin
  16790. // nested sub procedure -> no 'this'
  16791. ThisPas:=nil;
  16792. end
  16793. else if El.IsStatic or IsClassConDestructor then
  16794. ThisPas:=nil
  16795. else
  16796. begin
  16797. ThisPas:=ProcScope.ClassRecScope.Element;
  16798. if aResolver.IsHelper(ThisPas) then
  16799. begin
  16800. // helper method
  16801. HelperForType:=aResolver.ResolveAliasType(TPasClassType(ThisPas).HelperForType);
  16802. ThisPas:=HelperForType;
  16803. if HelperForType is TPasMembersType then
  16804. begin
  16805. // 'this' in a class/record helper method is the class (instance)
  16806. ThisKind:=cvkInstance;
  16807. end
  16808. else
  16809. begin
  16810. // 'this' in a type helper is a temporary getter/setter JS object
  16811. ThisKind:=cvkHelperTemp;
  16812. end;
  16813. end
  16814. else if aResolver.IsClassMethod(El) then
  16815. ThisKind:=cvkCurType
  16816. else
  16817. ThisKind:=cvkInstance;
  16818. if ProcScope.ImplProc<>nil then
  16819. SelfArg:=TPas2JSProcedureScope(ProcScope.ImplProc.CustomData).SelfArg
  16820. else
  16821. SelfArg:=ProcScope.SelfArg;
  16822. //writeln('TPasToJSConverter.ConvertProcedure El=',GetObjPath(El),' SelfArg=',GetObjPath(SelfArg));
  16823. end;
  16824. FuncContext.ThisVar.Element:=ThisPas;
  16825. FuncContext.ThisVar.Kind:=ThisKind;
  16826. if ThisPas<>nil then
  16827. begin
  16828. if (bsObjectChecks in FuncContext.ScannerBoolSwitches)
  16829. and (ThisKind in [cvkGlobal,cvkInstance,cvkCurType]) then
  16830. begin
  16831. // rtl.checkMethodCall(this,<class>)
  16832. Call:=CreateCallExpression(PosEl);
  16833. AddBodyStatement(Call,PosEl);
  16834. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),
  16835. GetBIName(pbifnCheckMethodCall)]);
  16836. Call.AddArg(CreatePrimitiveDotExpr('this',PosEl));
  16837. ClassPath:=CreateReferencePath(ProcScope.ClassRecScope.Element,AContext,rpkPathAndName);
  16838. Call.AddArg(CreatePrimitiveDotExpr(ClassPath,PosEl));
  16839. end;
  16840. //writeln('TPasToJSConverter.ConvertProcedure El=',GetObjPath(El),' SelfArg=',GetObjPath(SelfArg),' ThisPas=',GetObjPath(ThisPas));
  16841. if (ImplProc.Body.Functions.Count>0)
  16842. or aResolver.HasAnonymousFunctions(ImplProc.Body.Body) then
  16843. begin
  16844. // has nested procs -> add "var $Self = this;"
  16845. FuncContext.AddLocalVar(GetBIName(pbivnSelf),ThisPas,ThisKind,false);
  16846. SelfSt:=CreateVarStatement(GetBIName(pbivnSelf),
  16847. CreatePrimitiveDotExpr('this',ImplProc),ImplProc);
  16848. AddBodyStatement(SelfSt,PosEl);
  16849. if (SelfArg<>nil) and (ThisPas<>SelfArg) then
  16850. begin
  16851. // add alias (two PasElements for "this")
  16852. FuncContext.AddLocalVar(GetBIName(pbivnSelf),SelfArg,ThisKind,false);
  16853. end;
  16854. end
  16855. else if (SelfArg<>nil) and (ThisPas<>SelfArg) then
  16856. begin
  16857. // add alias (two PasElements for "this")
  16858. FuncContext.AddLocalVar('this',SelfArg,ThisKind,false);
  16859. end;
  16860. end;
  16861. end;
  16862. if (aResolver<>nil) then
  16863. for i:=0 to El.ProcType.Args.Count-1 do
  16864. begin
  16865. Arg:=TPasArgument(El.ProcType.Args[i]);
  16866. if Arg.ArgType=nil then continue;
  16867. aResolver.ComputeElement(Arg,ArgResolved,[rcType]);
  16868. ArgTypeEl:=ArgResolved.LoTypeEl;
  16869. if ArgTypeEl=nil then continue;
  16870. if (Arg.Access=argDefault) and aResolver.IsManagedJSType(ArgTypeEl) then
  16871. FuncContext.Add_InterfaceRelease(Arg);
  16872. if (bsRangeChecks in ImplProcScope.BoolSwitches) then
  16873. begin
  16874. if ArgResolved.BaseType in btAllJSRangeCheckTypes then
  16875. AddRangeCheckType(Arg,ArgTypeEl,FuncContext)
  16876. else if ArgResolved.BaseType=btContext then
  16877. begin
  16878. if ArgTypeEl.ClassType=TPasEnumType then
  16879. AddRangeCheckType(Arg,ArgTypeEl,FuncContext);
  16880. end
  16881. else if ArgResolved.BaseType=btRange then
  16882. begin
  16883. if ArgResolved.SubType in btAllJSRangeCheckTypes then
  16884. AddRangeCheckType(Arg,ArgTypeEl,FuncContext)
  16885. else if ArgResolved.SubType=btContext then
  16886. AddRangeCheckType(Arg,ArgTypeEl,FuncContext)
  16887. else
  16888. begin
  16889. {$IFDEF VerbosePas2JS}
  16890. writeln('TPasToJSConverter.ConvertProcedure ',GetResolverResultDbg(ArgResolved));
  16891. RaiseNotSupported(Arg,AContext,20180424120701);
  16892. {$ENDIF}
  16893. end;
  16894. end;
  16895. end;
  16896. end;
  16897. {$IFDEF VerbosePas2JS}
  16898. //FuncContext.WriteStack;
  16899. {$ENDIF}
  16900. if BodyPas<>nil then
  16901. AddBodyStatement(ConvertDeclarations(BodyPas,FuncContext),BodyPas);
  16902. finally
  16903. FuncContext.Free;
  16904. end;
  16905. end;
  16906. if ImplJS<>nil then
  16907. begin
  16908. ImplJS.BodyJS:=CreatePrecompiledJS(Result);
  16909. ImplJS.EmptyJS:=BodyPas.Body=nil;
  16910. end;
  16911. end;
  16912. function TPasToJSConverter.ConvertBeginEndStatement(El: TPasImplBeginBlock;
  16913. AContext: TConvertContext; NilIfEmpty: boolean): TJSElement;
  16914. begin
  16915. Result:=ConvertImplBlockElements(El,AContext,NilIfEmpty);
  16916. end;
  16917. function TPasToJSConverter.ConvertImplBlockElements(El: TPasImplBlock;
  16918. AContext: TConvertContext; NilIfEmpty: boolean): TJSElement;
  16919. var
  16920. First, Last: TJSStatementList;
  16921. I : Integer;
  16922. PasImpl: TPasImplElement;
  16923. JSImpl : TJSElement;
  16924. begin
  16925. if Not (Assigned(El.Elements) and (El.Elements.Count>0)) then
  16926. begin
  16927. if NilIfEmpty then
  16928. Result:=nil
  16929. else
  16930. Result:=TJSEmptyBlockStatement(CreateElement(TJSEmptyBlockStatement,El));
  16931. end
  16932. else
  16933. begin
  16934. Result:=nil;
  16935. try
  16936. First:=nil;
  16937. Last:=nil;
  16938. //writeln('TPasToJSConverter.ConvertImplBlockElements START El.Elements.Count=',El.Elements.Count);
  16939. For I:=0 to El.Elements.Count-1 do
  16940. begin
  16941. PasImpl:=TPasImplElement(El.Elements[i]);
  16942. JSImpl:=ConvertElement(PasImpl,AContext);
  16943. if JSImpl=nil then
  16944. continue; // e.g. "inherited;" when there is no ancestor proc
  16945. //writeln('TPasToJSConverter.ConvertImplBlockElements ',i,' ',JSImpl.ClassName);
  16946. AddToStatementList(First,Last,JSImpl,PasImpl);
  16947. end;
  16948. Result:=First;
  16949. finally
  16950. if Result=nil then
  16951. First.Free;
  16952. end;
  16953. end;
  16954. end;
  16955. function TPasToJSConverter.ConvertInitializationSection(El: TPasModule;
  16956. AContext: TConvertContext): TJSElement;
  16957. var
  16958. FDS: TJSFunctionDeclarationStatement;
  16959. FuncContext: TFunctionContext;
  16960. PosEl: TPasElement;
  16961. function CreateBody: TJSFunctionBody;
  16962. var
  16963. FuncDef: TJSFuncDef;
  16964. begin
  16965. FuncDef:=FDS.AFunction;
  16966. Result:=FuncDef.Body;
  16967. if Result=nil then
  16968. begin
  16969. Result:=TJSFunctionBody(CreateElement(TJSFunctionBody,PosEl));
  16970. FuncDef.Body:=Result;
  16971. end;
  16972. if FuncContext=nil then
  16973. FuncContext:=TFunctionContext.Create(PosEl,Result,AContext);
  16974. end;
  16975. var
  16976. FunName, S: String;
  16977. IsMain, NeedRTLCheckVersion: Boolean;
  16978. AssignSt: TJSSimpleAssignStatement;
  16979. Body: TJSFunctionBody;
  16980. Scope: TPas2JSInitialFinalizationScope;
  16981. Line, Col: integer;
  16982. Lit: TJSLiteral;
  16983. Section: TInitializationSection;
  16984. RootContext: TRootContext;
  16985. ImplJS: TPas2JSPrecompiledJS;
  16986. begin
  16987. // create: '$mod.$init=function(){}'
  16988. Result:=nil;
  16989. Section:=El.InitializationSection;
  16990. if Section<>nil then
  16991. begin
  16992. PosEl:=Section;
  16993. Scope:=TPas2JSInitialFinalizationScope(Section.CustomData);
  16994. end
  16995. else
  16996. begin
  16997. PosEl:=El;
  16998. Scope:=nil;
  16999. end;
  17000. if El.ClassType=TPasProgram then
  17001. begin
  17002. IsMain:=true;
  17003. FunName:=GetBIName(pbifnProgramMain)
  17004. end
  17005. else if El.ClassType=TPasLibrary then
  17006. begin
  17007. IsMain:=true;
  17008. FunName:=GetBIName(pbifnLibraryMain)
  17009. end
  17010. else
  17011. begin
  17012. IsMain:=false;
  17013. FunName:=GetBIName(pbifnUnitInit);
  17014. end;
  17015. NeedRTLCheckVersion:=IsMain and (coRTLVersionCheckMain in Options);
  17016. RootContext:=AContext.GetRootContext as TRootContext;
  17017. FuncContext:=nil;
  17018. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,PosEl));
  17019. try
  17020. // $mod.$init =
  17021. AssignSt.LHS:=CreateMemberExpression([GetBIName(pbivnModule),FunName]);
  17022. // = function(){...}
  17023. FDS:=CreateFunctionSt(PosEl,false);
  17024. AssignSt.Expr:=FDS;
  17025. Body:=FDS.AFunction.Body;
  17026. // first convert main/initialization statements
  17027. if Section<>nil then
  17028. begin
  17029. ImplJS:=Scope.ImplJS;
  17030. if ImplJS<>nil then
  17031. begin
  17032. S:=TrimRight(ImplJS.BodyJS);
  17033. if S<>'' then
  17034. begin
  17035. Body:=CreateBody;
  17036. // use precompiled JS
  17037. TPasResolver.UnmangleSourceLineNumber(El.SourceLinenumber,Line,Col);
  17038. Lit:=TJSLiteral.Create(Line,Col,El.SourceFilename);
  17039. Lit.Value.CustomValue:=StrToJSString(S);
  17040. Body.A:=Lit;
  17041. if coShortRefGlobals in Options then
  17042. CreateGlobalAlias_List(ImplJS.ShortRefs,AContext);
  17043. end;
  17044. end
  17045. else
  17046. begin
  17047. if (coStoreImplJS in Options) and (AContext.Resolver<>nil) then
  17048. begin
  17049. ImplJS:=TPas2JSPrecompiledJS.Create;
  17050. Scope.ImplJS:=ImplJS;
  17051. end;
  17052. if Section.Elements.Count>0 then
  17053. begin
  17054. Body:=CreateBody;
  17055. // Note: although the rtl sets 'this' as the module, the function can
  17056. // simply refer to $mod, so no need to set ThisPas here
  17057. Body.A:=ConvertImplBlockElements(Section,FuncContext,false);
  17058. FuncContext.BodySt:=Body.A;
  17059. AddInterfaceReleases(FuncContext,PosEl);
  17060. Body.A:=FuncContext.BodySt;
  17061. // store precompiled JS
  17062. if ImplJS<>nil then
  17063. begin
  17064. ImplJS.BodyJS:=TrimRight(CreatePrecompiledJS(Body.A));
  17065. ImplJS.EmptyJS:=ImplJS.BodyJS=''; // store the information, that there is an empty initialization section
  17066. end;
  17067. end
  17068. else if ImplJS<>nil then
  17069. ImplJS.EmptyJS:=true; // store the information, that there is an empty initialization section
  17070. end
  17071. end;
  17072. if length(RootContext.GlobalClassMethods)>0 then
  17073. begin
  17074. // prepend class constructors (which one depends on WPO)
  17075. Body:=CreateBody;
  17076. AddClassConstructors(FuncContext,El);
  17077. Body.A:=FuncContext.BodySt;
  17078. end;
  17079. if NeedRTLCheckVersion then
  17080. begin
  17081. // prepend rtl.versionCheck
  17082. Body:=CreateBody;
  17083. AddRTLVersionCheck(FuncContext,El);
  17084. Body.A:=FuncContext.BodySt;
  17085. end;
  17086. Result:=AssignSt;
  17087. finally
  17088. FuncContext.Free;
  17089. if Result=nil then
  17090. AssignSt.Free;
  17091. end;
  17092. end;
  17093. function TPasToJSConverter.ConvertFinalizationSection(El: TFinalizationSection;
  17094. AContext: TConvertContext): TJSElement;
  17095. begin
  17096. Result:=nil;
  17097. RaiseNotSupported(El,AContext,20161024192519);
  17098. end;
  17099. function TPasToJSConverter.ConvertTryStatement(El: TPasImplTry;
  17100. AContext: TConvertContext): TJSElement;
  17101. Var
  17102. T : TJSTryStatement;
  17103. ExceptBlock: TPasImplTryHandler;
  17104. i: Integer;
  17105. ExceptOn: TPasImplExceptOn;
  17106. IfSt, Last: TJSIfStatement;
  17107. begin
  17108. Result:=nil;
  17109. T:=nil;
  17110. try
  17111. if El.FinallyExcept is TPasImplTryFinally then
  17112. begin
  17113. T:=TJSTryFinallyStatement(CreateElement(TJSTryFinallyStatement,El));
  17114. T.Block:=ConvertImplBlockElements(El,AContext,true);
  17115. T.BFinally:=ConvertImplBlockElements(El.FinallyExcept,AContext,true);
  17116. end
  17117. else
  17118. begin
  17119. T:=TJSTryCatchStatement(CreateElement(TJSTryCatchStatement,El));
  17120. T.Block:=ConvertImplBlockElements(El,AContext,true);
  17121. // always set the catch except object, needed by nodejs
  17122. T.Ident:=TJSString(GetBIName(pbivnExceptObject));
  17123. ExceptBlock:=El.FinallyExcept;
  17124. if (ExceptBlock.Elements.Count>0)
  17125. and (TPasImplElement(ExceptBlock.Elements[0]) is TPasImplExceptOn) then
  17126. begin
  17127. Last:=nil;
  17128. for i:=0 to ExceptBlock.Elements.Count-1 do
  17129. begin
  17130. ExceptOn:=TObject(ExceptBlock.Elements[i]) as TPasImplExceptOn;
  17131. IfSt:=ConvertExceptOn(ExceptOn,AContext) as TJSIfStatement;
  17132. if Last=nil then
  17133. T.BCatch:=IfSt
  17134. else
  17135. Last.BFalse:=IfSt;
  17136. Last:=IfSt;
  17137. end;
  17138. if El.ElseBranch<>nil then
  17139. Last.BFalse:=ConvertImplBlockElements(El.ElseBranch,AContext,true)
  17140. else
  17141. begin
  17142. // default else: throw exceptobject
  17143. Last.BFalse:=TJSThrowStatement(CreateElement(TJSThrowStatement,El));
  17144. TJSThrowStatement(Last.BFalse).A:=
  17145. CreatePrimitiveDotExpr(GetBIName(pbivnExceptObject),El);
  17146. end;
  17147. end
  17148. else
  17149. begin
  17150. if El.ElseBranch<>nil then
  17151. RaiseNotSupported(El.ElseBranch,AContext,20170205003014);
  17152. T.BCatch:=ConvertImplBlockElements(ExceptBlock,AContext,true);
  17153. end;
  17154. end;
  17155. Result:=T;
  17156. finally
  17157. if Result=nil then
  17158. T.Free;
  17159. end;
  17160. end;
  17161. function TPasToJSConverter.ConvertCaseOfStatement(El: TPasImplCaseOf;
  17162. AContext: TConvertContext): TJSElement;
  17163. var
  17164. SubEl: TPasImplElement;
  17165. St: TPasImplCaseStatement;
  17166. ok, IsCaseOfString: Boolean;
  17167. i, j: Integer;
  17168. JSExpr: TJSElement;
  17169. StList: TJSStatementList;
  17170. Expr: TPasExpr;
  17171. IfSt, LastIfSt: TJSIfStatement;
  17172. TmpVar: TFCLocalIdentifier;
  17173. VarDecl: TJSVarDeclaration;
  17174. VarSt: TJSVariableStatement;
  17175. JSOrExpr: TJSLogicalOrExpression;
  17176. JSAndExpr: TJSLogicalAndExpression;
  17177. JSLEExpr: TJSRelationalExpressionLE;
  17178. JSGEExpr: TJSRelationalExpressionGE;
  17179. JSEQExpr: TJSEqualityExpressionSEQ;
  17180. aResolver: TPas2JSResolver;
  17181. CaseResolved: TPasResolverResult;
  17182. FuncCtx: TFunctionContext;
  17183. begin
  17184. Result:=nil;
  17185. aResolver:=AContext.Resolver;
  17186. IsCaseOfString:=false;
  17187. if aResolver<>nil then
  17188. begin
  17189. aResolver.ComputeElement(El.CaseExpr,CaseResolved,[]);
  17190. if CaseResolved.BaseType in btAllStrings then
  17191. IsCaseOfString:=true;
  17192. end;
  17193. if UseSwitchStatement then
  17194. begin
  17195. // convert to switch statement
  17196. // switch does not support ranges -> check
  17197. ok:=true;
  17198. for i:=0 to El.Elements.Count-1 do
  17199. begin
  17200. SubEl:=TPasImplElement(El.Elements[i]);
  17201. if not (SubEl is TPasImplCaseStatement) then
  17202. continue;
  17203. St:=TPasImplCaseStatement(SubEl);
  17204. for j:=0 to St.Expressions.Count-1 do
  17205. begin
  17206. Expr:=TPasExpr(St.Expressions[j]);
  17207. if (Expr is TBinaryExpr) and (TBinaryExpr(Expr).Kind=pekRange) then
  17208. begin
  17209. ok:=false;
  17210. break;
  17211. end;
  17212. end;
  17213. if not ok then break;
  17214. end;
  17215. if ok then
  17216. begin
  17217. Result:=CreateSwitchStatement(El,AContext);
  17218. exit;
  17219. end;
  17220. end;
  17221. // convert to if statements
  17222. StList:=TJSStatementList(CreateElement(TJSStatementList,El));
  17223. ok:=false;
  17224. try
  17225. // create var $tmp1=CaseExpr;
  17226. FuncCtx:=AContext.GetFunctionContext;
  17227. if FuncCtx=nil then
  17228. RaiseNotSupported(El,AContext,20200608132048);
  17229. TmpVar:=FuncCtx.AddLocalVar('$tmp',El.CaseExpr,cvkNone,true);
  17230. VarSt:=TJSVariableStatement(CreateElement(TJSVariableStatement,El.CaseExpr));
  17231. StList.A:=VarSt;
  17232. VarDecl:=TJSVarDeclaration(CreateElement(TJSVarDeclaration,El.CaseExpr));
  17233. VarSt.VarDecl:=VarDecl;
  17234. VarDecl.Name:=TJSString(TmpVar.Name);
  17235. VarDecl.Init:=ConvertExpression(El.CaseExpr,AContext);
  17236. LastIfSt:=nil;
  17237. for i:=0 to El.Elements.Count-1 do
  17238. begin
  17239. SubEl:=TPasImplElement(El.Elements[i]);
  17240. if SubEl is TPasImplCaseStatement then
  17241. begin
  17242. St:=TPasImplCaseStatement(SubEl);
  17243. // create for example "if (tmp==expr) || ((tmp>=expr) && (tmp<=expr)){}"
  17244. IfSt:=TJSIfStatement(CreateElement(TJSIfStatement,SubEl));
  17245. if LastIfSt=nil then
  17246. StList.B:=IfSt
  17247. else
  17248. LastIfSt.BFalse:=IfSt;
  17249. LastIfSt:=IfSt;
  17250. for j:=0 to St.Expressions.Count-1 do
  17251. begin
  17252. Expr:=TPasExpr(St.Expressions[j]);
  17253. if (Expr is TBinaryExpr) and (TBinaryExpr(Expr).Kind=pekRange) then
  17254. begin
  17255. // range -> create "(tmp>=left) && (tmp<=right)"
  17256. // create "() && ()"
  17257. JSAndExpr:=TJSLogicalAndExpression(CreateElement(TJSLogicalAndExpression,Expr));
  17258. JSExpr:=JSAndExpr;
  17259. // create "tmp>=left"
  17260. JSGEExpr:=TJSRelationalExpressionGE(CreateElement(TJSRelationalExpressionGE,Expr));
  17261. JSAndExpr.A:=JSGEExpr;
  17262. JSGEExpr.A:=CreatePrimitiveDotExpr(TmpVar.Name,El.CaseExpr);
  17263. JSGEExpr.B:=ConvertExpression(TBinaryExpr(Expr).left,AContext);
  17264. // create "tmp<=right"
  17265. JSLEExpr:=TJSRelationalExpressionLE(CreateElement(TJSRelationalExpressionLE,Expr));
  17266. JSAndExpr.B:=JSLEExpr;
  17267. JSLEExpr.A:=CreatePrimitiveDotExpr(TmpVar.Name,El.CaseExpr);
  17268. JSLEExpr.B:=ConvertExpression(TBinaryExpr(Expr).right,AContext);
  17269. if IsCaseOfString then
  17270. begin
  17271. // case of string, range -> "(tmp.length===1) &&"
  17272. JSEQExpr:=TJSEqualityExpressionSEQ(CreateElement(TJSEqualityExpressionSEQ,Expr));
  17273. JSEQExpr.A:=CreateDotNameExpr(Expr,
  17274. CreatePrimitiveDotExpr(TmpVar.Name,El.CaseExpr),
  17275. 'length');
  17276. JSEQExpr.B:=CreateLiteralNumber(Expr,1);
  17277. JSAndExpr:=TJSLogicalAndExpression(CreateElement(TJSLogicalAndExpression,Expr));
  17278. JSAndExpr.A:=JSEQExpr;
  17279. JSAndExpr.B:=JSExpr;
  17280. JSExpr:=JSAndExpr;
  17281. end;
  17282. end
  17283. else
  17284. begin
  17285. // value -> create (tmp===Expr)
  17286. JSEQExpr:=TJSEqualityExpressionSEQ(CreateElement(TJSEqualityExpressionSEQ,Expr));
  17287. JSExpr:=JSEQExpr;
  17288. JSEQExpr.A:=CreatePrimitiveDotExpr(TmpVar.Name,El.CaseExpr);
  17289. JSEQExpr.B:=ConvertExpression(Expr,AContext);
  17290. end;
  17291. if IfSt.Cond=nil then
  17292. // first expression
  17293. IfSt.Cond:=JSExpr
  17294. else
  17295. begin
  17296. // multi expression -> append with OR
  17297. JSOrExpr:=TJSLogicalOrExpression(CreateElement(TJSLogicalOrExpression,St));
  17298. JSOrExpr.A:=IfSt.Cond;
  17299. JSOrExpr.B:=JSExpr;
  17300. IfSt.Cond:=JSOrExpr;
  17301. end;
  17302. end;
  17303. // convert statement
  17304. if St.Body<>nil then
  17305. IfSt.BTrue:=ConvertElement(St.Body,AContext)
  17306. else
  17307. IfSt.BTrue:=TJSEmptyStatement(CreateElement(TJSEmptyStatement,St));
  17308. end
  17309. else if SubEl is TPasImplCaseElse then
  17310. begin
  17311. // Pascal 'else' or 'otherwise' -> create JS "else{}"
  17312. if LastIfSt=nil then
  17313. RaiseNotSupported(SubEl,AContext,20161128120802,'case-of needs at least one case');
  17314. LastIfSt.BFalse:=ConvertImplBlockElements(El.ElseBranch,AContext,true);
  17315. end
  17316. else
  17317. RaiseNotSupported(SubEl,AContext,20161128113055);
  17318. end;
  17319. ok:=true;
  17320. finally
  17321. if not ok then
  17322. StList.Free;
  17323. end;
  17324. Result:=StList;
  17325. end;
  17326. function TPasToJSConverter.ConvertAsmStatement(El: TPasImplAsmStatement;
  17327. AContext: TConvertContext): TJSElement;
  17328. var
  17329. s: String;
  17330. L: TJSLiteral;
  17331. AsmLines: TStrings;
  17332. Line, Col, StartLine: integer;
  17333. Statements: TJSStatementList;
  17334. begin
  17335. if AContext=nil then ;
  17336. AsmLines:=El.Tokens;
  17337. s:=Trim(AsmLines.Text);
  17338. if (s<>'') and (s[length(s)]=';') then
  17339. Delete(s,length(s),1);
  17340. if s='' then
  17341. Result:=TJSEmptyStatement(CreateElement(TJSEmptyStatement,El))
  17342. else begin
  17343. StartLine:=0;
  17344. while (StartLine<AsmLines.Count) and (Trim(AsmLines[StartLine])='') do
  17345. inc(StartLine);
  17346. TPasResolver.UnmangleSourceLineNumber(El.SourceLinenumber,Line,Col);
  17347. if StartLine>0 then
  17348. Col:=1;
  17349. L:=TJSLiteral.Create(Line+StartLine,Col,El.SourceFilename);
  17350. L.Value.CustomValue:=TJSString(s);
  17351. Result:=L;
  17352. if Pos(';',s)>0 then
  17353. begin
  17354. // multi statement JS
  17355. // for example "if e then asm a;b end;"
  17356. // -> if (e){ a;b }
  17357. Statements:=TJSStatementList.Create(L.Line,L.Column,L.Source);
  17358. Statements.A:=L;
  17359. Result:=Statements;
  17360. end;
  17361. end;
  17362. end;
  17363. function TPasToJSConverter.ConvertConstValue(Value: TResEvalValue;
  17364. AContext: TConvertContext; El: TPasElement): TJSElement;
  17365. var
  17366. Ranges: TResEvalSet.TItems;
  17367. Range: TResEvalSet.TItem;
  17368. Call: TJSCallExpression;
  17369. i: Integer;
  17370. begin
  17371. Result:=nil;
  17372. if Value=nil then
  17373. RaiseNotSupported(El,AContext,20170910211948);
  17374. case Value.Kind of
  17375. revkNil:
  17376. Result:=CreateLiteralNull(El);
  17377. revkBool:
  17378. Result:=CreateLiteralBoolean(El,TResEvalBool(Value).B);
  17379. revkInt:
  17380. Result:=CreateLiteralNumber(El,TResEvalInt(Value).Int);
  17381. revkUInt:
  17382. Result:=CreateLiteralNumber(El,TResEvalUInt(Value).UInt);
  17383. revkFloat:
  17384. Result:=CreateLiteralFloat(El,TResEvalFloat(Value).FloatValue);
  17385. {$IFDEF FPC_HAS_CPSTRING}
  17386. revkString:
  17387. Result:=CreateLiteralString(El,TResEvalString(Value).S);
  17388. {$ENDIF}
  17389. revkUnicodeString:
  17390. Result:=CreateLiteralJSString(El,TResEvalUTF16(Value).S);
  17391. revkEnum:
  17392. Result:=CreateReferencePathExpr(TResEvalEnum(Value).GetEnumValue,AContext);
  17393. revkSetOfInt:
  17394. if Value.IdentEl is TPasExpr then
  17395. Result:=ConvertExpression(TPasExpr(Value.IdentEl),AContext)
  17396. else
  17397. begin
  17398. {$IFDEF VerbosePas2JS}
  17399. writeln('TPasToJSConverter.ConvertConstValue Value=',Value.AsDebugString,' IdentEl=',GetObjName(Value.IdentEl));
  17400. {$ENDIF}
  17401. // rtl.createSet()
  17402. Call:=CreateCallExpression(El);
  17403. try
  17404. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnSet_Create)]);
  17405. Ranges:=TResEvalSet(Value).Ranges;
  17406. for i:=0 to length(Ranges)-1 do
  17407. begin
  17408. Range:=Ranges[i];
  17409. {$IFDEF VerbosePas2JS}
  17410. writeln('TPasToJSConverter.ConvertConstValue SetLiteral ',i,' ',Range.RangeStart,'..',Range.RangeEnd);
  17411. {$ENDIF}
  17412. if Range.RangeStart=Range.RangeEnd then
  17413. begin
  17414. // add one integer
  17415. Call.AddArg(CreateLiteralNumber(El,Range.RangeStart));
  17416. end
  17417. else
  17418. begin
  17419. // range -> add three parameters: null,left,right
  17420. Call.AddArg(CreateLiteralNull(El));
  17421. Call.AddArg(CreateLiteralNumber(El,Range.RangeStart));
  17422. Call.AddArg(CreateLiteralNumber(El,Range.RangeEnd));
  17423. end;
  17424. end;
  17425. Result:=Call;
  17426. finally
  17427. if Result=nil then
  17428. Call.Free;
  17429. end;
  17430. end
  17431. else
  17432. {$IFDEF VerbosePas2JS}
  17433. writeln('TPasToJSConverter.ConvertConstValue Value=',Value.AsDebugString);
  17434. {$ENDIF}
  17435. RaiseNotSupported(El,AContext,20170910211951);
  17436. end;
  17437. end;
  17438. function TPasToJSConverter.CreateImplementationSection(El: TPasModule;
  17439. IntfContext: TInterfaceSectionContext): TJSFunctionDeclarationStatement;
  17440. var
  17441. Src: TJSSourceElements;
  17442. ImplContext: TSectionContext;
  17443. ImplDecl, JS: TJSElement;
  17444. FunDecl: TJSFunctionDeclarationStatement;
  17445. i: Integer;
  17446. begin
  17447. Result:=nil;
  17448. // create function(){}
  17449. FunDecl:=CreateFunctionSt(El.ImplementationSection,true,true);
  17450. Src:=TJSSourceElements(FunDecl.AFunction.Body.A);
  17451. IntfContext.ImplSrcElements:=Src;
  17452. // create section context (a function)
  17453. ImplContext:=TSectionContext.Create(El.ImplementationSection,Src,IntfContext);
  17454. try
  17455. IntfContext.ImplContext:=ImplContext;
  17456. // ToDo: IntfContext.ThisPas:=El;
  17457. // ToDo: IntfContext.ThisKind:=cvkGlobal;
  17458. // add pending impl header statements
  17459. if IntfContext.ImplHeaderStatements<>nil then
  17460. begin
  17461. for i:=0 to IntfContext.ImplHeaderStatements.Count-1 do
  17462. begin
  17463. JS:=TJSElement(IntfContext.ImplHeaderStatements[i]);
  17464. ImplContext.AddHeaderStatement(JS);
  17465. IntfContext.ImplHeaderStatements[i]:=nil;
  17466. end;
  17467. FreeAndNil(IntfContext.ImplHeaderStatements);
  17468. end;
  17469. // create implementation declarations
  17470. if El.ImplementationSection<>nil then
  17471. begin
  17472. ImplDecl:=ConvertDeclarations(El.ImplementationSection,ImplContext);
  17473. if ImplDecl<>nil then
  17474. RaiseInconsistency(20170910175032,El); // elements should have been added directly
  17475. end;
  17476. IntfContext.ImplHeaderIndex:=ImplContext.HeaderIndex;
  17477. Result:=FunDecl;
  17478. finally
  17479. IntfContext.ImplContext:=nil;
  17480. ImplContext.Free;
  17481. if Result=nil then
  17482. begin
  17483. FunDecl.Free;
  17484. IntfContext.ImplSrcElements:=nil;
  17485. end;
  17486. end;
  17487. end;
  17488. procedure TPasToJSConverter.CreateInitSection(El: TPasModule;
  17489. Src: TJSSourceElements; AContext: TConvertContext);
  17490. var
  17491. RootContext: TRootContext;
  17492. begin
  17493. RootContext:=AContext.GetRootContext as TRootContext;
  17494. // add initialization section
  17495. if Assigned(El.InitializationSection)
  17496. or (El is TPasLibrary) // the begin..end is optional in a library, but the js it always needed
  17497. or (length(RootContext.GlobalClassMethods)>0) then
  17498. AddToSourceElements(Src,ConvertInitializationSection(El,AContext));
  17499. // finalization: not supported
  17500. if Assigned(El.FinalizationSection) then
  17501. raise Exception.Create('TPasToJSConverter.ConvertInitializationSection: finalization section is not supported');
  17502. end;
  17503. procedure TPasToJSConverter.CreateExportsSection(El: TPasLibrary;
  17504. Src: TJSSourceElements; AContext: TConvertContext);
  17505. // functions:
  17506. // export const func1 = pas.unit1.func1;
  17507. // variables:
  17508. // export const vars = {};
  17509. // Object.defineProperties(vars, {
  17510. // Var1: {
  17511. // get: function(){return pas.unit1.Var1;},
  17512. // set: function(v){pas.unit1.Var1 = v;},
  17513. // }
  17514. // });
  17515. procedure AddPropFunction(ObjLit: TJSObjectLiteral; AliasName, Arg1: TJSString;
  17516. BodyJS: TJSElement; PosEl: TPasElement);
  17517. var
  17518. Lit: TJSObjectLiteralElement;
  17519. FuncSt: TJSFunctionDeclarationStatement;
  17520. begin
  17521. Lit:=ObjLit.Elements.AddElement;
  17522. Lit.Name:=AliasName;
  17523. FuncSt:=CreateFunctionSt(PosEl,true,false);
  17524. Lit.Expr:=FuncSt;
  17525. if Arg1<>'' then
  17526. FuncSt.AFunction.TypedParams.AddParam(Arg1);
  17527. FuncSt.AFunction.Body.A:=BodyJS;
  17528. end;
  17529. var
  17530. ExportSymbols: TFPList;
  17531. aResolver: TPas2JSResolver;
  17532. VarsExpSt, ExpSt: TJSExportStatement;
  17533. i: Integer;
  17534. Symb: TPasExportSymbol;
  17535. Ref: TResolvedReference;
  17536. NamePath: String;
  17537. AliasName: TJSString;
  17538. EvalValue: TResEvalValue;
  17539. Decl: TPasElement;
  17540. ResolvedEl: TPasResolverResult;
  17541. Call: TJSCallExpression;
  17542. VarsObjLit, VarObjLit: TJSObjectLiteral;
  17543. Lit, SubLit: TJSObjectLiteralElement;
  17544. RetSt: TJSReturnStatement;
  17545. AssignSt: TJSSimpleAssignStatement;
  17546. begin
  17547. ExportSymbols:=El.LibrarySection.ExportSymbols;
  17548. if ExportSymbols.Count=0 then exit;
  17549. aResolver:=AContext.Resolver;
  17550. VarsExpSt:=nil;
  17551. for i:=0 to ExportSymbols.Count-1 do
  17552. begin
  17553. Symb:=TObject(ExportSymbols[i]) as TPasExportSymbol;
  17554. // name
  17555. if Symb.NameExpr<>nil then
  17556. begin
  17557. aResolver.ComputeElement(Symb.NameExpr,ResolvedEl,[rcConstant]);
  17558. Decl:=ResolvedEl.IdentEl;
  17559. end
  17560. else
  17561. begin
  17562. if not (Symb.CustomData is TResolvedReference) then
  17563. RaiseNotSupported(Symb,AContext,20211020142506,GetObjName(Symb.CustomData));
  17564. Ref:=TResolvedReference(Symb.CustomData);
  17565. Decl:=Ref.Declaration;
  17566. end;
  17567. NamePath:=CreateReferencePath(Decl,AContext,rpkPathAndName,true);
  17568. // alias
  17569. AliasName:='';
  17570. if Symb.ExportName<>nil then
  17571. begin
  17572. EvalValue:=aResolver.Eval(Symb.ExportName,[refConst]);
  17573. if EvalValue=nil then
  17574. RaiseNotSupported(Symb.ExportName,AContext,20211020144200);
  17575. case EvalValue.Kind of
  17576. {$ifdef FPC_HAS_CPSTRING}
  17577. revkString:
  17578. AliasName:=TJSString(TResEvalString(EvalValue).S);
  17579. {$endif}
  17580. revkUnicodeString:
  17581. AliasName:=TResEvalUTF16(EvalValue).S;
  17582. else
  17583. ReleaseEvalValue(EvalValue);
  17584. RaiseNotSupported(Symb.ExportName,AContext,20211020144404);
  17585. end;
  17586. ReleaseEvalValue(EvalValue);
  17587. end
  17588. else
  17589. begin
  17590. if Decl.Name='' then
  17591. RaiseNotSupported(Symb,AContext,20211020144730);
  17592. AliasName:=TJSString(Decl.Name);
  17593. end;
  17594. if Decl.ClassType=TPasVariable then
  17595. begin
  17596. if VarsExpSt=nil then
  17597. begin
  17598. // add "export const vars = {};"
  17599. VarsExpSt:=CreateExportStatement(vtConst,
  17600. TJSString(GetBIName(pbivnLibraryVars)),
  17601. TJSObjectLiteral(CreateElement(TJSObjectLiteral,Symb)),Symb);
  17602. AddToSourceElements(Src,VarsExpSt);
  17603. // add "Object.defineProperties(vars, { });"
  17604. Call:=CreateCallExpression(Symb);
  17605. AddToSourceElements(Src,Call);
  17606. Call.Expr:=CreatePrimitiveDotExpr('Object.defineProperties',Symb);
  17607. Call.AddArg(CreatePrimitiveDotExpr(GetBIName(pbivnLibraryVars),Symb));
  17608. VarsObjLit:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,Symb));
  17609. Call.AddArg(VarsObjLit);
  17610. end;
  17611. // add "Var1: {},"
  17612. Lit:=VarsObjLit.Elements.AddElement;
  17613. Lit.Name:=AliasName;
  17614. VarObjLit:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,Symb));
  17615. Lit.Expr:=VarObjLit;
  17616. // enumerable: true
  17617. SubLit:=VarObjLit.Elements.AddElement;
  17618. SubLit.Name:='enumerable';
  17619. SubLit.Expr:=CreateLiteralBoolean(Symb,true);
  17620. // get: function(){return pas.unit1.Var1;},
  17621. RetSt:=TJSReturnStatement(CreateElement(TJSReturnStatement,Symb));
  17622. RetSt.Expr:=CreatePrimitiveDotExpr(NamePath,Symb);
  17623. AddPropFunction(VarObjLit,'get','',RetSt,Symb);
  17624. // set: function(v){pas.unit1.Var1 = v;},
  17625. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,Symb));
  17626. AssignSt.LHS:=CreatePrimitiveDotExpr(NamePath,Symb);
  17627. AssignSt.Expr:=CreatePrimitiveDotExpr(TempRefObjSetterArgName,Symb);
  17628. AddPropFunction(VarObjLit,'set',TJSString(TempRefObjSetterArgName),AssignSt,Symb);
  17629. end
  17630. else
  17631. begin
  17632. // "export const AliasName = NamePath;"
  17633. ExpSt:=CreateExportStatement(vtConst,AliasName,CreatePrimitiveDotExpr(NamePath,Symb),Symb);
  17634. AddToSourceElements(Src,ExpSt);
  17635. end;
  17636. end;
  17637. end;
  17638. function TPasToJSConverter.AddRTLRun(El: TPasModule; ModuleName: string;
  17639. Src: TJSSourceElements; AContext: TConvertContext): TJSCallExpression;
  17640. var
  17641. Call: TJSCallExpression;
  17642. begin
  17643. if AContext=nil then ;
  17644. // add rtl.run('library');
  17645. Call:=CreateCallExpression(El);
  17646. AddToSourceElements(Src,Call);
  17647. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),'run']);
  17648. if ModuleName<>'' then
  17649. // add module name parameter
  17650. Call.AddArg(CreateLiteralString(El,ModuleName));
  17651. Result:=Call;
  17652. end;
  17653. procedure TPasToJSConverter.AddHeaderStatement(JS: TJSElement;
  17654. PosEl: TPasElement; aContext: TConvertContext);
  17655. var
  17656. SectionCtx: TSectionContext;
  17657. begin
  17658. if JS=nil then exit;
  17659. SectionCtx:=TSectionContext(aContext.GetMainSectionContext);
  17660. if SectionCtx=nil then
  17661. RaiseNotSupported(PosEl,aContext,20200606142555);
  17662. SectionCtx.AddHeaderStatement(JS);
  17663. end;
  17664. procedure TPasToJSConverter.AddImplHeaderStatement(JS: TJSElement;
  17665. PosEl: TPasElement; aContext: TConvertContext);
  17666. var
  17667. IntfSec: TInterfaceSectionContext;
  17668. begin
  17669. if JS=nil then exit;
  17670. IntfSec:=TInterfaceSectionContext(aContext.GetContextOfType(TInterfaceSectionContext));
  17671. if IntfSec=nil then
  17672. RaiseNotSupported(PosEl,aContext,20200606142555);
  17673. IntfSec.AddImplHeaderStatement(JS);
  17674. end;
  17675. function TPasToJSConverter.AddDelayedInits(El: TPasModule;
  17676. Src: TJSSourceElements; AContext: TConvertContext): boolean;
  17677. var
  17678. aResolver: TPas2JSResolver;
  17679. Hub: TPas2JSResolverHub;
  17680. i: Integer;
  17681. JS: TJSElement;
  17682. AssignSt: TJSSimpleAssignStatement;
  17683. FunDecl: TJSFunctionDeclarationStatement;
  17684. ImplSrc: TJSSourceElements;
  17685. begin
  17686. Result:=false;
  17687. aResolver:=AContext.Resolver;
  17688. if aResolver=nil then exit;
  17689. if El=nil then ;
  17690. Hub:=aResolver.Hub as TPas2JSResolverHub;
  17691. {$IFDEF VerbosePas2JS}
  17692. writeln('TPasToJSConverter.AddDelayedInits Hub.JSDelaySpecializeCount=',Hub.JSDelaySpecializeCount);
  17693. {$ENDIF}
  17694. ImplSrc:=nil;
  17695. for i:=0 to Hub.JSDelaySpecializeCount-1 do
  17696. begin
  17697. JS:=CreateDelaySpecializeInit(Hub.JSDelaySpecializes[i],AContext);
  17698. if JS=nil then continue;
  17699. if ImplSrc=nil then
  17700. begin
  17701. // create "$mod.$implcode = function(){ }"
  17702. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  17703. AddToSourceElements(Src,AssignSt);
  17704. AssignSt.LHS:=CreateMemberExpression([GetBIName(pbivnModule),GetBIName(pbivnImplCode)]);
  17705. // create function(){}
  17706. FunDecl:=CreateFunctionSt(El,true,true);
  17707. AssignSt.Expr:=FunDecl;
  17708. ImplSrc:=TJSSourceElements(FunDecl.AFunction.Body.A);
  17709. end;
  17710. AddToSourceElements(ImplSrc,JS);
  17711. Result:=true;
  17712. end;
  17713. end;
  17714. function TPasToJSConverter.CreateDelaySpecializeInit(El: TPasGenericType;
  17715. AContext: TConvertContext): TJSElement;
  17716. var
  17717. C: TClass;
  17718. Path: String;
  17719. Call: TJSCallExpression;
  17720. DotExpr: TJSDotMemberExpression;
  17721. AssignSt: TJSSimpleAssignStatement;
  17722. Arr: TPasArrayType;
  17723. ElTypeHi, ElTypeLo: TPasType;
  17724. aResolver: TPas2JSResolver;
  17725. begin
  17726. Result:=nil;
  17727. if not IsElementUsed(El) then exit;
  17728. if not AContext.Resolver.IsFullySpecialized(El) then
  17729. RaiseNotSupported(El,AContext,20201202145045,'not fully specialized, probably a bug in the analyzer');
  17730. if not SpecializeNeedsDelay(El,AContext) then exit;
  17731. C:=El.ClassType;
  17732. if (C=TPasRecordType)
  17733. or (C=TPasClassType) then
  17734. begin
  17735. if (C=TPasClassType) and TPasClassType(El).IsExternal then exit;
  17736. // pas.unitname.recordtype.$initSpec();
  17737. Path:=CreateReferencePath(El,AContext,rpkPathAndName)+'.'+GetBIName(pbifnClassInitSpecialize);
  17738. Call:=CreateCallExpression(El);
  17739. Call.Expr:=CreatePrimitiveDotExpr(Path,El);
  17740. Result:=Call;
  17741. end
  17742. else if (C=TPasProcedureType) or (C=TPasFunctionType) then
  17743. begin
  17744. if not HasTypeInfo(El,AContext) then
  17745. exit; // no RTTI needed
  17746. // pas.unitname.$rtti.TProcF.init();
  17747. DotExpr:=TJSDotMemberExpression(CreateElement(TJSDotMemberExpression,El));
  17748. DotExpr.MExpr:=CreateTypeInfoRef(El,AContext,El);
  17749. DotExpr.Name:=TJSString(GetBIName(pbivnRTTIProc_InitSpec));
  17750. Call:=CreateCallExpression(El);
  17751. Call.Expr:=DotExpr;
  17752. Result:=Call;
  17753. end
  17754. else if (C=TPasArrayType) then
  17755. begin
  17756. if not HasTypeInfo(El,AContext) then
  17757. exit; // no RTTI needed
  17758. // pas.unitname.$rtti.TArr.eltype=$mod.$rtti.TBird;
  17759. aResolver:=AContext.Resolver;
  17760. Arr:=TPasArrayType(El);
  17761. ElTypeHi:=aResolver.ResolveAliasType(Arr.ElType,false);
  17762. ElTypeLo:=aResolver.ResolveAliasType(ElTypeHi);
  17763. if length(Arr.Ranges)>0 then
  17764. begin
  17765. // static array
  17766. while ElTypeLo.ClassType=TPasArrayType do
  17767. begin
  17768. Arr:=TPasArrayType(ElTypeLo);
  17769. if length(Arr.Ranges)=0 then
  17770. RaiseNotSupported(Arr,AContext,20200902155418,'static array of anonymous array');
  17771. ElTypeHi:=aResolver.ResolveAliasType(Arr.ElType,false);
  17772. ElTypeLo:=aResolver.ResolveAliasType(ElTypeHi);
  17773. end;
  17774. end;
  17775. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  17776. AssignSt.LHS:=CreateDotNameExpr(El,CreateTypeInfoRef(El,AContext,El),
  17777. TJSString(GetBIName(pbivnRTTIArray_ElType)));
  17778. AssignSt.Expr:=CreateTypeInfoRef(ElTypeHi,AContext,El);
  17779. Result:=AssignSt;
  17780. end
  17781. else
  17782. RaiseNotSupported(El,AContext,20200831115251);
  17783. end;
  17784. function TPasToJSConverter.CreateReferencedSet(El: TPasElement; SetExpr: TJSElement
  17785. ): TJSElement;
  17786. var
  17787. Call: TJSCallExpression;
  17788. begin
  17789. Call:=CreateCallExpression(El);
  17790. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnSet_Reference)]);
  17791. Call.AddArg(SetExpr);
  17792. Result:=Call;
  17793. end;
  17794. function TPasToJSConverter.CreateRecordInit(aRecord: TPasRecordType;
  17795. Expr: TPasExpr; El: TPasElement; AContext: TConvertContext): TJSElement;
  17796. // without Expr: recordtype.$new()
  17797. // with Expr: recordtype.$clone(expr)
  17798. var
  17799. aResolver: TPas2JSResolver;
  17800. ObjLit: TJSObjectLiteral;
  17801. GUID: TGuid;
  17802. begin
  17803. Result:=nil;
  17804. if Expr<>nil then
  17805. begin
  17806. aResolver:=AContext.Resolver;
  17807. if aResolver<>nil then
  17808. begin
  17809. if aResolver.GetAssignGUIDString(aRecord,Expr,GUID) then
  17810. begin
  17811. // TGuid.$clone({ D1:...})
  17812. ObjLit:=CreateGUIDObjLit(aRecord,GUID,El,AContext);
  17813. Result:=CreateRecordCallClone(El,aRecord,ObjLit,AContext);
  17814. exit;
  17815. end;
  17816. end;
  17817. if Expr is TRecordValues then
  17818. // TRecord.$clone({...})
  17819. Result:=ConvertRecordValues(TRecordValues(Expr),AContext);
  17820. if Result=nil then
  17821. RaiseNotSupported(Expr,AContext,20161024192747);
  17822. end
  17823. else
  17824. begin
  17825. // TRecord.$new()
  17826. Result:=CreateRecordCallNew(El,aRecord,AContext);
  17827. end;
  17828. end;
  17829. function TPasToJSConverter.CreateRecordCallNew(PosEl: TPasElement;
  17830. RecTypeEl: TPasRecordType; AContext: TConvertContext): TJSCallExpression;
  17831. // create "RecordType.$new()"
  17832. var
  17833. Expr: TJSElement;
  17834. Call: TJSCallExpression;
  17835. begin
  17836. Expr:=CreateReferencePathExpr(RecTypeEl,AContext);
  17837. Call:=CreateCallExpression(PosEl);
  17838. Call.Expr:=CreateDotNameExpr(PosEl,Expr,
  17839. TJSString(GetBIName(pbifnRecordNew)));
  17840. Result:=Call;
  17841. end;
  17842. function TPasToJSConverter.CreateRecordCallClone(PosEl: TPasElement;
  17843. RecTypeEl: TPasRecordType; RecordExpr: TJSElement; AContext: TConvertContext
  17844. ): TJSCallExpression;
  17845. // create "RecordType.$clone(RecordExpr)
  17846. var
  17847. Expr, CallExpr: TJSElement;
  17848. DotExpr: TJSDotMemberExpression;
  17849. Call: TJSCallExpression;
  17850. begin
  17851. Expr:=CreateReferencePathExpr(RecTypeEl,AContext);
  17852. if RecordExpr is TJSCallExpression then
  17853. begin
  17854. CallExpr:=TJSCallExpression(RecordExpr).Expr;
  17855. if CallExpr is TJSDotMemberExpression then
  17856. begin
  17857. DotExpr:=TJSDotMemberExpression(CallExpr);
  17858. if JSEquals(Expr,DotExpr.MExpr) then
  17859. begin
  17860. if (DotExpr.Name=TJSString(GetBIName(pbifnRecordNew)))
  17861. or (DotExpr.Name=TJSString(GetBIName(pbifnRecordClone))) then
  17862. begin
  17863. // RecordExpr is already a RecordType.$new() or .$clone(...) -> skip clone
  17864. Expr.Free;
  17865. exit(TJSCallExpression(RecordExpr));
  17866. end;
  17867. end;
  17868. // Note: rtl.getIntfGUIDR returns a cached version, which must be cloned
  17869. end;
  17870. end;
  17871. Call:=CreateCallExpression(PosEl);
  17872. Call.Expr:=CreateDotNameExpr(PosEl,Expr,
  17873. TJSString(GetBIName(pbifnRecordClone)));
  17874. Result:=Call;
  17875. if RecordExpr<>nil then
  17876. Call.AddArg(RecordExpr);
  17877. end;
  17878. function TPasToJSConverter.CreateRecordFunctionNew(El: TPasRecordType;
  17879. AContext: TConvertContext; Fields: TFPList): TJSElement;
  17880. // this.$new = function(){
  17881. // var r = Object.create(this);
  17882. // r.aSet = {};
  17883. // return r;
  17884. // }
  17885. const
  17886. LocalVarName = 'r';
  17887. var
  17888. AssignSt, CurAssignSt: TJSSimpleAssignStatement;
  17889. FDS: TJSFunctionDeclarationStatement;
  17890. FD: TJSFuncDef;
  17891. RetSt: TJSReturnStatement;
  17892. i: Integer;
  17893. PasVar: TPasVariable;
  17894. Call: TJSCallExpression;
  17895. VarSt: TJSVariableStatement;
  17896. Src: TJSSourceElements;
  17897. VarName: String;
  17898. begin
  17899. Result:=nil;
  17900. if Fields.Count=0 then exit;
  17901. // add "this.$new ="
  17902. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  17903. try
  17904. AssignSt.LHS:=CreateMemberExpression(['this',GetBIName(pbifnRecordNew)]);
  17905. // add "function(){"
  17906. FDS:=CreateFunctionSt(El);
  17907. AssignSt.Expr:=FDS;
  17908. FD:=FDS.AFunction;
  17909. Src:=TJSSourceElements(CreateElement(TJSSourceElements,El));
  17910. FD.Body.A:=Src;
  17911. // add "var r = Object.create(this);"
  17912. Call:=CreateCallExpression(El);
  17913. Call.Expr:=CreateMemberExpression(['Object','create']);
  17914. Call.AddArg(CreatePrimitiveDotExpr('this',El));
  17915. //Call.AddArg(CreatePrimitiveDotExpr('this.'+GetBIName(pbivnPtrRecord),El));
  17916. VarSt:=CreateVarStatement(LocalVarName,Call,El);
  17917. AddToSourceElements(Src,VarSt);
  17918. // add "r.fieldname = initvalue;"
  17919. for i:=0 to Fields.Count-1 do
  17920. begin
  17921. PasVar:=TPasVariable(Fields[i]);
  17922. CurAssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  17923. VarName:=TransformElToJSName(PasVar,AContext);
  17924. CurAssignSt.LHS:=CreateMemberExpression([LocalVarName,VarName]);
  17925. CurAssignSt.Expr:=CreateVarInit(PasVar,AContext);
  17926. AddToSourceElements(Src,CurAssignSt);
  17927. end;
  17928. // add "return r;"
  17929. RetSt:=TJSReturnStatement(CreateElement(TJSReturnStatement,El));
  17930. AddToSourceElements(Src,RetSt);
  17931. RetSt.Expr:=CreatePrimitiveDotExpr(LocalVarName,El);
  17932. Result:=AssignSt;
  17933. finally
  17934. if Result=nil then
  17935. AssignSt.Free;
  17936. end;
  17937. end;
  17938. function TPasToJSConverter.CreateRecordFunctionEqual(El: TPasRecordType;
  17939. AContext: TConvertContext; Fields: TFPList): TJSElement;
  17940. // this.$eq = function(b){
  17941. // return (this.member1 == b.member1);
  17942. // };
  17943. const
  17944. EqualParamName = 'b';
  17945. var
  17946. LastAndExpr: TJSLogicalAndExpression;
  17947. procedure Add_AndExpr_ToReturnSt(RetSt: TJSReturnStatement;
  17948. PasVar: TPasVariable; Expr: TJSElement);
  17949. var
  17950. AndExpr: TJSLogicalAndExpression;
  17951. begin
  17952. if RetSt.Expr=nil then
  17953. RetSt.Expr:=Expr
  17954. else
  17955. begin
  17956. AndExpr:=TJSLogicalAndExpression(CreateElement(TJSLogicalAndExpression,PasVar));
  17957. if LastAndExpr=nil then
  17958. begin
  17959. AndExpr.A:=RetSt.Expr;
  17960. RetSt.Expr:=AndExpr;
  17961. end
  17962. else
  17963. begin
  17964. AndExpr.A:=LastAndExpr.B;
  17965. LastAndExpr.B:=AndExpr;
  17966. end;
  17967. AndExpr.B:=Expr;
  17968. LastAndExpr:=AndExpr;
  17969. end;
  17970. end;
  17971. var
  17972. AssignSt: TJSSimpleAssignStatement;
  17973. FD: TJSFuncDef;
  17974. RetSt: TJSReturnStatement;
  17975. i: Integer;
  17976. PasVar: TPasVariable;
  17977. FDS: TJSFunctionDeclarationStatement;
  17978. EqExpr: TJSEqualityExpressionSEQ;
  17979. VarType: TPasType;
  17980. Call: TJSCallExpression;
  17981. VarName: String;
  17982. aResolver: TPas2JSResolver;
  17983. begin
  17984. Result:=nil;
  17985. aResolver:=AContext.Resolver;
  17986. // add "this.$eq ="
  17987. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  17988. try
  17989. AssignSt.LHS:=CreateMemberExpression(['this',GetBIName(pbifnRecordEqual)]);
  17990. // add "function(b){"
  17991. FDS:=CreateFunctionSt(El);
  17992. AssignSt.Expr:=FDS;
  17993. FD:=FDS.AFunction;
  17994. FD.TypedParams.AddParam(EqualParamName);
  17995. // add "return "
  17996. RetSt:=TJSReturnStatement(CreateElement(TJSReturnStatement,El));
  17997. FD.Body.A:=RetSt;
  17998. LastAndExpr:=nil;
  17999. for i:=0 to Fields.Count-1 do
  18000. begin
  18001. PasVar:=TPasVariable(Fields[i]);
  18002. // "this.member = b.member;"
  18003. VarType:=PasVar.VarType;
  18004. if aResolver<>nil then
  18005. VarType:=aResolver.ResolveAliasType(VarType);
  18006. VarName:=TransformElToJSName(PasVar,aContext);
  18007. if VarType.ClassType=TPasRecordType then
  18008. begin
  18009. // record
  18010. // add "this.member.$eq(b.member)"
  18011. Call:=CreateCallExpression(PasVar);
  18012. Add_AndExpr_ToReturnSt(RetSt,PasVar,Call);
  18013. Call.Expr:=CreateMemberExpression(['this',VarName,GetBIName(pbifnRecordEqual)]);
  18014. Call.AddArg(CreateMemberExpression([EqualParamName,VarName]));
  18015. end
  18016. else if VarType.ClassType=TPasSetType then
  18017. begin
  18018. // set
  18019. // add "rtl.eqSet(this.member,b.member)"
  18020. Call:=CreateCallExpression(PasVar);
  18021. Add_AndExpr_ToReturnSt(RetSt,PasVar,Call);
  18022. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnSet_Equal)]);
  18023. Call.AddArg(CreateMemberExpression(['this',VarName]));
  18024. Call.AddArg(CreateMemberExpression([EqualParamName,VarName]));
  18025. end
  18026. else if VarType is TPasProcedureType then
  18027. begin
  18028. // proc type
  18029. // add "rtl.eqCallback(this.member,b.member)"
  18030. Call:=CreateCallExpression(PasVar);
  18031. Add_AndExpr_ToReturnSt(RetSt,PasVar,Call);
  18032. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnProcType_Equal)]);
  18033. Call.AddArg(CreateMemberExpression(['this',VarName]));
  18034. Call.AddArg(CreateMemberExpression([EqualParamName,VarName]));
  18035. end
  18036. else if (VarType.ClassType=TPasArrayType)
  18037. and (length(TPasArrayType(VarType).Ranges)>0) then
  18038. begin
  18039. // static array
  18040. // add "rtl.arrayEq(this.member,b.member)"
  18041. Call:=CreateCallExpression(PasVar);
  18042. Add_AndExpr_ToReturnSt(RetSt,PasVar,Call);
  18043. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnArray_Equal)]);
  18044. Call.AddArg(CreateMemberExpression(['this',VarName]));
  18045. Call.AddArg(CreateMemberExpression([EqualParamName,VarName]));
  18046. end
  18047. else
  18048. begin
  18049. // default: use strict equal "==="
  18050. EqExpr:=TJSEqualityExpressionSEQ(CreateElement(TJSEqualityExpressionSEQ,PasVar));
  18051. Add_AndExpr_ToReturnSt(RetSt,PasVar,EqExpr);
  18052. EqExpr.A:=CreateMemberExpression(['this',VarName]);
  18053. EqExpr.B:=CreateMemberExpression([EqualParamName,VarName]);
  18054. end;
  18055. end;
  18056. if RetSt.Expr=nil then
  18057. RetSt.Expr:=CreateLiteralBoolean(El,true); // no fields, "return true;"
  18058. Result:=AssignSt;
  18059. finally
  18060. if Result=nil then
  18061. AssignSt.Free;
  18062. end;
  18063. end;
  18064. function TPasToJSConverter.CreateRecordFunctionAssign(El: TPasRecordType;
  18065. AContext: TConvertContext; Fields: TFPList): TJSElement;
  18066. const
  18067. SrcParamName = 's';
  18068. var
  18069. AssignSt, VarAssignSt: TJSSimpleAssignStatement;
  18070. FDS: TJSFunctionDeclarationStatement;
  18071. FD: TJSFuncDef;
  18072. Src: TJSSourceElements;
  18073. i: Integer;
  18074. PasVar: TPasVariable;
  18075. VarName: String;
  18076. aResolver: TPas2JSResolver;
  18077. PasVarType: TPasType;
  18078. RetSt: TJSReturnStatement;
  18079. PasVarClass: TClass;
  18080. Call: TJSCallExpression;
  18081. SrcExpr: TJSElement;
  18082. begin
  18083. Result:=nil;
  18084. aResolver:=AContext.Resolver;
  18085. // add "this.$assign ="
  18086. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  18087. try
  18088. AssignSt.LHS:=CreateMemberExpression(['this',GetBIName(pbifnRecordAssign)]);
  18089. // add "function(s){"
  18090. FDS:=CreateFunctionSt(El);
  18091. AssignSt.Expr:=FDS;
  18092. FD:=FDS.AFunction;
  18093. FD.TypedParams.AddParam(SrcParamName);
  18094. Src:=TJSSourceElements(CreateElement(TJSSourceElements,El));
  18095. FD.Body.A:=Src;
  18096. PasVarType:=nil;
  18097. PasVarClass:=nil;
  18098. for i:=0 to Fields.Count-1 do
  18099. begin
  18100. PasVar:=TPasVariable(Fields[i]);
  18101. VarName:=TransformElToJSName(PasVar,AContext);
  18102. SrcExpr:=CreateMemberExpression([SrcParamName,VarName]);
  18103. if aResolver<>nil then
  18104. begin
  18105. PasVarType:=aResolver.ResolveAliasType(PasVar.VarType);
  18106. PasVarClass:=PasVarType.ClassType;
  18107. if PasVarClass=TPasRecordType then
  18108. begin
  18109. // assign sub record "this.A.$assign(s.A);"
  18110. Call:=CreateCallExpression(PasVar);
  18111. AddToSourceElements(Src,Call);
  18112. Call.Expr:=CreateMemberExpression(['this',VarName,GetBIName(pbifnRecordAssign)]);
  18113. Call.AddArg(SrcExpr);
  18114. continue;
  18115. end;
  18116. end;
  18117. // create "this.A = s.A;"
  18118. VarAssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,PasVar));
  18119. AddToSourceElements(Src,VarAssignSt);
  18120. VarAssignSt.LHS:=CreateSubDeclNameExpr(PasVar,aContext);
  18121. VarAssignSt.Expr:=SrcExpr;
  18122. if PasVarClass=TPasArrayType then
  18123. begin
  18124. if length(TPasArrayType(PasVarType).Ranges)>0 then
  18125. begin
  18126. // clone sub static array
  18127. VarAssignSt.Expr:=CreateCloneStaticArray(PasVar,TPasArrayType(PasVarType),
  18128. SrcExpr,aContext);
  18129. end
  18130. else if aResolver.IsManagedJSType(PasVarType) then
  18131. begin
  18132. // assign managed array -> "rtl.setIntfP(this,A,s.A);"
  18133. Call:=CreateCallExpression(PasVar);
  18134. AddToSourceElements(Src,Call);
  18135. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnIntfSetIntfP)]);
  18136. Call.AddArg(CreatePrimitiveDotExpr('this',PasVar));
  18137. Call.AddArg(CreatePrimitiveDotExpr(Varname,PasVar));
  18138. Call.AddArg(SrcExpr);
  18139. continue;
  18140. end
  18141. else
  18142. // reference dynamic array
  18143. VarAssignSt.Expr:=CreateArrayRef(PasVar,SrcExpr);
  18144. end
  18145. else if PasVarClass=TPasSetType then
  18146. begin
  18147. // clone sub set
  18148. VarAssignSt.Expr:=CreateReferencedSet(PasVar,SrcExpr);
  18149. end;
  18150. end;
  18151. // add "return this;"
  18152. RetSt:=TJSReturnStatement(CreateElement(TJSReturnStatement,El));
  18153. AddToSourceElements(Src,RetSt);
  18154. RetSt.Expr:=CreatePrimitiveDotExpr('this',El);
  18155. Result:=AssignSt;
  18156. finally
  18157. if Result=nil then
  18158. AssignSt.Free;
  18159. end;
  18160. end;
  18161. procedure TPasToJSConverter.CreateRecordRTTI(El: TPasRecordType;
  18162. Src: TJSSourceElements; FuncContext: TFunctionContext;
  18163. MembersSrc: TJSSourceElements; MembersFuncContext: TFunctionContext);
  18164. var
  18165. ObjLit: TJSObjectLiteral;
  18166. Call: TJSCallExpression;
  18167. HasRTTIMembers: Boolean;
  18168. begin
  18169. // module.$rtti.$Record("typename",{});
  18170. Call:=CreateRTTINewType(El,GetBIName(pbifnRTTINewRecord),false,FuncContext,ObjLit);
  18171. if ObjLit=nil then
  18172. begin
  18173. Call.Free;
  18174. RaiseInconsistency(20190105141430,El);
  18175. end;
  18176. HasRTTIMembers:=CreateRTTIMembers(El,Src,FuncContext,MembersSrc,MembersFuncContext,Call,false);
  18177. if HasRTTIMembers then
  18178. // append this: module.$rtti.$Record("typename",{},this);
  18179. // The rtti gets a $record reference to the record type.
  18180. Call.AddArg(CreatePrimitiveDotExpr('this', El))
  18181. else
  18182. begin
  18183. // no published members, add "module.$rtti.$Record..."
  18184. if Src=MembersSrc then
  18185. AddToSourceElements(Src,Call)
  18186. else
  18187. Src.Statements.InsertNode(0).Node:=Call;
  18188. end;
  18189. end;
  18190. function TPasToJSConverter.CreateDelayedInitMembersFunction(PosEl: TPasElement;
  18191. Src: TJSSourceElements; FuncContext: TFunctionContext; out
  18192. DelaySrc: TJSSourceElements): TFunctionContext;
  18193. var
  18194. AssignSt: TJSSimpleAssignStatement;
  18195. FunDecl: TJSFunctionDeclarationStatement;
  18196. begin
  18197. // this.$initSpec = function(){ DelaySrc }
  18198. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,PosEl));
  18199. AddToSourceElements(Src,AssignSt);
  18200. AssignSt.LHS:=CreatePrimitiveDotExpr('this.'+GetBIName(pbifnClassInitSpecialize),PosEl);
  18201. FunDecl:=CreateFunctionSt(PosEl,true,true);
  18202. AssignSt.Expr:=FunDecl;
  18203. DelaySrc:=TJSSourceElements(FunDecl.AFunction.Body.A);
  18204. Result:=TFunctionContext.Create(PosEl,DelaySrc,FuncContext);
  18205. Result.IsGlobal:=true;
  18206. Result.ThisVar.Element:=PosEl;
  18207. Result.ThisVar.Kind:=cvkCurType;
  18208. end;
  18209. function TPasToJSConverter.CreateArrayConcat(
  18210. ElTypeResolved: TPasResolverResult; PosEl: TPasElement;
  18211. AContext: TConvertContext; IsAppend: boolean): TJSCallExpression;
  18212. var
  18213. Call: TJSCallExpression;
  18214. Func: TPas2JSBuiltInName;
  18215. TypeEl: TPasType;
  18216. ArrayType: TPasArrayType;
  18217. C: TClass;
  18218. begin
  18219. Result:=nil;
  18220. Call:=CreateCallExpression(PosEl);
  18221. try
  18222. {$IFDEF VerbosePas2JS}
  18223. writeln('TPasToJSConverter.CreateArrayConcat ElType=',GetResolverResultDbg(ElTypeResolved));
  18224. {$ENDIF}
  18225. if IsAppend then
  18226. Func:=pbifnArray_Push
  18227. else
  18228. Func:=pbifnArray_Concat;
  18229. if ElTypeResolved.BaseType=btContext then
  18230. begin
  18231. TypeEl:=ElTypeResolved.LoTypeEl;
  18232. C:=TypeEl.ClassType;
  18233. if TypeEl.ClassType=TPasArrayType then
  18234. begin
  18235. // array of array
  18236. ArrayType:=TPasArrayType(TypeEl);
  18237. if length(ArrayType.Ranges)>0 then
  18238. begin
  18239. // array of static array
  18240. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(Func)]);
  18241. if AContext.Resolver.HasStaticArrayCloneFunc(ArrayType) then
  18242. // static array with $clone: rtl.arrayConcat(TArrayOfStaticRec$clone,array1,array2,...)
  18243. Call.AddArg(CreatePrimitiveDotExpr(CreateReferencePath(TypeEl,AContext,rpkPathAndName)+GetBIName(pbifnArray_Static_Clone),PosEl))
  18244. else
  18245. // static array of simple type: rtl.arrayConcat("slice",array1,array2,...)
  18246. Call.AddArg(CreateLiteralString(PosEl,'slice'));
  18247. end
  18248. end
  18249. else if C=TPasRecordType then
  18250. begin
  18251. // array of record: rtl.arrayConcat(RecordType,array1,array2,...)
  18252. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(Func)]);
  18253. Call.AddArg(CreateReferencePathExpr(TypeEl,AContext));
  18254. end
  18255. else if AContext.Resolver.IsManagedJSType(TypeEl) then
  18256. begin
  18257. // array of COM interface -> rtl.arrayConcat("R",array1,array2,...)
  18258. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(Func)]);
  18259. Call.AddArg(CreateLiteralString(TypeEl,GetBIName(pbivnIntfRefCnt)));
  18260. end;
  18261. end
  18262. else if ElTypeResolved.BaseType=btSet then
  18263. begin
  18264. // array of set: rtl.arrayConcat("refSet",array1,array2,...)
  18265. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(Func)]);
  18266. Call.AddArg(CreateLiteralString(PosEl,GetBIName(pbifnSet_Reference)));
  18267. end;
  18268. if Call.Expr=nil then
  18269. begin
  18270. // simple types: rtl.arrayConcatN(array1,array2,...)
  18271. if IsAppend then
  18272. Func:=pbifnArray_PushN
  18273. else
  18274. Func:=pbifnArray_ConcatN;
  18275. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(Func)]);
  18276. end;
  18277. Result:=Call;
  18278. finally
  18279. if Result=nil then
  18280. Call.Free;
  18281. end;
  18282. end;
  18283. function TPasToJSConverter.CreateArrayConcat(ArrayType: TPasArrayType;
  18284. PosEl: TPasElement; AContext: TConvertContext; IsAppend: boolean
  18285. ): TJSCallExpression;
  18286. var
  18287. ElTypeResolved: TPasResolverResult;
  18288. aResolver: TPas2JSResolver;
  18289. begin
  18290. if length(ArrayType.Ranges)>1 then
  18291. RaiseNotSupported(PosEl,AContext,20170331001021);
  18292. aResolver:=AContext.Resolver;
  18293. aResolver.ComputeElement(aResolver.GetArrayElType(ArrayType),ElTypeResolved,[rcType]);
  18294. Result:=CreateArrayConcat(ElTypeResolved,PosEl,AContext,IsAppend);
  18295. end;
  18296. function TPasToJSConverter.CreateArrayInit(ArrayType: TPasArrayType;
  18297. Expr: TPasExpr; El: TPasElement; AContext: TConvertContext): TJSElement;
  18298. function IsAdd(AnExpr: TPasExpr): Boolean;
  18299. begin
  18300. Result:=(AnExpr.ClassType=TBinaryExpr) and (AnExpr.OpCode=eopAdd);
  18301. end;
  18302. function ConvertArrayExpr(CurArrType: TPasArrayType; RgIndex: integer;
  18303. CurExpr: TPasExpr): TJSElement;
  18304. var
  18305. NextArrType: TPasArrayType;
  18306. NextRgIndex: integer;
  18307. function ConvertSubValues(ExprArray: TPasExprArray): TJSArrayLiteral;
  18308. var
  18309. i: Integer;
  18310. JS: TJSElement;
  18311. begin
  18312. Result:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,El));
  18313. for i:=0 to length(ExprArray)-1 do
  18314. begin
  18315. JS:=CreateArrayEl(ExprArray[i],AContext);
  18316. Result.Elements.AddElement.Expr:=JS;
  18317. end;
  18318. end;
  18319. procedure TraverseAdd(Bin: TBinaryExpr; ConcatCall: TJSCallExpression);
  18320. // A+B -> A,B
  18321. // (A+B)+C -> A,B,C
  18322. begin
  18323. if IsAdd(Bin.left) then
  18324. TraverseAdd(TBinaryExpr(Bin.left),ConcatCall)
  18325. else
  18326. ConcatCall.AddArg(ConvertArrayExpr(NextArrType,NextRgIndex,Bin.left));
  18327. if IsAdd(Bin.right) then
  18328. TraverseAdd(TBinaryExpr(Bin.right),ConcatCall)
  18329. else
  18330. ConcatCall.AddArg(ConvertArrayExpr(NextArrType,NextRgIndex,Bin.right));
  18331. end;
  18332. var
  18333. ElTypeResolved: TPasResolverResult;
  18334. Call: TJSCallExpression;
  18335. aResolver: TPas2JSResolver;
  18336. begin
  18337. Result:=nil;
  18338. NextArrType:=CurArrType;
  18339. NextRgIndex:=RgIndex+1;
  18340. aResolver:=AContext.Resolver;
  18341. if RgIndex>=length(CurArrType.Ranges)-1 then
  18342. begin
  18343. aResolver.ComputeElement(aResolver.GetArrayElType(CurArrType),ElTypeResolved,[rcType]);
  18344. if (ElTypeResolved.BaseType=btContext)
  18345. and (ElTypeResolved.LoTypeEl.ClassType=TPasArrayType) then
  18346. begin
  18347. NextArrType:=TPasArrayType(ElTypeResolved.LoTypeEl);
  18348. NextRgIndex:=0;
  18349. end
  18350. else
  18351. ; //IsLastRange:=true;
  18352. end;
  18353. if CurExpr.ClassType=TArrayValues then
  18354. begin
  18355. // (...,...)
  18356. Result:=ConvertSubValues(TArrayValues(CurExpr).Values);
  18357. exit;
  18358. end
  18359. else if (CurExpr.ClassType=TParamsExpr) and (TParamsExpr(CurExpr).Kind=pekSet) then
  18360. begin
  18361. // [...,...]
  18362. Result:=ConvertSubValues(TParamsExpr(CurExpr).Params);
  18363. exit;
  18364. end
  18365. else if IsAdd(CurExpr) then
  18366. begin
  18367. // A+B+... -> rtl.arrayConcat(type,A,B,...)
  18368. Call:=CreateArrayConcat(ArrayType,CurExpr,AContext);
  18369. try
  18370. TraverseAdd(TBinaryExpr(CurExpr),Call);
  18371. Result:=Call;
  18372. if aResolver.IsManagedJSType(ArrayType) then
  18373. Result:=CreateIntfRef(Result,AContext,CurExpr);
  18374. finally
  18375. if Result=nil then
  18376. Call.Free;
  18377. end;
  18378. exit;
  18379. end;
  18380. // use default, e.g. a.b or c[...] or copy(...)
  18381. Result:=ConvertExpression(CurExpr,AContext);
  18382. end;
  18383. function ConvertExprToVarRec(CurExpr: TPasExpr): TJSElement;
  18384. // convert [true,Int] to system.varrecs(1,true,0,Int)
  18385. var
  18386. aResolver: TPas2JSResolver;
  18387. Param: TPasExpr;
  18388. ParamResolved: TPasResolverResult;
  18389. procedure RaiseWrongTypeInArrayConstructor(id: TMaxPrecInt);
  18390. begin
  18391. aResolver.RaiseMsg(id,nWrongTypeXInArrayConstructor,sWrongTypeXInArrayConstructor,
  18392. [aResolver.GetResolverResultDescription(ParamResolved)],Param);
  18393. end;
  18394. var
  18395. Params: TParamsExpr;
  18396. ModScope: TPas2JSModuleScope;
  18397. Call: TJSCallExpression;
  18398. i, VType: Integer;
  18399. LoTypeEl: TPasType;
  18400. ParamsArr: TPasExprArray;
  18401. begin
  18402. Result:=nil;
  18403. aResolver:=AContext.Resolver;
  18404. if IsAdd(CurExpr) then
  18405. aResolver.RaiseMsg(20190215222435,nXExpectedButYFound,sXExpectedButYFound,
  18406. ['array of const',GetElementTypeName(CurExpr)],CurExpr);
  18407. if (not (CurExpr is TParamsExpr)) or (TParamsExpr(CurExpr).Kind<>pekSet) then
  18408. begin
  18409. // e.g. Format(args)
  18410. Result:=ConvertExpression(CurExpr,AContext);
  18411. exit;
  18412. end;
  18413. Params:=TParamsExpr(CurExpr);
  18414. ParamsArr:=Params.Params;
  18415. if length(ParamsArr)=0 then
  18416. begin
  18417. // e.g. Format([])
  18418. Result:=CreateElement(TJSArrayLiteral,Params);
  18419. exit;
  18420. end;
  18421. ModScope:=NoNil(aResolver.RootElement.CustomData) as TPas2JSModuleScope;
  18422. if ModScope.SystemVarRecs=nil then
  18423. RaiseNotSupported(Params,AContext,20190215215148);
  18424. Call:=CreateCallExpression(Params);
  18425. try
  18426. Call.Expr:=CreateReferencePathExpr(ModScope.SystemVarRecs,AContext);
  18427. for i:=0 to length(ParamsArr)-1 do
  18428. begin
  18429. Param:=ParamsArr[i];
  18430. aResolver.ComputeElement(Param,ParamResolved,[]);
  18431. if not (rrfReadable in ParamResolved.Flags) then
  18432. begin
  18433. if (ParamResolved.BaseType=btContext)
  18434. and (ParamResolved.IdentEl is TPasClassType)
  18435. and (TPasClassType(ParamResolved.IdentEl).ObjKind=okClass) then
  18436. VType:=pas2js_vtClass
  18437. else
  18438. RaiseWrongTypeInArrayConstructor(20190215221549);
  18439. end
  18440. else if ParamResolved.BaseType in [btByte,btShortInt,btWord,btSmallInt,btLongint] then
  18441. VType:=pas2js_vtInteger
  18442. else if ParamResolved.BaseType in [btLongWord,btUIntDouble,btIntDouble] then
  18443. VType:=pas2js_vtNativeInt
  18444. else if ParamResolved.BaseType in btAllJSBooleans then
  18445. VType:=pas2js_vtBoolean
  18446. else if ParamResolved.BaseType in btAllJSFloats then
  18447. VType:=pas2js_vtExtended
  18448. else if ParamResolved.BaseType in btAllJSChars then
  18449. VType:=pas2js_vtWideChar
  18450. else if ParamResolved.BaseType in btAllJSStrings then
  18451. VType:=pas2js_vtUnicodeString
  18452. else if ParamResolved.BaseType in [btNil,btPointer] then
  18453. VType:=pas2js_vtPointer
  18454. else if ParamResolved.BaseType=btCurrency then
  18455. VType:=pas2js_vtCurrency
  18456. else if ParamResolved.BaseType=btContext then
  18457. begin
  18458. LoTypeEl:=ParamResolved.LoTypeEl;
  18459. if LoTypeEl.ClassType=TPasClassType then
  18460. case TPasClassType(LoTypeEl).ObjKind of
  18461. okClass: VType:=pas2js_vtObject;
  18462. okInterface: VType:=pas2js_vtInterface;
  18463. else
  18464. RaiseWrongTypeInArrayConstructor(20190215221106);
  18465. end
  18466. else if LoTypeEl.ClassType=TPasClassOfType then
  18467. VType:=pas2js_vtClass
  18468. else
  18469. RaiseWrongTypeInArrayConstructor(20190215221122);
  18470. end
  18471. else if (ParamResolved.BaseType=btCustom)
  18472. and aResolver.IsJSBaseType(ParamResolved,pbtJSValue) then
  18473. VType:=pas2js_vtJSValue
  18474. else
  18475. RaiseWrongTypeInArrayConstructor(20190215221457);
  18476. Call.AddArg(CreateLiteralNumber(Param,VType));
  18477. Call.AddArg(ConvertExpression(Param,AContext));
  18478. end;
  18479. Result:=Call;
  18480. finally
  18481. if Result=nil then
  18482. Call.Free;
  18483. end;
  18484. end;
  18485. var
  18486. Call: TJSCallExpression;
  18487. ArrLit: TJSArrayLiteral;
  18488. i, DimSize: Integer;
  18489. RangeResolved, ElTypeResolved, ExprResolved: TPasResolverResult;
  18490. Range: TPasExpr;
  18491. Lit: TJSLiteral;
  18492. CurArrayType: TPasArrayType;
  18493. DefaultValue: TJSElement;
  18494. US: TJSString;
  18495. DimLits: TObjectList;
  18496. aResolver: TPas2JSResolver;
  18497. ArrScope: TPas2JSArrayScope;
  18498. aManaged: Boolean;
  18499. begin
  18500. {$IFDEF VerbosePas2JS}
  18501. writeln('TPasToJSConverter.CreateArrayInit ',GetObjName(ArrayType),' ',ArrayType.ParentPath,' Expr=',GetObjName(Expr));
  18502. {$ENDIF}
  18503. aResolver:=AContext.Resolver;
  18504. ArrScope:=(ArrayType.CustomData as TPas2JSArrayScope);
  18505. aManaged:=(ArrScope<>nil) and ArrScope.Managed;
  18506. if Assigned(Expr) then
  18507. begin
  18508. // init array with expression
  18509. if aResolver=nil then
  18510. DoError(20161024192739,nInitializedArraysNotSupported,sInitializedArraysNotSupported,[],ArrayType);
  18511. aResolver.ComputeElement(Expr,ExprResolved,[]);
  18512. if (ExprResolved.BaseType in [btArrayOrSet,btArrayLit])
  18513. or ((ExprResolved.BaseType=btContext)
  18514. and (ExprResolved.LoTypeEl.ClassType=TPasArrayType)) then
  18515. begin
  18516. if ArrayType.ElType=nil then
  18517. Result:=ConvertExprToVarRec(Expr)
  18518. else
  18519. begin
  18520. Result:=ConvertArrayExpr(ArrayType,0,Expr);
  18521. if aManaged then
  18522. begin
  18523. // pass an array literal to an array of COM interface
  18524. if Result is TJSArrayLiteral then
  18525. begin
  18526. if (TJSArrayLiteral(Result).Count=0) then
  18527. begin
  18528. // [] -> null
  18529. Result.Free;
  18530. Result:=CreateLiteralNull(Expr);
  18531. end
  18532. else
  18533. begin
  18534. // $ir.ref( rtl.arrayManaged(1,2,[values,...]) )
  18535. Result:=CreateArrayManaged(Expr,1,2,Result);
  18536. if not IsLiteralNull(Result) then
  18537. Result:=CreateIntfRef(Result,AContext,Expr);
  18538. end;
  18539. end;
  18540. end;
  18541. end;
  18542. end
  18543. else if ExprResolved.BaseType in btAllStringAndChars then
  18544. begin
  18545. US:=StrToJSString(aResolver.ComputeConstString(Expr,false,true));
  18546. ArrLit:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,Expr));
  18547. Result:=ArrLit;
  18548. for i:=1 to length(US) do
  18549. ArrLit.Elements.AddElement.Expr:=CreateLiteralJSString(Expr,US[i]);
  18550. end
  18551. else if ExprResolved.BaseType=btNil then
  18552. begin
  18553. if aManaged then
  18554. Result:=CreateLiteralNull(Expr)
  18555. else
  18556. Result:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,Expr));
  18557. end
  18558. else
  18559. RaiseNotSupported(Expr,AContext,20170223133034);
  18560. end
  18561. else if length(ArrayType.Ranges)=0 then
  18562. begin
  18563. // empty dynamic array: [] or null for managed
  18564. if aManaged then
  18565. Result:=CreateLiteralNull(El)
  18566. else
  18567. Result:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,El));
  18568. end
  18569. else
  18570. begin
  18571. // static array
  18572. // create "rtl.arraySetLength(null,defaultvalue,dim1,dim2,...)"
  18573. if aResolver=nil then
  18574. RaiseNotSupported(El,AContext,20170223113050,'');
  18575. Result:=nil;
  18576. DimLits:=TObjectList.Create(true);
  18577. try
  18578. Call:=CreateCallExpression(El);
  18579. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnArray_SetLength)]);
  18580. // add parameter null
  18581. Call.AddArg(CreateLiteralNull(El));
  18582. // create parameters dim1,dim2,...
  18583. CurArrayType:=ArrayType;
  18584. while true do
  18585. begin
  18586. for i:=0 to length(CurArrayType.Ranges)-1 do
  18587. begin
  18588. Range:=CurArrayType.Ranges[i];
  18589. // compute size of this dimension
  18590. DimSize:=aResolver.GetRangeLength(Range);
  18591. if DimSize=0 then
  18592. begin
  18593. aResolver.ComputeElement(Range,RangeResolved,[rcConstant]);
  18594. RaiseNotSupported(Range,AContext,20170223113318,GetResolverResultDbg(RangeResolved));
  18595. end;
  18596. Lit:=CreateLiteralNumber(El,DimSize);
  18597. DimLits.Add(Lit);
  18598. end;
  18599. aResolver.ComputeElement(aResolver.GetArrayElType(CurArrayType),ElTypeResolved,[rcType]);
  18600. if (ElTypeResolved.LoTypeEl is TPasArrayType) then
  18601. begin
  18602. CurArrayType:=TPasArrayType(ElTypeResolved.LoTypeEl);
  18603. if length(CurArrayType.Ranges)>0 then
  18604. begin
  18605. // nested static array
  18606. continue;
  18607. end;
  18608. end;
  18609. break;
  18610. end;
  18611. // add parameter defaultvalue
  18612. if ElTypeResolved.LoTypeEl is TPasRecordType then
  18613. begin
  18614. // array of record -> push the type reference
  18615. DefaultValue:=CreateReferencePathExpr(ElTypeResolved.LoTypeEl,AContext);
  18616. end
  18617. else
  18618. DefaultValue:=CreateValInit(ElTypeResolved.LoTypeEl,nil,El,AContext);
  18619. Call.AddArg(DefaultValue);
  18620. // add parameters dim1,dim2,...
  18621. for i:=0 to DimLits.Count-1 do
  18622. Call.AddArg(TJSElement(DimLits[i]));
  18623. DimLits.OwnsObjects:=false;
  18624. DimLits.Clear;
  18625. Result:=Call;
  18626. finally
  18627. DimLits.Free;
  18628. if Result=nil then
  18629. Call.Free;
  18630. end;
  18631. end;
  18632. if Result=nil then
  18633. RaiseInconsistency(20180617233317,Expr);
  18634. end;
  18635. function TPasToJSConverter.CreateArrayRef(El: TPasElement; ArrayExpr: TJSElement
  18636. ): TJSElement;
  18637. var
  18638. Call: TJSCallExpression;
  18639. begin
  18640. if ArrayExpr is TJSArrayLiteral then
  18641. exit(ArrayExpr);
  18642. Call:=CreateCallExpression(El);
  18643. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnArray_Reference)]);
  18644. Call.AddArg(ArrayExpr);
  18645. Result:=Call;
  18646. end;
  18647. function TPasToJSConverter.CreateCmpArrayWithNil(El: TPasElement;
  18648. JSArray: TJSElement; OpCode: TExprOpCode): TJSElement;
  18649. // convert "array = nil" to "rtl.length(array) > 0"
  18650. // convert "array <> nil" to "rtl.length(array) === 0"
  18651. var
  18652. Call: TJSCallExpression;
  18653. BinExpr: TJSBinaryExpression;
  18654. begin
  18655. if not (OpCode in [eopEqual,eopNotEqual]) then
  18656. RaiseInconsistency(20170401184819,El);
  18657. Call:=CreateCallExpression(El);
  18658. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnArray_Length)]);
  18659. Call.AddArg(JSArray);
  18660. if OpCode=eopEqual then
  18661. BinExpr:=TJSEqualityExpressionSEQ(CreateElement(TJSEqualityExpressionSEQ,El))
  18662. else
  18663. BinExpr:=TJSRelationalExpressionGT(CreateElement(TJSRelationalExpressionGT,El));
  18664. BinExpr.A:=Call;
  18665. BinExpr.B:=CreateLiteralNumber(El,0);
  18666. Result:=BinExpr;
  18667. end;
  18668. function TPasToJSConverter.CreateCloneStaticArray(El: TPasElement;
  18669. ArrTypeEl: TPasArrayType; ArrayExpr: TJSElement; AContext: TConvertContext
  18670. ): TJSElement;
  18671. var
  18672. Call: TJSCallExpression;
  18673. Path: String;
  18674. FuncContext: TFunctionContext;
  18675. DotExpr: TJSDotMemberExpression;
  18676. i: TMaxPrecInt;
  18677. JSExpr: TJSElement;
  18678. begin
  18679. if ArrayExpr is TJSArrayLiteral then
  18680. exit(ArrayExpr);
  18681. if AContext.Resolver.HasStaticArrayCloneFunc(ArrTypeEl) then
  18682. begin
  18683. // TArrayType$clone(ArrayExpr);
  18684. if ArrTypeEl.Name='' then
  18685. RaiseNotSupported(El,AContext,20180218230407,'copy anonymous multi dim static array');
  18686. FuncContext:=AContext.GetFunctionContext;
  18687. Path:=CreateReferencePath(ArrTypeEl,FuncContext,rpkPathAndName)
  18688. +GetBIName(pbifnArray_Static_Clone);
  18689. Call:=CreateCallExpression(El);
  18690. Call.Expr:=CreatePrimitiveDotExpr(Path,El);
  18691. Call.AddArg(ArrayExpr);
  18692. Result:=Call;
  18693. end
  18694. else
  18695. begin
  18696. // ArrayExpr.slice(0)
  18697. if ArrayExpr is TJSCallExpression then
  18698. begin
  18699. Call:=TJSCallExpression(ArrayExpr);
  18700. if Call.Expr is TJSDotMemberExpression then
  18701. begin
  18702. DotExpr:=TJSDotMemberExpression(Call.Expr);
  18703. if (DotExpr.Name='slice') and (Call.Args<>nil)
  18704. and (Call.Args.Elements.Count=1) then
  18705. begin
  18706. JSExpr:=Call.Args.Elements[0].Expr;
  18707. if IsLiteralInteger(JSExpr,i) and (i=0) then
  18708. exit(Call); // is already ".slice(0)"
  18709. end;
  18710. end;
  18711. end;
  18712. Call:=CreateCallExpression(El);
  18713. Call.Expr:=CreateDotNameExpr(El,ArrayExpr,'slice');
  18714. Call.AddArg(CreateLiteralNumber(El,0));
  18715. Result:=Call;
  18716. end;
  18717. end;
  18718. function TPasToJSConverter.CreateArrayManaged(El: TPasElement; RefCnt, aMode: integer;
  18719. Arg: TJSElement): TJSCallExpression;
  18720. var
  18721. Call: TJSCallExpression;
  18722. begin
  18723. Call:=CreateCallExpression(El);
  18724. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnArray_Managed)]);
  18725. Call.AddArg(CreateLiteralFloat(El,RefCnt));
  18726. if (Arg<>nil) or (aMode>0) then
  18727. Call.AddArg(CreateLiteralFloat(El,aMode));
  18728. if Arg<>nil then
  18729. Call.AddArg(Arg);
  18730. Result:=Call;
  18731. end;
  18732. procedure TPasToJSConverter.AddClassConDestructorFunction(El: TPasClassType;
  18733. Src: TJSSourceElements; ClassContext: TConvertContext; IsTObject: boolean;
  18734. Ancestor: TPasType; Kind: TMemberFunc);
  18735. const
  18736. MemberFuncName: array[TMemberFunc] of string = (
  18737. '$init',
  18738. '$final'
  18739. );
  18740. var
  18741. AncestorIsExternal: boolean;
  18742. function IsMemberNeeded(aMember: TPasElement): boolean;
  18743. begin
  18744. if IsElementUsed(aMember) then exit(true);
  18745. if IsTObject then
  18746. begin
  18747. if aMember.ClassType=TPasProcedure then
  18748. begin
  18749. if (CompareText(aMember.Name,'AfterConstruction')=0)
  18750. or (CompareText(aMember.Name,'BeforeDestruction')=0) then
  18751. exit(true);
  18752. end;
  18753. end;
  18754. Result:=false;
  18755. end;
  18756. procedure AddCallAncestorMemberFunction(ClassContext: TConvertContext;
  18757. Ancestor: TPasType; Src: TJSSourceElements; Kind: TMemberFunc);
  18758. var
  18759. Call: TJSCallExpression;
  18760. AncestorPath: String;
  18761. begin
  18762. if (Ancestor=nil) or AncestorIsExternal then
  18763. exit;
  18764. Call:=CreateCallExpression(El);
  18765. AncestorPath:=CreateReferencePath(Ancestor,ClassContext,rpkPathAndName);
  18766. Call.Expr:=CreatePrimitiveDotExpr(AncestorPath+'.'+MemberFuncName[Kind]+'.call',El);
  18767. Call.AddArg(CreatePrimitiveDotExpr('this',El));
  18768. AddToSourceElements(Src,Call);
  18769. end;
  18770. // add instance initialization function:
  18771. // this.$init = function(){
  18772. // ancestor.$init();
  18773. // ... init variables ...
  18774. // }
  18775. // or add instance finalization function:
  18776. // this.$final = function(){
  18777. // ... clear references ...
  18778. // ancestor.$final();
  18779. // }
  18780. var
  18781. FuncVD: TJSVarDeclaration;
  18782. New_Src: TJSSourceElements;
  18783. New_FuncContext: TFunctionContext;
  18784. I: Integer;
  18785. P: TPasElement;
  18786. NewEl: TJSElement;
  18787. Func: TJSFunctionDeclarationStatement;
  18788. VarType: TPasType;
  18789. AssignSt: TJSSimpleAssignStatement;
  18790. C: TClass;
  18791. Call: TJSCallExpression;
  18792. begin
  18793. // add instance members
  18794. AncestorIsExternal:=(Ancestor is TPasClassType) and TPasClassType(Ancestor).IsExternal;
  18795. New_Src:=TJSSourceElements(CreateElement(TJSSourceElements, El));
  18796. New_FuncContext:=TFunctionContext.Create(El,New_Src,ClassContext);
  18797. try
  18798. New_FuncContext.ThisVar.Element:=El;
  18799. New_FuncContext.ThisVar.Kind:=cvkCurType;
  18800. New_FuncContext.IsGlobal:=false;
  18801. // add class members
  18802. For I:=0 to El.Members.Count-1 do
  18803. begin
  18804. P:=TPasElement(El.Members[i]);
  18805. if not IsMemberNeeded(P) then continue;
  18806. NewEl:=nil;
  18807. if (P.ClassType=TPasVariable)
  18808. and (ClassVarModifiersType*TPasVariable(P).VarModifiers=[]) then
  18809. begin
  18810. if Kind=mfInit then
  18811. begin
  18812. // mfInit: init var
  18813. NewEl:=CreateVarDecl(TPasVariable(P),New_FuncContext); // can be nil
  18814. end
  18815. else
  18816. begin
  18817. // mfFinalize: clear reference
  18818. if vmExternal in TPasVariable(P).VarModifiers then continue;
  18819. VarType:=ClassContext.Resolver.ResolveAliasType(TPasVariable(P).VarType);
  18820. C:=VarType.ClassType;
  18821. if ClassContext.Resolver.IsManagedJSType(VarType) then
  18822. begin
  18823. // rtl.setIntfP(this,"FieldName",null)
  18824. Call:=CreateCallExpression(El);
  18825. NewEl:=Call;
  18826. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnIntfSetIntfP)]);
  18827. Call.AddArg(CreatePrimitiveDotExpr('this',El));
  18828. Call.AddArg(CreateLiteralString(El,TransformElToJSName(P,New_FuncContext)));
  18829. Call.AddArg(CreateLiteralNull(El));
  18830. end;
  18831. if (NewEl=nil)
  18832. and ((C=TPasRecordType)
  18833. or (C=TPasClassType)
  18834. or (C=TPasClassOfType)
  18835. or (C=TPasSetType)
  18836. or (C=TPasProcedureType)
  18837. or (C=TPasFunctionType)
  18838. or (C=TPasArrayType)) then
  18839. begin
  18840. // add 'this.FieldName = undefined;'
  18841. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  18842. NewEl:=AssignSt;
  18843. AssignSt.LHS:=CreateSubDeclNameExpr(P,New_FuncContext);
  18844. AssignSt.Expr:=CreateLiteralUndefined(El);
  18845. end;
  18846. end;
  18847. end;
  18848. if NewEl=nil then continue;
  18849. if (Kind=mfInit) and (New_Src.Statements.Count=0) then
  18850. // add call ancestor.$init.call(this)
  18851. AddCallAncestorMemberFunction(ClassContext,Ancestor,New_Src,Kind);
  18852. AddToSourceElements(New_Src,NewEl);
  18853. end;
  18854. if (Kind=mfFinalize) and (New_Src.Statements.Count>0) then
  18855. // call ancestor.$final.call(this)
  18856. AddCallAncestorMemberFunction(ClassContext,Ancestor,New_Src,Kind);
  18857. if (Ancestor<>nil) and (not AncestorIsExternal)
  18858. and (New_Src.Statements.Count=0) then
  18859. exit; // descendent does not need $init/$final
  18860. FuncVD:=TJSVarDeclaration(CreateElement(TJSVarDeclaration,El));
  18861. AddToSourceElements(Src,FuncVD);
  18862. FuncVD.Name:=TJSString('this.'+MemberFuncName[Kind]);
  18863. Func:=CreateFunctionSt(El);
  18864. FuncVD.Init:=Func;
  18865. Func.AFunction.Body.A:=New_Src;
  18866. New_Src:=nil;
  18867. finally
  18868. New_Src.Free;
  18869. New_FuncContext.Free;
  18870. end;
  18871. end;
  18872. procedure TPasToJSConverter.AddClassRTTI(El: TPasClassType;
  18873. Src: TJSSourceElements; FuncContext: TFunctionContext);
  18874. var
  18875. HasRTTIMembers, NeedLocalVar: Boolean;
  18876. RTTIExpr, AttrJS: TJSElement;
  18877. Attr: TPasExprArray;
  18878. AssignSt: TJSAssignStatement;
  18879. ClassScope: TPas2JSClassScope;
  18880. Creator: String;
  18881. ObjLit: TJSObjectLiteral;
  18882. Call: TJSCallExpression;
  18883. begin
  18884. AttrJS:=nil;
  18885. RTTIExpr:=nil;
  18886. try
  18887. ClassScope:=El.CustomData as TPas2JSClassScope;
  18888. if (ClassScope.SpecializedFromItem<>nil)
  18889. and not (coNoTypeInfo in Options)
  18890. and FuncContext.Resolver.HasTypeInfo(El) then
  18891. begin
  18892. // specialized class -> init RTTI
  18893. // add header: module.$rtti.$Class("classname");
  18894. Creator:=GetClassBIName(El,FuncContext);
  18895. Call:=CreateRTTINewType(El,Creator,true,FuncContext,ObjLit);
  18896. if ObjLit<>nil then
  18897. RaiseInconsistency(20200606134834,El);
  18898. AddHeaderStatement(Call,El,FuncContext);
  18899. end;
  18900. // this.$rtti
  18901. RTTIExpr:=CreateMemberExpression(['this',GetBIName(pbivnRTTI)]);
  18902. Attr:=FuncContext.Resolver.GetAttributeCallsEl(El);
  18903. AttrJS:=CreateRTTIAttributes(Attr,El,FuncContext);
  18904. NeedLocalVar:=(AttrJS<>nil);
  18905. HasRTTIMembers:=CreateRTTIMembers(El,Src,FuncContext,Src,FuncContext,RTTIExpr,NeedLocalVar);
  18906. if HasRTTIMembers then
  18907. RTTIExpr:=nil;
  18908. if AttrJS<>nil then
  18909. begin
  18910. // $r.attr = [];
  18911. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  18912. AddToSourceElements(Src,AssignSt);
  18913. AssignSt.LHS:=CreateMemberExpression([GetBIName(pbivnRTTILocal),GetBIName(pbivnRTTITypeAttributes)]);
  18914. AssignSt.Expr:=AttrJS;
  18915. AttrJS:=nil;
  18916. end;
  18917. finally
  18918. AttrJS.Free;
  18919. RTTIExpr.Free;
  18920. end;
  18921. end;
  18922. procedure TPasToJSConverter.AddClassConstructors(FuncContext: TFunctionContext;
  18923. PosEl: TPasElement);
  18924. var
  18925. i: Integer;
  18926. Proc: TPasProcedure;
  18927. First, Last: TJSStatementList;
  18928. St: TJSElement;
  18929. Call: TJSCallExpression;
  18930. Bracket: TJSUnaryBracketsExpression;
  18931. RootContext: TRootContext;
  18932. begin
  18933. RootContext:=TRootContext(FuncContext.GetRootContext);
  18934. First:=nil;
  18935. Last:=nil;
  18936. try
  18937. for i:=0 to length(RootContext.GlobalClassMethods)-1 do
  18938. begin
  18939. Proc:=RootContext.GlobalClassMethods[i];
  18940. St:=ConvertProcedure(Proc,FuncContext);
  18941. // create direct call ( function(){} )();
  18942. Bracket:=TJSUnaryBracketsExpression(CreateElement(TJSUnaryBracketsExpression,PosEl));
  18943. Bracket.A:=St;
  18944. Call:=CreateCallExpression(PosEl);
  18945. Call.Expr:=Bracket;
  18946. AddToStatementList(First,Last,Call,PosEl);
  18947. end;
  18948. PrependToStatementList(FuncContext.BodySt,First,PosEl);
  18949. First:=nil;
  18950. finally
  18951. First.Free;
  18952. end;
  18953. end;
  18954. procedure TPasToJSConverter.AddClassMessageIds(El: TPasClassType;
  18955. Src: TJSSourceElements; FuncContext: TFunctionContext;
  18956. pbivn: TPas2JSBuiltInName);
  18957. // $msgint = { id1:"proc1name", id2: "proc2name" ... }
  18958. var
  18959. Scope: TPas2JSClassScope;
  18960. List: TMessageIdToProc_List;
  18961. i: Integer;
  18962. AssignSt: TJSSimpleAssignStatement;
  18963. ObjLit: TJSObjectLiteral;
  18964. LitEl: TJSObjectLiteralElement;
  18965. Proc: TPasProcedure;
  18966. begin
  18967. Scope:=TPas2JSClassScope(El.CustomData);
  18968. case pbivn of
  18969. pbivnMessageInt: List:=Scope.MsgIntToProc;
  18970. pbivnMessageStr: List:=Scope.MsgStrToProc;
  18971. else
  18972. RaiseNotSupported(El,FuncContext,20190304001209,GetBIName(pbivn));
  18973. end;
  18974. if (List=nil) or (List.Count=0) then exit;
  18975. // this.$msgint = {}
  18976. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  18977. AddToSourceElements(Src,AssignSt);
  18978. AssignSt.LHS:=CreateMemberExpression(['this',GetBIName(pbivn)]);
  18979. ObjLit:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,El));
  18980. AssignSt.Expr:=ObjLit;
  18981. for i:=0 to List.Count-1 do
  18982. begin
  18983. LitEl:=ObjLit.Elements.AddElement;
  18984. LitEl.Name:=TJSString(List[i]);
  18985. Proc:=TPasProcedure(List.Objects[i]);
  18986. LitEl.Expr:=CreateLiteralJSString(Proc,TJSString(TransformElToJSName(Proc,FuncContext)));
  18987. end;
  18988. end;
  18989. function TPasToJSConverter.CreateCallback(Expr: TPasExpr;
  18990. ResolvedEl: TPasResolverResult; aSafeCall: boolean; AContext: TConvertContext
  18991. ): TJSElement;
  18992. // Expr is a reference to a proc
  18993. // if aSafeCall then create "rtl.createSafeCallback(Target,func)"
  18994. // for a proc or nested proc simply use the function
  18995. // for a method create "rtl.createCallback(Target,func)"
  18996. function NeedAppendClass(El: TPasElement): boolean;
  18997. var
  18998. TargetResolved: TPasResolverResult;
  18999. begin
  19000. AContext.Resolver.ComputeElement(El,TargetResolved,[]);
  19001. if (TargetResolved.IdentEl is TPasClassType)
  19002. or (TargetResolved.LoTypeEl is TPasClassOfType) then
  19003. // left side is a class
  19004. Result:=false
  19005. else
  19006. Result:=true;
  19007. end;
  19008. var
  19009. Call: TJSCallExpression;
  19010. TargetJS: TJSElement;
  19011. FunName, TargetName: String;
  19012. Proc: TPasProcedure;
  19013. IsHelper, NeedClass: Boolean;
  19014. Bin: TBinaryExpr;
  19015. aResolver: TPas2JSResolver;
  19016. OldAccess: TCtxAccess;
  19017. PosEl: TPasExpr;
  19018. Ref: TResolvedReference;
  19019. WithExprScope: TPas2JSWithExprScope;
  19020. SelfScope: TPasProcedureScope;
  19021. begin
  19022. Result:=nil;
  19023. if not (ResolvedEl.IdentEl is TPasProcedure) then
  19024. RaiseInconsistency(20170215140756,Expr);
  19025. aResolver:=AContext.Resolver;
  19026. Proc:=TPasProcedure(ResolvedEl.IdentEl);
  19027. if not aResolver.ProcHasSelf(Proc) then
  19028. begin
  19029. // not an "of object" method -> simply use the function
  19030. Result:=CreateReferencePathExpr(Proc,AContext);
  19031. if aSafeCall then
  19032. Result:=CreateSafeCallback(Expr,Result,AContext);
  19033. exit;
  19034. end;
  19035. IsHelper:=aResolver.IsHelperMethod(Proc);
  19036. NeedClass:=aResolver.IsClassMethod(Proc) and not aResolver.MethodIsStatic(Proc);
  19037. if Expr is TInlineSpecializeExpr then
  19038. Expr:=TInlineSpecializeExpr(Expr).NameExpr;
  19039. // an of-object method -> create "rtl.createCallback(Target,func)"
  19040. TargetJS:=nil;
  19041. Call:=nil;
  19042. try
  19043. if Expr is TBinaryExpr then
  19044. begin
  19045. // e.g. "target.func"
  19046. Bin:=TBinaryExpr(Expr);
  19047. if Bin.OpCode<>eopSubIdent then
  19048. RaiseNotSupported(Expr,AContext,20190205230811);
  19049. OldAccess:=AContext.Access;
  19050. AContext.Access:=caRead;
  19051. TargetJS:=ConvertExpression(Bin.left,AContext);
  19052. AContext.Access:=OldAccess;
  19053. if NeedClass then
  19054. NeedClass:=NeedAppendClass(Bin.left);
  19055. PosEl:=Bin.right;
  19056. end
  19057. else if aResolver.IsNameExpr(Expr) then
  19058. begin
  19059. // e.g. "func"
  19060. PosEl:=Expr;
  19061. if not (Expr.CustomData is TResolvedReference) then
  19062. RaiseNotSupported(Expr,AContext,20190205230915);
  19063. Ref:=TResolvedReference(Expr.CustomData);
  19064. WithExprScope:=Ref.WithExprScope as TPas2JSWithExprScope;
  19065. if WithExprScope<>nil then
  19066. begin
  19067. // e.g. "with target do f:=@func"
  19068. TargetName:=WithExprScope.WithVarName;
  19069. if (TargetName='') and IsHelper then
  19070. RaiseNotSupported(PosEl,AContext,20190209092355);
  19071. if NeedClass then
  19072. NeedClass:=NeedAppendClass(WithExprScope.Expr);
  19073. end
  19074. else
  19075. begin
  19076. // inside method e.g. "func" or "fly(@func)"
  19077. SelfScope:=aResolver.GetSelfScope(Expr);
  19078. if SelfScope=nil then
  19079. RaiseNotSupported(PosEl,AContext,20190205230919);
  19080. if SelfScope.SelfArg<>nil then
  19081. TargetName:=GetLocalName(SelfScope.SelfArg,cvkAll,AContext)
  19082. else if SelfScope.ClassRecScope<>nil then
  19083. begin
  19084. TargetName:=CreateReferencePath(SelfScope.ClassRecScope.Element,
  19085. AContext,rpkPathAndName);
  19086. NeedClass:=false;
  19087. end
  19088. else
  19089. RaiseNotSupported(PosEl,AContext,20190206104558,GetObjName(Proc));
  19090. if TargetName='' then
  19091. TargetName:='this';
  19092. if NeedClass then
  19093. NeedClass:=NeedAppendClass(SelfScope.SelfArg);
  19094. end;
  19095. TargetJS:=CreatePrimitiveDotExpr(TargetName,PosEl);
  19096. end
  19097. else
  19098. RaiseNotSupported(Expr,AContext,20190205230924);
  19099. if NeedClass then
  19100. // append '.$class'
  19101. TargetJS:=CreateDotExpression(Expr,TargetJS,
  19102. CreatePrimitiveDotExpr(GetBIName(pbivnPtrClass),PosEl));
  19103. Call:=CreateCallExpression(Expr);
  19104. // "rtl.createCallback"
  19105. if aSafeCall then
  19106. TargetName:=GetBIName(pbifnProcType_CreateSafe)
  19107. else
  19108. TargetName:=GetBIName(pbifnProcType_Create);
  19109. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),TargetName]);
  19110. // add target
  19111. Call.AddArg(TargetJS);
  19112. TargetJS:=nil;
  19113. // add function name as parameter
  19114. if IsHelper then
  19115. // create rtl.createCallback(target, THelperType.FunName)
  19116. Call.AddArg(CreateReferencePathExpr(Proc,AContext))
  19117. else
  19118. begin
  19119. // create rtl.createCallback(target, "FunName")
  19120. if (coShortRefGlobals in Options)
  19121. and (TPas2JSProcedureScope(Proc.CustomData).SpecializedFromItem<>nil) then
  19122. begin
  19123. FunName:=CreateStaticProcPath(Proc,AContext);
  19124. Call.AddArg(CreatePrimitiveDotExpr(FunName,Expr));
  19125. end
  19126. else
  19127. begin
  19128. FunName:=TransformElToJSName(Proc,AContext);
  19129. Call.AddArg(CreateLiteralString(Expr,FunName));
  19130. end;
  19131. end;
  19132. Result:=Call;
  19133. finally
  19134. if Result=nil then
  19135. begin
  19136. TargetJS.Free;
  19137. Call.Free;
  19138. end;
  19139. end;
  19140. end;
  19141. function TPasToJSConverter.CreateSafeCallback(Expr: TPasExpr; JS: TJSElement;
  19142. AContext: TConvertContext): TJSElement;
  19143. var
  19144. Call: TJSCallExpression;
  19145. DotExpr: TJSDotMemberExpression;
  19146. Prim: TJSPrimaryExpressionIdent;
  19147. begin
  19148. Result:=JS;
  19149. if AContext=nil then ;
  19150. if JS is TJSCallExpression then
  19151. begin
  19152. Call:=TJSCallExpression(JS);
  19153. if Call.Expr is TJSDotMemberExpression then
  19154. begin
  19155. DotExpr:=TJSDotMemberExpression(Call.Expr);
  19156. if DotExpr.MExpr is TJSPrimaryExpressionIdent then
  19157. begin
  19158. Prim:=TJSPrimaryExpressionIdent(DotExpr.MExpr);
  19159. if Prim.Name=TJSString(GetBIName(pbivnRTL)) then
  19160. begin
  19161. if DotExpr.Name=TJSString(GetBIName(pbifnProcType_Create)) then
  19162. // rtl.createCallback - > rtl.createSafeCallback
  19163. DotExpr.Name:=TJSString(GetBIName(pbifnProcType_CreateSafe));
  19164. end;
  19165. end;
  19166. end;
  19167. // Note: if the call is not a rtl.createCallback then there is no SafeCall
  19168. // e.g. aSafeCall:=Btn1.GetOnClick();
  19169. end
  19170. else
  19171. begin
  19172. // enclose JS in rtl.createSafeCallback()
  19173. Call:=CreateCallExpression(Expr);
  19174. Result:=Call;
  19175. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnProcType_CreateSafe)]);
  19176. if JS is TJSDotMemberExpression then
  19177. begin
  19178. // convert "a.fn" to "rtl.createSafeCallback(a,fn)"
  19179. DotExpr:=TJSDotMemberExpression(JS);
  19180. Call.AddArg(DotExpr.MExpr);
  19181. DotExpr.MExpr:=nil;
  19182. Call.AddArg(CreateLiteralJSString(Expr,DotExpr.Name));
  19183. JS.Free;
  19184. end
  19185. else
  19186. begin
  19187. // convert "JS" to "rtl.createSafeCallback(null,JS)"
  19188. Call.AddArg(CreateLiteralNull(Expr));
  19189. Call.AddArg(JS);
  19190. end;
  19191. end;
  19192. end;
  19193. function TPasToJSConverter.CreateExternalBracketAccessorCall(El: TParamsExpr;
  19194. AContext: TConvertContext): TJSElement;
  19195. var
  19196. Ref: TResolvedReference;
  19197. ArgContext: TConvertContext;
  19198. ok: Boolean;
  19199. AssignSt: TJSSimpleAssignStatement;
  19200. IndexJS: TJSElement;
  19201. WithData: TPas2JSWithExprScope;
  19202. Path: String;
  19203. BracketJS: TJSBracketMemberExpression;
  19204. begin
  19205. Result:=nil;
  19206. if length(El.Params)<1 then
  19207. RaiseInconsistency(20180511151259,El);
  19208. if not (El.Value.CustomData is TResolvedReference) then
  19209. RaiseInconsistency(20180511144445,El);
  19210. Ref:=TResolvedReference(El.Value.CustomData);
  19211. ArgContext:=AContext.GetNonDotContext;
  19212. ok:=false;
  19213. try
  19214. // First convert index, because it may raise an exception
  19215. IndexJS:=ConvertExpression(El.Params[0],ArgContext);
  19216. if Ref.WithExprScope<>nil then
  19217. begin
  19218. // with path do GetItems(astring) -> withtmp1[astring]
  19219. WithData:=Ref.WithExprScope as TPas2JSWithExprScope;
  19220. Path:=WithData.WithVarName;
  19221. if Path='' then
  19222. RaiseNotSupported(El,AContext,20190209092417);
  19223. end
  19224. else
  19225. begin
  19226. // GetItems(astring) -> this[astring]
  19227. Path:='this';
  19228. end;
  19229. BracketJS:=TJSBracketMemberExpression(CreateElement(TJSBracketMemberExpression,El));
  19230. Result:=BracketJS;
  19231. BracketJS.Name:=IndexJS;
  19232. BracketJS.MExpr:=CreatePrimitiveDotExpr(Path,El);
  19233. if length(El.Params)>1 then
  19234. begin
  19235. // SetItems(astring,value) -> this[astring]:=value
  19236. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  19237. AssignSt.LHS:=Result;
  19238. Result:=AssignSt;
  19239. AssignSt.Expr:=ConvertExpression(El.Params[1],ArgContext); // may raise an exception
  19240. end;
  19241. if length(El.Params)>2 then
  19242. DoError(20180511144047,nCantCallExtBracketAccessor,sCantCallExtBracketAccessor,[],El);
  19243. ok:=true;
  19244. finally
  19245. if not ok then Result.Free;
  19246. end;
  19247. end;
  19248. function TPasToJSConverter.CreateAssignStatement(LeftEl: TPasExpr;
  19249. AssignContext: TAssignContext): TJSElement;
  19250. var
  19251. LHS: TJSElement;
  19252. AssignSt: TJSSimpleAssignStatement;
  19253. begin
  19254. Result:=nil;
  19255. LHS:=ConvertExpression(LeftEl,AssignContext);
  19256. if AssignContext.Call<>nil then
  19257. begin
  19258. // has a setter -> right side was already added as parameter
  19259. if AssignContext.RightSide<>nil then
  19260. begin
  19261. LHS.Free;
  19262. RaiseInconsistency(20170207215447,LeftEl);
  19263. end;
  19264. Result:=LHS;
  19265. end
  19266. else
  19267. begin
  19268. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,AssignContext.PasElement));
  19269. AssignSt.LHS:=LHS;
  19270. AssignSt.Expr:=AssignContext.RightSide;
  19271. AssignContext.RightSide:=nil;
  19272. Result:=AssignSt;
  19273. end;
  19274. end;
  19275. function TPasToJSConverter.CreateGetEnumeratorLoop(El: TPasImplForLoop;
  19276. AContext: TConvertContext): TJSElement;
  19277. // for Item in List do
  19278. // convert to
  19279. // var $in=List.GetEnumerator();
  19280. // try{
  19281. // while ($in.MoveNext()){
  19282. // Item=$in.getCurrent;
  19283. // // code
  19284. // }
  19285. // } finally {
  19286. // $in=rtl.freeLoc($in);
  19287. // };
  19288. var
  19289. PosEl: TPasElement;
  19290. CurInVar: TFCLocalIdentifier;
  19291. function CreateInName: TJSElement;
  19292. var
  19293. Ident: TJSPrimaryExpressionIdent;
  19294. begin
  19295. Ident:=TJSPrimaryExpressionIdent(CreateElement(TJSPrimaryExpressionIdent,PosEl));
  19296. Ident.Name:=TJSString(CurInVar.Name); // do not lowercase
  19297. Result:=Ident;
  19298. end;
  19299. var
  19300. aResolver: TPas2JSResolver;
  19301. ForScope: TPasForLoopScope;
  19302. Statements: TJSStatementList;
  19303. VarSt: TJSVariableStatement;
  19304. FuncContext: TFunctionContext;
  19305. List, GetCurrent, J, LHS, RHS: TJSElement;
  19306. Call: TJSCallExpression;
  19307. TrySt: TJSTryFinallyStatement;
  19308. WhileSt: TJSWhileStatement;
  19309. AssignSt: TJSSimpleAssignStatement;
  19310. GetEnumeratorFunc, MoveNextFunc: TPasFunction;
  19311. CurrentProp: TPasProperty;
  19312. DotContext: TDotContext;
  19313. ResolvedEl, VarResolved: TPasResolverResult;
  19314. EnumeratorTypeEl, CurrentPropTypeEl: TPasType;
  19315. NeedTryFinally, NeedIntfRef, IsCurrentPropCOMIntf: Boolean;
  19316. begin
  19317. aResolver:=AContext.Resolver;
  19318. ForScope:=TPasForLoopScope(El.CustomData);
  19319. NeedTryFinally:=true;
  19320. NeedIntfRef:=false;
  19321. // find function GetEnumerator
  19322. GetEnumeratorFunc:=ForScope.GetEnumerator;
  19323. if (GetEnumeratorFunc=nil) then
  19324. RaiseNotSupported(El,AContext,20171225104212);
  19325. if GetEnumeratorFunc.ClassType<>TPasFunction then
  19326. RaiseNotSupported(El,AContext,20171225104237);
  19327. aResolver.ComputeResultElement(GetEnumeratorFunc.FuncType.ResultEl,ResolvedEl,[rcCall]);
  19328. EnumeratorTypeEl:=ResolvedEl.LoTypeEl;
  19329. if EnumeratorTypeEl is TPasClassType then
  19330. begin
  19331. case TPasClassType(EnumeratorTypeEl).ObjKind of
  19332. okClass,okClassHelper,okRecordHelper,okTypeHelper: ;
  19333. okInterface:
  19334. case TPasClassType(EnumeratorTypeEl).InterfaceType of
  19335. citCom: NeedIntfRef:=true;
  19336. citCorba: NeedTryFinally:=false;
  19337. else
  19338. RaiseNotSupported(El.VariableName,AContext,20180328192842){%H-};
  19339. end;
  19340. else
  19341. RaiseNotSupported(El.VariableName,AContext,20180328192452);
  19342. end;
  19343. end;
  19344. // find function MoveNext
  19345. MoveNextFunc:=ForScope.MoveNext;
  19346. if (MoveNextFunc=nil) then
  19347. RaiseNotSupported(El,AContext,20171225104249);
  19348. if MoveNextFunc.ClassType<>TPasFunction then
  19349. RaiseNotSupported(El,AContext,20171225104256);
  19350. if MoveNextFunc.Parent.ClassType<>TPasClassType then
  19351. RaiseNotSupported(El,AContext,20190208153949);
  19352. if TPasClassType(MoveNextFunc.Parent).HelperForType<>nil then
  19353. RaiseNotSupported(El,AContext,20190208155015);
  19354. // find property Current
  19355. CurrentProp:=ForScope.Current;
  19356. if (CurrentProp=nil) then
  19357. RaiseNotSupported(El,AContext,20171225104306);
  19358. if CurrentProp.ClassType<>TPasProperty then
  19359. RaiseNotSupported(El,AContext,20171225104316);
  19360. if CurrentProp.Parent.ClassType<>TPasClassType then
  19361. RaiseNotSupported(El,AContext,20190208154003);
  19362. CurrentPropTypeEl:=AContext.Resolver.ResolveAliasType(CurrentProp.VarType);
  19363. IsCurrentPropCOMIntf:=(CurrentPropTypeEl is TPasClassType)
  19364. and (TPasClassType(CurrentPropTypeEl).ObjKind=okInterface)
  19365. and (TPasClassType(CurrentPropTypeEl).InterfaceType=citCom);
  19366. // get function context
  19367. FuncContext:=AContext.GetFunctionContext;
  19368. PosEl:=El;
  19369. Statements:=TJSStatementList(CreateElement(TJSStatementList,PosEl));
  19370. DotContext:=nil;
  19371. try
  19372. // var...
  19373. VarSt:=TJSVariableStatement(CreateElement(TJSVariableStatement,PosEl));
  19374. Statements.A:=VarSt;
  19375. // List
  19376. PosEl:=El.StartExpr;
  19377. // List.GetEnumerator()
  19378. if aResolver.IsHelperMethod(GetEnumeratorFunc) then
  19379. Call:=CreateCallHelperMethod(GetEnumeratorFunc,El.StartExpr,AContext,true)
  19380. else
  19381. begin
  19382. List:=ConvertExpression(El.StartExpr,AContext); // beware: might fail
  19383. Call:=TJSCallExpression(CreateElement(TJSCallExpression,PosEl));
  19384. Call.Expr:=CreateDotExpression(PosEl,List,
  19385. CreateIdentifierExpr(GetEnumeratorFunc,AContext),true);
  19386. end;
  19387. // var $in=
  19388. CurInVar:=FuncContext.AddLocalVar(GetBIName(pbivnLoopIn),El.VariableName,cvkNone,true);
  19389. VarSt.VarDecl:=CreateVarDecl(CurInVar.Name,Call,PosEl);
  19390. PosEl:=El.VariableName;
  19391. TrySt:=nil;
  19392. if NeedTryFinally then
  19393. begin
  19394. // try()
  19395. TrySt:=TJSTryFinallyStatement(CreateElement(TJSTryFinallyStatement,PosEl));
  19396. Statements.B:=TrySt;
  19397. end;
  19398. // while ()
  19399. WhileSt:=TJSWhileStatement(CreateElement(TJSWhileStatement,PosEl));
  19400. if TrySt<>nil then
  19401. TrySt.Block:=WhileSt
  19402. else
  19403. Statements.B:=WhileSt;
  19404. // $in.MoveNext()
  19405. Call:=TJSCallExpression(CreateElement(TJSCallExpression,PosEl));
  19406. WhileSt.Cond:=Call;
  19407. Call.Expr:=CreateDotExpression(PosEl,CreateInName,
  19408. CreateIdentifierExpr(MoveNextFunc,AContext));
  19409. // read property "Current"
  19410. // Item=$in.GetCurrent(); or Item=$in.FCurrent;
  19411. LHS:=nil;
  19412. RHS:=nil;
  19413. DotContext:=nil;
  19414. try
  19415. LHS:=ConvertExpression(El.VariableName,AContext); // beware: might fail
  19416. DotContext:=TDotContext.Create(El.StartExpr,nil,AContext);
  19417. GetCurrent:=CreatePropertyGet(CurrentProp,nil,DotContext,PosEl); // beware: might fail
  19418. if DotContext.JS<>nil then
  19419. RaiseNotSupported(El,AContext,20180509134302,GetObjName(DotContext.JS));
  19420. RHS:=CreateDotExpression(PosEl,CreateInName,GetCurrent,true);
  19421. if IsCurrentPropCOMIntf then
  19422. begin
  19423. // create "Item = rtl.setIntfL(Item,$in.GetCurrent);"
  19424. aResolver.ComputeElement(El.VariableName,VarResolved,[]);
  19425. WhileSt.Body:=CreateAssignManagedVar(VarResolved,LHS,RHS,AContext,El.VariableName);
  19426. LHS:=nil;
  19427. RHS:=nil;
  19428. end
  19429. else
  19430. begin
  19431. // Item=$in.GetCurrent(); or Item=$in.FCurrent;
  19432. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,PosEl));
  19433. WhileSt.Body:=AssignSt;
  19434. AssignSt.LHS:=LHS;
  19435. LHS:=nil;
  19436. AssignSt.Expr:=RHS;
  19437. RHS:=nil;
  19438. end;
  19439. finally
  19440. FreeAndNil(DotContext);
  19441. FreeAndNil(LHS);
  19442. FreeAndNil(RHS);
  19443. end;
  19444. // add body
  19445. if El.Body<>nil then
  19446. begin
  19447. J:=ConvertElement(El.Body,AContext); // beware: might fail
  19448. if J<>nil then
  19449. begin
  19450. List:=TJSStatementList(CreateElement(TJSStatementList,PosEl));
  19451. TJSStatementList(List).A:=WhileSt.Body;
  19452. TJSStatementList(List).B:=J;
  19453. WhileSt.Body:=List;
  19454. end;
  19455. end;
  19456. PosEl:=El.StartExpr;
  19457. if TrySt<>nil then
  19458. begin
  19459. // finally{ $in=rtl.freeLoc($in) }
  19460. if NeedIntfRef then
  19461. begin
  19462. Call:=CreateCallExpression(PosEl);
  19463. TrySt.BFinally:=Call;
  19464. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnIntf_Release)]);
  19465. Call.AddArg(CreateInName);
  19466. end
  19467. else
  19468. TrySt.BFinally:=CreateCallRTLFreeLoc(CreateInName,CreateInName,PosEl);
  19469. end;
  19470. Result:=Statements;
  19471. finally
  19472. DotContext.Free;
  19473. if Result=nil then
  19474. Statements.Free;
  19475. end;
  19476. end;
  19477. function TPasToJSConverter.CreateCallRTLFreeLoc(Setter, Getter: TJSElement;
  19478. Src: TPasElement): TJSElement;
  19479. // create "Setter=rtl.freeLoc(Getter)"
  19480. var
  19481. Call: TJSCallExpression;
  19482. AssignSt: TJSSimpleAssignStatement;
  19483. begin
  19484. Call:=CreateCallExpression(Src);
  19485. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnFreeLocalVar)]);
  19486. Call.Args.AddElement(Getter);
  19487. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,Src));
  19488. AssignSt.LHS:=Setter;
  19489. AssignSt.Expr:=Call;
  19490. Result:=AssignSt;
  19491. end;
  19492. function TPasToJSConverter.CreatePropertyGet(Prop: TPasProperty;
  19493. Expr: TPasExpr; AContext: TConvertContext; PosEl: TPasElement): TJSElement;
  19494. var
  19495. aResolver: TPas2JSResolver;
  19496. Decl: TPasElement;
  19497. Call: TJSCallExpression;
  19498. Name: String;
  19499. Ref: TResolvedReference;
  19500. begin
  19501. aResolver:=AContext.Resolver;
  19502. Decl:=aResolver.GetPasPropertyGetter(Prop);
  19503. if (Expr<>nil) and (Expr.CustomData is TResolvedReference) then
  19504. Ref:=TResolvedReference(Expr.CustomData)
  19505. else
  19506. Ref:=nil;
  19507. if Decl is TPasFunction then
  19508. begin
  19509. // call function
  19510. if aResolver.IsHelperMethod(Decl) then
  19511. begin
  19512. if (Expr=nil) then
  19513. // implicit property read, e.g. enumerator property Current
  19514. RaiseNotSupported(PosEl,AContext,20190208111355,GetObjName(Prop));
  19515. Result:=CreateCallHelperMethod(TPasProcedure(Decl),Expr,AContext);
  19516. exit;
  19517. end;
  19518. Call:=CreateCallExpression(PosEl);
  19519. try
  19520. Call.Expr:=CreateReferencePathExpr(Decl,AContext,false,Ref);
  19521. Result:=AppendPropertyReadArgs(Call,Prop,AContext,PosEl);
  19522. finally
  19523. if Result=nil then
  19524. Call.Free;
  19525. end;
  19526. end
  19527. else
  19528. begin
  19529. // read field
  19530. Name:=CreateReferencePath(Decl,AContext,rpkPathAndName,false,Ref);
  19531. Result:=CreatePrimitiveDotExpr(Name,PosEl);
  19532. end;
  19533. end;
  19534. function TPasToJSConverter.AppendPropertyAssignArgs(Call: TJSCallExpression;
  19535. Prop: TPasProperty; AssignContext: TAssignContext; PosEl: TPasElement
  19536. ): TJSCallExpression;
  19537. var
  19538. aResolver: TPas2JSResolver;
  19539. IndexExpr: TPasExpr;
  19540. Value: TResEvalValue;
  19541. begin
  19542. AssignContext.Call:=Call;
  19543. AssignContext.PropertyEl:=Prop;
  19544. aResolver:=AssignContext.Resolver;
  19545. IndexExpr:=aResolver.GetPasPropertyIndex(Prop);
  19546. if IndexExpr<>nil then
  19547. begin
  19548. Value:=aResolver.Eval(IndexExpr,[refConst]);
  19549. try
  19550. Call.AddArg(ConvertConstValue(Value,AssignContext,PosEl));
  19551. finally
  19552. ReleaseEvalValue(Value);
  19553. end;
  19554. end;
  19555. Call.AddArg(AssignContext.RightSide);
  19556. AssignContext.RightSide:=nil;
  19557. Result:=Call;
  19558. end;
  19559. function TPasToJSConverter.AppendPropertyReadArgs(Call: TJSCallExpression;
  19560. Prop: TPasProperty; aContext: TConvertContext; PosEl: TPasElement
  19561. ): TJSCallExpression;
  19562. var
  19563. aResolver: TPas2JSResolver;
  19564. IndexExpr: TPasExpr;
  19565. Value: TResEvalValue;
  19566. TypeEl: TPasType;
  19567. begin
  19568. aResolver:=aContext.Resolver;
  19569. IndexExpr:=aResolver.GetPasPropertyIndex(Prop);
  19570. if IndexExpr<>nil then
  19571. begin
  19572. Value:=aResolver.Eval(IndexExpr,[refConst]);
  19573. try
  19574. Call.AddArg(ConvertConstValue(Value,AContext.GetFunctionContext,PosEl));
  19575. finally
  19576. ReleaseEvalValue(Value);
  19577. end;
  19578. end;
  19579. TypeEl:=aResolver.GetPasPropertyType(Prop);
  19580. if aResolver.IsManagedJSType(TypeEl) then
  19581. Call:=CreateIntfRef(Call,AContext,PosEl);
  19582. Result:=Call;
  19583. end;
  19584. function TPasToJSConverter.CreateDotSplit(El: TPasElement; Expr: TJSElement
  19585. ): TJSElement;
  19586. // create Expr.split('')
  19587. var
  19588. DotExpr: TJSDotMemberExpression;
  19589. Call: TJSCallExpression;
  19590. begin
  19591. Call:=CreateCallExpression(El);
  19592. DotExpr:=TJSDotMemberExpression(CreateElement(TJSDotMemberExpression,El));
  19593. Call.Expr:=DotExpr;
  19594. DotExpr.MExpr:=Expr;
  19595. DotExpr.Name:='split';
  19596. Call.AddArg(CreateLiteralJSString(El,''));
  19597. Result:=Call;
  19598. end;
  19599. function TPasToJSConverter.CreateExportStatement(VarType: TJSVarType;
  19600. AliasName: TJSString; InitJS: TJSElement; PosEl: TPasElement
  19601. ): TJSExportStatement;
  19602. var
  19603. VarSt: TJSVariableStatement;
  19604. VarDecl: TJSVarDeclaration;
  19605. begin
  19606. Result:=TJSExportStatement(CreateElement(TJSExportStatement,PosEl));
  19607. VarSt:=TJSVariableStatement(CreateElement(TJSVariableStatement,PosEl));
  19608. Result.Declaration:=VarSt;
  19609. VarSt.VarType:=VarType;
  19610. VarDecl:=TJSVarDeclaration(CreateElement(TJSVarDeclaration,PosEl));
  19611. VarSt.VarDecl:=VarDecl;
  19612. VarDecl.Name:=AliasName;
  19613. VarDecl.Init:=InitJS;
  19614. end;
  19615. function TPasToJSConverter.CreatePrecompiledJS(El: TJSElement): string;
  19616. var
  19617. aWriter: TBufferWriter;
  19618. aJSWriter: TJSWriter;
  19619. begin
  19620. aJSWriter:=nil;
  19621. aWriter:=TBufferWriter.Create(1000);
  19622. try
  19623. aJSWriter:=TJSWriter.Create(aWriter);
  19624. aJSWriter.Options:=DefaultJSWriterOptions;
  19625. aJSWriter.IndentSize:=2;
  19626. aJSWriter.SkipCurlyBrackets:=true;
  19627. aJSWriter.Writer.LineBreak:=#10;
  19628. aJSWriter.WriteJS(El);
  19629. Result:=aWriter.AsString;
  19630. finally
  19631. aJSWriter.Free;
  19632. aWriter.Free;
  19633. end;
  19634. end;
  19635. function TPasToJSConverter.CreateRaisePropReadOnly(PosEl: TPasElement
  19636. ): TJSElement;
  19637. var
  19638. Call: TJSCallExpression;
  19639. begin
  19640. Call:=CreateCallExpression(PosEl);
  19641. Result:=Call;
  19642. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnRaiseException)]);
  19643. Call.AddArg(CreateLiteralJSString(PosEl,'EPropReadOnly'));
  19644. end;
  19645. procedure TPasToJSConverter.AddRTLVersionCheck(FuncContext: TFunctionContext;
  19646. PosEl: TPasElement);
  19647. var
  19648. Call: TJSCallExpression;
  19649. begin
  19650. // rtl.checkVersion(RTLVersion)
  19651. Call:=CreateCallExpression(PosEl);
  19652. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnCheckVersion)]);
  19653. Call.AddArg(CreateLiteralNumber(PosEl,FGlobals.RTLVersion));
  19654. PrependToStatementList(FuncContext.BodySt,Call,PosEl);
  19655. end;
  19656. function TPasToJSConverter.CreateTypeInfoRef(El: TPasType;
  19657. AContext: TConvertContext; ErrorEl: TPasElement): TJSElement;
  19658. var
  19659. aName, aModName: String;
  19660. aModule: TPasModule;
  19661. Bracket: TJSBracketMemberExpression;
  19662. begin
  19663. El:=ResolveSimpleAliasType(El);
  19664. if El is TPasSpecializeType then
  19665. El:=TPasSpecializeTypeData(El.CustomData).SpecializedType;
  19666. aName:=GetTypeInfoName(El,AContext,ErrorEl);
  19667. if aName=GetBIName(pbivnRTTILocal) then
  19668. Result:=CreatePrimitiveDotExpr(aName,El)
  19669. else if LeftStr(aName,length(GetBIName(pbivnRTL))+1)=GetBIName(pbivnRTL)+'.' then
  19670. Result:=CreatePrimitiveDotExpr(aName,El)
  19671. else
  19672. begin
  19673. aModule:=El.GetModule;
  19674. aModName:=TransformModuleName(aModule,true,AContext);
  19675. Bracket:=TJSBracketMemberExpression(CreateElement(TJSBracketMemberExpression,El));
  19676. Bracket.MExpr:=CreateMemberExpression([aModName,GetBIName(pbivnRTTI)]);
  19677. Bracket.Name:=CreateLiteralString(El,aName);
  19678. Result:=Bracket;
  19679. end;
  19680. end;
  19681. function TPasToJSConverter.CreateRTTIArgList(Parent: TPasElement;
  19682. Args: TFPList; AContext: TConvertContext): TJSElement;
  19683. var
  19684. Params: TJSArrayLiteral;
  19685. i: Integer;
  19686. begin
  19687. Result:=nil;
  19688. if Args.Count=0 then
  19689. Result:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,Parent))
  19690. else
  19691. try
  19692. Params:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,Parent));
  19693. for i:=0 to Args.Count-1 do
  19694. AddRTTIArgument(TPasArgument(Args[i]),Params,AContext);
  19695. Result:=Params;
  19696. finally
  19697. if Result=nil then
  19698. Params.Free;
  19699. end;
  19700. end;
  19701. procedure TPasToJSConverter.AddRTTIArgument(Arg: TPasArgument;
  19702. TargetParams: TJSArrayLiteral; AContext: TConvertContext);
  19703. var
  19704. Param: TJSArrayLiteral;
  19705. ArgName: String;
  19706. Flags: Integer;
  19707. ArrType: TPasArrayType;
  19708. aResolver: TPas2JSResolver;
  19709. begin
  19710. aResolver:=AContext.Resolver;
  19711. // for each param add "["argname",argtype,flags]" Note: flags only if >0
  19712. Param:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,Arg));
  19713. TargetParams.Elements.AddElement.Expr:=Param;
  19714. // add "argname"
  19715. ArgName:=TransformToJSName(Arg,Arg.Name,true,AContext); // use Pascal name
  19716. Param.Elements.AddElement.Expr:=CreateLiteralString(Arg,ArgName);
  19717. Flags:=0;
  19718. // add "argtype"
  19719. if Arg.ArgType=nil then
  19720. // untyped
  19721. Param.Elements.AddElement.Expr:=CreateLiteralNull(Arg)
  19722. else if (Arg.ArgType.Name='') and (Arg.ArgType.ClassType=TPasArrayType) then
  19723. begin
  19724. // open array param
  19725. inc(Flags,pfArray);
  19726. ArrType:=TPasArrayType(Arg.ArgType);
  19727. Param.Elements.AddElement.Expr:=
  19728. CreateTypeInfoRef(aResolver.GetArrayElType(ArrType),AContext,Arg);
  19729. end
  19730. else
  19731. Param.Elements.AddElement.Expr:=CreateTypeInfoRef(Arg.ArgType,AContext,Arg);
  19732. // add flags
  19733. case Arg.Access of
  19734. argDefault: ;
  19735. argConst,argConstRef: inc(Flags,pfConst);
  19736. argVar: inc(Flags,pfVar);
  19737. argOut: inc(Flags,pfOut);
  19738. else
  19739. RaiseNotSupported(Arg,AContext,20170409192127,AccessNames[Arg.Access]){%H-};
  19740. end;
  19741. if Flags>0 then
  19742. Param.Elements.AddElement.Expr:=CreateLiteralNumber(Arg,Flags);
  19743. end;
  19744. function TPasToJSConverter.GetClassBIName(El: TPasClassType;
  19745. AContext: TConvertContext): string;
  19746. begin
  19747. case El.ObjKind of
  19748. okClass:
  19749. if El.IsExternal then
  19750. Result:=GetBIName(pbifnRTTINewExtClass)
  19751. else
  19752. Result:=GetBIName(pbifnRTTINewClass);
  19753. okInterface:
  19754. Result:=GetBIName(pbifnRTTINewInterface);
  19755. else
  19756. RaiseNotSupported(El,AContext,20190128102749);
  19757. end;
  19758. end;
  19759. function TPasToJSConverter.CreateRTTINewType(El: TPasType;
  19760. const CallFuncName: string; IsForward: boolean; AContext: TConvertContext;
  19761. out ObjLit: TJSObjectLiteral): TJSCallExpression;
  19762. // module.$rtti.$Something("name",{})
  19763. var
  19764. RttiPath, TypeName: String;
  19765. Call: TJSCallExpression;
  19766. aModule: TPasModule;
  19767. aResolver: TPas2JSResolver;
  19768. Attr: TPasExprArray;
  19769. AttrJS: TJSElement;
  19770. ObjLitEl: TJSObjectLiteralElement;
  19771. begin
  19772. Result:=nil;
  19773. ObjLit:=nil;
  19774. aResolver:=AContext.Resolver;
  19775. // get module path
  19776. aModule:=El.GetModule;
  19777. if aModule=nil then
  19778. RaiseInconsistency(20170418115552,El);
  19779. RttiPath:=TransformModuleName(aModule,true,AContext);
  19780. Call:=CreateCallExpression(El);
  19781. try
  19782. // module.$rtti.$Something
  19783. Call.Expr:=CreateMemberExpression([RttiPath,GetBIName(pbivnRTTI),CallFuncName]);
  19784. // add param "typename"
  19785. TypeName:=GetTypeInfoName(El,AContext,El,true);
  19786. Call.AddArg(CreateLiteralString(El,TypeName));
  19787. if El is TPasTypeAliasType then
  19788. begin
  19789. // add desttype
  19790. Call.AddArg(CreateTypeInfoRef(TPasTypeAliasType(El).DestType,AContext,El));
  19791. end;
  19792. if not IsForward then
  19793. begin
  19794. // add {}
  19795. ObjLit:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,El));
  19796. Call.AddArg(ObjLit);
  19797. Attr:=aResolver.GetAttributeCallsEl(El);
  19798. AttrJS:=CreateRTTIAttributes(Attr,El,AContext);
  19799. if AttrJS<>nil then
  19800. begin
  19801. // attr: [...]
  19802. ObjLitEl:=ObjLit.Elements.AddElement;
  19803. ObjLitEl.Name:=TJSString(GetBIName(pbivnRTTITypeAttributes));
  19804. ObjLitEl.Expr:=AttrJS;
  19805. end;
  19806. end;
  19807. Result:=Call;
  19808. finally
  19809. if Result=nil then
  19810. Call.Free;
  19811. end;
  19812. end;
  19813. function TPasToJSConverter.CreateRTTIAttributes(const Attr: TPasExprArray;
  19814. PosEl: TPasElement; aContext: TConvertContext): TJSElement;
  19815. // create [Attr1Class,'Attr1ProcName',[Attr1Params],...]
  19816. var
  19817. AttrArrayLit, ParamsArrayLit: TJSArrayLiteral;
  19818. i, j: Integer;
  19819. Expr, ParamExpr: TPasExpr;
  19820. aResolver: TPas2JSResolver;
  19821. Ref: TResolvedReference;
  19822. AttrClass, ConstrParent: TPasClassType;
  19823. aConstructor: TPasConstructor;
  19824. aName: String;
  19825. Params: TPasExprArray;
  19826. Value: TResEvalValue;
  19827. JSExpr: TJSElement;
  19828. begin
  19829. Result:=nil;
  19830. aResolver:=aContext.Resolver;
  19831. AttrArrayLit:=nil;
  19832. try
  19833. for i:=0 to length(Attr)-1 do
  19834. begin
  19835. Expr:=Attr[i];
  19836. if Expr is TParamsExpr then
  19837. Expr:=TParamsExpr(Expr).Value;
  19838. if (Expr is TBinaryExpr) and (TBinaryExpr(Expr).OpCode=eopSubIdent) then
  19839. Expr:=TBinaryExpr(Expr).right;
  19840. if not aResolver.IsNameExpr(Expr) then
  19841. RaiseNotSupported(Expr,aContext,20190222182742,GetObjName(Expr));
  19842. // attribute class
  19843. Ref:=Expr.CustomData as TResolvedReference;
  19844. if Ref=nil then
  19845. // unknown attribute -> silently skip (delphi 10.3 compatible)
  19846. continue;
  19847. AttrClass:=Ref.Declaration as TPasClassType;
  19848. if AttrClass.IsAbstract then
  19849. continue; // silently skip abstract class (Delphi 10.3 compatible)
  19850. // attribute constructor name as string
  19851. if not (Ref.Context is TResolvedRefCtxAttrProc) then
  19852. RaiseNotSupported(Expr,aContext,20190223085831,GetObjName(Expr));
  19853. aConstructor:=TResolvedRefCtxAttrProc(Ref.Context).Proc;
  19854. if aConstructor.IsAbstract then
  19855. continue; // silently skip abstract method (Delphi 10.3 compatible)
  19856. ConstrParent:=aConstructor.Parent as TPasClassType;
  19857. if ConstrParent.HelperForType<>nil then
  19858. aResolver.RaiseMsg(20190223220134,nXExpectedButYFound,sXExpectedButYFound,
  19859. ['class method','helper method'],Expr);
  19860. aName:=TransformElToJSName(aConstructor,aContext);
  19861. if AttrArrayLit=nil then
  19862. AttrArrayLit:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,PosEl));
  19863. // add class reference pas.system.TCustomAttribute
  19864. AttrArrayLit.AddElement(CreateReferencePathExpr(AttrClass,aContext));
  19865. // add constructor name 'Create$1'
  19866. AttrArrayLit.AddElement(CreateLiteralString(PosEl,aName));
  19867. // add attribute params as [] if needed
  19868. ParamsArrayLit:=nil;
  19869. Expr:=Attr[i];
  19870. if Expr is TParamsExpr then
  19871. begin
  19872. Params:=TParamsExpr(Expr).Params;
  19873. for j:=0 to length(Params)-1 do
  19874. begin
  19875. ParamExpr:=Params[j];
  19876. Value:=aResolver.Eval(ParamExpr,[]);
  19877. if Value<>nil then
  19878. try
  19879. JSExpr:=ConvertConstValue(Value,aContext,PosEl);
  19880. finally
  19881. ReleaseEvalValue(Value);
  19882. end
  19883. else
  19884. JSExpr:=ConvertExpression(ParamExpr,aContext);
  19885. if ParamsArrayLit=nil then
  19886. begin
  19887. ParamsArrayLit:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,PosEl));
  19888. AttrArrayLit.AddElement(ParamsArrayLit);
  19889. end;
  19890. ParamsArrayLit.AddElement(JSExpr);
  19891. end;
  19892. end;
  19893. end;
  19894. Result:=AttrArrayLit;
  19895. finally
  19896. if Result=nil then
  19897. AttrArrayLit.Free;
  19898. end;
  19899. end;
  19900. function TPasToJSConverter.GetExtRTTIVisibilityParam(El: TPasElement; const Vis: TPasMembersType.
  19901. TRTTIVisibilitySections): word;
  19902. var
  19903. ExtVis: TPasMembersType.TRTTIVisibilitySection;
  19904. begin
  19905. ExtVis:=TPasMembersType.VisibilityToExtRTTI[El.Visibility];
  19906. case ExtVis of
  19907. vcPrivate:
  19908. if El.Visibility=visStrictPrivate then
  19909. Result:=ExtRTTIVisStrictPrivate
  19910. else
  19911. Result:=ExtRTTIVisPrivate;
  19912. vcProtected:
  19913. if El.Visibility=visStrictProtected then
  19914. Result:=ExtRTTIVisStrictProtected
  19915. else
  19916. Result:=ExtRTTIVisProtected;
  19917. vcPublic: Result:=ExtRTTIVisPublic;
  19918. vcPublished:
  19919. if not (vcPublished in Vis) then
  19920. Result:=ExtRTTIVisPublicPublished
  19921. else
  19922. Result:=ExtRTTIVisPublished;
  19923. end;
  19924. end;
  19925. function TPasToJSConverter.CreateRTTIMemberField(ParentEl: TPasMembersType; Members: TFPList;
  19926. Index: integer; AContext: TConvertContext): TJSElement;
  19927. // create $r.addField("varname",typeinfo);
  19928. // create $r.addField("varname",typeinfo,options);
  19929. var
  19930. V: TPasVariable;
  19931. Call: TJSCallExpression;
  19932. OptionsEl: TJSObjectLiteral;
  19933. ExtVis: word;
  19934. procedure AddExtRTTIVisibility;
  19935. begin
  19936. Call.AddArg(CreateLiteralNumber(V,ExtVis));
  19937. end;
  19938. procedure AddOption(const aName: String; JS: TJSElement);
  19939. var
  19940. ObjLit: TJSObjectLiteralElement;
  19941. begin
  19942. if JS=nil then exit;
  19943. if OptionsEl=nil then
  19944. begin
  19945. if ExtVis=ExtRTTIVisDefaultField then
  19946. AddExtRTTIVisibility;
  19947. OptionsEl:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,V));
  19948. Call.AddArg(OptionsEl);
  19949. end;
  19950. ObjLit:=OptionsEl.Elements.AddElement;
  19951. ObjLit.Name:=TJSString(aName);
  19952. ObjLit.Expr:=JS;
  19953. end;
  19954. function VarTypeInfoAlreadyCreated(VarType: TPasType): boolean;
  19955. var
  19956. i: Integer;
  19957. PrevMember: TPasElement;
  19958. begin
  19959. i:=Index-1;
  19960. while (i>=0) do
  19961. begin
  19962. PrevMember:=TPasElement(Members[i]);
  19963. if (PrevMember is TPasVariable) and (TPasVariable(PrevMember).VarType=VarType)
  19964. and IsElementUsed(PrevMember) then
  19965. exit(true);
  19966. dec(i);
  19967. end;
  19968. Result:=false;
  19969. end;
  19970. var
  19971. JSTypeInfo: TJSElement;
  19972. aName: String;
  19973. aResolver: TPas2JSResolver;
  19974. Attr: TPasExprArray;
  19975. VarType: TPasType;
  19976. begin
  19977. Result:=nil;
  19978. aResolver:=AContext.Resolver;
  19979. V:=TPasVariable(Members[Index]);
  19980. VarType:=V.VarType;
  19981. if (VarType<>nil) and (VarType.Name='') then
  19982. begin
  19983. if not VarTypeInfoAlreadyCreated(VarType) then
  19984. CreateRTTIAnonymous(VarType,AContext); // only needed by precompiled files from 2.0.0
  19985. end;
  19986. JSTypeInfo:=CreateTypeInfoRef(VarType,AContext,V);
  19987. OptionsEl:=nil;
  19988. ExtVis:=GetExtRTTIVisibilityParam(V,ParentEl.RTTIVisibility.Fields);
  19989. // Note: create JSTypeInfo first, it may raise an exception
  19990. Call:=CreateCallExpression(V);
  19991. try
  19992. // $r.addField
  19993. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTTILocal),GetBIName(pbifnRTTIAddField)]);
  19994. // param "varname"
  19995. aName:=TransformElToJSName(V,AContext);
  19996. Call.AddArg(CreateLiteralString(V,aName));
  19997. // param typeinfo
  19998. Call.AddArg(JSTypeInfo);
  19999. // extended RTTI
  20000. if ExtVis<>ExtRTTIVisDefaultField then
  20001. AddExtRTTIVisibility;
  20002. // param options if needed as {}
  20003. // option: attributes
  20004. Attr:=aResolver.GetAttributeCalls(Members,Index);
  20005. if length(Attr)>0 then
  20006. AddOption(GetBIName(pbivnRTTIMemberAttributes),
  20007. CreateRTTIAttributes(Attr,V,AContext));
  20008. Result:=Call;
  20009. Call:=nil;
  20010. finally
  20011. Call.Free;
  20012. end;
  20013. end;
  20014. function TPasToJSConverter.CreateRTTIMemberMethod(ParentEl: TPasMembersType; Members: TFPList;
  20015. Index: integer; AContext: TConvertContext): TJSElement;
  20016. // create $r.addMethod("funcname",methodkind,params,resulttype,options)
  20017. var
  20018. Proc: TPasProcedure;
  20019. OptionsEl: TJSObjectLiteral;
  20020. ResultTypeInfo: TJSElement;
  20021. Call: TJSCallExpression;
  20022. Flags: Integer;
  20023. ExtVis: Integer;
  20024. procedure AddExtRTTIVisibility;
  20025. begin
  20026. if ExtVis > -1 then
  20027. Call.AddArg(CreateLiteralNumber(Proc,ExtVis));
  20028. ExtVis := -1;
  20029. end;
  20030. procedure AddOption(const aName: String; JS: TJSElement);
  20031. var
  20032. ObjLit: TJSObjectLiteralElement;
  20033. begin
  20034. if JS=nil then exit;
  20035. if OptionsEl=nil then
  20036. begin
  20037. AddExtRTTIVisibility;
  20038. OptionsEl:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,Proc));
  20039. Call.AddArg(OptionsEl);
  20040. end;
  20041. ObjLit:=OptionsEl.Elements.AddElement;
  20042. ObjLit.Name:=TJSString(aName);
  20043. ObjLit.Expr:=JS;
  20044. end;
  20045. var
  20046. FunName: String;
  20047. C: TClass;
  20048. MethodKind: Integer;
  20049. ResultEl: TPasResultElement;
  20050. ProcScope, OverriddenProcScope: TPasProcedureScope;
  20051. OverriddenClass: TPasClassType;
  20052. aResolver: TPas2JSResolver;
  20053. Attr: TPasExprArray;
  20054. begin
  20055. Result:=nil;
  20056. Proc:=TPasProcedure(Members[Index]);
  20057. aResolver:=AContext.Resolver;
  20058. if Proc.IsOverride then
  20059. begin
  20060. ProcScope:=Proc.CustomData as TPasProcedureScope;
  20061. if ProcScope.OverriddenProc.Visibility=visPublished then
  20062. begin
  20063. // overridden proc is published as well
  20064. OverriddenProcScope:=ProcScope.OverriddenProc.CustomData as TPasProcedureScope;
  20065. OverriddenClass:=OverriddenProcScope.ClassRecScope.Element as TPasClassType;
  20066. if HasTypeInfo(OverriddenClass,AContext) then
  20067. exit; // overridden proc was already published in ancestor
  20068. end;
  20069. end;
  20070. if (Proc.ClassType=TPasClassConstructor)
  20071. or (Proc.ClassType=TPasClassDestructor) then
  20072. exit; // no RTTI for class constructor
  20073. OptionsEl:=nil;
  20074. ResultTypeInfo:=nil;
  20075. try
  20076. // $r.addMethod
  20077. Call:=CreateCallExpression(Proc);
  20078. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTTILocal),GetBIName(pbifnRTTIAddMethod)]);
  20079. // param "funname"
  20080. FunName:=TransformElToJSName(Proc,AContext);
  20081. Call.AddArg(CreateLiteralString(Proc,FunName));
  20082. // param methodkind as number
  20083. C:=Proc.ClassType;
  20084. if C=TPasProcedure then
  20085. MethodKind:=ord(mkProcedure)
  20086. else if C=TPasFunction then
  20087. MethodKind:=ord(mkFunction)
  20088. else if C=TPasConstructor then
  20089. MethodKind:=ord(mkConstructor)
  20090. else if C=TPasDestructor then
  20091. MethodKind:=ord(mkDestructor)
  20092. else if C=TPasClassProcedure then
  20093. MethodKind:=ord(mkClassProcedure)
  20094. else if C=TPasClassFunction then
  20095. MethodKind:=ord(mkClassFunction)
  20096. else
  20097. RaiseNotSupported(Proc,AContext,20170409190242);
  20098. Call.AddArg(CreateLiteralNumber(Proc,MethodKind));
  20099. // param params as []
  20100. Call.AddArg(CreateRTTIArgList(Proc,Proc.ProcType.Args,AContext));
  20101. // add visibility
  20102. ExtVis:=GetExtRTTIVisibilityParam(Proc,ParentEl.RTTIVisibility.Methods);
  20103. if ExtVis<>ExtRTTIVisDefaultMethod then
  20104. AddExtRTTIVisibility;
  20105. // optional params:
  20106. ResultTypeInfo:=nil;
  20107. Flags:=0;
  20108. if Proc.IsStatic then
  20109. inc(Flags,pfStatic);
  20110. if ptmVarargs in Proc.ProcType.Modifiers then
  20111. inc(Flags,pfVarargs);
  20112. if ptmAsync in Proc.ProcType.Modifiers then
  20113. inc(Flags,pfAsync);
  20114. if Proc.IsExternal then
  20115. inc(Flags,pfExternal);
  20116. Attr:=aResolver.GetAttributeCalls(Members,Index);
  20117. // param resulttype as typeinfo reference
  20118. if C.InheritsFrom(TPasFunction) then
  20119. begin
  20120. ResultEl:=TPasFunction(Proc).FuncType.ResultEl;
  20121. ResultTypeInfo:=CreateTypeInfoRef(ResultEl.ResultType,AContext,ResultEl);
  20122. if ResultTypeInfo<>nil then
  20123. begin
  20124. AddExtRTTIVisibility;
  20125. Call.AddArg(ResultTypeInfo);
  20126. end;
  20127. end;
  20128. if (ResultTypeInfo=nil) and ((Flags>0) or (length(Attr)>0)) then
  20129. begin
  20130. AddExtRTTIVisibility;
  20131. Call.AddArg(CreateLiteralNull(Proc));
  20132. end;
  20133. // flags if needed
  20134. if (Flags>0) or (length(Attr)>0) then
  20135. Call.AddArg(CreateLiteralNumber(Proc,Flags));
  20136. // param options if needed as {}
  20137. if length(Attr)>0 then
  20138. AddOption(GetBIName(pbivnRTTIMemberAttributes),
  20139. CreateRTTIAttributes(Attr,Proc,AContext));
  20140. Result:=Call;
  20141. finally
  20142. if Result=nil then
  20143. Call.Free;
  20144. end;
  20145. end;
  20146. function TPasToJSConverter.CreateRTTIMemberProperty(ParentEl: TPasMembersType; Members: TFPList;
  20147. Index: integer; AContext: TConvertContext): TJSElement;
  20148. // create $r.addProperty("propname",flags,proptype,"getter","setter",{options})
  20149. var
  20150. Prop: TPasProperty;
  20151. Call: TJSCallExpression;
  20152. OptionsEl: TJSObjectLiteral;
  20153. ExtVis: word;
  20154. procedure AddExtRTTIVisibility;
  20155. begin
  20156. Call.AddArg(CreateLiteralNumber(Prop,ExtVis));
  20157. end;
  20158. function GetAccessorName(Decl: TPasElement): String;
  20159. begin
  20160. Result:=TransformElToJSName(Decl,AContext);
  20161. end;
  20162. procedure AddOption(const aName: String; JS: TJSElement);
  20163. var
  20164. ObjLit: TJSObjectLiteralElement;
  20165. begin
  20166. if JS=nil then exit;
  20167. if OptionsEl=nil then
  20168. begin
  20169. if ExtVis=ExtRTTIVisDefaultProperty then
  20170. AddExtRTTIVisibility;
  20171. OptionsEl:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,Prop));
  20172. Call.AddArg(OptionsEl);
  20173. end;
  20174. ObjLit:=OptionsEl.Elements.AddElement;
  20175. ObjLit.Name:=TJSString(aName);
  20176. ObjLit.Expr:=JS;
  20177. end;
  20178. var
  20179. PropName: String;
  20180. Flags: Integer;
  20181. GetterPas, SetterPas, DeclEl: TPasElement;
  20182. ResultTypeInfo, DefValue: TJSElement;
  20183. VarType: TPasType;
  20184. StoredExpr, IndexExpr, DefaultExpr: TPasExpr;
  20185. StoredResolved, VarTypeResolved: TPasResolverResult;
  20186. StoredValue, PasValue, IndexValue: TResEvalValue;
  20187. aResolver: TPas2JSResolver;
  20188. Attr: TPasExprArray;
  20189. begin
  20190. Result:=nil;
  20191. Prop:=TPasProperty(Members[Index]);
  20192. aResolver:=AContext.Resolver;
  20193. OptionsEl:=nil;
  20194. try
  20195. // $r.addProperty
  20196. Call:=CreateCallExpression(Prop);
  20197. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTTILocal),GetBIName(pbifnRTTIAddProperty)]);
  20198. // param "propname"
  20199. PropName:=TransformToJSName(Prop,Prop.Name,false,AContext); // use Pascal name
  20200. Call.AddArg(CreateLiteralString(Prop,PropName));
  20201. // add flags
  20202. Flags:=0;
  20203. GetterPas:=aResolver.GetPasPropertyGetter(Prop);
  20204. if GetterPas is TPasProcedure then
  20205. inc(Flags,pfGetFunction);
  20206. SetterPas:=aResolver.GetPasPropertySetter(Prop);
  20207. if SetterPas is TPasProcedure then
  20208. inc(Flags,pfSetProcedure);
  20209. StoredExpr:=aResolver.GetPasPropertyStoredExpr(Prop);
  20210. IndexExpr:=aResolver.GetPasPropertyIndex(Prop);
  20211. if IndexExpr<>nil then
  20212. inc(Flags,pfHasIndex);
  20213. DefaultExpr:=aResolver.GetPasPropertyDefaultExpr(Prop);
  20214. if StoredExpr<>nil then
  20215. begin
  20216. aResolver.ComputeElement(StoredExpr,StoredResolved,[rcNoImplicitProc]);
  20217. if StoredResolved.IdentEl is TPasProcedure then
  20218. // stored <function>
  20219. inc(Flags,pfStoredFunction)
  20220. else
  20221. begin
  20222. if (StoredResolved.BaseType=btBoolean) and (StoredResolved.ExprEl<>nil) then
  20223. begin
  20224. // could be a const boolean
  20225. // -> try evaluating const boolean
  20226. StoredValue:=aResolver.Eval(StoredExpr,[]);
  20227. if StoredValue<>nil then
  20228. try
  20229. // stored <const bool>
  20230. if StoredValue.Kind<>revkBool then
  20231. RaiseInconsistency(20170924082845,Prop);
  20232. StoredExpr:=nil;
  20233. if TResEvalBool(StoredValue).B then
  20234. inc(Flags,pfStoredTrue)
  20235. else
  20236. inc(Flags,pfStoredFalse);
  20237. finally
  20238. ReleaseEvalValue(StoredValue);
  20239. end;
  20240. end;
  20241. if StoredExpr<>nil then
  20242. // stored <field>
  20243. inc(Flags,pfStoredField);
  20244. end;
  20245. end;
  20246. if Prop.IsClass then
  20247. inc(Flags,pfClassProperty);
  20248. Call.AddArg(CreateLiteralNumber(Prop,Flags));
  20249. // add type
  20250. VarType:=aResolver.GetPasPropertyType(Prop);
  20251. aResolver.ComputeElement(VarType,VarTypeResolved,[rcType]);
  20252. ResultTypeInfo:=CreateTypeInfoRef(VarType,AContext,Prop);
  20253. if ResultTypeInfo<>nil then
  20254. Call.AddArg(ResultTypeInfo)
  20255. else
  20256. Call.AddArg(CreateLiteralNull(Prop));
  20257. // add "getter"
  20258. if GetterPas=nil then
  20259. Call.AddArg(CreateLiteralString(Prop,''))
  20260. else
  20261. Call.AddArg(CreateLiteralString(Prop,GetAccessorName(GetterPas)));
  20262. // add "setter"
  20263. if SetterPas=nil then
  20264. Call.AddArg(CreateLiteralString(Prop,''))
  20265. else
  20266. Call.AddArg(CreateLiteralString(Prop,GetAccessorName(SetterPas)));
  20267. // add visibility
  20268. ExtVis:=GetExtRTTIVisibilityParam(Prop,ParentEl.RTTIVisibility.Properties);
  20269. if ExtVis<>ExtRTTIVisDefaultProperty then
  20270. AddExtRTTIVisibility;
  20271. // add option "index"
  20272. IndexExpr:=aResolver.GetPasPropertyIndex(Prop);
  20273. if IndexExpr<>nil then
  20274. begin
  20275. IndexValue:=aResolver.Eval(IndexExpr,[refConst]);
  20276. try
  20277. AddOption(GetBIName(pbivnRTTIPropIndex),
  20278. ConvertConstValue(IndexValue,AContext,Prop));
  20279. finally
  20280. ReleaseEvalValue(IndexValue);
  20281. end;
  20282. end;
  20283. // add option "stored"
  20284. if StoredExpr<>nil then
  20285. begin
  20286. DeclEl:=(StoredExpr.CustomData as TResolvedReference).Declaration;
  20287. AddOption(GetBIName(pbivnRTTIPropStored),
  20288. CreateLiteralString(Prop,GetAccessorName(DeclEl)));
  20289. end;
  20290. // add option "defaultvalue"
  20291. if DefaultExpr<>nil then
  20292. begin
  20293. PasValue:=aResolver.Eval(DefaultExpr,[refConst],false);
  20294. try
  20295. DefValue:=nil;
  20296. if VarTypeResolved.BaseType in [btSet,btArrayOrSet] then
  20297. DefValue:=CreateValInit(VarType,DefaultExpr,DefaultExpr,AContext);
  20298. if DefValue=nil then
  20299. DefValue:=ConvertConstValue(PasValue,AContext,Prop);
  20300. AddOption(GetBIName(pbivnRTTIPropDefault),DefValue);
  20301. finally
  20302. ReleaseEvalValue(PasValue);
  20303. end;
  20304. end;
  20305. // add option "attr"
  20306. Attr:=aResolver.GetAttributeCalls(Members,Index);
  20307. if length(Attr)>0 then
  20308. AddOption(GetBIName(pbivnRTTIMemberAttributes),
  20309. CreateRTTIAttributes(Attr,Prop,AContext));
  20310. Result:=Call;
  20311. finally
  20312. if Result=nil then
  20313. Call.Free;
  20314. end;
  20315. end;
  20316. procedure TPasToJSConverter.CreateRTTIAnonymous(El: TPasType;
  20317. AContext: TConvertContext);
  20318. // if El has any anonymous types, create the RTTI
  20319. var
  20320. C: TClass;
  20321. JS: TJSElement;
  20322. GlobalCtx: TFunctionContext;
  20323. Src: TJSSourceElements;
  20324. begin
  20325. if El.Name<>'' then
  20326. RaiseNotSupported(El,AContext,20170905162324,'inconsistency');
  20327. GlobalCtx:=AContext.GetGlobalFunc;
  20328. if GlobalCtx=nil then
  20329. RaiseNotSupported(El,AContext,20181229130835);
  20330. if not (GlobalCtx.JSElement is TJSSourceElements) then
  20331. begin
  20332. {$IFDEF VerbosePas2JS}
  20333. writeln('TPasToJSConverter.CreateRTTIAnonymous GlobalCtx=',GetObjName(GlobalCtx),' JSElement=',GetObjName(GlobalCtx.JSElement));
  20334. {$ENDIF}
  20335. RaiseNotSupported(El,AContext,20181229130926);
  20336. end;
  20337. Src:=TJSSourceElements(GlobalCtx.JSElement);
  20338. C:=El.ClassType;
  20339. if C=TPasArrayType then
  20340. begin
  20341. JS:=ConvertArrayType(TPasArrayType(El),AContext);
  20342. AddToSourceElements(Src,JS);
  20343. end;
  20344. end;
  20345. function TPasToJSConverter.CreateRTTIAnonymousArray(El: TPasArrayType;
  20346. AContext: TConvertContext): TJSCallExpression;
  20347. var
  20348. Scope: TPas2JSArrayScope;
  20349. SpecializeDelay: Boolean;
  20350. CallName: String;
  20351. Call: TJSCallExpression;
  20352. Obj: TJSObjectLiteral;
  20353. aResolver: TPas2JSResolver;
  20354. ElTypeHi, ElTypeLo: TPasType;
  20355. Prop: TJSObjectLiteralElement;
  20356. ArrLit: TJSArrayLiteral;
  20357. Arr: TPasArrayType;
  20358. Index: Integer;
  20359. RangeEl: TPasExpr;
  20360. RgLen: TMaxPrecInt;
  20361. begin
  20362. Result:=nil;
  20363. aResolver:=AContext.Resolver;
  20364. Scope:=El.CustomData as TPas2JSArrayScope;
  20365. SpecializeDelay:=(Scope<>nil) and (SpecializeNeedsDelay(El,AContext));
  20366. // module.$rtti.$DynArray("name",{...})
  20367. if length(El.Ranges)>0 then
  20368. CallName:=GetBIName(pbifnRTTINewStaticArray)
  20369. else
  20370. CallName:=GetBIName(pbifnRTTINewDynArray);
  20371. Call:=CreateRTTINewType(El,CallName,false,AContext,Obj);
  20372. try
  20373. ElTypeHi:=aResolver.ResolveAliasType(El.ElType,false);
  20374. ElTypeLo:=aResolver.ResolveAliasType(ElTypeHi);
  20375. if length(El.Ranges)>0 then
  20376. begin
  20377. // static array
  20378. // dims: [dimsize1,dimsize2,...]
  20379. Prop:=Obj.Elements.AddElement;
  20380. Prop.Name:=TJSString(GetBIName(pbivnRTTIArray_Dims));
  20381. ArrLit:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,El));
  20382. Prop.Expr:=ArrLit;
  20383. Arr:=El;
  20384. Index:=0;
  20385. repeat
  20386. RangeEl:=Arr.Ranges[Index];
  20387. RgLen:=aResolver.GetRangeLength(RangeEl);
  20388. ArrLit.AddElement(CreateLiteralNumber(RangeEl,RgLen));
  20389. inc(Index);
  20390. if Index=length(Arr.Ranges) then
  20391. begin
  20392. if ElTypeLo.ClassType<>TPasArrayType then
  20393. break;
  20394. Arr:=TPasArrayType(ElTypeLo);
  20395. if length(Arr.Ranges)=0 then
  20396. RaiseNotSupported(Arr,AContext,20170411222315,'static array of anonymous array');
  20397. ElTypeHi:=aResolver.ResolveAliasType(Arr.ElType,false);
  20398. ElTypeLo:=aResolver.ResolveAliasType(ElTypeHi);
  20399. Index:=0;
  20400. end;
  20401. until false;
  20402. end;
  20403. // eltype: ref
  20404. if not SpecializeDelay then
  20405. begin
  20406. Prop:=Obj.Elements.AddElement;
  20407. Prop.Name:=TJSString(GetBIName(pbivnRTTIArray_ElType));
  20408. Prop.Expr:=CreateTypeInfoRef(ElTypeHi,AContext,El);
  20409. end;
  20410. Result:=Call;
  20411. finally
  20412. if Result=nil then
  20413. Call.Free;
  20414. end;
  20415. end;
  20416. function TPasToJSConverter.CreateRTTIMembers(El: TPasMembersType;
  20417. Src: TJSSourceElements; FuncContext: TFunctionContext;
  20418. MembersSrc: TJSSourceElements; MembersFuncContext: TFunctionContext;
  20419. RTTIExpr: TJSElement; NeedLocalVar: boolean): boolean;
  20420. type
  20421. TMemberType = (
  20422. mtClass,
  20423. mtInterface,
  20424. mtRecord
  20425. );
  20426. procedure CreateLocalvar;
  20427. var
  20428. VarSt: TJSVariableStatement;
  20429. begin
  20430. if Result then exit;
  20431. // add "var $r = module.$rtti.$Record..."
  20432. Result:=true;
  20433. VarSt:=CreateVarStatement(GetBIName(pbivnRTTILocal),RTTIExpr,El);
  20434. if Src=MembersSrc then
  20435. AddToSourceElements(Src,VarSt)
  20436. else
  20437. Src.Statements.InsertNode(0).Node:=VarSt;
  20438. end;
  20439. var
  20440. mt: TMemberType;
  20441. i: integer;
  20442. P: TPasElement;
  20443. C: TClass;
  20444. NewEl: TJSElement;
  20445. Members: TFPList;
  20446. aResolver: TPas2JSResolver;
  20447. begin
  20448. Result:=false;
  20449. aResolver:=FuncContext.Resolver;
  20450. if El.ClassType=TPasRecordType then
  20451. mt:=mtRecord
  20452. else if El.ClassType=TPasClassType then
  20453. case TPasClassType(El).ObjKind of
  20454. okInterface: mt:=mtInterface;
  20455. else mt:=mtClass;
  20456. end
  20457. else
  20458. RaiseNotSupported(El,FuncContext,20190223211808,GetObjName(El));
  20459. // add $r to local vars, to avoid name clashes and for nicer debugging
  20460. FuncContext.AddLocalJSVar(GetBIName(pbivnRTTILocal),false);
  20461. if NeedLocalVar then
  20462. CreateLocalvar;
  20463. Members:=El.Members;
  20464. For i:=0 to Members.Count-1 do
  20465. begin
  20466. NewEl:=nil;
  20467. P:=TPasElement(Members[i]);
  20468. C:=P.ClassType;
  20469. //writeln('TPasToJSConverter.CreateRTTIMembers ',GetObjPath(P));
  20470. if C.InheritsFrom(TPasType) and HasTypeInfo(TPasType(P),MembersFuncContext) then
  20471. begin
  20472. // published subtype
  20473. if aResolver.IsAnonymousElType(TPasType(P)) then
  20474. begin
  20475. // published anonymous eltype
  20476. if C.InheritsFrom(TPasArrayType) then
  20477. NewEl:=CreateRTTIAnonymousArray(TPasArrayType(P),MembersFuncContext);
  20478. end;
  20479. end
  20480. else
  20481. begin
  20482. // check visibility
  20483. case mt of
  20484. mtClass:
  20485. if (P.Visibility=visPublished) then
  20486. // published member
  20487. else if El.HasExtRTTI(P) then
  20488. // extended RTTI
  20489. else
  20490. continue;
  20491. mtInterface: ; // all members of an interface are published
  20492. mtRecord:
  20493. // a published record publishes all non private members
  20494. if P.Visibility in [visPrivate,visStrictPrivate] then
  20495. begin
  20496. if not El.HasExtRTTI(P) then
  20497. continue;
  20498. end
  20499. else if P.ClassType=TPasConst then
  20500. continue;
  20501. end;
  20502. if not IsElementUsed(P) then continue;
  20503. if C=TPasVariable then
  20504. NewEl:=CreateRTTIMemberField(El,Members,i,MembersFuncContext)
  20505. else if C.InheritsFrom(TPasProcedure) then
  20506. begin
  20507. if aResolver.GetProcTemplateTypes(TPasProcedure(P))<>nil then
  20508. continue; // parametrized functions cannot be published
  20509. if (P.CustomData as TPas2JSProcedureScope).SpecializedFromItem<>nil then
  20510. continue; // specialized function cannot be published
  20511. NewEl:=CreateRTTIMemberMethod(El,Members,i,MembersFuncContext);
  20512. end
  20513. else if C=TPasProperty then
  20514. NewEl:=CreateRTTIMemberProperty(El,Members,i,MembersFuncContext)
  20515. else if C.InheritsFrom(TPasType)
  20516. or (C=TPasAttributes) then
  20517. else
  20518. DoError(20190105142236,nSymbolCannotBePublished,sSymbolCannotBePublished,[],P);
  20519. end;
  20520. if NewEl=nil then
  20521. continue; // e.g. abstract or external proc
  20522. // add RTTI element
  20523. if not Result then
  20524. CreateLocalvar;
  20525. AddToSourceElements(MembersSrc,NewEl);
  20526. end;
  20527. end;
  20528. procedure TPasToJSConverter.AddIntfDelegations(ClassEl: TPasElement;
  20529. Prop: TPasProperty; FinishedGUIDs: TStringList; ObjLit: TJSObjectLiteral;
  20530. aContext: TFunctionContext);
  20531. var
  20532. i: Integer;
  20533. Expr: TPasExpr;
  20534. ResolvedEl: TPasResolverResult;
  20535. OrigIntfType, OrigPropType, PropType: TPasType;
  20536. IntfType: TPasClassType;
  20537. LitEl: TJSObjectLiteralElement;
  20538. Scope: TPas2JSClassScope;
  20539. FunSt: TJSFunctionDeclarationStatement;
  20540. aResolver: TPas2JSResolver;
  20541. GetterJS: TJSElement;
  20542. RetSt: TJSReturnStatement;
  20543. Call: TJSCallExpression;
  20544. FunName: String;
  20545. FuncContext: TFunctionContext;
  20546. begin
  20547. aResolver:=aContext.Resolver;
  20548. GetterJS:=nil;
  20549. FuncContext:=nil;
  20550. try
  20551. for i:=0 to length(Prop.Implements)-1 do
  20552. begin
  20553. Expr:=Prop.Implements[i];
  20554. aResolver.ComputeElement(Expr,ResolvedEl,[rcNoImplicitProc]);
  20555. if not (ResolvedEl.IdentEl is TPasType) then
  20556. RaiseInconsistency(20180327183019,Expr);
  20557. // mark interface as finished
  20558. OrigIntfType:=TPasType(ResolvedEl.IdentEl);
  20559. IntfType:=aResolver.ResolveAliasType(OrigIntfType) as TPasClassType;
  20560. Scope:=IntfType.CustomData as TPas2JSClassScope;
  20561. if Scope.GUID='' then
  20562. RaiseInconsistency(20180327184912,Expr);
  20563. if FinishedGUIDs.IndexOf(Scope.GUID)>=0 then
  20564. continue;
  20565. FinishedGUIDs.Add(Scope.GUID);
  20566. // "guid" : function(){ return ...}
  20567. LitEl:=ObjLit.Elements.AddElement;
  20568. LitEl.Name:=TJSString(Scope.GUID);
  20569. FunSt:=CreateFunctionSt(ClassEl,true,false);
  20570. LitEl.Expr:=FunSt;
  20571. RetSt:=TJSReturnStatement(CreateElement(TJSReturnStatement,Prop));
  20572. FunSt.AFunction.Body.A:=RetSt;
  20573. // check property type
  20574. OrigPropType:=aResolver.GetPasPropertyType(Prop);
  20575. aResolver.ComputeElement(OrigPropType,ResolvedEl,[rcType]);
  20576. if not (ResolvedEl.IdentEl is TPasType) then
  20577. RaiseInconsistency(20180327190201,Prop);
  20578. PropType:=aResolver.ResolveAliasType(TPasType(ResolvedEl.IdentEl));
  20579. if not (PropType is TPasClassType) then
  20580. RaiseInconsistency(20180327190442,Prop);
  20581. if FuncContext<>nil then
  20582. FreeAndNil(FuncContext);
  20583. FuncContext:=TFunctionContext.Create(Prop,RetSt,AContext);
  20584. FuncContext.ThisVar.Element:=ClassEl;
  20585. FuncContext.ThisVar.Kind:=cvkInstance;
  20586. // check property getter
  20587. if aResolver.GetPasPropertyArgs(Prop).Count>0 then
  20588. RaiseNotSupported(Prop,aContext,20180327191159);
  20589. GetterJS:=CreatePropertyGet(Prop,nil,FuncContext,Prop);
  20590. case TPasClassType(PropType).ObjKind of
  20591. okClass:
  20592. begin
  20593. // delegate to class instance
  20594. case TPasClassType(IntfType).InterfaceType of
  20595. citCom:
  20596. // 'guid': function(){ return rtl.queryIntfT(this.FField,IntfType); }
  20597. // 'guid': function(){ return rtl.queryIntfT(this.GetObj(),IntfType); }
  20598. FunName:=GetBIName(pbifnIntfQueryIntfT);
  20599. citCorba:
  20600. // 'guid': function(){ return rtl.getIntfT(this.FField,IntfType); }
  20601. // 'guid': function(){ return rtl.getIntfT(this.GetObj(),IntfType); }
  20602. FunName:=GetBIName(pbifnIntfGetIntfT);
  20603. else
  20604. RaiseNotSupported(Prop,aContext,20180406085319,InterfaceTypeNames[TPasClassType(IntfType).InterfaceType]){%H-};
  20605. end;
  20606. Call:=CreateCallExpression(Prop);
  20607. RetSt.Expr:=Call;
  20608. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),FunName]);
  20609. Call.AddArg(GetterJS);
  20610. GetterJS:=nil;
  20611. Call.AddArg(CreateReferencePathExpr(IntfType,FuncContext));
  20612. end;
  20613. okInterface:
  20614. begin
  20615. // delegate to interface
  20616. case TPasClassType(IntfType).InterfaceType of
  20617. citCom:
  20618. begin
  20619. if IsInterfaceRef(GetterJS) then
  20620. // 'guid': function(){ return this.GetIntf(); },
  20621. GetterJS:=RemoveIntfRef(TJSCallExpression(GetterJS),FuncContext)
  20622. else
  20623. begin
  20624. // 'guid': function(){ return rtl._AddRef(this.FField); },
  20625. GetterJS:=CreateAddRef(GetterJS,Prop);
  20626. end;
  20627. end;
  20628. citCorba:
  20629. begin
  20630. // 'guid': function(){ return this.FField; },
  20631. // 'guid': function(){ return this.GetIntf(); },
  20632. end;
  20633. else
  20634. RaiseNotSupported(Prop,FuncContext,20180406085053,InterfaceTypeNames[TPasClassType(IntfType).InterfaceType]){%H-};
  20635. end;
  20636. RetSt.Expr:=GetterJS;
  20637. GetterJS:=nil;
  20638. end;
  20639. else
  20640. RaiseNotSupported(Prop,FuncContext,20180327190538,ObjKindNames[TPasClassType(PropType).ObjKind]);
  20641. end;
  20642. end;
  20643. finally
  20644. FuncContext.Free;
  20645. GetterJS.Free;
  20646. end;
  20647. end;
  20648. function TPasToJSConverter.CreateGUIDObjLit(aTGUIDRecord: TPasRecordType;
  20649. const GUID: TGUID; PosEl: TPasElement; AContext: TConvertContext
  20650. ): TJSObjectLiteral;
  20651. var
  20652. i: integer;
  20653. Members: TFPList;
  20654. function GetMember(const aName: string): TPasElement;
  20655. begin
  20656. while i<Members.Count do
  20657. begin
  20658. Result:=TPasElement(Members[i]);
  20659. inc(i);
  20660. if (Result is TPasVariable) then
  20661. if SameText(Result.Name,aName) then
  20662. exit
  20663. else
  20664. RaiseInconsistency(20180415094721,PosEl);
  20665. end;
  20666. RaiseInconsistency(20210306223031,PosEl);
  20667. end;
  20668. var
  20669. PropEl: TJSObjectLiteralElement;
  20670. MemberEl: TPasElement;
  20671. ArrLit: TJSArrayLiteral;
  20672. begin
  20673. Members:=aTGUIDRecord.Members;
  20674. Result:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,PosEl));
  20675. i:=0;
  20676. // D1: 0x12345678
  20677. MemberEl:=GetMember('D1');
  20678. PropEl:=Result.Elements.AddElement;
  20679. PropEl.Name:=TJSString(TransformElToJSName(MemberEl,AContext));
  20680. PropEl.Expr:=CreateLiteralHexNumber(PosEl,GUID.D1,8);
  20681. // D2: 0x1234
  20682. MemberEl:=GetMember('D2');
  20683. PropEl:=Result.Elements.AddElement;
  20684. PropEl.Name:=TJSString(TransformElToJSName(MemberEl,AContext));
  20685. PropEl.Expr:=CreateLiteralHexNumber(PosEl,GUID.D2,4);
  20686. // D3: 0x1234
  20687. MemberEl:=GetMember('D3');
  20688. PropEl:=Result.Elements.AddElement;
  20689. PropEl.Name:=TJSString(TransformElToJSName(MemberEl,AContext));
  20690. PropEl.Expr:=CreateLiteralHexNumber(PosEl,GUID.D3,4);
  20691. // D4: [0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12]
  20692. MemberEl:=GetMember('D4');
  20693. PropEl:=Result.Elements.AddElement;
  20694. PropEl.Name:=TJSString(TransformElToJSName(MemberEl,AContext));
  20695. ArrLit:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,PosEl));
  20696. PropEl.Expr:=ArrLit;
  20697. for i:=0 to 7 do
  20698. ArrLit.AddElement(CreateLiteralHexNumber(PosEl,GUID.D4[i],2));
  20699. end;
  20700. function TPasToJSConverter.CreateAssignManagedVar(
  20701. const LeftResolved: TPasResolverResult; var LHS, RHS: TJSElement;
  20702. AContext: TConvertContext; PosEl: TPasElement): TJSElement;
  20703. procedure AddProcRelease(Proc: TPasProcedure; SubEl: TPasElement);
  20704. var
  20705. FuncContext: TFunctionContext;
  20706. begin
  20707. FuncContext:=AContext.GetFuncContextOfPasElement(Proc);
  20708. if FuncContext<>nil then
  20709. begin
  20710. if SubEl is TPasResultElement then
  20711. FuncContext.ResultNeedsIntfRelease:=true
  20712. else
  20713. FuncContext.Add_InterfaceRelease(SubEl);
  20714. end
  20715. else
  20716. begin
  20717. {$IFDEF VerbosePas2JS}
  20718. AContext.WriteStack;
  20719. {$ENDIF}
  20720. RaiseInconsistency(20180401164150,PosEl);
  20721. end;
  20722. end;
  20723. var
  20724. Call: TJSCallExpression;
  20725. AssignSt: TJSSimpleAssignStatement;
  20726. Prim: TJSPrimaryExpressionIdent;
  20727. IdentEl: TPasElement;
  20728. Proc: TPasProcedure;
  20729. ok, SkipAddRef: Boolean;
  20730. begin
  20731. {$IFDEF VerbosePas2JS}
  20732. writeln('TPasToJSConverter.CreateAssignManagedVar LeftResolved=',GetResolverResultDbg(LeftResolved),' LHS=',LHS.ClassName,' RHS=',RHS.ClassName);
  20733. {$ENDIF}
  20734. Result:=nil;
  20735. ok:=false;
  20736. try
  20737. SkipAddRef:=false;
  20738. if IsInterfaceRef(RHS) then
  20739. begin
  20740. // simplify RHS: $ir.ref(id,expr) -> expr
  20741. RHS:=RemoveIntfRef(TJSCallExpression(RHS),AContext);
  20742. SkipAddRef:=true;
  20743. end;
  20744. Call:=CreateCallExpression(PosEl);
  20745. Result:=Call;
  20746. if LHS is TJSDotMemberExpression then
  20747. begin
  20748. // path.name = RHS -> rtl.setIntfP(path,"name",RHS)
  20749. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnIntfSetIntfP)]);
  20750. Call.AddArg(TJSDotMemberExpression(LHS).MExpr);
  20751. TJSDotMemberExpression(LHS).MExpr:=nil;
  20752. Call.AddArg(CreateLiteralJSString(PosEl,TJSDotMemberExpression(LHS).Name));
  20753. FreeAndNil(LHS);
  20754. Call.AddArg(RHS);
  20755. RHS:=nil;
  20756. if SkipAddRef then
  20757. Call.AddArg(CreateLiteralBoolean(PosEl,true));
  20758. end
  20759. else if LHS is TJSBracketMemberExpression then
  20760. begin
  20761. // path[index] = RHS -> rtl.setIntfP(path,index,RHS)
  20762. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnIntfSetIntfP)]);
  20763. Call.AddArg(TJSBracketMemberExpression(LHS).MExpr);
  20764. TJSBracketMemberExpression(LHS).MExpr:=nil;
  20765. Call.AddArg(TJSBracketMemberExpression(LHS).Name);
  20766. TJSBracketMemberExpression(LHS).Name:=nil;
  20767. FreeAndNil(LHS);
  20768. Call.AddArg(RHS);
  20769. RHS:=nil;
  20770. if SkipAddRef then
  20771. Call.AddArg(CreateLiteralBoolean(PosEl,true));
  20772. end
  20773. else if LHS is TJSPrimaryExpressionIdent then
  20774. begin
  20775. // name = RHS -> name = rtl.setIntfL(name,RHS)
  20776. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnIntfSetIntfL)]);
  20777. // add parameter name
  20778. Prim:=TJSPrimaryExpressionIdent(CreateElement(TJSPrimaryExpressionIdent,PosEl));
  20779. Prim.Name:=TJSPrimaryExpressionIdent(LHS).Name;
  20780. Call.AddArg(Prim);
  20781. // add parameter RHS
  20782. Call.AddArg(RHS);
  20783. RHS:=nil;
  20784. if SkipAddRef then
  20785. Call.AddArg(CreateLiteralBoolean(PosEl,true));
  20786. // name = ...
  20787. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,PosEl));
  20788. AssignSt.LHS:=LHS;
  20789. LHS:=nil;
  20790. AssignSt.Expr:=Call;
  20791. Result:=AssignSt;
  20792. end
  20793. else
  20794. RaiseNotSupported(PosEl,AContext,20180401105030,GetObjName(LHS));
  20795. IdentEl:=LeftResolved.IdentEl;
  20796. if (IdentEl<>nil) then
  20797. begin
  20798. if (IdentEl.ClassType=TPasVariable) and (IdentEl.Parent is TProcedureBody) then
  20799. begin
  20800. // local variable
  20801. Proc:=TPasProcedure(IdentEl.Parent.Parent);
  20802. AddProcRelease(Proc,IdentEl);
  20803. end
  20804. else if (IdentEl.ClassType=TPasArgument)
  20805. and (IdentEl.Parent is TPasProcedureType)
  20806. and (IdentEl.Parent.Parent is TPasProcedure) then
  20807. begin
  20808. // argument
  20809. Proc:=TPasProcedure(IdentEl.Parent.Parent);
  20810. AddProcRelease(Proc,IdentEl);
  20811. end
  20812. else if IdentEl.ClassType=TPasResultElement then
  20813. begin
  20814. // Result variable
  20815. Proc:=TPasFunction(TPasFunctionType(IdentEl.Parent).Parent);
  20816. AddProcRelease(Proc,IdentEl);
  20817. end;
  20818. end;
  20819. ok:=true;
  20820. finally
  20821. if not ok then Result.Free;
  20822. end;
  20823. end;
  20824. function TPasToJSConverter.IsInterfaceRef(Expr: TJSElement): boolean;
  20825. var
  20826. Call: TJSCallExpression;
  20827. DotExpr: TJSDotMemberExpression;
  20828. begin
  20829. Result:=false;
  20830. if Expr=nil then exit;
  20831. if Expr.ClassType<>TJSCallExpression then exit;
  20832. Call:=TJSCallExpression(Expr);
  20833. if Call.Expr.ClassType<>TJSDotMemberExpression then exit;
  20834. DotExpr:=TJSDotMemberExpression(Call.Expr);
  20835. Result:=(DotExpr.Name=TJSString(GetBIName(pbifnIntfExprRefsAdd)))
  20836. and (DotExpr.MExpr is TJSPrimaryExpressionIdent)
  20837. and (TJSPrimaryExpressionIdent(DotExpr.MExpr).Name=TJSString(GetBIName(pbivnIntfExprRefs)));
  20838. end;
  20839. function TPasToJSConverter.CreateAddRef(Expr: TJSElement; PosEl: TPasElement): TJSCallExpression;
  20840. begin
  20841. Result:=CreateCallExpression(PosEl);
  20842. Result.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnIntf_AddRef)]);
  20843. Result.AddArg(Expr);
  20844. end;
  20845. function TPasToJSConverter.CreateIntfRef(Expr: TJSElement;
  20846. aContext: TConvertContext; PosEl: TPasElement): TJSCallExpression;
  20847. // enclose Expr
  20848. // -> $ir.ref(id,Expr)
  20849. var
  20850. FuncContext: TFunctionContext;
  20851. Call: TJSCallExpression;
  20852. begin
  20853. FuncContext:=aContext.GetFunctionContext;
  20854. if FuncContext=nil then
  20855. RaiseNotSupported(PosEl,aContext,20180402183859);
  20856. if IsInterfaceRef(Expr) then
  20857. exit(TJSCallExpression(Expr));
  20858. inc(FuncContext.IntfExprReleaseCount);
  20859. Call:=CreateCallExpression(PosEl);
  20860. Call.Expr:=CreatePrimitiveDotExpr(GetBIName(pbivnIntfExprRefs)+'.'+GetBIName(pbifnIntfExprRefsAdd),PosEl);
  20861. Call.AddArg(CreateLiteralNumber(PosEl,FuncContext.IntfExprReleaseCount));
  20862. Call.AddArg(Expr);
  20863. Result:=Call;
  20864. end;
  20865. function TPasToJSConverter.RemoveIntfRef(Call: TJSCallExpression;
  20866. AContext: TConvertContext): TJSElement;
  20867. var
  20868. Lit: TJSArrayLiteralElement;
  20869. LitValue: TJSValue;
  20870. FuncContext: TFunctionContext;
  20871. begin
  20872. Lit:=Call.Args.Elements[1];
  20873. Result:=Lit.Expr;
  20874. Lit.Expr:=nil;
  20875. // check if $ir is still needed
  20876. Lit:=Call.Args.Elements[0];
  20877. if (Lit.Expr is TJSLiteral) then
  20878. begin
  20879. LitValue:=TJSLiteral(Lit.Expr).Value;
  20880. FuncContext:=AContext.GetFunctionContext;
  20881. if (FuncContext<>nil)
  20882. and (FuncContext.IntfExprReleaseCount=LitValue.AsNumber) then
  20883. dec(FuncContext.IntfExprReleaseCount);
  20884. end;
  20885. Call.Free;
  20886. end;
  20887. procedure TPasToJSConverter.CreateFunctionTryFinally(
  20888. FuncContext: TFunctionContext);
  20889. begin
  20890. if FuncContext.TrySt<>nil then exit;
  20891. FuncContext.TrySt:=TJSTryFinallyStatement(CreateElement(TJSTryFinallyStatement,FuncContext.PasElement));
  20892. FuncContext.TrySt.Block:=FuncContext.BodySt;
  20893. FuncContext.BodySt:=FuncContext.TrySt;
  20894. end;
  20895. procedure TPasToJSConverter.AddFunctionFinallySt(NewEl: TJSElement;
  20896. PosEl: TPasElement; FuncContext: TFunctionContext);
  20897. begin
  20898. CreateFunctionTryFinally(FuncContext);
  20899. AddToStatementList(FuncContext.FinallyFirst,FuncContext.FinallyLast,NewEl,PosEl);
  20900. FuncContext.TrySt.BFinally:=FuncContext.FinallyFirst;
  20901. end;
  20902. procedure TPasToJSConverter.AddFunctionFinallyRelease(SubEl: TPasElement;
  20903. FuncContext: TFunctionContext);
  20904. // add to finally: rtl._Release(IntfVar)
  20905. var
  20906. Call: TJSCallExpression;
  20907. FuncName: String;
  20908. begin
  20909. Call:=CreateCallExpression(SubEl);
  20910. AddFunctionFinallySt(Call,SubEl,FuncContext);
  20911. FuncName:=GetBIName(pbifnIntf_Release);
  20912. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),FuncName]);
  20913. Call.AddArg(CreateReferencePathExpr(SubEl,FuncContext));
  20914. end;
  20915. procedure TPasToJSConverter.AddInFrontOfFunctionTry(NewEl: TJSElement;
  20916. PosEl: TPasElement; FuncContext: TFunctionContext);
  20917. var
  20918. St, OldSt: TJSStatementList;
  20919. begin
  20920. CreateFunctionTryFinally(FuncContext);
  20921. if FuncContext.BodySt=FuncContext.TrySt then
  20922. begin
  20923. St:=TJSStatementList(CreateElement(TJSStatementList,PosEl));
  20924. St.A:=NewEl;
  20925. St.B:=FuncContext.TrySt;
  20926. FuncContext.BodySt:=St;
  20927. end
  20928. else if FuncContext.BodySt is TJSStatementList then
  20929. begin
  20930. OldSt:=TJSStatementList(FuncContext.BodySt);
  20931. while OldSt.B is TJSStatementList do
  20932. OldSt:=TJSStatementList(OldSt.B);
  20933. St:=TJSStatementList(CreateElement(TJSStatementList,PosEl));
  20934. St.A:=NewEl;
  20935. St.B:=OldSt.B;
  20936. OldSt.B:=St;
  20937. end
  20938. else
  20939. RaiseInconsistency(20180402103144,PosEl);
  20940. end;
  20941. procedure TPasToJSConverter.AddInterfaceReleases(FuncContext: TFunctionContext;
  20942. PosEl: TPasElement);
  20943. // add the interface release object $ir
  20944. var
  20945. i: Integer;
  20946. P: TPasElement;
  20947. Call: TJSCallExpression;
  20948. VarSt: TJSVariableStatement;
  20949. begin
  20950. if FuncContext.IntfExprReleaseCount>0 then
  20951. begin
  20952. // add in front of try..finally "var $ir = rtl.createIntfRefs();"
  20953. Call:=CreateCallExpression(PosEl);
  20954. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnIntfExprRefsCreate)]);
  20955. VarSt:=CreateVarStatement(GetBIName(pbivnIntfExprRefs),Call,PosEl);
  20956. AddInFrontOfFunctionTry(VarSt,PosEl,FuncContext);
  20957. // add in finally: "$ir.free();"
  20958. Call:=CreateCallExpression(PosEl);
  20959. Call.Expr:=CreateMemberExpression([GetBIName(pbivnIntfExprRefs),GetBIName(pbifnIntfExprRefsFree)]);
  20960. AddFunctionFinallySt(Call,PosEl,FuncContext);
  20961. end;
  20962. if FuncContext.IntfElReleases<>nil then
  20963. for i:=0 to FuncContext.IntfElReleases.Count-1 do
  20964. begin
  20965. // enclose body in try..finally and add release statement
  20966. P:=TPasElement(FuncContext.IntfElReleases[i]);
  20967. if P.ClassType=TPasVariable then
  20968. begin
  20969. AddFunctionFinallyRelease(P,FuncContext);
  20970. end
  20971. else if (P.ClassType=TPasArgument) and (TPasArgument(P).Access=argDefault) then
  20972. begin
  20973. // add in front of try..finally "rtl._AddRef(arg);"
  20974. Call:=CreateAddRef(CreateReferencePathExpr(P,FuncContext),P);
  20975. AddInFrontOfFunctionTry(Call,PosEl,FuncContext);
  20976. // add in finally: "rtl._Release(arg);"
  20977. AddFunctionFinallyRelease(P,FuncContext);
  20978. end
  20979. else
  20980. RaiseInconsistency(20180401165742,P);
  20981. end;
  20982. end;
  20983. procedure TPasToJSConverter.AddInterfaceRelease_Result(FuncContext: TFunctionContext;
  20984. const ResultVarName: string; PosEl: TPasElement);
  20985. // add interface release for Result if not $ok
  20986. var
  20987. VarSt: TJSVariableStatement;
  20988. AssignSt: TJSSimpleAssignStatement;
  20989. IfSt: TJSIfStatement;
  20990. Call: TJSCallExpression;
  20991. begin
  20992. // add in front of try "var $ok=false;"
  20993. VarSt:=CreateVarStatement(GetBIName(pbivnProcOk),CreateLiteralBoolean(PosEl,false),PosEl);
  20994. AddInFrontOfFunctionTry(VarSt,PosEl,FuncContext);
  20995. // add in front of finally "$ok=true;"
  20996. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,PosEl));
  20997. AddToStatementList(FuncContext.TrySt.Block as TJSStatementList,AssignSt,PosEl);
  20998. AssignSt.LHS:=CreatePrimitiveDotExpr(GetBIName(pbivnProcOk),PosEl);
  20999. AssignSt.Expr:=CreateLiteralBoolean(PosEl,true);
  21000. // add finally: "if(!$ok) rtl._Release(Result);"
  21001. IfSt:=TJSIfStatement(CreateElement(TJSIfStatement,PosEl));
  21002. AddFunctionFinallySt(IfSt,PosEl,FuncContext);
  21003. // !$ok
  21004. IfSt.Cond:=CreateUnaryNot(
  21005. CreatePrimitiveDotExpr(GetBIName(pbivnProcOk),PosEl),PosEl);
  21006. // rtl._Release(Result)
  21007. Call:=CreateCallExpression(PosEl);
  21008. IfSt.BTrue:=Call;
  21009. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnIntf_Release)]);
  21010. Call.AddArg(CreatePrimitiveDotExpr(ResultVarName,PosEl));
  21011. end;
  21012. procedure TPasToJSConverter.AddClassSupportedInterfaces(El: TPasClassType;
  21013. Src: TJSSourceElements; FuncContext: TFunctionContext);
  21014. function IsClassInterfaceNeeded(aMember: TPasElement): boolean;
  21015. var
  21016. SpecData: TPasSpecializeTypeData;
  21017. begin
  21018. if aMember is TPasSpecializeType then
  21019. begin
  21020. SpecData:=aMember.CustomData as TPasSpecializeTypeData;
  21021. aMember:=SpecData.SpecializedType;
  21022. end;
  21023. if IsElementUsed(aMember) then exit(true);
  21024. Result:=false;
  21025. end;
  21026. procedure AddMapProcs(Map: TPasClassIntfMap; Call: TJSCallExpression;
  21027. var ObjLit: TJSObjectLiteral; FuncContext: TConvertContext);
  21028. var
  21029. i: Integer;
  21030. MapItem: TObject;
  21031. Proc, IntfProc: TPasProcedure;
  21032. ProcName, IntfProcName: String;
  21033. Intf: TPasClassType;
  21034. Lit: TJSObjectLiteralElement;
  21035. begin
  21036. Intf:=Map.Intf;
  21037. if Map.Procs<>nil then
  21038. for i:=0 to Map.Procs.Count-1 do
  21039. begin
  21040. MapItem:=TObject(Map.Procs[i]);
  21041. if not (MapItem is TPasProcedure) then continue;
  21042. Proc:=TPasProcedure(MapItem);
  21043. ProcName:=TransformElToJSName(Proc,FuncContext);
  21044. IntfProc:=TObject(Intf.Members[i]) as TPasProcedure;
  21045. IntfProcName:=TransformElToJSName(IntfProc,FuncContext);
  21046. if IntfProcName=ProcName then continue;
  21047. if ObjLit=nil then
  21048. begin
  21049. ObjLit:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,El));
  21050. Call.AddArg(ObjLit);
  21051. end;
  21052. Lit:=ObjLit.Elements.AddElement;
  21053. Lit.Name:=TJSString(IntfProcName);
  21054. Lit.Expr:=CreateLiteralString(El,ProcName);
  21055. end;
  21056. if Map.AncestorMap<>nil then
  21057. AddMapProcs(Map.AncestorMap,Call,ObjLit,FuncContext);
  21058. end;
  21059. var
  21060. Call: TJSCallExpression;
  21061. ObjLit: TJSObjectLiteral;
  21062. i: Integer;
  21063. Scope, CurScope: TPas2JSClassScope;
  21064. o: TObject;
  21065. IntfMaps: TJSSimpleAssignStatement;
  21066. MapsObj: TJSObjectLiteral;
  21067. Map: TPasClassIntfMap;
  21068. FinishedGUIDs: TStringList;
  21069. Intf: TPasType;
  21070. CurEl: TPasClassType;
  21071. NeedIntfMap, HasInterfaces: Boolean;
  21072. begin
  21073. HasInterfaces:=false;
  21074. NeedIntfMap:=false;
  21075. Scope:=TPas2JSClassScope(El.CustomData);
  21076. repeat
  21077. if Scope.Interfaces<>nil then
  21078. begin
  21079. for i:=0 to Scope.Interfaces.Count-1 do
  21080. begin
  21081. CurEl:=TPasClassType(Scope.Element);
  21082. if not IsClassInterfaceNeeded(TPasElement(CurEl.Interfaces[i])) then continue;
  21083. HasInterfaces:=true;
  21084. o:=TObject(Scope.Interfaces[i]);
  21085. if o is TPasProperty then
  21086. // interface delegation -> needs $intfmaps={}
  21087. NeedIntfMap:=true;
  21088. end;
  21089. end;
  21090. Scope:=TPas2JSClassScope(Scope.AncestorScope);
  21091. until Scope=nil;
  21092. if not HasInterfaces then exit;
  21093. IntfMaps:=nil;
  21094. FinishedGUIDs:=TStringList.Create;
  21095. try
  21096. ObjLit:=nil;
  21097. Scope:=TPas2JSClassScope(El.CustomData);
  21098. repeat
  21099. if Scope.Interfaces<>nil then
  21100. begin
  21101. for i:=0 to Scope.Interfaces.Count-1 do
  21102. begin
  21103. CurEl:=TPasClassType(Scope.Element);
  21104. if not IsClassInterfaceNeeded(TPasElement(CurEl.Interfaces[i])) then continue;
  21105. if NeedIntfMap then
  21106. begin
  21107. // add "this.$intfmaps = {};"
  21108. IntfMaps:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  21109. AddToSourceElements(Src,IntfMaps);
  21110. IntfMaps.LHS:=CreatePrimitiveDotExpr('this.'+GetBIName(pbivnIntfMaps),El);
  21111. MapsObj:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,El));
  21112. IntfMaps.Expr:=MapsObj;
  21113. NeedIntfMap:=false;
  21114. end;
  21115. o:=TObject(Scope.Interfaces[i]);
  21116. if o is TPasClassIntfMap then
  21117. begin
  21118. // add rtl.addIntf(this,intftype,{ intfprocname: "procname", ...});
  21119. Map:=TPasClassIntfMap(o);
  21120. Intf:=Map.Intf;
  21121. CurScope:=TPas2JSClassScope(Intf.CustomData);
  21122. if FinishedGUIDs.IndexOf(CurScope.GUID)>=0 then continue;
  21123. FinishedGUIDs.Add(CurScope.GUID);
  21124. Call:=CreateCallExpression(El);
  21125. AddToSourceElements(Src,Call);
  21126. Call.Expr:=CreatePrimitiveDotExpr(GetBIName(pbivnRTL)+'.'+GetBIName(pbifnIntfAddMap),El);
  21127. Call.AddArg(CreatePrimitiveDotExpr('this',El));
  21128. Call.AddArg(CreateReferencePathExpr(Map.Intf,FuncContext));
  21129. AddMapProcs(Map,Call,ObjLit,FuncContext);
  21130. end
  21131. else if o is TPasProperty then
  21132. AddIntfDelegations(El,TPasProperty(o),FinishedGUIDs,MapsObj,FuncContext)
  21133. else
  21134. RaiseNotSupported(El,FuncContext,20180326234026,GetObjName(o));
  21135. end;
  21136. end;
  21137. Scope:=TPas2JSClassScope(Scope.AncestorScope);
  21138. until Scope=nil;
  21139. finally
  21140. FinishedGUIDs.Free;
  21141. end;
  21142. end;
  21143. function TPasToJSConverter.CreateCallHelperMethod(Proc: TPasProcedure;
  21144. Expr: TPasExpr; AContext: TConvertContext; Implicit: boolean
  21145. ): TJSCallExpression;
  21146. var
  21147. Left: TPasExpr;
  21148. WithExprScope: TPas2JSWithExprScope;
  21149. SelfScope: TPasProcedureScope;
  21150. function ConvertLeftExpr: TJSElement;
  21151. var
  21152. OldAccess: TCtxAccess;
  21153. Path: String;
  21154. begin
  21155. if WithExprScope<>nil then
  21156. Result:=CreatePrimitiveDotExpr(WithExprScope.WithVarName,Expr)
  21157. else if SelfScope<>nil then
  21158. begin
  21159. Path:=GetLocalName(SelfScope.SelfArg,cvkAll,AContext);
  21160. Result:=CreatePrimitiveDotExpr(Path,Expr);
  21161. end
  21162. else if Left=nil then
  21163. begin
  21164. RaiseNotSupported(Expr,AContext,20190205172904);
  21165. Result:=nil;
  21166. end
  21167. else
  21168. begin
  21169. OldAccess:=AContext.Access;
  21170. AContext.Access:=caRead;
  21171. Result:=ConvertExpression(Left,AContext);
  21172. AContext.Access:=OldAccess;
  21173. end;
  21174. end;
  21175. function CreateRefObj(PosEl: TPasElement; PathExpr: TJSElement;
  21176. GetExpr, SetExpr: TJSElement; SetterArgName: string;
  21177. const LeftResolved: TPasResolverResult): TJSObjectLiteral;
  21178. function CreateRgCheck(aType: TPasType): TJSElement;
  21179. begin
  21180. Result:=CreateRangeCheckCall_TypeRange(aType,
  21181. CreatePrimitiveDotExpr(SetterArgName,PosEl),AContext,PosEl);
  21182. end;
  21183. var
  21184. Obj: TJSObjectLiteral;
  21185. ObjLit: TJSObjectLiteralElement;
  21186. FuncSt: TJSFunctionDeclarationStatement;
  21187. RetSt: TJSReturnStatement;
  21188. TypeEl: TPasType;
  21189. RgCheck: TJSElement;
  21190. List: TJSStatementList;
  21191. begin
  21192. RgCheck:=nil;
  21193. if (SetExpr is TJSSimpleAssignStatement)
  21194. and (SetterArgName<>'')
  21195. and (bsRangeChecks in AContext.ScannerBoolSwitches) then
  21196. begin
  21197. TypeEl:=LeftResolved.LoTypeEl;
  21198. if TypeEl<>nil then
  21199. begin
  21200. if LeftResolved.BaseType in btAllJSRangeCheckTypes then
  21201. RgCheck:=CreateRgCheck(TypeEl)
  21202. else if LeftResolved.BaseType=btContext then
  21203. begin
  21204. if TypeEl.ClassType=TPasEnumType then
  21205. RgCheck:=CreateRgCheck(TypeEl);
  21206. end
  21207. else if LeftResolved.BaseType=btRange then
  21208. begin
  21209. if LeftResolved.SubType in btAllJSRangeCheckTypes then
  21210. RgCheck:=CreateRgCheck(TypeEl)
  21211. else if LeftResolved.SubType=btContext then
  21212. RgCheck:=CreateRgCheck(TypeEl)
  21213. else
  21214. begin
  21215. {$IFDEF VerbosePas2JS}
  21216. writeln('TPasToJSConverter.CreateCallHelperMethod ',GetResolverResultDbg(LeftResolved));
  21217. RaiseNotSupported(PosEl,AContext,20190220011900);
  21218. {$ENDIF}
  21219. end;
  21220. end;
  21221. end;
  21222. end;
  21223. Obj:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,PosEl));
  21224. Result:=Obj;
  21225. if PathExpr<>nil then
  21226. begin
  21227. // add "p:path"
  21228. ObjLit:=Obj.Elements.AddElement;
  21229. ObjLit.Name:=TJSString(TempRefGetPathName);
  21230. ObjLit.Expr:=PathExpr;
  21231. end;
  21232. // add "get: function(){return Left}"
  21233. ObjLit:=Obj.Elements.AddElement;
  21234. ObjLit.Name:=TempRefObjGetterName;
  21235. FuncSt:=CreateFunctionSt(PosEl);
  21236. ObjLit.Expr:=FuncSt;
  21237. RetSt:=TJSReturnStatement(CreateElement(TJSReturnStatement,PosEl));
  21238. FuncSt.AFunction.Body.A:=RetSt;
  21239. RetSt.Expr:=GetExpr;
  21240. // add "set: function(v){Left=v}"
  21241. ObjLit:=Obj.Elements.AddElement;
  21242. ObjLit.Name:=TempRefObjSetterName;
  21243. FuncSt:=CreateFunctionSt(PosEl);
  21244. ObjLit.Expr:=FuncSt;
  21245. if SetterArgName<>'' then
  21246. FuncSt.AFunction.TypedParams.AddParam(TJSString(SetterArgName));
  21247. if RgCheck<>nil then
  21248. begin
  21249. List:=TJSStatementList(CreateElement(TJSStatementList,PosEl));
  21250. List.A:=RgCheck;
  21251. List.B:=SetExpr;
  21252. SetExpr:=List;
  21253. end;
  21254. FuncSt.AFunction.Body.A:=SetExpr;
  21255. end;
  21256. function ConvertImplicitLeftIdentifier(PosEl: TPasElement;
  21257. const LeftResolved: TPasResolverResult): TJSElement;
  21258. var
  21259. GetExpr, SetExpr, RHS: TJSElement;
  21260. SetterArgName: string;
  21261. AssignSt: TJSSimpleAssignStatement;
  21262. Arg: TPasArgument;
  21263. TypeEl: TPasType;
  21264. aManaged: Boolean;
  21265. begin
  21266. // implicit Left (e.g. "with Left do proc", or "Proc")
  21267. if LeftResolved.IdentEl is TPasArgument then
  21268. begin
  21269. Arg:=TPasArgument(LeftResolved.IdentEl);
  21270. if Arg.Access in [argVar,argOut] then
  21271. begin
  21272. // implicit Left is already a reference
  21273. Result:=CreatePrimitiveDotExpr(TransformArgName(Arg,AContext),PosEl);
  21274. exit;
  21275. end;
  21276. end;
  21277. // -> {get: function(){return GetExpr},set:function(v){SetExpr}}
  21278. // GetExpr "ImplicitLeft"
  21279. GetExpr:=ConvertLeftExpr;
  21280. if rrfWritable in LeftResolved.Flags then
  21281. begin
  21282. // SetExpr "ImplicitLeft = v"
  21283. TypeEl:=LeftResolved.LoTypeEl;
  21284. aManaged:=AContext.Resolver.IsManagedJSType(TypeEl);
  21285. SetExpr:=ConvertLeftExpr;
  21286. SetterArgName:=TempRefObjSetterArgName;
  21287. FindAvailableLocalName(SetterArgName,SetExpr);
  21288. RHS:=CreatePrimitiveDotExpr(SetterArgName,PosEl);
  21289. if aManaged then
  21290. begin
  21291. // create rtl.setIntfP(path,"IntfVar",v)
  21292. SetExpr:=CreateAssignManagedVar(LeftResolved,SetExpr,RHS,AContext,PosEl);
  21293. end
  21294. else
  21295. begin
  21296. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,PosEl));
  21297. AssignSt.LHS:=SetExpr;
  21298. AssignSt.Expr:=RHS;
  21299. SetExpr:=AssignSt;
  21300. end;
  21301. end
  21302. else
  21303. begin
  21304. // SetExpr rtl.raiseE("EPropReadOnly")
  21305. SetterArgName:='';
  21306. SetExpr:=CreateRaisePropReadOnly(PosEl);
  21307. end;
  21308. Result:=CreateRefObj(PosEl,nil,GetExpr,SetExpr,SetterArgName,LeftResolved);
  21309. end;
  21310. function CreatePropertyReference(PosEl: TPasElement;
  21311. const LeftResolved: TPasResolverResult): TJSElement;
  21312. var
  21313. Prop: TPasProperty;
  21314. OldAccess: TCtxAccess;
  21315. GetExpr, SetExpr, LeftJS, PathExpr, RHS: TJSElement;
  21316. DotExpr: TJSDotMemberExpression;
  21317. AssignSt: TJSSimpleAssignStatement;
  21318. SetterArgName, aName: String;
  21319. TypeEl: TPasType;
  21320. aManaged: Boolean;
  21321. begin
  21322. // explicit Left is property
  21323. // path.Prop.Proc or Prop.Proc
  21324. Prop:=TPasProperty(LeftResolved.IdentEl);
  21325. OldAccess:=AContext.Access;
  21326. AContext.Access:=caRead;
  21327. LeftJS:=ConvertExpression(Left,AContext);
  21328. AContext.Access:=OldAccess;
  21329. {$IFDEF VerbosePas2JS}
  21330. writeln('CreatePropertyReference LeftJS=',GetObjName(LeftJS));
  21331. {$ENDIF}
  21332. TypeEl:=LeftResolved.LoTypeEl;
  21333. aManaged:=AContext.Resolver.IsManagedJSType(TypeEl);
  21334. PathExpr:=nil;
  21335. SetterArgName:='';
  21336. if LeftJS=nil then
  21337. DoError(20190211105946,nNoMemberIsProvidedToAccessProperty,sNoMemberIsProvidedToAccessProperty,[],PosEl)
  21338. else if LeftJS.ClassType=TJSLiteral then
  21339. begin
  21340. // getter is a const
  21341. // convert to {get:function(){return value},set:function(v){ error }}
  21342. SetExpr:=CreateRaisePropReadOnly(PosEl);
  21343. GetExpr:=LeftJS;
  21344. end
  21345. else if LeftJS.ClassType=TJSDotMemberExpression then
  21346. begin
  21347. // getter is a field
  21348. // convert to {p:path,get:function(){return this.p.field},set:function(v){ this.p.field=v }}
  21349. DotExpr:=TJSDotMemberExpression(LeftJS);
  21350. PathExpr:=DotExpr.MExpr;
  21351. DotExpr.MExpr:=nil;
  21352. aName:=String(DotExpr.Name);
  21353. DotExpr.Free;
  21354. GetExpr:=CreateMemberExpression(['this',TempRefGetPathName,aName]);
  21355. SetterArgName:=TempRefObjSetterArgName;
  21356. RHS:=CreatePrimitiveDotExpr(SetterArgName,PosEl);
  21357. if vmClass in Prop.VarModifiers then
  21358. // assign class field -> always use class path
  21359. SetExpr:=CreateDotExpression(PosEl,
  21360. CreateReferencePathExpr(Prop.Parent,AContext),
  21361. CreatePrimitiveDotExpr(aName,PosEl))
  21362. else
  21363. SetExpr:=CreateMemberExpression(['this',TempRefGetPathName,aName]);
  21364. if aManaged then
  21365. begin
  21366. // create rtl.setIntfP(path,"IntfVar",v)
  21367. SetExpr:=CreateAssignManagedVar(LeftResolved,SetExpr,RHS,AContext,PosEl);
  21368. end
  21369. else
  21370. begin
  21371. // create SetExpr=v
  21372. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,PosEl));
  21373. AssignSt.LHS:=SetExpr;
  21374. SetExpr:=AssignSt;
  21375. AssignSt.Expr:=RHS;
  21376. end;
  21377. end
  21378. else if LeftJS.ClassType=TJSCallExpression then
  21379. begin
  21380. // getter is a function
  21381. // convert to {p:FuncResult(),get:function(){return this.p},set:function(v){ this.p=v }}
  21382. PathExpr:=TJSCallExpression(LeftJS);
  21383. GetExpr:=CreateMemberExpression(['this',TempRefGetPathName]);
  21384. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,PosEl));
  21385. AssignSt.LHS:=CreateMemberExpression(['this',TempRefGetPathName]);
  21386. SetExpr:=AssignSt;
  21387. SetterArgName:=TempRefObjSetterArgName;
  21388. AssignSt.Expr:=CreatePrimitiveDotExpr(SetterArgName,PosEl);
  21389. end
  21390. else
  21391. RaiseNotSupported(PosEl,AContext,20190210193605,GetObjName(LeftJS));
  21392. Result:=CreateRefObj(PosEl,PathExpr,GetExpr,SetExpr,SetterArgName,LeftResolved);
  21393. end;
  21394. function CreateReference(PosEl: TPasElement;
  21395. const LeftResolved: TPasResolverResult): TJSElement;
  21396. var
  21397. ProcScope: TPas2JSProcedureScope;
  21398. begin
  21399. if Left=nil then
  21400. Result:=ConvertImplicitLeftIdentifier(PosEl,LeftResolved)
  21401. else if LeftResolved.IdentEl is TPasProperty then
  21402. Result:=CreatePropertyReference(PosEl,LeftResolved)
  21403. else
  21404. begin
  21405. ProcScope:=Proc.CustomData as TPas2JSProcedureScope;
  21406. if ProcScope.SelfArg=nil then
  21407. begin
  21408. {$IFDEF VerbosePas2JS}
  21409. writeln('CreateReference Proc=',GetObjPath(Proc),' Left=',GetObjPath(Left),' LeftResolved=',GetResolverResultDbg(LeftResolved),' ProcScope.DeclarationProc=',GetObjPath(ProcScope.DeclarationProc));
  21410. {$ENDIF}
  21411. RaiseNotSupported(PosEl,AContext,20190209214906,GetObjName(Proc));
  21412. end;
  21413. Result:=CreateProcCallArgRef(Left,LeftResolved,ProcScope.SelfArg,AContext);
  21414. end;
  21415. end;
  21416. var
  21417. aResolver: TPas2JSResolver;
  21418. LoTypeEl: TPasType;
  21419. Bin: TBinaryExpr;
  21420. LeftResolved: TPasResolverResult;
  21421. SelfJS: TJSElement;
  21422. PosEl, NameExpr: TPasExpr;
  21423. ProcPath: String;
  21424. Call: TJSCallExpression;
  21425. IdentEl: TPasElement;
  21426. IsStatic, IsConstructorNormalCall: Boolean;
  21427. Ref: TResolvedReference;
  21428. ProcType: TPasProcedureType;
  21429. ParamsExpr: TParamsExpr;
  21430. ArgElements : TJSArrayLiteralElements;
  21431. ArrLit: TJSArrayLiteral;
  21432. Prop: TPasProperty;
  21433. C: TClass;
  21434. begin
  21435. {$IFDEF VerbosePas2JS}
  21436. writeln('TPasToJSConverter.CreateCallHelperMethod Proc=',GetObjName(Proc),' Expr=',GetObjName(Expr),' Implicit=',Implicit);
  21437. {$ENDIF}
  21438. Result:=nil;
  21439. aResolver:=AContext.Resolver;
  21440. //Helper:=Proc.Parent as TPasClassType;
  21441. //HelperForType:=aResolver.ResolveAliasType(Helper.HelperForType);
  21442. IsStatic:=aResolver.MethodIsStatic(Proc);
  21443. WithExprScope:=nil;
  21444. SelfScope:=nil;
  21445. PosEl:=Expr;
  21446. Ref:=nil;
  21447. Prop:=nil;
  21448. Left:=nil;
  21449. SelfJS:=nil;
  21450. Call:=nil;
  21451. ArgElements:=nil;
  21452. try
  21453. if Implicit then
  21454. begin
  21455. Left:=Expr;
  21456. PosEl:=Expr;
  21457. aResolver.ComputeElement(Left,LeftResolved,[]);
  21458. end
  21459. else
  21460. begin
  21461. NameExpr:=Expr;
  21462. if NameExpr is TInlineSpecializeExpr then
  21463. NameExpr:=TInlineSpecializeExpr(NameExpr).NameExpr;
  21464. if NameExpr is TBinaryExpr then
  21465. begin
  21466. // e.g. "path.proc(args)" or "path.proc"
  21467. Bin:=TBinaryExpr(NameExpr);
  21468. if Bin.OpCode<>eopSubIdent then
  21469. RaiseNotSupported(NameExpr,AContext,20190201163152);
  21470. Left:=Bin.left;
  21471. aResolver.ComputeElement(Left,LeftResolved,[]);
  21472. PosEl:=Bin.right;
  21473. if PosEl.CustomData is TResolvedReference then
  21474. Ref:=TResolvedReference(PosEl.CustomData);
  21475. end
  21476. else if aResolver.IsNameExpr(NameExpr) then
  21477. begin
  21478. // e.g. "proc(args)"
  21479. PosEl:=NameExpr;
  21480. if not (NameExpr.CustomData is TResolvedReference) then
  21481. RaiseNotSupported(NameExpr,AContext,20190201163210);
  21482. Ref:=TResolvedReference(NameExpr.CustomData);
  21483. WithExprScope:=Ref.WithExprScope as TPas2JSWithExprScope;
  21484. if WithExprScope<>nil then
  21485. begin
  21486. // e.g. "with left do proc()"
  21487. // -> Left is the WithVarName
  21488. aResolver.ComputeElement(WithExprScope.Expr,LeftResolved,[]);
  21489. end
  21490. else
  21491. begin
  21492. // inside helper method, no explicit left expression
  21493. if IsStatic then
  21494. LeftResolved:=default(TPasResolverResult)
  21495. else
  21496. begin
  21497. SelfScope:=aResolver.GetSelfScope(NameExpr);
  21498. if SelfScope=nil then
  21499. RaiseNotSupported(PosEl,AContext,20190205171529);
  21500. if SelfScope.SelfArg=nil then
  21501. RaiseNotSupported(PosEl,AContext,20190205171902,GetObjName(SelfScope.Element));
  21502. aResolver.ComputeElement(SelfScope.SelfArg,LeftResolved,[]);
  21503. end;
  21504. end;
  21505. end
  21506. else if NameExpr is TParamsExpr then
  21507. begin
  21508. // implicit call, e.g. default property a[]
  21509. PosEl:=NameExpr;
  21510. if not (NameExpr.CustomData is TResolvedReference) then
  21511. RaiseNotSupported(NameExpr,AContext,20190208105144);
  21512. Ref:=TResolvedReference(PosEl.CustomData);
  21513. if Ref.Declaration.ClassType<>TPasProperty then
  21514. RaiseNotSupported(NameExpr,AContext,20190208105222);
  21515. Left:=TParamsExpr(NameExpr).Value;
  21516. aResolver.ComputeElement(Left,LeftResolved,[]);
  21517. end
  21518. else
  21519. begin
  21520. RaiseNotSupported(NameExpr,AContext,20190201163210);
  21521. LeftResolved:=default(TPasResolverResult);
  21522. end;
  21523. end;
  21524. LoTypeEl:=LeftResolved.LoTypeEl;
  21525. IdentEl:=LeftResolved.IdentEl;
  21526. IsConstructorNormalCall:=false;
  21527. if Ref<>nil then
  21528. begin
  21529. IsConstructorNormalCall:=(Proc.ClassType=TPasConstructor)
  21530. and not (rrfNewInstance in Ref.Flags);
  21531. if Ref.Declaration.ClassType=TPasProperty then
  21532. Prop:=TPasProperty(Ref.Declaration);
  21533. end;
  21534. {$IFDEF VerbosePas2JS}
  21535. writeln('TPasToJSConverter.CreateCallHelperMethod IsStatic=',IsStatic,' IsConstructorNormalCall=',IsConstructorNormalCall,' Ref=',GetObjName(Ref),' Left=',GetObjName(Left),' ',GetResolverResultDbg(LeftResolved));
  21536. {$ENDIF}
  21537. if IsStatic then
  21538. begin
  21539. // call static helper method -> HelperType.HelperCall(args?)
  21540. if (Proc.ClassType<>TPasClassFunction)
  21541. and (Proc.ClassType<>TPasClassProcedure) then
  21542. RaiseNotSupported(PosEl,AContext,20190206151034,GetObjName(Proc));
  21543. end
  21544. else if (Proc.ClassType=TPasClassFunction) or (Proc.ClassType=TPasClassProcedure) then
  21545. begin
  21546. // call non static helper class method
  21547. // Note: only allowed for class helpers because "this" must be the class type
  21548. if LoTypeEl=nil then
  21549. RaiseNotSupported(PosEl,AContext,20190201163453,GetResolverResultDbg(LeftResolved));
  21550. if (IdentEl is TPasClassType) then
  21551. begin
  21552. // ClassType.HelperCall -> HelperType.HelperCall.call(ClassType,args?)
  21553. if TPasClassType(LeftResolved.IdentEl).IsExternal then
  21554. RaiseNotSupported(PosEl,AContext,20190201165636);
  21555. SelfJS:=CreateReferencePathExpr(LeftResolved.IdentEl,AContext);
  21556. end
  21557. else if (LoTypeEl.ClassType=TPasClassType) and (rrfReadable in LeftResolved.Flags) then
  21558. begin
  21559. // ClassInstance.HelperCall -> HelperType.HelperCall.call(ClassInstance.$class,args?)
  21560. if TPasClassType(LeftResolved.LoTypeEl).IsExternal then
  21561. RaiseNotSupported(PosEl,AContext,20190201165656);
  21562. SelfJS:=ConvertLeftExpr;
  21563. SelfJS:=CreateDotExpression(PosEl,SelfJS,
  21564. CreatePrimitiveDotExpr(GetBIName(pbivnPtrClass),PosEl));
  21565. end
  21566. else if (LoTypeEl.ClassType=TPasClassOfType) and (rrfReadable in LeftResolved.Flags) then
  21567. begin
  21568. // ClassOfVar.HelperCall -> HelperType.HelperCall.call(ClassOfVar,args?)
  21569. SelfJS:=ConvertLeftExpr;
  21570. end
  21571. else
  21572. RaiseNotSupported(PosEl,AContext,20190201162601,GetResolverResultDbg(LeftResolved));
  21573. end
  21574. else if (Proc.ClassType=TPasFunction) or (Proc.ClassType=TPasProcedure)
  21575. or IsConstructorNormalCall then
  21576. begin
  21577. // normal method, neither static nor class method
  21578. if IdentEl is TPasType then
  21579. RaiseNotSupported(PosEl,AContext,20190201170843);
  21580. if (LoTypeEl is TPasClassType) and (rrfReadable in LeftResolved.Flags)
  21581. and (TPasClassType(LoTypeEl).ObjKind=okClass) then
  21582. begin
  21583. // ClassInstance.HelperCall -> HelperType.HelperCall.call(ClassInstance,args?)
  21584. SelfJS:=ConvertLeftExpr;
  21585. end
  21586. else if (LoTypeEl is TPasRecordType) and (rrfReadable in LeftResolved.Flags) then
  21587. begin
  21588. // RecordInstance.HelperCall -> HelperType.HelperCall.call(RecordInstance,args?)
  21589. SelfJS:=ConvertLeftExpr;
  21590. end
  21591. else if IdentEl<>nil then
  21592. begin
  21593. C:=IdentEl.ClassType;
  21594. if (C=TPasArgument)
  21595. or (C=TPasVariable)
  21596. or (C=TPasConst)
  21597. or (C=TPasProperty)
  21598. or (C=TPasResultElement)
  21599. or (C=TPasEnumValue)
  21600. or (C=TPasClassType) then
  21601. begin
  21602. // Left.HelperCall -> HelperType.HelperCall.call({get,set},args?)
  21603. SelfJS:=CreateReference(PosEl,LeftResolved);
  21604. end
  21605. else
  21606. RaiseNotSupported(PosEl,AContext,20190209224904,GetResolverResultDbg(LeftResolved));
  21607. end
  21608. else if (LeftResolved.ExprEl<>nil) and (rrfReadable in LeftResolved.Flags) then
  21609. begin
  21610. // LeftExpr.HelperCall -> HelperType.HelperCall.call({get,set},args?)
  21611. SelfJS:=CreateReference(PosEl,LeftResolved);
  21612. end
  21613. else
  21614. begin
  21615. // Literal.HelperCall -> HelperType.HelperCall.call({p: Literal,get,set},args?)
  21616. {$IFDEF VerbosePas2JS}
  21617. writeln('TPasToJSConverter.CreateCallHelperMethod Left=',GetObjName(Left),' LeftResolved=',GetResolverResultDbg(LeftResolved));
  21618. {$ENDIF}
  21619. RaiseNotSupported(PosEl,AContext,20190131211753);
  21620. end;
  21621. end
  21622. else if Proc.ClassType=TPasConstructor then
  21623. begin
  21624. if Ref=nil then
  21625. RaiseNotSupported(PosEl,AContext,20190206151234);
  21626. if not (rrfNewInstance in Ref.Flags) then
  21627. RaiseNotSupported(PosEl,AContext,20190206151901);
  21628. // new instance
  21629. if (LoTypeEl<>nil)
  21630. and ((LoTypeEl.ClassType=TPasClassType)
  21631. or (LoTypeEl.ClassType=TPasClassOfType)) then
  21632. begin
  21633. // aClassVarOrType.HelperCall(args)
  21634. // -> aClassVarOrType.$create(HelperType.HelperCall,[args])
  21635. if (LoTypeEl.ClassType=TPasClassType) and (TPasClassType(LoTypeEl).ObjKind<>okClass) then
  21636. RaiseNotSupported(PosEl,AContext,20190302154215,GetElementTypeName(LoTypeEl));
  21637. Call:=CreateCallExpression(PosEl);
  21638. SelfJS:=ConvertLeftExpr;
  21639. Call.Expr:=CreateDotExpression(PosEl,SelfJS,
  21640. CreatePrimitiveDotExpr(GetBIName(pbifnClassInstanceNew),PosEl));
  21641. SelfJS:=nil;
  21642. Call.AddArg(CreateReferencePathExpr(Proc,AContext));
  21643. end
  21644. else
  21645. begin
  21646. // record, simpletype -> HelperType.$new('HelperCall',[args])
  21647. Call:=CreateCallExpression(PosEl);
  21648. ProcPath:=CreateReferencePath(Proc.Parent,AContext,rpkPathAndName)+'.'+GetBIName(pbifnHelperNew);
  21649. Call.Expr:=CreatePrimitiveDotExpr(ProcPath,PosEl);
  21650. ProcPath:=TransformElToJSName(Proc,AContext);
  21651. Call.AddArg(CreateLiteralString(PosEl,ProcPath));
  21652. end;
  21653. ArrLit:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,PosEl));
  21654. Call.AddArg(ArrLit);
  21655. ArgElements:=ArrLit.Elements;
  21656. end
  21657. else
  21658. RaiseNotSupported(PosEl,AContext,20190201162609,GetObjName(Proc));
  21659. if Call=nil then
  21660. begin
  21661. if (SelfJS=nil) and not IsStatic then
  21662. RaiseNotSupported(PosEl,AContext,20190203171010,GetResolverResultDbg(LeftResolved));
  21663. // create HelperType.HelperCall.call(SelfJS)
  21664. Call:=CreateCallExpression(Expr);
  21665. if (coShortRefGlobals in Options)
  21666. and (TPas2JSProcedureScope(Proc.CustomData).SpecializedFromItem<>nil) then
  21667. ProcPath:=CreateGlobalElPath(Proc,AContext)
  21668. else
  21669. ProcPath:=CreateReferencePath(Proc,AContext,rpkPathAndName);
  21670. if not IsStatic then
  21671. ProcPath:=ProcPath+'.call';
  21672. Call.Expr:=CreatePrimitiveDotExpr(ProcPath,Expr);
  21673. if SelfJS<>nil then
  21674. begin
  21675. Call.AddArg(SelfJS);
  21676. SelfJS:=nil;
  21677. end;
  21678. ArgElements:=Call.Args.Elements;
  21679. end;
  21680. if Prop<>nil then
  21681. begin
  21682. if aResolver.GetPasPropertyArgs(Prop).Count>0 then
  21683. begin
  21684. // arguments are passed by ConvertParamsExpr
  21685. Result:=Call;
  21686. Call:=nil;
  21687. exit;
  21688. end;
  21689. case AContext.Access of
  21690. caAssign:
  21691. begin
  21692. // call property setter, e.g. left.prop:=RightSide
  21693. // -> HelperType.HelperSetter.call(SelfJS,RightSide)
  21694. // append index and RightSide
  21695. Result:=AppendPropertyAssignArgs(Call,Prop,TAssignContext(AContext),PosEl);
  21696. Call:=nil;
  21697. exit;
  21698. end;
  21699. caRead:
  21700. begin
  21701. Result:=AppendPropertyReadArgs(Call,Prop,aContext,PosEl);
  21702. Call:=nil;
  21703. exit;
  21704. end;
  21705. else
  21706. RaiseNotSupported(PosEl,AContext,20190207122708);
  21707. end;
  21708. end;
  21709. // append args
  21710. ProcType:=Proc.ProcType;
  21711. if (Expr.Parent is TParamsExpr) and (TParamsExpr(Expr.Parent).Value=Expr) then
  21712. ParamsExpr:=TParamsExpr(Expr.Parent)
  21713. else
  21714. ParamsExpr:=nil;
  21715. CreateProcedureCallArgs(ArgElements,ParamsExpr,ProcType,AContext);
  21716. if (ProcType is TPasFunctionType)
  21717. and aResolver.IsManagedJSType(TPasFunctionType(ProcType).ResultEl.ResultType)
  21718. then
  21719. // need interface reference: $ir.ref(id,fnname())
  21720. // ToDo: if Result is not used, use rtl._release() instead
  21721. Call:=CreateIntfRef(Call,AContext,PosEl);
  21722. Result:=Call;
  21723. Call:=nil;
  21724. finally
  21725. Call.Free;
  21726. SelfJS.Free;
  21727. end;
  21728. end;
  21729. procedure TPasToJSConverter.AddHelperConstructor(El: TPasClassType;
  21730. Src: TJSSourceElements; AContext: TConvertContext);
  21731. const
  21732. FunName = 'fn';
  21733. ArgsName = 'args';
  21734. ValueName = 'p';
  21735. var
  21736. aResolver: TPas2JSResolver;
  21737. HelperForType: TPasType;
  21738. AssignSt: TJSSimpleAssignStatement;
  21739. Func, FuncSt: TJSFunctionDeclarationStatement;
  21740. New_Src: TJSSourceElements;
  21741. Call: TJSCallExpression;
  21742. DotExpr: TJSDotMemberExpression;
  21743. BracketExpr: TJSBracketMemberExpression;
  21744. New_FuncContext: TFunctionContext;
  21745. SelfJS: TJSElement;
  21746. ReturnSt, RetSt: TJSReturnStatement;
  21747. Obj: TJSObjectLiteral;
  21748. ObjLit: TJSObjectLiteralElement;
  21749. SetterArgName: AnsiChar;
  21750. begin
  21751. if El.HelperForType=nil then exit;
  21752. aResolver:=AContext.Resolver;
  21753. HelperForType:=aResolver.ResolveAliasType(El.HelperForType);
  21754. if HelperForType.ClassType=TPasClassType then
  21755. exit; // a class helper does not need a special sub function
  21756. New_Src:=TJSSourceElements(CreateElement(TJSSourceElements, El));
  21757. New_FuncContext:=TFunctionContext.Create(El,New_Src,AContext);
  21758. try
  21759. New_FuncContext.ThisVar.Element:=El;
  21760. New_FuncContext.ThisVar.Kind:=cvkCurType;
  21761. New_FuncContext.IsGlobal:=true;
  21762. // Note: a newinstance call looks like this: THelper.$new("NewHlp", [3]);
  21763. // The $new function:
  21764. // this.$new = function(fnname,args){
  21765. // record:
  21766. // return this[fnname].apply(TRecType.$new(),args);
  21767. // other:
  21768. // return this[fnname].apply({p:SelfJS,get,set},args);
  21769. // }
  21770. ReturnSt:=TJSReturnStatement(CreateElement(TJSReturnStatement,El));
  21771. AddToSourceElements(New_Src,ReturnSt);
  21772. Call:=CreateCallExpression(El);
  21773. ReturnSt.Expr:=Call;
  21774. DotExpr:=TJSDotMemberExpression(CreateElement(TJSDotMemberExpression,El));
  21775. Call.Expr:=DotExpr;
  21776. BracketExpr:=TJSBracketMemberExpression(CreateElement(TJSBracketMemberExpression,El));
  21777. DotExpr.MExpr:=BracketExpr;
  21778. DotExpr.Name:='apply';
  21779. BracketExpr.MExpr:=CreatePrimitiveDotExpr('this',El);
  21780. BracketExpr.Name:=CreatePrimitiveDotExpr(FunName,El);
  21781. SelfJS:=CreateValInit(HelperForType,nil,El,New_FuncContext);
  21782. if HelperForType.ClassType=TPasRecordType then
  21783. // pass new record directly
  21784. else
  21785. begin
  21786. // pass new value as reference
  21787. Obj:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,El));
  21788. // add "p: SelfJS"
  21789. ObjLit:=Obj.Elements.AddElement;
  21790. ObjLit.Name:=TJSString(ValueName);
  21791. ObjLit.Expr:=SelfJS;
  21792. SelfJS:=Obj;
  21793. // add "get: function(){return this.p}"
  21794. ObjLit:=Obj.Elements.AddElement;
  21795. ObjLit.Name:=TempRefObjGetterName;
  21796. FuncSt:=CreateFunctionSt(El);
  21797. ObjLit.Expr:=FuncSt;
  21798. RetSt:=TJSReturnStatement(CreateElement(TJSReturnStatement,El));
  21799. FuncSt.AFunction.Body.A:=RetSt;
  21800. RetSt.Expr:=CreateMemberExpression(['this',ValueName]);
  21801. // add "set: function(v){this.p=v}"
  21802. ObjLit:=Obj.Elements.AddElement;
  21803. ObjLit.Name:=TempRefObjSetterName;
  21804. FuncSt:=CreateFunctionSt(El);
  21805. ObjLit.Expr:=FuncSt;
  21806. SetterArgName:=TempRefObjSetterArgName;
  21807. FuncSt.AFunction.TypedParams.AddParam(TJSString(SetterArgName));
  21808. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  21809. FuncSt.AFunction.Body.A:=AssignSt;
  21810. AssignSt.LHS:=CreateMemberExpression(['this',ValueName]);
  21811. AssignSt.Expr:=CreatePrimitiveDotExpr(SetterArgName,El);
  21812. end;
  21813. Call.AddArg(SelfJS);
  21814. Call.AddArg(CreatePrimitiveDotExpr(ArgsName,El));
  21815. // this.$new = function(fnname,args){
  21816. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  21817. AddToSourceElements(Src,AssignSt);
  21818. AssignSt.LHS:=CreatePrimitiveDotExpr('this.'+GetBIName(pbifnHelperNew),El);
  21819. Func:=CreateFunctionSt(El);
  21820. AssignSt.Expr:=Func;
  21821. Func.AFunction.TypedParams.AddParam(FunName);
  21822. Func.AFunction.TypedParams.AddParam(ArgsName);
  21823. Func.AFunction.Body.A:=New_Src;
  21824. New_Src:=nil;
  21825. finally
  21826. New_Src.Free;
  21827. New_FuncContext.Free;
  21828. end;
  21829. end;
  21830. function TPasToJSConverter.ConvertImplBlock(El: TPasImplBlock;
  21831. AContext: TConvertContext): TJSElement;
  21832. begin
  21833. //writeln('TPasToJSConverter.ConvertImplBlock ');
  21834. Result:=Nil;
  21835. if (El is TPasImplStatement) then
  21836. Result:=ConvertStatement(TPasImplStatement(El),AContext)
  21837. else if (El.ClassType=TPasImplIfElse) then
  21838. Result:=ConvertIfStatement(TPasImplIfElse(El),AContext)
  21839. else if (El.ClassType=TPasImplRepeatUntil) then
  21840. Result:=ConvertRepeatStatement(TPasImplRepeatUntil(El),AContext)
  21841. else if (El.ClassType=TPasImplBeginBlock) then
  21842. Result:=ConvertBeginEndStatement(TPasImplBeginBlock(El),AContext,true)
  21843. else if (El.ClassType=TInitializationSection) then
  21844. Result:=ConvertInitializationSection(TPasModule(El.Parent),AContext)
  21845. else if (El.ClassType=TFinalizationSection) then
  21846. Result:=ConvertFinalizationSection(TFinalizationSection(El),AContext)
  21847. else if (El.ClassType=TPasImplTry) then
  21848. Result:=ConvertTryStatement(TPasImplTry(El),AContext)
  21849. else if (El.ClassType=TPasImplCaseOf) then
  21850. Result:=ConvertCaseOfStatement(TPasImplCaseOf(El),AContext)
  21851. else
  21852. RaiseNotSupported(El,AContext,20161024192156);
  21853. end;
  21854. function TPasToJSConverter.ConvertImplCommand(El: TPasImplCommand;
  21855. AContext: TConvertContext): TJSElement;
  21856. begin
  21857. if El.Command<>'' then
  21858. RaiseNotSupported(El,AContext,20181013224809,El.Command);
  21859. if not (El.Parent is TPasImplIfElse) then
  21860. RaiseNotSupported(El,AContext,20181013224929,GetObjName(El.Parent));
  21861. Result:=nil;
  21862. end;
  21863. function TPasToJSConverter.ConvertPackage(El: TPasPackage;
  21864. AContext: TConvertContext): TJSElement;
  21865. begin
  21866. RaiseNotSupported(El,AContext,20161024192555);
  21867. Result:=Nil;
  21868. // ToDo TPasPackage = class(TPasElement)
  21869. end;
  21870. function TPasToJSConverter.ConvertResString(El: TPasResString;
  21871. AContext: TConvertContext): TJSElement;
  21872. begin
  21873. RaiseNotSupported(El,AContext,20161024192604);
  21874. Result:=Nil;
  21875. // ToDo: TPasResString
  21876. end;
  21877. function TPasToJSConverter.ConvertVariable(El: TPasVariable;
  21878. AContext: TConvertContext): TJSElement;
  21879. Var
  21880. V : TJSVarDeclaration;
  21881. vm: TVariableModifier;
  21882. begin
  21883. for vm in TVariableModifier do
  21884. if (vm in El.VarModifiers) and (not (vm in [vmClass,vmExternal])) then
  21885. RaiseNotSupported(El,AContext,20170208141622,'modifier '+VariableModifierNames[vm]);
  21886. if El.LibraryName<>nil then
  21887. RaiseNotSupported(El,AContext,20170208141844,'library name');
  21888. if El.AbsoluteExpr<>nil then
  21889. RaiseNotSupported(El,AContext,20170208141926,'absolute');
  21890. V:=TJSVarDeclaration(CreateElement(TJSVarDeclaration,El));
  21891. V.Name:=TJSString(TransformElToJSName(El,AContext));
  21892. V.Init:=CreateVarInit(El,AContext);
  21893. Result:=V;
  21894. end;
  21895. function TPasToJSConverter.ConvertProperty(El: TPasProperty;
  21896. AContext: TConvertContext): TJSElement;
  21897. begin
  21898. Result:=Nil;
  21899. if El.DispIDExpr<>nil then
  21900. RaiseNotSupported(El.DispIDExpr,AContext,20170215103029,'property dispid expression');
  21901. // does not need any declaration. Access is redirected to getter/setter.
  21902. // RTTI is created in CreateRTTIMemberProperty
  21903. end;
  21904. function TPasToJSConverter.ConvertExportSymbol(El: TPasExportSymbol;
  21905. AContext: TConvertContext): TJSElement;
  21906. begin
  21907. RaiseNotSupported(El,AContext,20161024192650);
  21908. Result:=Nil;
  21909. // ToDo: TPasExportSymbol
  21910. end;
  21911. function TPasToJSConverter.ConvertLabels(El: TPasLabels;
  21912. AContext: TConvertContext): TJSElement;
  21913. begin
  21914. RaiseNotSupported(El,AContext,20161024192701);
  21915. Result:=Nil;
  21916. // ToDo: TPasLabels = class(TPasImplElement)
  21917. end;
  21918. function TPasToJSConverter.ConvertRaiseStatement(El: TPasImplRaise;
  21919. AContext: TConvertContext): TJSElement;
  21920. Var
  21921. E : TJSElement;
  21922. T : TJSThrowStatement;
  21923. begin
  21924. if El.ExceptObject<>Nil then
  21925. E:=ConvertExpression(El.ExceptObject,AContext)
  21926. else
  21927. E:=CreatePrimitiveDotExpr(GetBIName(pbivnExceptObject),El);
  21928. T:=TJSThrowStatement(CreateElement(TJSThrowStatement,El));
  21929. T.A:=E;
  21930. Result:=T;
  21931. end;
  21932. function TPasToJSConverter.ConvertAssignStatement(El: TPasImplAssign;
  21933. AContext: TConvertContext): TJSElement;
  21934. var
  21935. lRightIsTemp, lRightIsTempValid: boolean;
  21936. lLeftIsConstSetter, lLeftIsConstSetterValid: boolean;
  21937. procedure NotSupported(AssignContext: TAssignContext; id: TMaxPrecInt);
  21938. begin
  21939. {$IFDEF VerbosePas2JS}
  21940. writeln('NotSupported Left=',GetResolverResultDbg(AssignContext.LeftResolved),
  21941. ' Op=',AssignKindNames[El.Kind],
  21942. ' Right=',GetResolverResultDbg(AssignContext.RightResolved));
  21943. {$ENDIF}
  21944. RaiseNotSupported(El,AContext,id,
  21945. GetResolverResultDbg(AssignContext.LeftResolved)+AssignKindNames[El.Kind]
  21946. +GetResolverResultDbg(AssignContext.RightResolved));
  21947. end;
  21948. function RightIsTemporaryVar: boolean;
  21949. // returns true if right side is a temporary variable, e.g. a function result
  21950. begin
  21951. if not lRightIsTempValid then
  21952. begin
  21953. lRightIsTempValid:=true;
  21954. lRightIsTemp:=IsExprTemporaryVar(El.Right);
  21955. end;
  21956. Result:=lRightIsTemp;
  21957. end;
  21958. function LeftIsConstSetter: boolean;
  21959. // returns true if left side is a property setter with const argument
  21960. begin
  21961. if not lLeftIsConstSetterValid then
  21962. begin
  21963. lLeftIsConstSetterValid:=true;
  21964. lLeftIsConstSetter:=IsExprPropertySetterConst(El.Left,AContext);
  21965. end;
  21966. Result:=lLeftIsConstSetter
  21967. end;
  21968. function CreateRangeCheck(AssignSt: TJSElement;
  21969. MinVal, MaxVal: TMaxPrecInt; RTLFunc: TPas2JSBuiltInName): TJSElement;
  21970. var
  21971. Call: TJSCallExpression;
  21972. begin
  21973. Call:=CreateCallExpression(El);
  21974. Call.Expr:=CreatePrimitiveDotExpr(GetBIName(pbivnRTL)+'.'+GetBIName(RTLFunc),El);
  21975. if AssignSt.ClassType=TJSSimpleAssignStatement then
  21976. begin
  21977. // LHS:=rtl.rc(RHS,min,max) check before assign
  21978. Result:=AssignSt;
  21979. Call.AddArg(TJSSimpleAssignStatement(AssignSt).Expr);
  21980. TJSSimpleAssignStatement(AssignSt).Expr:=Call;
  21981. end
  21982. else
  21983. begin
  21984. // rtl.rc(LHS+=RHS,min,max) check after assign
  21985. Call.AddArg(AssignSt);
  21986. Result:=Call;
  21987. end;
  21988. Call.AddArg(CreateLiteralNumber(El.Right,MinVal));
  21989. Call.AddArg(CreateLiteralNumber(El.Right,MaxVal));
  21990. end;
  21991. function ApplyRangeCheck_Type(AssignSt: TJSElement; aType: TPasType): TJSElement;
  21992. var
  21993. Value: TResEvalValue;
  21994. begin
  21995. Result:=AssignSt;
  21996. Value:=AContext.Resolver.EvalTypeRange(aType,[refConst]);
  21997. if Value=nil then
  21998. RaiseNotSupported(El,AContext,20180424110758,'range checking '+GetObjName(aType));
  21999. try
  22000. case Value.Kind of
  22001. revkRangeInt:
  22002. case TResEvalRangeInt(Value).ElKind of
  22003. revskEnum, revskInt:
  22004. Result:=CreateRangeCheck(AssignSt,TResEvalRangeInt(Value).RangeStart,
  22005. TResEvalRangeInt(Value).RangeEnd,pbifnRangeCheckInt);
  22006. revskChar:
  22007. Result:=CreateRangeCheck(AssignSt,TResEvalRangeInt(Value).RangeStart,
  22008. TResEvalRangeInt(Value).RangeEnd,pbifnRangeCheckChar);
  22009. revskBool: ; // maybe check for type?
  22010. else
  22011. RaiseNotSupported(El,AContext,20190220003746,'range checking '+Value.AsDebugString);
  22012. end;
  22013. else
  22014. RaiseNotSupported(El,AContext,20180424111037,'range checking '+Value.AsDebugString);
  22015. end;
  22016. finally
  22017. ReleaseEvalValue(Value);
  22018. end;
  22019. end;
  22020. Var
  22021. LHS: TJSElement;
  22022. T: TJSAssignStatement;
  22023. AssignContext: TAssignContext;
  22024. Flags: TPasResolverComputeFlags;
  22025. LeftIsProcType: Boolean;
  22026. Call: TJSCallExpression;
  22027. MinVal, MaxVal: TMaxPrecInt;
  22028. LeftTypeEl, RightTypeEl: TPasType;
  22029. aResolver: TPas2JSResolver;
  22030. ObjLit: TJSObjectLiteral;
  22031. GUID: TGUID;
  22032. begin
  22033. Result:=nil;
  22034. LHS:=nil;
  22035. aResolver:=AContext.Resolver;
  22036. lLeftIsConstSetterValid:=false;
  22037. lRightIsTempValid:=false;
  22038. AssignContext:=TAssignContext.Create(El,nil,AContext);
  22039. try
  22040. if aResolver<>nil then
  22041. begin
  22042. aResolver.ComputeElement(El.Left,AssignContext.LeftResolved,[rcNoImplicitProc]);
  22043. Flags:=[];
  22044. LeftIsProcType:=aResolver.IsProcedureType(AssignContext.LeftResolved,false);
  22045. if LeftIsProcType then
  22046. begin
  22047. if msDelphi in AContext.CurrentModeSwitches then
  22048. Include(Flags,rcNoImplicitProc)
  22049. else
  22050. Include(Flags,rcNoImplicitProcType);
  22051. end;
  22052. aResolver.ComputeElement(El.Right,AssignContext.RightResolved,Flags);
  22053. {$IFDEF VerbosePas2JS}
  22054. writeln('TPasToJSConverter.ConvertAssignStatement Left={',GetResolverResultDbg(AssignContext.LeftResolved),'} Right={',GetResolverResultDbg(AssignContext.RightResolved),'}');
  22055. {$ENDIF}
  22056. if LeftIsProcType and (msDelphi in AContext.CurrentModeSwitches)
  22057. and (AssignContext.RightResolved.BaseType=btProc)
  22058. and (AssignContext.RightResolved.IdentEl is TPasProcedure) then
  22059. begin
  22060. // Delphi allows assigning a proc without @: proctype:=proc
  22061. LeftTypeEl:=AssignContext.LeftResolved.LoTypeEl;
  22062. AssignContext.RightSide:=CreateCallback(El.Right,
  22063. AssignContext.RightResolved,
  22064. TPasProcedureType(LeftTypeEl).CallingConvention=ccSafeCall,
  22065. AContext);
  22066. end
  22067. else if AssignContext.RightResolved.BaseType=btNil then
  22068. begin
  22069. if aResolver.IsArrayType(AssignContext.LeftResolved) then
  22070. begin
  22071. // array:=nil
  22072. if aResolver.IsManagedJSType(AssignContext.LeftResolved.LoTypeEl) then
  22073. // -> rtl.setIntfL(...,null,...)
  22074. AssignContext.RightSide:=CreateLiteralNull(El.Right)
  22075. else
  22076. // -> array=[]
  22077. AssignContext.RightSide:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,El.Right));
  22078. end;
  22079. end
  22080. else if AssignContext.LeftResolved.BaseType=btContext then
  22081. begin
  22082. LeftTypeEl:=AssignContext.LeftResolved.LoTypeEl;
  22083. if (LeftTypeEl.ClassType=TPasRecordType)
  22084. and (AssignContext.RightResolved.BaseType in btAllStrings) then
  22085. begin
  22086. if aResolver.GetAssignGUIDString(TPasRecordType(LeftTypeEl),El.Right,GUID) then
  22087. begin
  22088. // guidvar:='{...}'; -> convert string to GUID object { D1:x12345678, D2:0x1234,...}
  22089. // Note: the "guidvar.$assign()" is done by left side
  22090. ObjLit:=CreateGUIDObjLit(TPasRecordType(LeftTypeEl),GUID,El,AContext);
  22091. AssignContext.RightSide:=ObjLit;
  22092. end
  22093. else
  22094. RaiseNotSupported(El,AContext,20180415101516);
  22095. end;
  22096. if (LeftTypeEl.ClassType=TPasArrayType) then
  22097. begin
  22098. if (El.Kind<>akDefault) then
  22099. aResolver.RaiseMsg(20201028212754,nIllegalQualifier,sIllegalQualifier,[AssignKindNames[El.Kind]],El);
  22100. if aResolver.IsReadEqWrite(AssignContext.LeftResolved) then
  22101. begin
  22102. AssignContext.RightSide:=ConvertDirectAssignArrayStatement(El,AssignContext);
  22103. end;
  22104. end;
  22105. end;
  22106. end;
  22107. if AssignContext.RightSide=nil then
  22108. AssignContext.RightSide:=ConvertExpression(El.Right,AContext);
  22109. if (AssignContext.RightResolved.BaseType in [btSet,btArrayOrSet])
  22110. and (AssignContext.RightResolved.IdentEl<>nil) then
  22111. begin
  22112. // right side is a set variable -> create reference
  22113. {$IFDEF VerbosePas2JS}
  22114. //writeln('TPasToJSConverter.ConvertAssignStatement SET variable Right={',GetResolverResultDbg(AssignContext.RightResolved),'} AssignContext.RightResolved.IdentEl=',GetObjName(AssignContext.RightResolved.IdentEl));
  22115. {$ENDIF}
  22116. // create rtl.refSet(right)
  22117. AssignContext.RightSide:=CreateReferencedSet(El.Right,AssignContext.RightSide);
  22118. end
  22119. else if AssignContext.LeftResolved.BaseType=btCurrency then
  22120. begin
  22121. if AssignContext.RightResolved.BaseType=btCurrency then
  22122. // currency := currency
  22123. else if AssignContext.RightResolved.BaseType in btAllJSFloats then
  22124. begin
  22125. // currency := double -> currency := rtl.trunc(double*10000)
  22126. AssignContext.RightSide:=CreateMulNumber(El,AssignContext.RightSide,10000);
  22127. AssignContext.RightSide:=CreateTruncFloor(El,AssignContext.RightSide,true);
  22128. end
  22129. else if AssignContext.RightResolved.BaseType in btAllJSInteger then
  22130. begin
  22131. // currency := integer -> currency := double*10000
  22132. AssignContext.RightSide:=CreateMulNumber(El,AssignContext.RightSide,10000);
  22133. end
  22134. else
  22135. RaiseNotSupported(El,AContext,20181016094542,GetResolverResultDbg(AssignContext.RightResolved));
  22136. end
  22137. else if AssignContext.RightResolved.BaseType=btCurrency then
  22138. begin
  22139. // noncurrency := currency
  22140. // e.g. double := currency -> double := currency/10000
  22141. AssignContext.RightSide:=CreateDivideNumber(El,AssignContext.RightSide,10000);
  22142. end
  22143. else if (AssignContext.LeftResolved.BaseType<>AssignContext.RightResolved.BaseType)
  22144. and (AssignContext.LeftResolved.BaseType in btAllJSInteger)
  22145. and (AssignContext.RightResolved.BaseType in btAllJSInteger) then
  22146. begin
  22147. // AnInteger := OtherInteger
  22148. PrepareAssignDifferentIntegers(El,AssignContext);
  22149. end
  22150. else if AssignContext.RightResolved.BaseType in btAllStringAndChars then
  22151. begin
  22152. if AssignContext.LeftResolved.BaseType=btContext then
  22153. begin
  22154. if AssignContext.LeftResolved.LoTypeEl is TPasArrayType then
  22155. begin
  22156. // AnArray:=aString -> AnArray:=aString.split("")
  22157. AssignContext.RightSide:=CreateDotSplit(El.Right,AssignContext.RightSide);
  22158. end;
  22159. end;
  22160. end
  22161. else if AssignContext.RightResolved.BaseType=btContext then
  22162. begin
  22163. RightTypeEl:=AssignContext.RightResolved.LoTypeEl;
  22164. if RightTypeEl.ClassType=TPasArrayType then
  22165. begin
  22166. if length(TPasArrayType(RightTypeEl).Ranges)>0 then
  22167. begin
  22168. // right side is a static array -> clone
  22169. if (not RightIsTemporaryVar)
  22170. and (not LeftIsConstSetter) then
  22171. begin
  22172. {$IFDEF VerbosePas2JS}
  22173. writeln('TPasToJSConverter.ConvertAssignStatement STATIC ARRAY variable Right={',GetResolverResultDbg(AssignContext.RightResolved),'} AssignContext.RightResolved.IdentEl=',GetObjName(AssignContext.RightResolved.IdentEl));
  22174. {$ENDIF}
  22175. AssignContext.RightSide:=CreateCloneStaticArray(El.Right,
  22176. TPasArrayType(RightTypeEl),AssignContext.RightSide,AContext);
  22177. end;
  22178. end
  22179. else if RightTypeEl.Parent.ClassType=TPasArgument then
  22180. // right side is open array
  22181. else
  22182. begin
  22183. // right side is dynamic array
  22184. if (AssignContext.LeftResolved.BaseType=btContext)
  22185. and (AssignContext.LeftResolved.LoTypeEl is TPasArrayType) then
  22186. begin
  22187. if El.Kind<>akDefault then
  22188. aResolver.RaiseMsg(20201028213335,nIllegalQualifier,sIllegalQualifier,[AssignKindNames[El.Kind]],El);
  22189. if (not RightIsTemporaryVar) and (not LeftIsConstSetter) then
  22190. begin
  22191. if aResolver.IsManagedJSType(AssignContext.LeftResolved.LoTypeEl) then
  22192. begin
  22193. // ManagedDynArr := ManagedDynArr -> uses normal rtl.setIntfL/P
  22194. end
  22195. else
  22196. begin
  22197. // DynArrayA := DynArrayB -> DynArrayA = rtl.arrayRef(DynArrayB)
  22198. AssignContext.RightSide:=CreateArrayRef(El.Right,AssignContext.RightSide);
  22199. end;
  22200. end;
  22201. end;
  22202. end;
  22203. end
  22204. else if RightTypeEl.ClassType=TPasClassType then
  22205. begin
  22206. if AssignContext.LeftResolved.BaseType in btAllStrings then
  22207. begin
  22208. if TPasClassType(RightTypeEl).ObjKind=okInterface then
  22209. begin
  22210. // aString:=IntfTypeOrVar -> intfTypeOrVar.$guid
  22211. AssignContext.RightSide:=CreateDotNameExpr(El,
  22212. AssignContext.RightSide,TJSString(GetBIName(pbivnIntfGUID)));
  22213. end;
  22214. end
  22215. else if AssignContext.LeftResolved.BaseType=btContext then
  22216. begin
  22217. LeftTypeEl:=AssignContext.LeftResolved.LoTypeEl;
  22218. if LeftTypeEl.ClassType=TPasRecordType then
  22219. begin
  22220. if (TPasClassType(RightTypeEl).ObjKind=okInterface)
  22221. and SameText(LeftTypeEl.Name,'TGUID') then
  22222. begin
  22223. // GUIDRecord:=IntfTypeOrVar -> rtl.getIntfGUIDR(IntfTypeOrVar)
  22224. // Note: the GUIDRecord.$assign() is created by the left side
  22225. Call:=CreateCallExpression(El);
  22226. Call.Expr:=CreatePrimitiveDotExpr(GetBIName(pbivnRTL)+'.'+GetBIName(pbifnIntfGetGUIDR),El);
  22227. Call.AddArg(AssignContext.RightSide);
  22228. AssignContext.RightSide:=Call;
  22229. end
  22230. else
  22231. RaiseNotSupported(El,AContext,20180413194856);
  22232. end
  22233. else if LeftTypeEl.ClassType=TPasClassType then
  22234. case TPasClassType(LeftTypeEl).ObjKind of
  22235. okClass:
  22236. case TPasClassType(RightTypeEl).ObjKind of
  22237. okClass: ; // ClassInstVar:=ClassInstVar
  22238. else
  22239. NotSupported(AssignContext,20180327202735);
  22240. end;
  22241. okInterface:
  22242. case TPasClassType(RightTypeEl).ObjKind of
  22243. okClass:
  22244. begin
  22245. // IntfVar:=ClassInstVar
  22246. if TPasClassType(RightTypeEl).IsExternal then
  22247. RaiseNotSupported(El.Right,AContext,20180327210004,'external class instance');
  22248. if AssignContext.LeftResolved.LoTypeEl=nil then
  22249. RaiseNotSupported(El.Right,AContext,20180327204021);
  22250. Call:=CreateCallExpression(El.Right);
  22251. case TPasClassType(LeftTypeEl).InterfaceType of
  22252. // COM: $ir.ref(id,rtl.queryIntfT(ClassInstVar,IntfVarType))
  22253. citCom:
  22254. begin
  22255. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnIntfQueryIntfT)]);
  22256. Call.AddArg(AssignContext.RightSide);
  22257. AssignContext.RightSide:=Call;
  22258. Call.AddArg(CreateReferencePathExpr(AssignContext.LeftResolved.LoTypeEl,
  22259. AContext));
  22260. Call:=CreateIntfRef(Call,AContext,El);
  22261. AssignContext.RightSide:=Call;
  22262. end;
  22263. // CORBA: rtl.getIntfT(ClassInstVar,IntfVarType)
  22264. citCorba:
  22265. begin
  22266. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnIntfGetIntfT)]);
  22267. Call.AddArg(AssignContext.RightSide);
  22268. AssignContext.RightSide:=Call;
  22269. Call.AddArg(CreateReferencePathExpr(AssignContext.LeftResolved.LoTypeEl,
  22270. AContext));
  22271. end;
  22272. else RaiseNotSupported(El,AContext,20180401225931,InterfaceTypeNames[TPasClassType(RightTypeEl).InterfaceType]){%H-};
  22273. end;
  22274. end;
  22275. okInterface: ;// IntfVar:=IntfVar
  22276. else
  22277. NotSupported(AssignContext,20180327203326);
  22278. end;
  22279. else
  22280. NotSupported(AssignContext,20180327203334);
  22281. end;
  22282. end;
  22283. end
  22284. else if RightTypeEl.ClassType=TPasRecordType then
  22285. begin
  22286. // right side is a record
  22287. if AssignContext.LeftResolved.BaseType in btAllStrings then
  22288. begin
  22289. if aResolver.IsTGUID(TPasRecordType(RightTypeEl)) then
  22290. begin
  22291. // aString:=GUIDVar -> rtl.guidrToStr(GUIDVar)
  22292. Call:=CreateCallExpression(El);
  22293. Call.Expr:=CreatePrimitiveDotExpr(GetBIName(pbivnRTL)+'.'+GetBIName(pbifnIntfGuidRToStr),El);
  22294. Call.AddArg(AssignContext.RightSide);
  22295. AssignContext.RightSide:=Call;
  22296. end;
  22297. end;
  22298. end
  22299. else if RightTypeEl is TPasProcedureType then
  22300. begin
  22301. LeftTypeEl:=AssignContext.LeftResolved.LoTypeEl;
  22302. if (LeftTypeEl is TPasProcedureType)
  22303. and (TPasProcedureType(AssignContext.LeftResolved.LoTypeEl).CallingConvention=ccSafeCall)
  22304. and (El.Right is TUnaryExpr)
  22305. and (TUnaryExpr(El.Right).OpCode=eopAddress) then
  22306. begin
  22307. // aSafeCall:=@Proc
  22308. AssignContext.RightSide:=CreateSafeCallback(El.Right,AssignContext.RightSide,AContext);
  22309. end;
  22310. end;
  22311. end;
  22312. // convert left side
  22313. LHS:=ConvertExpression(El.Left,AssignContext);
  22314. if AssignContext.Call<>nil then
  22315. begin
  22316. // left side is a Setter -> RightSide was already inserted as parameter
  22317. if AssignContext.RightSide<>nil then
  22318. RaiseInconsistency(20170207215544,El.Left);
  22319. Result:=LHS;
  22320. end
  22321. else
  22322. begin
  22323. // left side is a variable
  22324. if AssignContext.RightSide=nil then
  22325. RaiseInconsistency(20180622211919,El);
  22326. LeftTypeEl:=AssignContext.LeftResolved.LoTypeEl;
  22327. if AssignContext.LeftResolved.BaseType=btContext then
  22328. begin
  22329. if aResolver.IsManagedJSType(LeftTypeEl) then
  22330. begin
  22331. // left side is a COM interface variable (or array of COM intf)
  22332. Result:=CreateAssignManagedVar(AssignContext.LeftResolved,
  22333. LHS,AssignContext.RightSide,AssignContext,El);
  22334. if Result<>nil then exit;
  22335. end;
  22336. end;
  22337. // create normal assign statement
  22338. case El.Kind of
  22339. akDefault: T:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  22340. akAdd: T:=TJSAddEqAssignStatement(CreateElement(TJSAddEqAssignStatement,El));
  22341. akMinus: T:=TJSSubEqAssignStatement(CreateElement(TJSSubEqAssignStatement,El));
  22342. akMul: T:=TJSMulEqAssignStatement(CreateElement(TJSMulEqAssignStatement,El));
  22343. akDivision: T:=TJSDivEqAssignStatement(CreateElement(TJSDivEqAssignStatement,El));
  22344. else RaiseNotSupported(El,AContext,20161107221807){%H-};
  22345. end;
  22346. T.Expr:=AssignContext.RightSide;
  22347. AssignContext.RightSide:=nil;
  22348. T.LHS:=LHS;
  22349. Result:=T;
  22350. LHS:=nil;
  22351. if (bsRangeChecks in AContext.ScannerBoolSwitches)
  22352. and not (T.Expr is TJSLiteral) then
  22353. begin
  22354. // range checks
  22355. if AssignContext.LeftResolved.BaseType in btAllJSInteger then
  22356. begin
  22357. if LeftTypeEl is TPasUnresolvedSymbolRef then
  22358. begin
  22359. if not aResolver.GetIntegerRange(AssignContext.LeftResolved.BaseType,MinVal,MaxVal) then
  22360. RaiseNotSupported(El.Left,AContext,20180119154120);
  22361. Result:=CreateRangeCheck(Result,MinVal,MaxVal,pbifnRangeCheckInt);
  22362. end
  22363. else if LeftTypeEl.ClassType=TPasRangeType then
  22364. Result:=ApplyRangeCheck_Type(Result,LeftTypeEl);
  22365. end
  22366. else if AssignContext.LeftResolved.BaseType in btAllJSChars then
  22367. Result:=ApplyRangeCheck_Type(Result,LeftTypeEl)
  22368. else if AssignContext.LeftResolved.BaseType=btContext then
  22369. begin
  22370. if LeftTypeEl.ClassType=TPasEnumType then
  22371. Result:=ApplyRangeCheck_Type(Result,LeftTypeEl);
  22372. end
  22373. else if AssignContext.LeftResolved.BaseType=btRange then
  22374. begin
  22375. if AssignContext.LeftResolved.SubType in btAllJSRangeCheckTypes then
  22376. Result:=ApplyRangeCheck_Type(Result,LeftTypeEl)
  22377. else if AssignContext.LeftResolved.SubType=btContext then
  22378. Result:=ApplyRangeCheck_Type(Result,LeftTypeEl)
  22379. else
  22380. begin
  22381. {$IFDEF VerbosePas2JS}
  22382. writeln('TPasToJSConverter.ConvertAssignStatement ',GetResolverResultDbg(AssignContext.LeftResolved));
  22383. RaiseNotSupported(El,AContext,20180424121201);
  22384. {$ENDIF}
  22385. end;
  22386. end;
  22387. end;
  22388. end;
  22389. finally
  22390. if Result=nil then
  22391. LHS.Free;
  22392. AssignContext.RightSide.Free;
  22393. AssignContext.Free;
  22394. end;
  22395. end;
  22396. function TPasToJSConverter.ConvertDirectAssignArrayStatement(
  22397. El: TPasImplAssign; AssignContext: TAssignContext): TJSElement;
  22398. // AnArrayVar:=
  22399. var
  22400. RightExpr, FuncExpr: TPasExpr;
  22401. Ref: TResolvedReference;
  22402. Decl: TPasElement;
  22403. BuiltInProc: TResElDataBuiltInProc;
  22404. Params: TParamsExpr;
  22405. begin
  22406. Result:=nil;
  22407. RightExpr:=El.Right;
  22408. if RightExpr.Kind=pekFuncParams then
  22409. begin
  22410. Params:=TParamsExpr(RightExpr);
  22411. FuncExpr:=Params.Value;
  22412. if FuncExpr.CustomData is TResolvedReference then
  22413. begin
  22414. Ref:=TResolvedReference(FuncExpr.CustomData);
  22415. Decl:=Ref.Declaration;
  22416. if Decl.CustomData is TResElDataBuiltInProc then
  22417. begin
  22418. BuiltInProc:=TResElDataBuiltInProc(Decl.CustomData);
  22419. {$IFDEF VerbosePas2JS}
  22420. writeln('TPasToJSConverter.ConvertDirectAssignArrayStatement BuiltInProc ',Decl.Name,' ',ResolverBuiltInProcNames[BuiltInProc.BuiltIn]);
  22421. {$ENDIF}
  22422. case BuiltInProc.BuiltIn of
  22423. bfConcatArray:
  22424. Result:=ConvertDirectAssignArrayConcat(El,Params,AssignContext);
  22425. end;
  22426. end;
  22427. end;
  22428. end
  22429. else if (RightExpr.Kind=pekBinary) and (RightExpr.OpCode=eopAdd) then
  22430. Result:=ConvertDirectAssignArrayAdd(El,TBinaryExpr(RightExpr),AssignContext);
  22431. end;
  22432. function TPasToJSConverter.ConvertDirectAssignArrayConcat(El: TPasImplAssign;
  22433. Params: TParamsExpr; AssignContext: TAssignContext): TJSElement;
  22434. // AnArrayVar:=Concat()
  22435. var
  22436. FirstParam, LeftExpr, SecondParam: TPasExpr;
  22437. LeftRef, ParamRef: TResolvedReference;
  22438. SubParams: TParamsExpr;
  22439. ParentContext: TConvertContext;
  22440. Call: TJSCallExpression;
  22441. i: Integer;
  22442. JS: TJSElement;
  22443. begin
  22444. Result:=nil;
  22445. LeftExpr:=El.Left;
  22446. if not (LeftExpr.CustomData is TResolvedReference) then exit;
  22447. LeftRef:=TResolvedReference(LeftExpr.CustomData);
  22448. FirstParam:=Params.Params[0];
  22449. if FirstParam.CustomData is TResolvedReference then
  22450. begin
  22451. ParamRef:=TResolvedReference(FirstParam.CustomData);
  22452. if LeftRef.Declaration=ParamRef.Declaration then
  22453. begin
  22454. {$IFDEF VerbosePas2JS}
  22455. writeln('TPasToJSConverter.ConvertDirectAssignArrayConcat A:=Concat(A,...)');
  22456. {$ENDIF}
  22457. ParentContext:=AssignContext.Parent;
  22458. if length(Params.Params)=1 then
  22459. begin
  22460. // A:=Concat(A) -> A;
  22461. Result:=ConvertExpression(FirstParam,ParentContext);
  22462. exit;
  22463. end;
  22464. // A:=Concat(A,...) -> append to array
  22465. if length(Params.Params)=2 then
  22466. begin
  22467. SecondParam:=Params.Params[1];
  22468. if (SecondParam.Kind=pekSet) then
  22469. begin
  22470. // A:=Concat(A,[b,c,...])
  22471. SubParams:=TParamsExpr(SecondParam);
  22472. if length(SubParams.Params)=0 then
  22473. begin
  22474. // A:=Concat(A,[]) -> A;
  22475. Result:=ConvertExpression(FirstParam,ParentContext);
  22476. exit;
  22477. end;
  22478. // A:=Concat(A,[b,c]) -> A=rtl.arrayPushN(A,b,c); or arrayPush
  22479. try
  22480. Call:=CreateArrayConcat(AssignContext.LeftResolved.LoTypeEl as TPasArrayType,
  22481. El,ParentContext,true);
  22482. Call.AddArg(ConvertExpression(FirstParam,ParentContext));
  22483. for i:=0 to length(SubParams.Params)-1 do
  22484. begin
  22485. JS:=ConvertExpression(SubParams.Params[i],ParentContext);
  22486. Call.AddArg(JS);
  22487. end;
  22488. if AssignContext.Resolver.IsManagedJSType(AssignContext.LeftResolved.LoTypeEl) then
  22489. Result:=CreateIntfRef(Result,AssignContext,El);
  22490. Result:=Call;
  22491. finally
  22492. if Result=nil then
  22493. Call.Free;
  22494. end;
  22495. end;
  22496. end;
  22497. end;
  22498. end;
  22499. end;
  22500. function TPasToJSConverter.ConvertDirectAssignArrayAdd(El: TPasImplAssign;
  22501. Bin: TBinaryExpr; AssignContext: TAssignContext): TJSElement;
  22502. var
  22503. BinLeft, BinRight: TPasExpr;
  22504. Ref: TResolvedReference;
  22505. Decl: TPasElement;
  22506. ParentContext: TConvertContext;
  22507. SubParams: TParamsExpr;
  22508. Call: TJSCallExpression;
  22509. i: Integer;
  22510. JS: TJSElement;
  22511. begin
  22512. Result:=nil;
  22513. BinLeft:=Bin.Left;
  22514. if not (BinLeft.CustomData is TResolvedReference) then
  22515. exit;
  22516. Ref:=TResolvedReference(BinLeft.CustomData);
  22517. Decl:=Ref.Declaration;
  22518. if not (El.Left.CustomData is TResolvedReference) then exit;
  22519. if (Decl<>TResolvedReference(El.Left.CustomData).Declaration) then
  22520. exit;
  22521. // A:=A+...
  22522. BinRight:=Bin.Right;
  22523. if BinRight.Kind=pekSet then
  22524. begin
  22525. // A:=A+[b,...] -> A=rtl.arrayPush(A,b,...); or arrayPushN
  22526. SubParams:=TParamsExpr(BinRight);
  22527. ParentContext:=AssignContext.Parent;
  22528. if length(SubParams.Params)=0 then
  22529. begin
  22530. // A:=Concat(A,[]) -> A;
  22531. Result:=ConvertExpression(BinLeft,ParentContext);
  22532. exit;
  22533. end;
  22534. try
  22535. Call:=CreateArrayConcat(AssignContext.LeftResolved.LoTypeEl as TPasArrayType,
  22536. El,ParentContext,true);
  22537. Call.AddArg(ConvertExpression(BinLeft,ParentContext));
  22538. for i:=0 to length(SubParams.Params)-1 do
  22539. begin
  22540. JS:=ConvertExpression(SubParams.Params[i],ParentContext);
  22541. //JS:=CreateArrayEl(SubParams.Params[i],ParentContext);
  22542. Call.AddArg(JS);
  22543. end;
  22544. Result:=Call;
  22545. if AssignContext.Resolver.IsManagedJSType(AssignContext.LeftResolved.LoTypeEl) then
  22546. Result:=CreateIntfRef(Result,AssignContext,El);
  22547. finally
  22548. if Result=nil then
  22549. Call.Free;
  22550. end;
  22551. end;
  22552. end;
  22553. function TPasToJSConverter.ConvertIfStatement(El: TPasImplIfElse;
  22554. AContext: TConvertContext): TJSElement;
  22555. Var
  22556. C, BThen, BElse: TJSElement;
  22557. T: TJSIfStatement;
  22558. begin
  22559. Result:=nil;
  22560. if AContext=nil then ;
  22561. C:=Nil;
  22562. BThen:=Nil;
  22563. BElse:=Nil;
  22564. try
  22565. C:=ConvertExpression(El.ConditionExpr,AContext);
  22566. if Assigned(El.IfBranch) then
  22567. BThen:=ConvertElement(El.IfBranch,AContext);
  22568. if Assigned(El.ElseBranch) then
  22569. BElse:=ConvertElement(El.ElseBranch,AContext);
  22570. T:=TJSIfStatement(CreateElement(TJSIfStatement,El));
  22571. T.Cond:=C;
  22572. T.BTrue:=BThen;
  22573. T.BFalse:=BElse;
  22574. Result:=T;
  22575. finally
  22576. if Result=nil then
  22577. begin
  22578. FreeAndNil(C);
  22579. FreeAndNil(BThen);
  22580. FreeAndNil(BElse);
  22581. end;
  22582. end;
  22583. end;
  22584. function TPasToJSConverter.ConvertWhileStatement(El: TPasImplWhileDo;
  22585. AContext: TConvertContext): TJSElement;
  22586. Var
  22587. C : TJSElement;
  22588. B : TJSElement;
  22589. W : TJSWhileStatement;
  22590. ok: Boolean;
  22591. begin
  22592. Result:=Nil;
  22593. C:=Nil;
  22594. B:=Nil;
  22595. ok:=false;
  22596. try
  22597. C:=ConvertExpression(El.ConditionExpr,AContext);
  22598. if Assigned(El.Body) then
  22599. B:=ConvertElement(El.Body,AContext)
  22600. else
  22601. B:=TJSEmptyBlockStatement(CreateElement(TJSEmptyBlockStatement,El));
  22602. ok:=true;
  22603. finally
  22604. if not ok then
  22605. begin
  22606. FreeAndNil(B);
  22607. FreeAndNil(C);
  22608. end;
  22609. end;
  22610. W:=TJSWhileStatement(CreateElement(TJSWhileStatement,El));
  22611. W.Cond:=C;
  22612. W.Body:=B;
  22613. Result:=W;
  22614. end;
  22615. function TPasToJSConverter.ConvertRepeatStatement(El: TPasImplRepeatUntil;
  22616. AContext: TConvertContext): TJSElement;
  22617. // do{implblock}while(!untilcondition);
  22618. var
  22619. C : TJSElement;
  22620. W : TJSDoWhileStatement;
  22621. B : TJSElement;
  22622. begin
  22623. Result:=Nil;
  22624. C:=Nil;
  22625. B:=Nil;
  22626. try
  22627. C:=ConvertExpression(El.ConditionExpr,AContext);
  22628. if C is TJSUnaryNotExpression then
  22629. begin
  22630. // Note: do..while(condition) checks for truthiness, same as the ! operator
  22631. // therefore do..while(!!expr) is the same as do..while(expr)
  22632. B:=C;
  22633. C:=TJSUnaryNotExpression(B).A;
  22634. TJSUnaryNotExpression(B).A:=nil;
  22635. B.Free;
  22636. B:=nil;
  22637. end
  22638. else
  22639. C:=CreateUnaryNot(C,El.ConditionExpr);
  22640. B:=ConvertImplBlockElements(El,AContext,false);
  22641. W:=TJSDoWhileStatement(CreateElement(TJSDoWhileStatement,El));
  22642. W.Cond:=C;
  22643. W.Body:=B;
  22644. Result:=W;
  22645. finally
  22646. if Result=nil then
  22647. begin
  22648. FreeAndNil(B);
  22649. FreeAndNil(C);
  22650. end;
  22651. end;
  22652. end;
  22653. function TPasToJSConverter.ConvertForStatement(El: TPasImplForLoop;
  22654. AContext: TConvertContext): TJSElement;
  22655. // Creates the following code:
  22656. // for (var $loop1 = <startexpr>, $loopend = <endexpr>; $loop<=$loopend; $loop++){
  22657. // VariableName = $loop;
  22658. // ...Body...
  22659. // }
  22660. //
  22661. // For compatibility:
  22662. // LoopVar can be a varname or programname.varname
  22663. // The StartExpr must be executed exactly once at beginning.
  22664. // The EndExpr must be executed exactly once at beginning.
  22665. // If the loop is not executed the Variable is not set, aka keeps its old value.
  22666. // After the loop the variable has the last value.
  22667. type
  22668. TInKind = (
  22669. ikNone,
  22670. ikEnum,
  22671. ikBool,
  22672. ikChar,
  22673. ikString,
  22674. ikArray,
  22675. ikArrayManaged,
  22676. ikSetInt,
  22677. ikSetBool,
  22678. ikSetChar,
  22679. ikSetString
  22680. );
  22681. var
  22682. aResolver: TPas2JSResolver;
  22683. function ConvExpr(Expr: TPasExpr): TJSElement; overload;
  22684. var
  22685. ResolvedEl: TPasResolverResult;
  22686. begin
  22687. Result:=ConvertExpression(Expr,AContext);
  22688. if Result is TJSLiteral then
  22689. case TJSLiteral(Result).Value.ValueType of
  22690. jstBoolean:
  22691. // convert bool literal to int
  22692. TJSLiteral(Result).Value.AsNumber:=ord(TJSLiteral(Result).Value.AsBoolean);
  22693. jstNumber:
  22694. exit;
  22695. jstString:
  22696. begin
  22697. // convert char literal to int
  22698. ConvertCharLiteralToInt(TJSLiteral(Result),Expr,AContext);
  22699. exit;
  22700. end;
  22701. else
  22702. Result.Free;
  22703. RaiseNotSupported(Expr,AContext,20171112021222);
  22704. end
  22705. else if aResolver<>nil then
  22706. begin
  22707. aResolver.ComputeElement(Expr,ResolvedEl,[]);
  22708. if (ResolvedEl.BaseType in btAllChars)
  22709. or ((ResolvedEl.BaseType=btRange) and (ResolvedEl.SubType in btAllChars)) then
  22710. begin
  22711. // convertchar variable to int: append .charCodeAt()
  22712. Result:=CreateCallCharCodeAt(Result,0,Expr);
  22713. end
  22714. else if (ResolvedEl.BaseType in btAllJSBooleans)
  22715. or ((ResolvedEl.BaseType=btRange) and (ResolvedEl.SubType in btAllJSBooleans)) then
  22716. begin
  22717. // convert bool variable to int: +expr
  22718. Result:=CreateUnaryPlus(Result,Expr);
  22719. end;
  22720. end;
  22721. end;
  22722. function GetOrd(Value: TResEvalValue; ErrorEl: TPasElement): TMaxPrecInt; overload;
  22723. var
  22724. OrdValue: TResEvalValue;
  22725. begin
  22726. if Value=nil then
  22727. exit(0);
  22728. OrdValue:=aResolver.ExprEvaluator.OrdValue(Value,ErrorEl);
  22729. case OrdValue.Kind of
  22730. revkInt: Result:=TResEvalInt(OrdValue).Int;
  22731. else
  22732. RaiseNotSupported(ErrorEl,AContext,20171112133917);
  22733. end;
  22734. if Value<>OrdValue then
  22735. ReleaseEvalValue(OrdValue);
  22736. end;
  22737. function GetEnumValue(EnumType: TPasEnumType; Int: TMaxPrecInt): TResEvalValue; overload;
  22738. begin
  22739. if (coEnumNumbers in Options) or (Int<0) or (Int>=EnumType.Values.Count) then
  22740. Result:=TResEvalInt.CreateValue(Int)
  22741. else
  22742. Result:=TResEvalEnum.CreateValue(Int,TObject(EnumType.Values[Int]) as TPasEnumValue);
  22743. end;
  22744. var
  22745. FuncContext: TFunctionContext;
  22746. VarResolved, InResolved: TPasResolverResult;
  22747. StartValue, EndValue, InValue: TResEvalValue;
  22748. StartInt, EndInt: TMaxPrecInt;
  22749. HasLoopVar, HasEndVar, HasInVar: Boolean;
  22750. InKind: TInKind;
  22751. ForScope: TPasForLoopScope;
  22752. function InitWithResolver: boolean;
  22753. var
  22754. EnumType: TPasEnumType;
  22755. TypeEl: TPasType;
  22756. ArgResolved, LengthResolved, PropResultResolved: TPasResolverResult;
  22757. begin
  22758. Result:=true;
  22759. aResolver.ComputeElement(El.VariableName,VarResolved,[rcNoImplicitProc]);
  22760. if (not (VarResolved.IdentEl is TPasVariable))
  22761. and not (VarResolved.IdentEl is TPasResultElement) then
  22762. DoError(20170213214404,nXExpectedButYFound,sXExpectedButYFound,['var',
  22763. aResolver.GetResolverResultDescription(VarResolved)],El.VariableName);
  22764. case El.LoopType of
  22765. ltNormal,ltDown:
  22766. begin
  22767. StartValue:=aResolver.Eval(El.StartExpr,[],false);
  22768. StartInt:=GetOrd(StartValue,El.StartExpr);
  22769. EndValue:=aResolver.Eval(El.EndExpr,[],false);
  22770. EndInt:=GetOrd(EndValue,El.EndExpr);
  22771. end;
  22772. ltIn:
  22773. begin
  22774. if ForScope.GetEnumerator<>nil then
  22775. begin
  22776. ConvertForStatement:=CreateGetEnumeratorLoop(El,AContext);
  22777. exit(false);
  22778. end;
  22779. aResolver.ComputeElement(El.StartExpr,InResolved,[]);
  22780. HasInVar:=true;
  22781. InValue:=aResolver.Eval(El.StartExpr,[],false);
  22782. if InValue=nil then
  22783. begin
  22784. if InResolved.IdentEl is TPasType then
  22785. begin
  22786. TypeEl:=aResolver.ResolveAliasType(TPasType(InResolved.IdentEl));
  22787. if TypeEl is TPasArrayType then
  22788. begin
  22789. if length(TPasArrayType(TypeEl).Ranges)=1 then
  22790. InValue:=aResolver.Eval(TPasArrayType(TypeEl).Ranges[0],[refConst]);
  22791. end
  22792. else if TypeEl is TPasSetType then
  22793. InValue:=aResolver.EvalTypeRange(TPasSetType(TypeEl).EnumType,[refConst]);
  22794. end;
  22795. end;
  22796. if InValue<>nil then
  22797. begin
  22798. // for <var> in <constant> do
  22799. case InValue.Kind of
  22800. {$IFDEF FPC_HAS_CPSTRING}
  22801. revkString,
  22802. {$ENDIF}
  22803. revkUnicodeString:
  22804. begin
  22805. // example:
  22806. // for c in 'foo' do ;
  22807. // -> for (var $l1 = 0, $li2 = 'foo'; $l1<=2; $l1++) c = $li2.charAt($l1);
  22808. InKind:=ikString;
  22809. StartInt:=0;
  22810. {$IFDEF FPC_HAS_CPSTRING}
  22811. if InValue.Kind=revkString then
  22812. EndInt:=TMaxPrecInt(length(UTF8Decode(TResEvalString(InValue).S)))-1
  22813. else
  22814. {$ENDIF}
  22815. EndInt:=TMaxPrecInt(length(TResEvalUTF16(InValue).S))-1;
  22816. ReleaseEvalValue(InValue);
  22817. end;
  22818. revkRangeInt,revkSetOfInt:
  22819. begin
  22820. if InValue.Kind=revkSetOfInt then
  22821. begin
  22822. if length(TResEvalSet(InValue).Ranges)=0 then
  22823. exit(false);
  22824. if length(TResEvalSet(InValue).Ranges)>1 then
  22825. begin
  22826. // set, non continuous range
  22827. case TResEvalSet(InValue).ElKind of
  22828. revskEnum,revskInt: InKind:=ikSetInt;
  22829. revskChar: InKind:=ikSetChar;
  22830. revskBool: InKind:=ikSetBool;
  22831. end;
  22832. HasInVar:=false;
  22833. HasLoopVar:=InKind<>ikSetInt;
  22834. HasEndVar:=false;
  22835. exit;
  22836. end;
  22837. end;
  22838. StartInt:=TResEvalRangeInt(InValue).RangeStart;
  22839. EndInt:=TResEvalRangeInt(InValue).RangeEnd;
  22840. HasInVar:=false;
  22841. HasEndVar:=false;
  22842. case TResEvalRangeInt(InValue).ElKind of
  22843. revskEnum:
  22844. if coEnumNumbers in Options then
  22845. InKind:=ikNone
  22846. else
  22847. begin
  22848. InKind:=ikEnum;
  22849. EnumType:=TPasEnumType(TResEvalRangeInt(InValue).ElType);
  22850. StartValue:=GetEnumValue(EnumType,StartInt);
  22851. EndValue:=GetEnumValue(EnumType,EndInt);
  22852. end;
  22853. revskInt:
  22854. InKind:=ikNone;
  22855. revskChar:
  22856. InKind:=ikChar;
  22857. revskBool:
  22858. InKind:=ikBool;
  22859. else
  22860. {$IFDEF VerbosePas2JS}
  22861. writeln('TPasToJSConverter.ConvertForStatement ',GetObjName(El.StartExpr),' InValue=',InValue.AsDebugString);
  22862. {$ENDIF}
  22863. RaiseNotSupported(El.StartExpr,AContext,20171113023419);
  22864. end;
  22865. end
  22866. else
  22867. {$IFDEF VerbosePas2JS}
  22868. writeln('TPasToJSConverter.ConvertForStatement ',GetObjName(El.StartExpr),' InValue=',InValue.AsDebugString);
  22869. {$ENDIF}
  22870. RaiseNotSupported(El.StartExpr,AContext,20171112161527);
  22871. end;
  22872. end
  22873. else if rrfReadable in InResolved.Flags then
  22874. begin
  22875. // for v in <variable> do
  22876. if InResolved.BaseType in btAllStrings then
  22877. begin
  22878. // for v in string do
  22879. InKind:=ikString;
  22880. StartInt:=0;
  22881. end
  22882. else if InResolved.BaseType=btCustom then
  22883. begin
  22884. if aResolver.IsJSBaseType(InResolved,pbtJSValue) then
  22885. begin
  22886. // for v in jsvalue do
  22887. InKind:=ikSetString;
  22888. HasInVar:=false;
  22889. HasLoopVar:=false;
  22890. HasEndVar:=false;
  22891. exit;
  22892. end;
  22893. end
  22894. else if InResolved.BaseType=btContext then
  22895. begin
  22896. TypeEl:=InResolved.LoTypeEl;
  22897. if TypeEl.ClassType=TPasArrayType then
  22898. begin
  22899. if length(TPasArrayType(TypeEl).Ranges)<=1 then
  22900. begin
  22901. if aResolver.IsManagedJSType(VarResolved.LoTypeEl) then
  22902. InKind:=ikArrayManaged
  22903. else
  22904. InKind:=ikArray;
  22905. StartInt:=0;
  22906. end
  22907. else
  22908. begin
  22909. {$IFDEF VerbosePas2JS}
  22910. writeln('TPasToJSConverter.ConvertForStatement.InitWithResolver ResolvedIn=',GetResolverResultDbg(InResolved),' length(Ranges)=',length(TPasArrayType(TypeEl).Ranges));
  22911. {$ENDIF}
  22912. RaiseNotSupported(El.StartExpr,AContext,20171220010147);
  22913. end;
  22914. end
  22915. else if (TypeEl.ClassType=TPasClassType) and TPasClassType(TypeEl).IsExternal then
  22916. begin
  22917. if aResolver.IsForInExtArray(El,VarResolved,InResolved,
  22918. ArgResolved,LengthResolved,PropResultResolved) then
  22919. begin
  22920. // for v in JSArray do
  22921. InKind:=ikArray;
  22922. StartInt:=0;
  22923. end
  22924. else
  22925. begin
  22926. // for v in jsobject do -> for(v in jsobject){ }
  22927. InKind:=ikSetString;
  22928. HasInVar:=false;
  22929. HasLoopVar:=false;
  22930. HasEndVar:=false;
  22931. exit;
  22932. end;
  22933. end
  22934. else
  22935. begin
  22936. {$IFDEF VerbosePas2JS}
  22937. writeln('TPasToJSConverter.ConvertForStatement.InitWithResolver El.StartExpr=',GetObjName(El.StartExpr),' ResolvedIn=',GetResolverResultDbg(InResolved));
  22938. {$ENDIF}
  22939. RaiseNotSupported(El.StartExpr,AContext,20171113012226);
  22940. end;
  22941. end
  22942. else if InResolved.BaseType in [btSet,btArrayOrSet] then
  22943. begin
  22944. if InResolved.SubType in btAllJSBooleans then
  22945. InKind:=ikSetBool
  22946. else if InResolved.SubType in btAllChars then
  22947. InKind:=ikSetChar
  22948. else
  22949. InKind:=ikSetInt;
  22950. HasInVar:=false;
  22951. HasLoopVar:=true;
  22952. HasEndVar:=false;
  22953. exit;
  22954. end
  22955. else
  22956. begin
  22957. {$IFDEF VerbosePas2JS}
  22958. writeln('TPasToJSConverter.ConvertForStatement.InitWithResolver ResolvedIn=',GetResolverResultDbg(InResolved));
  22959. {$ENDIF}
  22960. RaiseNotSupported(El.StartExpr,AContext,20171220221747);
  22961. end;
  22962. end
  22963. else
  22964. begin
  22965. {$IFDEF VerbosePas2JS}
  22966. writeln('TPasToJSConverter.ConvertForStatement.InitWithResolver ResolvedIn=',GetResolverResultDbg(InResolved));
  22967. {$ENDIF}
  22968. RaiseNotSupported(El.StartExpr,AContext,20171112195629);
  22969. end;
  22970. end;
  22971. end;
  22972. if EndValue<>nil then
  22973. begin
  22974. HasEndVar:=false;
  22975. if (StartValue<>nil) then
  22976. begin
  22977. if StartInt<=EndInt then
  22978. begin
  22979. // loop is always executed
  22980. if StartValue.Kind in [revkInt,revkUInt,revkEnum] then
  22981. HasLoopVar:=false; // variable can be used as runner
  22982. end
  22983. else
  22984. begin
  22985. // loop is never executed
  22986. if coEliminateDeadCode in Options then exit;
  22987. end;
  22988. end;
  22989. end;
  22990. end;
  22991. function CreateStrictNotEqual0(Left: TJSElement; PosEl: TPasElement): TJSElement;
  22992. var
  22993. SNE: TJSEqualityExpressionSNE;
  22994. begin
  22995. SNE:=TJSEqualityExpressionSNE(CreateElement(TJSEqualityExpressionSNE,PosEl));
  22996. SNE.A:=Left;
  22997. SNE.B:=CreateLiteralNumber(PosEl,0);
  22998. Result:=SNE;
  22999. end;
  23000. Var
  23001. ForSt : TJSBodyStatement;
  23002. List: TJSStatementList;
  23003. SimpleAss : TJSSimpleAssignStatement;
  23004. Incr: TJSUNaryExpression;
  23005. BinExp : TJSBinaryExpression;
  23006. VarStat: TJSVariableStatement;
  23007. CurLoopVarName, CurEndVarName, CurInVarName: String;
  23008. PosEl: TPasElement;
  23009. Statements, V: TJSElement;
  23010. Call: TJSCallExpression;
  23011. Br: TJSBracketMemberExpression;
  23012. begin
  23013. Result:=Nil;
  23014. if AContext.Access<>caRead then
  23015. RaiseInconsistency(20170213213740,El);
  23016. aResolver:=AContext.Resolver;
  23017. ForScope:=El.CustomData as TPasForLoopScope; // can be nil!
  23018. case El.LoopType of
  23019. ltNormal,ltDown: ;
  23020. ltIn:
  23021. if aResolver=nil then
  23022. RaiseNotSupported(El,AContext,20171112160707);
  23023. else
  23024. {$IFDEF VerbosePas2JS}
  23025. writeln('TPasToJSConverter.ConvertForStatement LoopType=',El.LoopType){%H-};
  23026. {$ENDIF}
  23027. RaiseNotSupported(El,AContext,20171110141937){%H-};
  23028. end;
  23029. // get function context
  23030. FuncContext:=AContext.GetFunctionContext;
  23031. StartValue:=nil;
  23032. StartInt:=0;
  23033. EndValue:=nil;
  23034. EndInt:=0;
  23035. InValue:=nil;
  23036. InKind:=ikNone;
  23037. Statements:=nil;
  23038. try
  23039. HasLoopVar:=true;
  23040. HasEndVar:=true;
  23041. HasInVar:=false;
  23042. if (aResolver<>nil) and not InitWithResolver then
  23043. exit;
  23044. // create unique var names $l, $end, $in
  23045. if FuncContext=nil then
  23046. begin
  23047. CurInVarName:='$in';
  23048. CurLoopVarName:='$l';
  23049. CurEndVarName:='$end';
  23050. end
  23051. else
  23052. begin
  23053. if HasInVar then
  23054. CurInVarName:=FuncContext.AddLocalJSVar(GetBIName(pbivnLoopIn),true).Name
  23055. else
  23056. CurInVarName:='';
  23057. if HasLoopVar then
  23058. CurLoopVarName:=FuncContext.AddLocalJSVar(GetBIName(pbivnLoop),true).Name
  23059. else
  23060. CurLoopVarName:='';
  23061. if HasEndVar then
  23062. CurEndVarName:=FuncContext.AddLocalJSVar(GetBIName(pbivnLoopEnd),true).Name
  23063. else
  23064. CurEndVarName:='';
  23065. end;
  23066. // add "for()"
  23067. if InKind in [ikSetInt,ikSetBool,ikSetChar,ikSetString] then
  23068. ForSt:=TJSForInStatement(CreateElement(TJSForInStatement,El))
  23069. else
  23070. ForSt:=TJSForStatement(CreateElement(TJSForStatement,El));
  23071. Statements:=ForSt;
  23072. PosEl:=El;
  23073. // add in front of for(): variable=<startexpr>
  23074. if (not HasLoopVar) and (HasEndVar or HasInVar) then
  23075. begin
  23076. // for example:
  23077. // i=<startexpr>;
  23078. // for (var $end = <endexpr>; $i<$end; $i++)...
  23079. List:=TJSStatementList(CreateElement(TJSStatementList,El));
  23080. SimpleAss:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El.VariableName));
  23081. List.A:=SimpleAss;
  23082. List.B:=Statements;
  23083. Statements:=List;
  23084. SimpleAss.LHS:=ConvertExpression(El.VariableName,AContext);
  23085. if StartValue<>nil then
  23086. SimpleAss.Expr:=CreateLiteralNumber(El.StartExpr,StartInt)
  23087. else
  23088. SimpleAss.Expr:=ConvertExpression(El.StartExpr,AContext);
  23089. PosEl:=El.StartExpr;
  23090. end;
  23091. if ForSt.ClassType=TJSForInStatement then
  23092. begin
  23093. if HasLoopVar then
  23094. begin
  23095. // add for("var $l" in <startexpr>)
  23096. VarStat:=TJSVariableStatement(CreateElement(TJSVariableStatement,PosEl));
  23097. VarStat.VarDecl:=CreatePrimitiveDotExpr(CurLoopVarName,PosEl);
  23098. TJSForInStatement(ForSt).LHS:=VarStat;
  23099. end
  23100. else
  23101. // add for("<varname>" in <startexpr>)
  23102. TJSForInStatement(ForSt).LHS:=ConvertExpression(El.VariableName,AContext);
  23103. // add for(<varname> in "<startexpr>")
  23104. TJSForInStatement(ForSt).List:=ConvertExpression(El.StartExpr,AContext);
  23105. end
  23106. else if HasLoopVar or HasEndVar or HasInVar then
  23107. begin
  23108. // add "for(var ..."
  23109. VarStat:=TJSVariableStatement(CreateElement(TJSVariableStatement,El));
  23110. TJSForStatement(ForSt).Init:=VarStat;
  23111. if HasInVar then
  23112. begin
  23113. // add "$in=<InExpr>"
  23114. PosEl:=El.StartExpr;
  23115. if (InValue<>nil) and (InValue.Kind<>revkSetOfInt) then
  23116. V:=ConvertConstValue(InValue,AContext,PosEl)
  23117. else
  23118. V:=ConvertExpression(El.StartExpr,AContext);
  23119. V:=CreateVarDecl(CurInVarName,V,PosEl);
  23120. AddToVarStatement(VarStat,V,PosEl);
  23121. end;
  23122. if HasLoopVar then
  23123. begin
  23124. // add "$l=<StartExpr>"
  23125. PosEl:=El.StartExpr;
  23126. if StartValue<>nil then
  23127. V:=CreateLiteralNumber(PosEl,StartInt)
  23128. else if El.LoopType=ltIn then
  23129. V:=CreateLiteralNumber(PosEl,StartInt)
  23130. else
  23131. V:=ConvExpr(El.StartExpr);
  23132. V:=CreateVarDecl(CurLoopVarName,V,PosEl);
  23133. AddToVarStatement(VarStat,V,PosEl);
  23134. end;
  23135. if HasEndVar then
  23136. begin
  23137. // add "$end=<EndExpr>"
  23138. PosEl:=El.EndExpr;
  23139. if PosEl=nil then
  23140. PosEl:=El.StartExpr;
  23141. if EndValue<>nil then
  23142. V:=CreateLiteralNumber(PosEl,EndInt)
  23143. else if El.LoopType=ltIn then
  23144. case InKind of
  23145. ikEnum,ikBool,ikChar:
  23146. V:=CreateLiteralNumber(PosEl,EndInt);
  23147. ikString:
  23148. begin
  23149. // add "$in.length-1"
  23150. V:=TJSAdditiveExpressionMinus(CreateElement(TJSAdditiveExpressionMinus,PosEl));
  23151. TJSAdditiveExpressionMinus(V).A:=CreatePrimitiveDotExpr(CurInVarName+'.length',PosEl);
  23152. TJSAdditiveExpressionMinus(V).B:=CreateLiteralNumber(PosEl,1);
  23153. end;
  23154. ikArray,ikArrayManaged:
  23155. begin
  23156. // add "rtl.length($in)-1"
  23157. Call:=CreateCallExpression(PosEl);
  23158. Call.Expr:=CreatePrimitiveDotExpr(GetBIName(pbivnRTL)+'.'+GetBIName(pbifnArray_Length),PosEl);
  23159. Call.AddArg(CreatePrimitiveDotExpr(CurInVarName,PosEl));
  23160. V:=TJSAdditiveExpressionMinus(CreateElement(TJSAdditiveExpressionMinus,PosEl));
  23161. TJSAdditiveExpressionMinus(V).A:=Call;
  23162. TJSAdditiveExpressionMinus(V).B:=CreateLiteralNumber(PosEl,1);
  23163. end;
  23164. else
  23165. RaiseNotSupported(El.StartExpr,AContext,20171113015445);
  23166. end
  23167. else
  23168. V:=ConvExpr(El.EndExpr);
  23169. V:=CreateVarDecl(CurEndVarName,V,PosEl);
  23170. AddToVarStatement(VarStat,V,PosEl);
  23171. end;
  23172. end
  23173. else
  23174. begin
  23175. // No new vars. For example:
  23176. // for (VariableName = <startexpr>; VariableName <= <EndExpr>; VariableName++)
  23177. SimpleAss:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El.VariableName));
  23178. TJSForStatement(ForSt).Init:=SimpleAss;
  23179. SimpleAss.LHS:=ConvertExpression(El.VariableName,AContext);
  23180. if StartValue<>nil then
  23181. SimpleAss.Expr:=CreateLiteralNumber(El.StartExpr,StartInt)
  23182. else
  23183. SimpleAss.Expr:=ConvertExpression(El.StartExpr,AContext);
  23184. PosEl:=El.StartExpr;
  23185. end;
  23186. if ForSt.ClassType=TJSForStatement then
  23187. begin
  23188. // add "$l<=$end"
  23189. if (El.EndExpr<>nil) then
  23190. PosEl:=El.EndExpr;
  23191. if El.Down then
  23192. BinExp:=TJSRelationalExpressionGE(CreateElement(TJSRelationalExpressionGE,PosEl))
  23193. else
  23194. BinExp:=TJSRelationalExpressionLE(CreateElement(TJSRelationalExpressionLE,PosEl));
  23195. TJSForStatement(ForSt).Cond:=BinExp;
  23196. if HasLoopVar then
  23197. BinExp.A:=CreatePrimitiveDotExpr(CurLoopVarName,PosEl)
  23198. else
  23199. BinExp.A:=ConvertExpression(El.VariableName,AContext);
  23200. if HasEndVar then
  23201. BinExp.B:=CreatePrimitiveDotExpr(CurEndVarName,PosEl)
  23202. else
  23203. BinExp.B:=CreateLiteralNumber(PosEl,EndInt);
  23204. // add "$l++"
  23205. if El.Down then
  23206. Incr:=TJSUnaryPostMinusMinusExpression(CreateElement(TJSUnaryPostMinusMinusExpression,PosEl))
  23207. else
  23208. Incr:=TJSUnaryPostPlusPlusExpression(CreateElement(TJSUnaryPostPlusPlusExpression,PosEl));
  23209. TJSForStatement(ForSt).Incr:=Incr;
  23210. if HasLoopVar then
  23211. Incr.A:=CreatePrimitiveDotExpr(CurLoopVarName,PosEl)
  23212. else
  23213. Incr.A:=ConvertExpression(El.VariableName,AContext);
  23214. end;
  23215. // add "VariableName:=$l;"
  23216. if HasLoopVar then
  23217. begin
  23218. PosEl:=El.Body;
  23219. if PosEl=nil then
  23220. PosEl:=El;
  23221. PosEl:=El.VariableName;
  23222. SimpleAss:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,PosEl));
  23223. ForSt.Body:=SimpleAss;
  23224. SimpleAss.LHS:=ConvertExpression(El.VariableName,AContext);
  23225. SimpleAss.Expr:=CreatePrimitiveDotExpr(CurLoopVarName,PosEl);
  23226. if aResolver<>nil then
  23227. begin
  23228. if InKind<>ikNone then
  23229. case InKind of
  23230. ikEnum,ikSetInt:
  23231. if ForSt.ClassType=TJSForInStatement then
  23232. // $in=+$l
  23233. SimpleAss.Expr:=CreateUnaryPlus(SimpleAss.Expr,PosEl);
  23234. ikBool,ikSetBool:
  23235. // $in!==0;
  23236. SimpleAss.Expr:=CreateStrictNotEqual0(SimpleAss.Expr,PosEl);
  23237. ikChar,ikSetChar:
  23238. // String.fromCharCode($l)
  23239. SimpleAss.Expr:=CreateCallFromCharCode(SimpleAss.Expr,PosEl);
  23240. ikString:
  23241. begin
  23242. // $in.charAt($l)
  23243. Call:=CreateCallExpression(PosEl);
  23244. Call.Expr:=CreateDotNameExpr(PosEl,
  23245. CreatePrimitiveDotExpr(CurInVarName,El.StartExpr),
  23246. 'charAt');
  23247. Call.AddArg(SimpleAss.Expr);
  23248. SimpleAss.Expr:=Call;
  23249. end;
  23250. ikArray,ikArrayManaged:
  23251. begin
  23252. // $in[$l]
  23253. Br:=TJSBracketMemberExpression(CreateElement(TJSBracketMemberExpression,PosEl));
  23254. Br.MExpr:=CreatePrimitiveDotExpr(CurInVarName,El.StartExpr);
  23255. Br.Name:=SimpleAss.Expr;
  23256. SimpleAss.Expr:=Br;
  23257. if InKind=ikArrayManaged then
  23258. begin
  23259. // VarName=rtl.setIntfL(VarName,$in[$l])
  23260. Call:=CreateCallExpression(PosEl);
  23261. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnIntfSetIntfL)]);
  23262. Call.AddArg(ConvertExpression(El.VariableName,AContext));
  23263. Call.AddArg(Br);
  23264. SimpleAss.Expr:=Call;
  23265. if VarResolved.IdentEl=nil then
  23266. RaiseNotSupported(El.VariableName,AContext,20250625190022,'for-in variable');
  23267. FuncContext.Add_InterfaceRelease(VarResolved.IdentEl)
  23268. end;
  23269. end;
  23270. else
  23271. {$IFDEF VerbosePas2JS}
  23272. writeln('TPasToJSConverter.ConvertForStatement InKind=',InKind);
  23273. {$ENDIF}
  23274. RaiseNotSupported(El.StartExpr,AContext,20171113002550);
  23275. end
  23276. else if (VarResolved.BaseType in btAllChars)
  23277. or ((VarResolved.BaseType=btRange) and (VarResolved.SubType in btAllChars)) then
  23278. begin
  23279. // convert int to char
  23280. SimpleAss.Expr:=CreateCallFromCharCode(SimpleAss.Expr,PosEl);
  23281. end
  23282. else if (VarResolved.BaseType in btAllJSBooleans)
  23283. or ((VarResolved.BaseType=btRange) and (VarResolved.SubType in btAllJSBooleans)) then
  23284. begin
  23285. // convert int to bool -> $l!=0
  23286. SimpleAss.Expr:=CreateStrictNotEqual0(SimpleAss.Expr,PosEl);
  23287. end
  23288. end;
  23289. end;
  23290. // add body
  23291. if El.Body<>nil then
  23292. begin
  23293. V:=ConvertElement(El.Body,AContext);
  23294. if ForSt.Body=nil then
  23295. ForSt.Body:=V
  23296. else
  23297. begin
  23298. List:=TJSStatementList(CreateElement(TJSStatementList,El.Body));
  23299. List.A:=ForSt.Body;
  23300. List.B:=V;
  23301. ForSt.Body:=List;
  23302. end;
  23303. end;
  23304. Result:=Statements;
  23305. finally
  23306. ReleaseEvalValue(StartValue);
  23307. ReleaseEvalValue(EndValue);
  23308. ReleaseEvalValue(InValue);
  23309. if Result=nil then
  23310. Statements.Free;
  23311. end;
  23312. end;
  23313. function TPasToJSConverter.ConvertSimpleStatement(El: TPasImplSimple;
  23314. AContext: TConvertContext): TJSElement;
  23315. Var
  23316. E : TJSElement;
  23317. C: TClass;
  23318. begin
  23319. E:=ConvertExpression(EL.Expr,AContext);
  23320. if E=nil then
  23321. exit(nil); // e.g. "inherited;" without ancestor proc
  23322. C:=E.ClassType;
  23323. if (C=TJSExpressionStatement)
  23324. or (C=TJSStatementList) then
  23325. Result:=E
  23326. else
  23327. begin
  23328. Result:=TJSExpressionStatement(CreateElement(TJSExpressionStatement,El));
  23329. TJSExpressionStatement(Result).A:=E;
  23330. end;
  23331. end;
  23332. function TPasToJSConverter.ConvertWithStatement(El: TPasImplWithDo;
  23333. AContext: TConvertContext): TJSElement;
  23334. Var
  23335. aResolver: TPas2JSResolver;
  23336. FuncContext: TFunctionContext;
  23337. WithScope: TPasWithScope;
  23338. WithExprScope: TPas2JSWithExprScope;
  23339. PasExpr: TPasExpr;
  23340. ResolvedEl: TPasResolverResult;
  23341. B,E , Expr: TJSElement;
  23342. W,W2 : TJSWithStatement;
  23343. I : Integer;
  23344. ok: Boolean;
  23345. V: TJSVariableStatement;
  23346. FirstSt, LastSt: TJSStatementList;
  23347. TypeEl: TPasType;
  23348. begin
  23349. Result:=nil;
  23350. aResolver:=AContext.Resolver;
  23351. if aResolver<>nil then
  23352. begin
  23353. // with Resolver:
  23354. // Insert for each expression a local var. Example:
  23355. // with aPoint do X:=3;
  23356. // convert to
  23357. // var $with1 = aPoint;
  23358. // $with1.X = 3;
  23359. FuncContext:=TFunctionContext(AContext.GetContextOfType(TFunctionContext));
  23360. if FuncContext=nil then
  23361. RaiseInconsistency(20170212003759,El);
  23362. FirstSt:=nil;
  23363. LastSt:=nil;
  23364. try
  23365. WithScope:=El.CustomData as TPasWithScope;
  23366. for i:=0 to El.Expressions.Count-1 do
  23367. begin
  23368. PasExpr:=TPasExpr(El.Expressions[i]);
  23369. aResolver.ComputeElement(PasExpr,ResolvedEl,[]);
  23370. if ResolvedEl.IdentEl is TPasType then
  23371. begin
  23372. TypeEl:=ResolvedEl.LoTypeEl;
  23373. if (TypeEl.ClassType=TPasClassType)
  23374. or (TypeEl.ClassType=TPasRecordType)
  23375. or (TypeEl.ClassType=TPasEnumType) then
  23376. // have JS object -> ok
  23377. else
  23378. begin
  23379. // e.g. "with byte do" allowed with type helpers
  23380. continue;
  23381. end;
  23382. end;
  23383. Expr:=ConvertExpression(PasExpr,AContext);
  23384. WithExprScope:=WithScope.ExpressionScopes[i] as TPas2JSWithExprScope;
  23385. if (Expr is TJSPrimaryExpressionIdent)
  23386. and IsValidJSIdentifier(TJSPrimaryExpressionIdent(Expr).Name) then
  23387. begin
  23388. // expression is already a local variable
  23389. WithExprScope.WithVarName:=String(TJSPrimaryExpressionIdent(Expr).Name);
  23390. Expr.Free;
  23391. end
  23392. else if Expr is TJSPrimaryExpressionThis then
  23393. begin
  23394. // expression is 'this'
  23395. WithExprScope.WithVarName:='this';
  23396. Expr.Free;
  23397. end
  23398. else
  23399. begin
  23400. // create unique local var name
  23401. WithExprScope.WithVarName:=FuncContext.AddLocalJSVar(GetBIName(pbivnWith),true).Name;
  23402. // create local "var $with1 = expr;"
  23403. V:=CreateVarStatement(WithExprScope.WithVarName,Expr,PasExpr);
  23404. AddToStatementList(FirstSt,LastSt,V,PasExpr);
  23405. end;
  23406. end;
  23407. // convert with body
  23408. if Assigned(El.Body) then
  23409. begin
  23410. B:=ConvertElement(El.Body,AContext);
  23411. AddToStatementList(FirstSt,LastSt,B,El.Body);
  23412. end;
  23413. Result:=FirstSt;
  23414. finally
  23415. if Result=nil then
  23416. FreeAndNil(FirstSt);
  23417. end;
  23418. end
  23419. else
  23420. begin
  23421. // without Resolver use as fallback the JavaScript with(){}
  23422. W:=Nil;
  23423. if Assigned(El.Body) then
  23424. B:=ConvertElement(El.Body,AContext)
  23425. else
  23426. B:=TJSEmptyBlockStatement(CreateElement(TJSEmptyBlockStatement,El));
  23427. ok:=false;
  23428. try
  23429. For I:=0 to El.Expressions.Count-1 do
  23430. begin
  23431. PasExpr:=TPasExpr(El.Expressions[i]);
  23432. E:=ConvertExpression(PasExpr,AContext);
  23433. W2:=TJSWithStatement(CreateElement(TJSWithStatement,PasExpr));
  23434. if Not Assigned(Result) then // result is the first
  23435. Result:=W2;
  23436. if Assigned(W) then // Chain
  23437. W.B:=W2;
  23438. W:=W2; // W is the last
  23439. W.A:=E;
  23440. end;
  23441. ok:=true;
  23442. finally
  23443. if not ok then
  23444. begin
  23445. FreeAndNil(E);
  23446. FreeAndNil(Result);
  23447. end;
  23448. end;
  23449. W.B:=B;
  23450. end;
  23451. end;
  23452. function TPasToJSConverter.IsElementUsed(El: TPasElement): boolean;
  23453. begin
  23454. if Assigned(OnIsElementUsed) then
  23455. Result:=OnIsElementUsed(Self,El)
  23456. else
  23457. Result:=true;
  23458. end;
  23459. function TPasToJSConverter.IsSystemUnit(aModule: TPasModule): boolean;
  23460. begin
  23461. Result:=(CompareText(aModule.Name,'system')=0) and (aModule.ClassType=TPasModule);
  23462. end;
  23463. function TPasToJSConverter.HasTypeInfo(El: TPasType; AContext: TConvertContext
  23464. ): boolean;
  23465. begin
  23466. Result:=false;
  23467. if coNoTypeInfo in Options then exit;
  23468. if AContext.Resolver=nil then exit;
  23469. if not AContext.Resolver.HasTypeInfo(El) then exit;
  23470. if Assigned(OnIsTypeInfoUsed) and not OnIsTypeInfoUsed(Self,El) then exit;
  23471. Result:=true;
  23472. end;
  23473. function TPasToJSConverter.IsClassRTTICreatedBefore(aClass: TPasClassType;
  23474. Before: TPasElement; AConText: TConvertContext): boolean;
  23475. var
  23476. Decls: TPasDeclarations;
  23477. i: Integer;
  23478. List: TFPList;
  23479. C: TClass;
  23480. aParent, Decl: TPasElement;
  23481. begin
  23482. Result:=false;
  23483. aParent:=aClass.Parent;
  23484. if aParent<>Before.Parent then
  23485. exit(true);
  23486. if not aParent.InheritsFrom(TPasDeclarations) then
  23487. RaiseInconsistency(20170412101457,aClass);
  23488. Decls:=TPasDeclarations(aParent);
  23489. List:=Decls.Declarations;
  23490. for i:=0 to List.Count-1 do
  23491. begin
  23492. Decl:=TPasElement(List[i]);
  23493. if Decl=Before then exit;
  23494. if Decl=aClass then exit(true);
  23495. C:=Decl.ClassType;
  23496. if C=TPasClassType then
  23497. begin
  23498. if TPasClassType(Decl).IsForward and (Decl.CustomData is TResolvedReference)
  23499. and (TResolvedReference(Decl.CustomData).Declaration=aClass) then
  23500. exit(true);
  23501. end
  23502. else if C=TPasClassOfType then
  23503. begin
  23504. if AConText.Resolver.ResolveAliasType(TPasClassOfType(Decl).DestType)=aClass then
  23505. exit(true);
  23506. end;
  23507. end;
  23508. end;
  23509. function TPasToJSConverter.IsExprTemporaryVar(Expr: TPasExpr): boolean;
  23510. var
  23511. Params: TParamsExpr;
  23512. Ref: TResolvedReference;
  23513. C: TClass;
  23514. begin
  23515. if Expr.CustomData is TResolvedReference then
  23516. begin
  23517. Ref:=TResolvedReference(Expr.CustomData);
  23518. if [rrfNewInstance,rrfImplicitCallWithoutParams]*Ref.Flags<>[] then
  23519. exit(true);
  23520. end;
  23521. C:=Expr.ClassType;
  23522. if C=TParamsExpr then
  23523. begin
  23524. Params:=TParamsExpr(Expr);
  23525. if Params.Kind=pekFuncParams then
  23526. exit(true);
  23527. end
  23528. else if C.InheritsFrom(TBinaryExpr) then
  23529. exit(true);
  23530. Result:=false;
  23531. end;
  23532. function TPasToJSConverter.IsExprPropertySetterConst(Expr: TPasExpr;
  23533. AContext: TConvertContext): boolean;
  23534. var
  23535. Bin: TBinaryExpr;
  23536. Ref: TResolvedReference;
  23537. Prop: TPasProperty;
  23538. Setter, Arg: TPasElement;
  23539. Args: TFPList;
  23540. begin
  23541. if Expr is TBinaryExpr then
  23542. begin
  23543. Bin:=TBinaryExpr(Expr);
  23544. if Bin.OpCode=eopSubIdent then
  23545. Expr:=Bin.right;
  23546. end;
  23547. if Expr.CustomData is TResolvedReference then
  23548. begin
  23549. Ref:=TResolvedReference(Expr.CustomData);
  23550. if Ref.Declaration is TPasProperty then
  23551. begin
  23552. Prop:=TPasProperty(Ref.Declaration);
  23553. Setter:=AContext.Resolver.GetPasPropertySetter(Prop);
  23554. if Setter is TPasProcedure then
  23555. begin
  23556. Args:=TPasProcedure(Setter).ProcType.Args;
  23557. if Args.Count>0 then
  23558. begin
  23559. Arg:=TPasElement(Args[Args.Count-1]);
  23560. if (Arg is TPasArgument) and (TPasArgument(Arg).Access in [argConst,argConstRef]) then
  23561. exit(true);
  23562. end;
  23563. end;
  23564. end;
  23565. end;
  23566. Result:=false;
  23567. end;
  23568. procedure TPasToJSConverter.FindAvailableLocalName(var aName: string;
  23569. JSExpr: TJSElement);
  23570. var
  23571. StartJSName, JSName: TJSString;
  23572. n: integer;
  23573. Changed: boolean;
  23574. procedure Next;
  23575. var
  23576. ch: WideChar;
  23577. begin
  23578. Changed:=true;
  23579. // name clash -> change JSName
  23580. if (n=0) and (length(JSName)=1) then
  23581. begin
  23582. // single letter -> choose next single letter
  23583. ch:=JSName[1];
  23584. case ch of
  23585. 'a'..'x': JSName:=succ(ch);
  23586. 'z': JSName:='a';
  23587. end;
  23588. if JSName=StartJSName then
  23589. begin
  23590. n:=1;
  23591. JSName:=StartJSName+TJSString(IntToStr(n));
  23592. end;
  23593. end
  23594. else
  23595. begin
  23596. inc(n);
  23597. JSName:=StartJSName+TJSString(IntToStr(n));
  23598. end;
  23599. end;
  23600. procedure Find(El: TJSElement);
  23601. var
  23602. C: TClass;
  23603. Call: TJSCallExpression;
  23604. i: Integer;
  23605. begin
  23606. if El=nil then exit;
  23607. C:=El.ClassType;
  23608. if C=TJSPrimaryExpressionIdent then
  23609. begin
  23610. if TJSPrimaryExpressionIdent(El).Name=JSName then
  23611. Next;
  23612. end
  23613. else if C.InheritsFrom(TJSMemberExpression) then
  23614. begin
  23615. Find(TJSMemberExpression(El).MExpr);
  23616. if C=TJSBracketMemberExpression then
  23617. Find(TJSBracketMemberExpression(El).Name)
  23618. else if C=TJSNewMemberExpression then
  23619. with TJSNewMemberExpression(El).Args.Elements do
  23620. for i:=0 to Count-1 do
  23621. Find(Elements[i].Expr);
  23622. end
  23623. else if C=TJSCallExpression then
  23624. begin
  23625. Call:=TJSCallExpression(El);
  23626. Find(Call.Expr);
  23627. if Call.Args<>nil then
  23628. with Call.Args.Elements do
  23629. for i:=0 to Count-1 do
  23630. Find(Elements[i].Expr);
  23631. end
  23632. else if C.InheritsFrom(TJSUnary) then
  23633. Find(TJSUnary(El).A)
  23634. else if C.InheritsFrom(TJSBinary) then
  23635. begin
  23636. Find(TJSBinary(El).A);
  23637. Find(TJSBinary(El).B);
  23638. end
  23639. else if C=TJSArrayLiteral then
  23640. begin
  23641. with TJSArrayLiteral(El).Elements do
  23642. for i:=0 to Count-1 do
  23643. Find(Elements[i].Expr);
  23644. end
  23645. else if C=TJSConditionalExpression then
  23646. begin
  23647. Find(TJSConditionalExpression(El).A);
  23648. Find(TJSConditionalExpression(El).B);
  23649. Find(TJSConditionalExpression(El).C);
  23650. end
  23651. else if C.InheritsFrom(TJSAssignStatement) then
  23652. begin
  23653. Find(TJSAssignStatement(El).LHS);
  23654. Find(TJSAssignStatement(El).Expr);
  23655. end
  23656. else if C=TJSVarDeclaration then
  23657. Find(TJSVarDeclaration(El).Init)
  23658. else if C=TJSObjectLiteral then
  23659. begin
  23660. with TJSObjectLiteral(El).Elements do
  23661. for i:=0 to Count-1 do
  23662. Find(Elements[i].Expr);
  23663. end
  23664. else if C=TJSIfStatement then
  23665. begin
  23666. Find(TJSIfStatement(El).Cond);
  23667. Find(TJSIfStatement(El).BTrue);
  23668. Find(TJSIfStatement(El).BFalse);
  23669. end
  23670. else if C.InheritsFrom(TJSBodyStatement) then
  23671. begin
  23672. Find(TJSBodyStatement(El).Body);
  23673. if C.InheritsFrom(TJSCondLoopStatement) then
  23674. begin
  23675. Find(TJSCondLoopStatement(El).Cond);
  23676. if C=TJSForStatement then
  23677. begin
  23678. Find(TJSForStatement(El).Init);
  23679. Find(TJSForStatement(El).Incr);
  23680. end;
  23681. end
  23682. else if C=TJSForInStatement then
  23683. begin
  23684. Find(TJSForInStatement(El).LHS);
  23685. Find(TJSForInStatement(El).List);
  23686. end;
  23687. end
  23688. else if C=TJSSwitchStatement then
  23689. begin
  23690. Find(TJSSwitchStatement(El).Cond);
  23691. with TJSSwitchStatement(El).Cases do
  23692. for i:=0 to Count-1 do
  23693. with Cases[i] do
  23694. begin
  23695. Find(Expr);
  23696. Find(Body);
  23697. end;
  23698. if TJSSwitchStatement(El).TheDefault<>nil then
  23699. with TJSSwitchStatement(El).TheDefault do
  23700. begin
  23701. Find(Expr);
  23702. Find(Body);
  23703. end;
  23704. end;
  23705. end;
  23706. begin
  23707. if JSExpr=nil then exit;
  23708. StartJSName:=TJSString(aName);
  23709. JSName:=StartJSName;
  23710. n:=0;
  23711. Changed:=false;
  23712. Find(JSExpr);
  23713. if not Changed then exit;
  23714. repeat
  23715. Changed:=false;
  23716. Find(JSExpr);
  23717. until not changed;
  23718. aName:=JSStringToString(JSName);
  23719. end;
  23720. function TPasToJSConverter.GetImplJSProcScope(El: TPasElement;
  23721. Src: TJSSourceElements; AContext: TConvertContext): TPas2JSProcedureScope;
  23722. begin
  23723. if (Src=nil) or not (coStoreImplJS in Options) or (AContext.Resolver=nil) then
  23724. exit(nil);
  23725. Result:=AContext.Resolver.GetTopLvlProcScope(El);
  23726. end;
  23727. function TPasToJSConverter.SpecializeNeedsDelay(El: TPasGenericType;
  23728. AContext: TConvertContext): boolean;
  23729. var
  23730. SpecItem: TPRSpecializedItem;
  23731. C: TClass;
  23732. Members: TFPList;
  23733. ChildEl: TPasElement;
  23734. PasVar: TPasVariable;
  23735. aResolver: TPas2JSResolver;
  23736. PasVarType: TPasType;
  23737. IsRecord, NeedInitFunction: Boolean;
  23738. aClass: TPasClassType;
  23739. ClassScope: TPas2JSClassScope;
  23740. IntfKind: String;
  23741. i: Integer;
  23742. begin
  23743. Result:=false;
  23744. aResolver:=AContext.Resolver;
  23745. if aResolver=nil then exit;
  23746. if not (El.CustomData is TPasGenericScope) then exit;
  23747. SpecItem:=TPasGenericScope(El.CustomData).SpecializedFromItem;
  23748. if aResolver.SpecializeParamsNeedDelay(SpecItem)=nil then
  23749. exit; // params are declared in front of generic -> no need to delay
  23750. if HasTypeInfo(El,AContext) then
  23751. exit(true); // RTTI -> delay needed
  23752. C:=El.ClassType;
  23753. if El.InheritsFrom(TPasMembersType) then
  23754. begin
  23755. IsRecord:=C=TPasRecordType;
  23756. if C=TPasClassType then
  23757. begin
  23758. aClass:=TPasClassType(El);
  23759. ClassScope:=TPas2JSClassScope(El.CustomData);
  23760. if aClass.ObjKind=okInterface then
  23761. begin
  23762. IntfKind:='';
  23763. if (ClassScope.AncestorScope=nil) and (not (coNoTypeInfo in Options)) then
  23764. case aClass.InterfaceType of
  23765. citCom: IntfKind:='com';
  23766. citCorba: ; // default
  23767. else
  23768. RaiseNotSupported(El,AContext,20200905132130){%H-};
  23769. end;
  23770. NeedInitFunction:=(pcsfPublished in ClassScope.Flags) or (IntfKind<>'');
  23771. if not NeedInitFunction then
  23772. exit; // interface without init function -> no need to delay
  23773. end;
  23774. end;
  23775. Members:=TPasMembersType(El).Members;
  23776. for i:=0 to Members.Count-1 do
  23777. begin
  23778. ChildEl:=TPasElement(Members[i]);
  23779. if not IsElementUsed(ChildEl) then continue;
  23780. if ChildEl is TPasVariable then
  23781. begin
  23782. PasVar:=TPasVariable(ChildEl);
  23783. if ChildEl.ClassType=TPasConst then
  23784. else if ChildEl.ClassType=TPasVariable then
  23785. begin
  23786. if (not IsRecord) and (PasVar.VarModifiers*[vmClass, vmStatic]=[]) then
  23787. continue; // class field -> no delay needed
  23788. end
  23789. else
  23790. continue;
  23791. PasVarType:=aResolver.ResolveAliasType(PasVar.VarType);
  23792. if (PasVarType.ClassType=TPasRecordType) then
  23793. exit(true) // global record -> needs delay (Eventually: check if it uses one of the after params)
  23794. else if (PasVarType.ClassType=TPasArrayType) and (length(TPasArrayType(PasVarType).Ranges)>0) then
  23795. exit(true); // global static array -> needs delay (Eventually: check if it uses one of the after params)
  23796. end;
  23797. end;
  23798. end;
  23799. end;
  23800. function TPasToJSConverter.CreateUnary(const Members: array of string; E: TJSElement): TJSUnary;
  23801. var
  23802. unary: TJSUnary;
  23803. asi: TJSSimpleAssignStatement;
  23804. begin
  23805. unary := TJSUnary.Create(0, 0, '');
  23806. asi := TJSSimpleAssignStatement.Create(0, 0, '');
  23807. unary.A := asi;
  23808. asi.Expr := E;
  23809. asi.LHS := CreateMemberExpression(Members);
  23810. Result := unary;
  23811. end;
  23812. function TPasToJSConverter.CreateUnaryPlus(Expr: TJSElement; El: TPasElement
  23813. ): TJSUnaryPlusExpression;
  23814. begin
  23815. Result:=TJSUnaryPlusExpression(CreateElement(TJSUnaryPlusExpression,El));
  23816. Result.A:=Expr;
  23817. end;
  23818. function TPasToJSConverter.CreateMemberExpression(const Members: array of string): TJSElement;
  23819. // Examples:
  23820. // foo -> foo
  23821. // foo,bar -> foo.bar
  23822. // foo,[1] -> foo[1]
  23823. var
  23824. Prim: TJSPrimaryExpressionIdent;
  23825. MExpr, LastMExpr: TJSMemberExpression;
  23826. k: integer;
  23827. CurName: String;
  23828. begin
  23829. if Length(Members) < 1 then
  23830. DoError(20161024192715,'internal error: member expression needs at least one element');
  23831. LastMExpr := nil;
  23832. for k:=High(Members) downto Low(Members)+1 do
  23833. begin
  23834. CurName:=Members[k];
  23835. if CurName='' then
  23836. DoError(20190124114806,'internal error: member expression needs name');
  23837. if CurName[1]='[' then
  23838. begin
  23839. if CurName[length(CurName)]=']' then
  23840. CurName:=copy(CurName,2,length(CurName)-2)
  23841. else
  23842. CurName:=copy(CurName,2,length(CurName)-1);
  23843. MExpr := TJSBracketMemberExpression.Create(0,0,'');
  23844. Prim := TJSPrimaryExpressionIdent.Create(0, 0, '');
  23845. Prim.Name:=TJSString(CurName);
  23846. TJSBracketMemberExpression(MExpr).Name := Prim;
  23847. end
  23848. else
  23849. begin
  23850. MExpr := TJSDotMemberExpression.Create(0, 0, '');
  23851. TJSDotMemberExpression(MExpr).Name := TJSString(CurName);
  23852. end;
  23853. if LastMExpr=nil then
  23854. Result := MExpr
  23855. else
  23856. LastMExpr.MExpr := MExpr;
  23857. LastMExpr := MExpr;
  23858. end;
  23859. Prim := TJSPrimaryExpressionIdent.Create(0, 0, '');
  23860. Prim.Name := TJSString(Members[Low(Members)]);
  23861. if LastMExpr=nil then
  23862. Result:=Prim
  23863. else
  23864. LastMExpr.MExpr := Prim;
  23865. end;
  23866. function TPasToJSConverter.CreateCallExpression(El: TPasElement
  23867. ): TJSCallExpression;
  23868. begin
  23869. Result:=TJSCallExpression(CreateElement(TJSCallExpression,El));
  23870. Result.Args:=TJSArguments(CreateElement(TJSArguments,El));
  23871. end;
  23872. function TPasToJSConverter.CreateCallCharCodeAt(Arg: TJSElement;
  23873. aNumber: integer; El: TPasElement): TJSCallExpression;
  23874. begin
  23875. Result:=CreateCallExpression(El);
  23876. Result.Expr:=CreateDotNameExpr(El,Arg,'charCodeAt');
  23877. if aNumber<>0 then
  23878. Result.Args.AddElement(CreateLiteralNumber(El,aNumber));
  23879. end;
  23880. function TPasToJSConverter.CreateCallFromCharCode(Arg: TJSElement;
  23881. El: TPasElement): TJSCallExpression;
  23882. begin
  23883. Result:=CreateCallExpression(El);
  23884. Result.Expr:=CreateMemberExpression(['String','fromCharCode']);
  23885. Result.AddArg(Arg);
  23886. end;
  23887. function TPasToJSConverter.CreateUsesList(UsesSection: TPasSection;
  23888. AContext: TConvertContext): TJSArrayLiteral;
  23889. var
  23890. ArgArray: TJSArrayLiteral;
  23891. i: Integer;
  23892. anUnitName: String;
  23893. ArgEx: TJSLiteral;
  23894. UsesClause: TPasUsesClause;
  23895. aModule: TPasModule;
  23896. begin
  23897. UsesClause:=UsesSection.UsesClause;
  23898. ArgArray:=TJSArrayLiteral.Create(0,0);
  23899. for i:=0 to length(UsesClause)-1 do
  23900. begin
  23901. aModule:=UsesClause[i].Module as TPasModule;
  23902. if (not IsElementUsed(aModule)) and not IsSystemUnit(aModule) then
  23903. continue;
  23904. anUnitName := TransformModuleName(aModule,false,AContext);
  23905. ArgEx := CreateLiteralString(UsesSection,anUnitName);
  23906. ArgArray.Elements.AddElement.Expr := ArgEx;
  23907. end;
  23908. Result:=ArgArray;
  23909. end;
  23910. procedure TPasToJSConverter.AddToStatementList(var First,
  23911. Last: TJSStatementList; Add: TJSElement; Src: TPasElement);
  23912. var
  23913. SL2: TJSStatementList;
  23914. begin
  23915. if Add=nil then exit;
  23916. if Add is TJSStatementList then
  23917. begin
  23918. // add list
  23919. if TJSStatementList(Add).A=nil then
  23920. begin
  23921. // empty list -> skip
  23922. if TJSStatementList(Add).B<>nil then
  23923. raise Exception.Create('internal error: AddToStatementList add list A=nil, B<>nil, B='+TJSStatementList(Add).B.ClassName);
  23924. FreeAndNil(Add);
  23925. end
  23926. else if Last=nil then
  23927. begin
  23928. // our list is not yet started -> simply take the extra list
  23929. Last:=TJSStatementList(Add);
  23930. First:=Last;
  23931. end
  23932. else
  23933. begin
  23934. // merge lists (append)
  23935. if Last.B<>nil then
  23936. begin
  23937. // add a nil to the end of chain
  23938. SL2:=TJSStatementList(CreateElement(TJSStatementList,Src));
  23939. SL2.A:=Last.B;
  23940. Last.B:=SL2;
  23941. Last:=SL2;
  23942. // Last.B is now nil
  23943. end;
  23944. Last.B:=Add;
  23945. while Last.B is TJSStatementList do
  23946. Last:=TJSStatementList(Last.B);
  23947. end;
  23948. end
  23949. else
  23950. begin
  23951. if Last=nil then
  23952. begin
  23953. // start list
  23954. Last:=TJSStatementList(CreateElement(TJSStatementList,Src));
  23955. First:=Last;
  23956. Last.A:=Add;
  23957. end
  23958. else if Last.B=nil then
  23959. // second element
  23960. Last.B:=Add
  23961. else
  23962. begin
  23963. // add to chain
  23964. while Last.B is TJSStatementList do
  23965. Last:=TJSStatementList(Last.B);
  23966. SL2:=TJSStatementList(CreateElement(TJSStatementList,Src));
  23967. SL2.A:=Last.B;
  23968. Last.B:=SL2;
  23969. Last:=SL2;
  23970. Last.B:=Add;
  23971. end;
  23972. end;
  23973. end;
  23974. procedure TPasToJSConverter.AddToStatementList(St: TJSStatementList;
  23975. Add: TJSElement; Src: TPasElement);
  23976. var
  23977. First, Last: TJSStatementList;
  23978. begin
  23979. First:=St;
  23980. Last:=St;
  23981. while Last.B is TJSStatementList do
  23982. Last:=TJSStatementList(Last.B);
  23983. AddToStatementList(First,Last,Add,Src);
  23984. end;
  23985. procedure TPasToJSConverter.PrependToStatementList(var St: TJSElement;
  23986. Add: TJSElement; PosEl: TPasElement);
  23987. var
  23988. NewSt: TJSStatementList;
  23989. begin
  23990. if St=nil then
  23991. St:=Add
  23992. else if St is TJSEmptyBlockStatement then
  23993. begin
  23994. St.Free;
  23995. St:=Add;
  23996. end
  23997. else if St is TJSStatementList then
  23998. begin
  23999. NewSt:=TJSStatementList(CreateElement(TJSStatementList,PosEl));
  24000. NewSt.A:=Add;
  24001. NewSt.B:=St;
  24002. St:=NewSt;
  24003. end
  24004. else
  24005. begin
  24006. {$IFDEF VerbosePas2JS}
  24007. writeln('TPasToJSConverter.PrependToStatementList St=',GetObjName(St));
  24008. {$ENDIF}
  24009. RaiseNotSupported(PosEl,nil,20181002154026,GetObjName(St));
  24010. end;
  24011. end;
  24012. procedure TPasToJSConverter.AddToVarStatement(VarStat: TJSVariableStatement;
  24013. Add: TJSElement; Src: TPasElement);
  24014. var
  24015. List: TJSVariableDeclarationList;
  24016. begin
  24017. if VarStat.VarDecl=nil then
  24018. VarStat.VarDecl:=Add
  24019. else
  24020. begin
  24021. List:=TJSVariableDeclarationList(CreateElement(TJSVariableDeclarationList,Src));
  24022. List.A:=VarStat.VarDecl;
  24023. List.B:=Add;
  24024. VarStat.VarDecl:=List;
  24025. end;
  24026. end;
  24027. function TPasToJSConverter.CreateValInit(PasType: TPasType; Expr: TPasExpr;
  24028. El: TPasElement; AContext: TConvertContext): TJSElement;
  24029. var
  24030. T: TPasType;
  24031. Lit: TJSLiteral;
  24032. bt: TResolverBaseType;
  24033. JSBaseType: TPas2jsBaseType;
  24034. C: TClass;
  24035. aResolver: TPas2JSResolver;
  24036. Value: TResEvalValue;
  24037. begin
  24038. T:=PasType;
  24039. aResolver:=AContext.Resolver;
  24040. if aResolver<>nil then
  24041. T:=aResolver.ResolveAliasType(T);
  24042. //writeln('START TPasToJSConverter.CreateValInit PasType=',GetObjName(PasType),' El=',GetObjName(El),' T=',GetObjName(T),' Expr=',GetObjName(Expr));
  24043. if T=nil then
  24044. begin
  24045. // untyped var/const
  24046. if Expr=nil then
  24047. begin
  24048. if aResolver=nil then
  24049. exit(CreateLiteralUndefined(El));
  24050. RaiseInconsistency(20170415185745,El);
  24051. end;
  24052. Result:=ConvertExpression(Expr,AContext);
  24053. if Result=nil then
  24054. begin
  24055. {$IFDEF VerbosePas2JS}
  24056. writeln('TPasToJSConverter.CreateValInit PasType=',GetObjName(PasType),' El=',GetObjName(El),' T=',GetObjName(T),' Expr=',GetObjName(Expr));
  24057. {$ENDIF}
  24058. RaiseNotSupported(Expr,AContext,20170415185927);
  24059. end;
  24060. exit;
  24061. end;
  24062. C:=T.ClassType;
  24063. if C=TPasArrayType then
  24064. Result:=CreateArrayInit(TPasArrayType(T),Expr,El,AContext)
  24065. else if C=TPasRecordType then
  24066. Result:=CreateRecordInit(TPasRecordType(T),Expr,El,AContext)
  24067. else if Assigned(Expr) then
  24068. // if there is an expression then simply convert it
  24069. Result:=ConvertExpression(Expr,AContext)
  24070. else if C=TPasSetType then
  24071. // a "set" without initial value
  24072. Result:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,El))
  24073. else if (C=TPasRangeType) and (aResolver<>nil) then
  24074. begin
  24075. // a custom range without initial value
  24076. // -> for FPC/Delphi compatibility use 0 even if it is out of range
  24077. Value:=AContext.Resolver.Eval(TPasRangeType(T).RangeExpr.left,[refConst]);
  24078. try
  24079. case Value.Kind of
  24080. revkInt,revkUInt: Result:=CreateLiteralNumber(El,0);
  24081. else
  24082. Result:=ConvertConstValue(Value,AContext,El);
  24083. end;
  24084. finally
  24085. ReleaseEvalValue(Value);
  24086. end;
  24087. end
  24088. else
  24089. begin
  24090. // always init with a default value to create a typed variable (faster and more readable)
  24091. Lit:=TJSLiteral(CreateElement(TJSLiteral,El));
  24092. Result:=Lit;
  24093. if (C=TPasPointerType)
  24094. or (C=TPasClassType)
  24095. or (C=TPasClassOfType)
  24096. or (C=TPasProcedureType)
  24097. or (C=TPasFunctionType) then
  24098. Lit.Value.IsNull:=true
  24099. else if C=TPasStringType then
  24100. Lit.Value.AsString:=''
  24101. else if C=TPasEnumType then
  24102. Lit.Value.AsNumber:=0
  24103. else if C=TPasUnresolvedSymbolRef then
  24104. begin
  24105. if T.CustomData is TResElDataBaseType then
  24106. begin
  24107. bt:=TResElDataBaseType(T.CustomData).BaseType;
  24108. if bt in btAllJSInteger then
  24109. Lit.Value.AsNumber:=0
  24110. else if bt in btAllJSFloats then
  24111. Lit.Value.CustomValue:='0.0'
  24112. else if bt in btAllJSChars then
  24113. Lit.Value.AsString := #0
  24114. else if bt in btAllJSStrings then
  24115. Lit.Value.AsString:=''
  24116. else if bt in btAllJSBooleans then
  24117. Lit.Value.AsBoolean:=false
  24118. else if bt in [btNil,btPointer,btProc] then
  24119. Lit.Value.IsNull:=true
  24120. else if (bt=btCustom) and (T.CustomData is TResElDataPas2JSBaseType) then
  24121. begin
  24122. JSBaseType:=TResElDataPas2JSBaseType(T.CustomData).JSBaseType;
  24123. if JSBaseType=pbtJSValue then
  24124. Lit.Value.IsUndefined:=true;
  24125. end
  24126. else
  24127. begin
  24128. {$IFDEF VerbosePas2JS}
  24129. writeln('TPasToJSConverter.CreateVarInit unknown PasType T=',GetObjName(T),' basetype=',aResolver.BaseTypeNames[bt]);
  24130. {$ENDIF}
  24131. RaiseNotSupported(PasType,AContext,20170208162121);
  24132. end;
  24133. end
  24134. else if aResolver<>nil then
  24135. begin
  24136. {$IFDEF VerbosePas2JS}
  24137. writeln('TPasToJSConverter.CreateValInit PasType=',GetObjName(PasType),' El=',GetObjName(El),' T=',GetObjName(T),' Expr=',GetObjName(Expr));
  24138. {$ENDIF}
  24139. RaiseNotSupported(El,AContext,20170415190259);
  24140. end
  24141. else if (CompareText(T.Name,'longint')=0)
  24142. or (CompareText(T.Name,'int64')=0)
  24143. or (CompareText(T.Name,'real')=0)
  24144. or (CompareText(T.Name,'double')=0)
  24145. or (CompareText(T.Name,'single')=0) then
  24146. Lit.Value.AsNumber:=0.0
  24147. else if (CompareText(T.Name,'boolean')=0) then
  24148. Lit.Value.AsBoolean:=false
  24149. else if (CompareText(T.Name,'string')=0)
  24150. or (CompareText(T.Name,'char')=0)
  24151. then
  24152. Lit.Value.AsString:=''
  24153. else
  24154. begin
  24155. Lit.Value.IsUndefined:=true;
  24156. {$IFDEF VerbosePas2JS}
  24157. writeln('TPasToJSConverter.CreateVarInit unknown PasType class=',T.ClassName,' name=',T.Name);
  24158. {$ENDIF}
  24159. end;
  24160. end
  24161. else
  24162. begin
  24163. {$IFDEF VerbosePas2JS}
  24164. writeln('TPasToJSConverter.CreateValInit unknown PasType ',GetObjName(T));
  24165. {$ENDIF}
  24166. RaiseNotSupported(PasType,AContext,20170208161506);
  24167. end;
  24168. end;
  24169. if Result=nil then
  24170. begin
  24171. {$IFDEF VerbosePas2JS}
  24172. writeln('TPasToJSConverter.CreateValInit PasType=',GetObjName(PasType),' El=',GetObjName(El),' T=',GetObjName(T),' Expr=',GetObjName(Expr));
  24173. {$ENDIF}
  24174. RaiseNotSupported(El,AContext,20170415190103);
  24175. end;
  24176. end;
  24177. function TPasToJSConverter.CreateVarInit(El: TPasVariable;
  24178. AContext: TConvertContext): TJSElement;
  24179. begin
  24180. Result:=CreateValInit(El.VarType,El.Expr,El,AContext);
  24181. end;
  24182. function TPasToJSConverter.CreateVarStatement(const aName: String;
  24183. Init: TJSElement; El: TPasElement): TJSVariableStatement;
  24184. // create "var aname = init"
  24185. begin
  24186. Result:=TJSVariableStatement(CreateElement(TJSVariableStatement,El));
  24187. Result.VarDecl:=CreateVarDecl(aName,Init,El);
  24188. end;
  24189. function TPasToJSConverter.CreateVarDecl(const aName: String; Init: TJSElement;
  24190. El: TPasElement): TJSVarDeclaration;
  24191. begin
  24192. Result:=TJSVarDeclaration(CreateElement(TJSVarDeclaration,El));
  24193. Result.Name:=TJSString(aName);
  24194. Result.Init:=Init;
  24195. end;
  24196. function TPasToJSConverter.CreateLiteralNumber(El: TPasElement;
  24197. const n: TJSNumber): TJSLiteral;
  24198. begin
  24199. Result:=TJSLiteral(CreateElement(TJSLiteral,El));
  24200. Result.Value.AsNumber:=n;
  24201. end;
  24202. function TPasToJSConverter.CreateLiteralFloat(El: TPasElement;
  24203. const n: TJSNumber): TJSElement;
  24204. var
  24205. DivExpr: TJSMultiplicativeExpressionDiv;
  24206. Lit: TJSLiteral;
  24207. begin
  24208. if IsInfinite(n) then
  24209. begin
  24210. DivExpr:=TJSMultiplicativeExpressionDiv(CreateElement(TJSMultiplicativeExpressionDiv,El));
  24211. if n<0 then
  24212. DivExpr.A:=CreateLiteralNumber(El,-1)
  24213. else
  24214. DivExpr.A:=CreateLiteralNumber(El,1);
  24215. DivExpr.B:=CreateLiteralNumber(El,0);
  24216. Result:=DivExpr;
  24217. end
  24218. else
  24219. begin
  24220. Lit:=TJSLiteral(CreateElement(TJSLiteral,El));
  24221. Lit.Value.AsNumber:=n;
  24222. Result:=Lit;
  24223. end;
  24224. end;
  24225. function TPasToJSConverter.CreateLiteralHexNumber(El: TPasElement;
  24226. const n: TMaxPrecInt; Digits: byte): TJSLiteral;
  24227. begin
  24228. Result:=TJSLiteral(CreateElement(TJSLiteral,El));
  24229. Result.Value.AsNumber:=n;
  24230. Result.Value.CustomValue:=TJSString('0x'+HexStr(n,Digits));
  24231. end;
  24232. function TPasToJSConverter.CreateLiteralString(El: TPasElement; const s: string
  24233. ): TJSLiteral;
  24234. begin
  24235. Result:=TJSLiteral(CreateElement(TJSLiteral,El));
  24236. Result.Value.AsString:=TJSString(s);
  24237. end;
  24238. function TPasToJSConverter.CreateLiteralJSString(El: TPasElement;
  24239. const s: TJSString): TJSLiteral;
  24240. begin
  24241. Result:=TJSLiteral(CreateElement(TJSLiteral,El));
  24242. Result.Value.AsString:=s;
  24243. end;
  24244. function TPasToJSConverter.CreateLiteralBoolean(El: TPasElement; b: boolean
  24245. ): TJSLiteral;
  24246. begin
  24247. Result:=TJSLiteral(CreateElement(TJSLiteral,El));
  24248. Result.Value.AsBoolean:=b;
  24249. end;
  24250. function TPasToJSConverter.CreateLiteralNull(El: TPasElement): TJSLiteral;
  24251. begin
  24252. Result:=TJSLiteral(CreateElement(TJSLiteral,El));
  24253. Result.Value.IsNull:=true;
  24254. end;
  24255. function TPasToJSConverter.CreateLiteralUndefined(El: TPasElement): TJSLiteral;
  24256. begin
  24257. Result:=TJSLiteral(CreateElement(TJSLiteral,El));
  24258. Result.Value.IsUndefined:=true;
  24259. end;
  24260. function TPasToJSConverter.CreateLiteralCustomValue(El: TPasElement;
  24261. const s: TJSString): TJSLiteral;
  24262. begin
  24263. Result:=TJSLiteral(CreateElement(TJSLiteral,El));
  24264. Result.Value.CustomValue:=s;
  24265. end;
  24266. function TPasToJSConverter.CreateSetLiteralElement(Expr: TPasExpr;
  24267. AContext: TConvertContext): TJSElement;
  24268. var
  24269. LitVal: TJSValue;
  24270. NewEl: TJSElement;
  24271. WS: TJSString;
  24272. ExprResolved: TPasResolverResult;
  24273. Call: TJSCallExpression;
  24274. DotExpr: TJSDotMemberExpression;
  24275. aResolver: TPas2JSResolver;
  24276. bt: TResolverBaseType;
  24277. C: TClass;
  24278. begin
  24279. Result:=ConvertExpression(Expr,AContext);
  24280. if Result=nil then
  24281. RaiseNotSupported(Expr,AContext,20170415192209);
  24282. if Result.ClassType=TJSLiteral then
  24283. begin
  24284. // argument is a literal -> convert to number
  24285. LitVal:=TJSLiteral(Result).Value;
  24286. case LitVal.ValueType of
  24287. jstBoolean:
  24288. begin
  24289. if LitVal.AsBoolean=LowJSBoolean then
  24290. NewEl:=CreateLiteralNumber(Expr,0)
  24291. else
  24292. NewEl:=CreateLiteralNumber(Expr,1);
  24293. Result.Free;
  24294. exit(NewEl);
  24295. end;
  24296. jstNumber:
  24297. exit;
  24298. jstString:
  24299. begin
  24300. WS:=LitVal.AsString;
  24301. Result.Free;
  24302. if length(WS)<>1 then
  24303. DoError(20170415193254,nXExpectedButYFound,sXExpectedButYFound,['char','string'],Expr);
  24304. Result:=CreateLiteralNumber(Expr,ord(WS[1]));
  24305. exit;
  24306. end;
  24307. else
  24308. RaiseNotSupported(Expr,AContext,20170415205955);
  24309. end;
  24310. end
  24311. else if Result.ClassType=TJSCallExpression then
  24312. begin
  24313. Call:=TJSCallExpression(Result);
  24314. if (Call.Expr is TJSDotMemberExpression) then
  24315. begin
  24316. DotExpr:=TJSDotMemberExpression(Call.Expr);
  24317. if DotExpr.Name='charCodeAt' then
  24318. exit;
  24319. if DotExpr.Name='charAt' then
  24320. begin
  24321. DotExpr.Name:='charCodeAt';
  24322. exit;
  24323. end;
  24324. end;
  24325. end;
  24326. aResolver:=AContext.Resolver;
  24327. if aResolver<>nil then
  24328. begin
  24329. aResolver.ComputeElement(Expr,ExprResolved,[]);
  24330. bt:=ExprResolved.BaseType;
  24331. if bt=btRange then
  24332. bt:=ExprResolved.SubType;
  24333. if bt in btAllJSStringAndChars then
  24334. begin
  24335. // aChar -> aChar.charCodeAt()
  24336. Result:=CreateCallCharCodeAt(Result,0,Expr);
  24337. end
  24338. else if bt in btAllJSInteger then
  24339. begin
  24340. // ok
  24341. end
  24342. else if bt=btContext then
  24343. begin
  24344. C:=ExprResolved.LoTypeEl.ClassType;
  24345. if (C=TPasEnumType) or (C=TPasRangeType) then
  24346. // ok
  24347. else
  24348. RaiseNotSupported(Expr,AContext,20170415191933);
  24349. end
  24350. else
  24351. begin
  24352. {$IFDEF VerbosePas2JS}
  24353. writeln('TPasToJSConverter.CreateSetLiteralElement ',GetResolverResultDbg(ExprResolved));
  24354. {$ENDIF}
  24355. RaiseNotSupported(Expr,AContext,20170415191822);
  24356. end;
  24357. end;
  24358. end;
  24359. function TPasToJSConverter.CreateUnaryNot(El: TJSElement; Src: TPasElement
  24360. ): TJSUnaryNotExpression;
  24361. begin
  24362. Result:=TJSUnaryNotExpression(CreateElement(TJSUnaryNotExpression,Src));
  24363. Result.A:=El;
  24364. end;
  24365. procedure TPasToJSConverter.ConvertCharLiteralToInt(Lit: TJSLiteral;
  24366. ErrorEl: TPasElement; AContext: TConvertContext);
  24367. var
  24368. JS: TJSString;
  24369. begin
  24370. if Lit.Value.ValueType<>jstString then
  24371. RaiseInconsistency(20171112020856,ErrorEl);
  24372. if Lit.Value.CustomValue<>'' then
  24373. JS:=Lit.Value.CustomValue
  24374. else
  24375. JS:=Lit.Value.AsString;
  24376. if length(JS)<>1 then
  24377. RaiseNotSupported(ErrorEl,AContext,20171112021003);
  24378. Lit.Value.AsNumber:=ord(JS[1]);
  24379. end;
  24380. function TPasToJSConverter.ClonePrimaryExpression(El: TJSPrimaryExpression;
  24381. Src: TPasElement): TJSPrimaryExpression;
  24382. begin
  24383. Result:=TJSPrimaryExpression(CreateElement(TJSElementClass(El.ClassType),Src));
  24384. if Result.ClassType=TJSPrimaryExpressionIdent then
  24385. TJSPrimaryExpressionIdent(Result).Name:=TJSPrimaryExpressionIdent(El).Name;
  24386. end;
  24387. function TPasToJSConverter.CreateMulNumber(El: TPasElement; JS: TJSElement;
  24388. n: TMaxPrecInt): TJSElement;
  24389. // create JS*n
  24390. var
  24391. Mul: TJSMultiplicativeExpressionMul;
  24392. Value: TJSValue;
  24393. begin
  24394. if JS is TJSLiteral then
  24395. begin
  24396. Value:=TJSLiteral(JS).Value;
  24397. case Value.ValueType of
  24398. jstUNDEFINED:
  24399. begin
  24400. // undefined * number -> NaN
  24401. Value.AsNumber:=NaN;
  24402. exit(JS);
  24403. end;
  24404. jstNull:
  24405. begin
  24406. // null*number -> 0
  24407. Value.AsNumber:=0;
  24408. exit(JS);
  24409. end;
  24410. jstBoolean:
  24411. begin
  24412. // true is 1, false is 0
  24413. if Value.AsBoolean then
  24414. Value.AsNumber:=n
  24415. else
  24416. Value.AsNumber:=0;
  24417. exit(JS);
  24418. end;
  24419. jstNumber:
  24420. if IsNan(Value.AsNumber) or IsInfinite(Value.AsNumber) then
  24421. else
  24422. begin
  24423. Value.AsNumber:=Value.AsNumber*n;
  24424. exit(JS);
  24425. end;
  24426. end;
  24427. end;
  24428. Mul:=TJSMultiplicativeExpressionMul(CreateElement(TJSMultiplicativeExpressionMul,El));
  24429. Result:=Mul;
  24430. Mul.A:=JS;
  24431. Mul.B:=CreateLiteralNumber(El,n);
  24432. end;
  24433. function TPasToJSConverter.CreateDivideNumber(El: TPasElement; JS: TJSElement;
  24434. n: TMaxPrecInt): TJSElement;
  24435. // create JS/n
  24436. var
  24437. Mul: TJSMultiplicativeExpressionDiv;
  24438. Value: TJSValue;
  24439. begin
  24440. if (n<>0) and (JS is TJSLiteral) then
  24441. begin
  24442. Value:=TJSLiteral(JS).Value;
  24443. case Value.ValueType of
  24444. jstUNDEFINED:
  24445. begin
  24446. // undefined / number -> NaN
  24447. Value.AsNumber:=NaN;
  24448. exit(JS);
  24449. end;
  24450. jstNull:
  24451. begin
  24452. // null / number -> 0
  24453. Value.AsNumber:=0;
  24454. exit(JS);
  24455. end;
  24456. jstBoolean:
  24457. begin
  24458. // true is 1, false is 0
  24459. if Value.AsBoolean then
  24460. Value.AsNumber:=1/n
  24461. else
  24462. Value.AsNumber:=0;
  24463. exit(JS);
  24464. end;
  24465. jstNumber:
  24466. if IsNan(Value.AsNumber) or IsInfinite(Value.AsNumber) then
  24467. else
  24468. begin
  24469. Value.AsNumber:=Value.AsNumber / n;
  24470. exit(JS);
  24471. end;
  24472. end;
  24473. end;
  24474. Mul:=TJSMultiplicativeExpressionDiv(CreateElement(TJSMultiplicativeExpressionDiv,El));
  24475. Result:=Mul;
  24476. Mul.A:=JS;
  24477. Mul.B:=CreateLiteralNumber(El,n);
  24478. end;
  24479. function TPasToJSConverter.CreateTruncFloor(El: TPasElement; JS: TJSElement;
  24480. FloorAndCeil: boolean): TJSElement;
  24481. // create Math.floor(JS)
  24482. var
  24483. Value: TJSValue;
  24484. Call: TJSCallExpression;
  24485. begin
  24486. if JS is TJSLiteral then
  24487. begin
  24488. Value:=TJSLiteral(JS).Value;
  24489. case Value.ValueType of
  24490. jstUNDEFINED:
  24491. begin
  24492. // Math.floor(undefined) -> NaN
  24493. Value.AsNumber:=NaN;
  24494. exit(JS);
  24495. end;
  24496. jstNull:
  24497. begin
  24498. // Math.floor(null) -> 0
  24499. Value.AsNumber:=0;
  24500. exit(JS);
  24501. end;
  24502. jstBoolean:
  24503. begin
  24504. // true is 1, false is 0
  24505. if Value.AsBoolean then
  24506. Value.AsNumber:=1
  24507. else
  24508. Value.AsNumber:=0;
  24509. exit(JS);
  24510. end;
  24511. jstNumber:
  24512. begin
  24513. if IsNan(Value.AsNumber) or IsInfinite(Value.AsNumber) then
  24514. exit(JS);
  24515. if FloorAndCeil then
  24516. Value.AsNumber:=Trunc(Value.AsNumber)
  24517. else
  24518. Value.AsNumber:=Floor(Value.AsNumber);
  24519. exit(JS);
  24520. end;
  24521. end;
  24522. end;
  24523. Call:=CreateCallExpression(El);
  24524. Result:=Call;
  24525. if FloorAndCeil then
  24526. Call.Expr:=CreatePrimitiveDotExpr(GetBIName(pbivnRTL)+'.'+GetBIName(pbifnTrunc),El)
  24527. else
  24528. Call.Expr:=CreatePrimitiveDotExpr('Math.floor',El);
  24529. Call.AddArg(JS);
  24530. end;
  24531. function TPasToJSConverter.CreateDotNameExpr(PosEl: TPasElement;
  24532. MExpr: TJSElement; const aName: TJSString): TJSDotMemberExpression;
  24533. begin
  24534. Result:=TJSDotMemberExpression(CreateElement(TJSDotMemberExpression,PosEl));
  24535. Result.MExpr:=MExpr;
  24536. Result.Name:=aName;
  24537. end;
  24538. function TPasToJSConverter.CreateDotExpression(aParent: TPasElement; Left,
  24539. Right: TJSElement; CheckRightIntfRef: boolean): TJSElement;
  24540. var
  24541. Dot: TJSDotMemberExpression;
  24542. RightParent, Expr: TJSElement;
  24543. ok: Boolean;
  24544. Call: TJSCallExpression;
  24545. begin
  24546. Result:=nil;
  24547. if Left=nil then
  24548. RaiseInconsistency(20170201140827,aParent);
  24549. if Right=nil then
  24550. RaiseInconsistency(20170211192018,aParent);
  24551. if CheckRightIntfRef and IsInterfaceRef(Right) then
  24552. begin
  24553. // right was an implicit call
  24554. // convert "$ir.ref(id,Expr)" -> $ir.ref(id,Left.Expr)
  24555. Call:=TJSCallExpression(Right);
  24556. Expr:=Call.Args.Elements[1].Expr;
  24557. Call.Args.Elements[1].Expr:=CreateDotExpression(aParent,Left,Expr);
  24558. Result:=Call;
  24559. exit;
  24560. end;
  24561. ok:=false;
  24562. try
  24563. // create a TJSDotMemberExpression of Left and the left-most identifier of Right
  24564. // Left becomes the new left-most element of Right.
  24565. Result:=Right;
  24566. RightParent:=nil;
  24567. repeat
  24568. if (Right.ClassType=TJSCallExpression) then
  24569. begin
  24570. RightParent:=Right;
  24571. Right:=TJSCallExpression(Right).Expr;
  24572. if Right=nil then
  24573. begin
  24574. // left-most is nil -> insert Left
  24575. TJSCallExpression(RightParent).Expr:=Left;
  24576. break;
  24577. end;
  24578. end
  24579. else if (Right.ClassType=TJSBracketMemberExpression) then
  24580. begin
  24581. RightParent:=Right;
  24582. Right:=TJSBracketMemberExpression(Right).MExpr;
  24583. if Right=nil then
  24584. begin
  24585. // left-most is nil -> insert Left
  24586. TJSBracketMemberExpression(RightParent).MExpr:=Left;
  24587. break;
  24588. end;
  24589. end
  24590. else if (Right.ClassType=TJSDotMemberExpression) then
  24591. begin
  24592. RightParent:=Right;
  24593. Right:=TJSDotMemberExpression(Right).MExpr;
  24594. if Right=nil then
  24595. begin
  24596. // left-most is nil -> insert Left
  24597. TJSDotMemberExpression(RightParent).MExpr:=Left;
  24598. break;
  24599. end;
  24600. end
  24601. else if (Right.ClassType=TJSPrimaryExpressionIdent) then
  24602. begin
  24603. // left-most identifier found
  24604. // -> replace it
  24605. Dot := TJSDotMemberExpression(CreateElement(TJSDotMemberExpression, aParent));
  24606. if Result=Right then
  24607. Result:=Dot
  24608. else if RightParent is TJSBracketMemberExpression then
  24609. TJSBracketMemberExpression(RightParent).MExpr:=Dot
  24610. else if RightParent is TJSCallExpression then
  24611. TJSCallExpression(RightParent).Expr:=Dot
  24612. else if RightParent is TJSDotMemberExpression then
  24613. TJSDotMemberExpression(RightParent).MExpr:=Dot
  24614. else
  24615. begin
  24616. Dot.Free;
  24617. {$IFDEF VerbosePas2JS}
  24618. writeln('TPasToJSConverter.CreateDotExpression Right=',GetObjName(Right),' RightParent=',GetObjName(RightParent),' Result=',GetObjName(Result));
  24619. {$ENDIF}
  24620. RaiseInconsistency(20170129141307,aParent);
  24621. end;
  24622. Dot.MExpr := Left;
  24623. Dot.Name := TJSPrimaryExpressionIdent(Right).Name;
  24624. FreeAndNil(Right);
  24625. break;
  24626. end
  24627. else
  24628. begin
  24629. {$IFDEF VerbosePas2JS}
  24630. writeln('CreateDotExpression Right=',Right.ClassName);
  24631. {$ENDIF}
  24632. DoError(20161024191240,nMemberExprMustBeIdentifier,sMemberExprMustBeIdentifier,[],aParent);
  24633. end;
  24634. until false;
  24635. ok:=true;
  24636. finally
  24637. if not ok then
  24638. begin
  24639. Left.Free;
  24640. FreeAndNil(Result);
  24641. end;
  24642. end;
  24643. end;
  24644. function TPasToJSConverter.CreateOverflowCheckCall(GetExpr: TJSElement;
  24645. PosEl: TPasElement): TJSCallExpression;
  24646. var
  24647. Call: TJSCallExpression;
  24648. begin
  24649. Call:=CreateCallExpression(PosEl);
  24650. Call.Expr:=CreatePrimitiveDotExpr(GetBIName(pbivnRTL)+'.'+GetBIName(pbifnOverflowCheckInt),PosEl);
  24651. Call.AddArg(GetExpr);
  24652. Result:=Call;
  24653. end;
  24654. function TPasToJSConverter.CreateRangeCheckCall(GetExpr: TJSElement; MinVal,
  24655. MaxVal: TMaxPrecInt; RTLFunc: TPas2JSBuiltInName; PosEl: TPasElement
  24656. ): TJSCallExpression;
  24657. var
  24658. Call: TJSCallExpression;
  24659. begin
  24660. Call:=CreateCallExpression(PosEl);
  24661. Call.Expr:=CreatePrimitiveDotExpr(GetBIName(pbivnRTL)+'.'+GetBIName(RTLFunc),PosEl);
  24662. Call.AddArg(GetExpr);
  24663. Call.AddArg(CreateLiteralNumber(PosEl,MinVal));
  24664. Call.AddArg(CreateLiteralNumber(PosEl,MaxVal));
  24665. Result:=Call;
  24666. end;
  24667. function TPasToJSConverter.CreateRangeCheckCall_TypeRange(aType: TPasType;
  24668. GetExpr: TJSElement; AContext: TConvertContext; PosEl: TPasElement
  24669. ): TJSCallExpression;
  24670. var
  24671. Value: TResEvalValue;
  24672. begin
  24673. Result:=nil;
  24674. Value:=AContext.Resolver.EvalTypeRange(aType,[refConst]);
  24675. try
  24676. if Value=nil then
  24677. RaiseNotSupported(PosEl,AContext,20180424111936,'range checking '+GetObjName(aType));
  24678. case Value.Kind of
  24679. revkRangeInt:
  24680. case TResEvalRangeInt(Value).ElKind of
  24681. revskEnum, revskInt:
  24682. Result:=CreateRangeCheckCall(GetExpr,TResEvalRangeInt(Value).RangeStart,
  24683. TResEvalRangeInt(Value).RangeEnd,pbifnRangeCheckInt,PosEl);
  24684. revskChar:
  24685. Result:=CreateRangeCheckCall(GetExpr,TResEvalRangeInt(Value).RangeStart,
  24686. TResEvalRangeInt(Value).RangeEnd,pbifnRangeCheckChar,PosEl);
  24687. revskBool: ; // range check not needed
  24688. else
  24689. RaiseNotSupported(PosEl,AContext,20190220002007,'range checking '+Value.AsDebugString);
  24690. end;
  24691. else
  24692. RaiseNotSupported(PosEl,AContext,20180424112010,'range checking '+Value.AsDebugString);
  24693. end;
  24694. finally
  24695. ReleaseEvalValue(Value);
  24696. if Result=nil then
  24697. GetExpr.Free;
  24698. end;
  24699. end;
  24700. procedure TPasToJSConverter.PrepareAssignDifferentIntegers(El: TPasImplAssign;
  24701. AssignContext: TAssignContext);
  24702. function CutToUIntDouble(IntValue: TMaxPrecInt): TMaxPrecInt;
  24703. begin
  24704. {$IFDEF pas2js}
  24705. Result:=((IntValue div $80000000) and $003fffff)*$80000000 +(IntValue and $7FFFFFFF);
  24706. {$ELSE}
  24707. Result:=IntValue and MaxSafeIntDouble;
  24708. {$ENDIF}
  24709. end;
  24710. var
  24711. aResolver: TPas2JSResolver;
  24712. LeftBT, RightBT: TResolverBaseType;
  24713. Value: TResEvalValue;
  24714. IntValue, LeftMinVal, LeftMaxVal, RightMinVal, RightMaxVal: TMaxPrecInt;
  24715. Lit: TJSLiteral;
  24716. begin
  24717. aResolver:=AssignContext.Resolver;
  24718. LeftBT:=AssignContext.LeftResolved.BaseType;
  24719. RightBT:=AssignContext.RightResolved.BaseType;
  24720. if not aResolver.GetIntegerRange(LeftBT,LeftMinVal,LeftMaxVal) then
  24721. RaiseNotSupported(El.Left,AssignContext,20210815195159);
  24722. if not aResolver.GetIntegerRange(RightBT,RightMinVal,RightMaxVal) then
  24723. RaiseNotSupported(El.Right,AssignContext,20210815195228);
  24724. if (LeftMinVal<=RightMinVal) and (LeftMaxVal>=RightMaxVal) then
  24725. exit; // right is subset of left
  24726. // right might not fit into left
  24727. Value:=aResolver.Eval(El.Right,[]);
  24728. try
  24729. if Value<>nil then
  24730. begin
  24731. case Value.Kind of
  24732. revkInt:
  24733. begin
  24734. IntValue:=TResEvalInt(Value).Int;
  24735. if (IntValue>=LeftMinVal) and (IntValue<=LeftMaxVal) then
  24736. exit;
  24737. end;
  24738. revkUInt:
  24739. begin
  24740. if TResEvalUInt(Value).UInt<=HighIntAsUInt then
  24741. begin
  24742. IntValue:=TMaxPrecInt(TResEvalUInt(Value).UInt);
  24743. if (IntValue>=LeftMinVal) and (IntValue<=LeftMaxVal) then
  24744. exit;
  24745. end
  24746. else
  24747. {$IFDEF Pas2js}
  24748. RaiseNotSupported(El.right,AssignContext,20210815214534);
  24749. {$ELSE}
  24750. IntValue:=PMaxPrecInt(@TResEvalUInt(Value).UInt)^;
  24751. {$ENDIF}
  24752. end;
  24753. revkExternal:
  24754. exit;
  24755. else
  24756. RaiseNotSupported(El.Right,AssignContext,20210815204203,'right='+Value.AsDebugString);
  24757. end;
  24758. case LeftBT of
  24759. btByte: IntValue:=IntValue and $FF; // Note: "and" handles negative numbers
  24760. btShortInt:
  24761. begin
  24762. IntValue:=(IntValue and $FF);
  24763. if IntValue>$7F then IntValue:=IntValue-$100;
  24764. end;
  24765. btWord: IntValue:=IntValue and $FFFF;
  24766. btSmallInt:
  24767. begin
  24768. IntValue:=(IntValue and $FFFF);
  24769. if IntValue>$7FFF then IntValue:=IntValue-$10000;
  24770. end;
  24771. btLongWord: IntValue:=IntValue and $FFFFFFFF;
  24772. btLongint:
  24773. begin
  24774. IntValue:=(IntValue and $FFFFFFFF);
  24775. if IntValue>$7FFFFFFF then IntValue:=IntValue-$100000000;
  24776. end;
  24777. btUIntDouble:
  24778. IntValue:=CutToUIntDouble(IntValue);
  24779. btIntDouble:
  24780. IntValue:=CutToUIntDouble(IntValue);
  24781. end;
  24782. if AssignContext.RightSide is TJSLiteral then
  24783. begin
  24784. Lit:=TJSLiteral(AssignContext.RightSide);
  24785. if Lit.Value.ValueType=jstNumber then
  24786. begin
  24787. Lit.Value.AsNumber:=IntValue;
  24788. Lit.Value.CustomValue:='';
  24789. exit;
  24790. end;
  24791. end;
  24792. if AssignContext.RightSide<>nil then
  24793. AssignContext.RightSide.Free;
  24794. AssignContext.RightSide:=CreateLiteralNumber(El.Right,IntValue);
  24795. end;
  24796. finally
  24797. ReleaseEvalValue(Value);
  24798. end;
  24799. end;
  24800. function TPasToJSConverter.CreateReferencePath(El: TPasElement;
  24801. AContext: TConvertContext; Kind: TRefPathKind; Full: boolean;
  24802. Ref: TResolvedReference): string;
  24803. { Notes:
  24804. - local var, argument or result variable, even higher lvl does not need a reference path
  24805. local vars are also argument, result var, result variable
  24806. - with context uses the local $withnnn var
  24807. - auto created local var
  24808. otherwise use absolute path
  24809. }
  24810. var
  24811. aResolver: TPas2JSResolver;
  24812. function IsLocalVar: boolean;
  24813. begin
  24814. Result:=false;
  24815. if El.ClassType=TPasArgument then
  24816. exit(true);
  24817. if El.ClassType=TPasResultElement then
  24818. exit(true);
  24819. if aResolver=nil then
  24820. exit(true);
  24821. if El.Parent=nil then
  24822. RaiseNotSupported(El,AContext,20170203121306,GetObjName(El));
  24823. if El.Parent.ClassType=TPasImplExceptOn then
  24824. exit(true);
  24825. if not (El.Parent is TProcedureBody) then exit;
  24826. Result:=true;
  24827. end;
  24828. procedure Prepend(var aPath: string; Prefix: string);
  24829. begin
  24830. if (aPath<>'') and (aPath[1]<>'[') then
  24831. aPath:='.'+aPath;
  24832. aPath:=Prefix+aPath;
  24833. end;
  24834. procedure PrependClassOrRecName(var Path: string; ClassOrRec: TPasMembersType);
  24835. begin
  24836. if (ClassOrRec.ClassType=TPasClassType) and TPasClassType(ClassOrRec).IsExternal then
  24837. repeat
  24838. Prepend(Path,TPasClassType(ClassOrRec).ExternalName);
  24839. if ClassOrRec.Parent.ClassType=TPasClassType then
  24840. ClassOrRec := ClassOrRec.Parent as TPasClassType
  24841. else
  24842. break;
  24843. until false
  24844. else
  24845. Prepend(Path,CreateGlobalTypePath(ClassOrRec,AContext));
  24846. end;
  24847. function NeedsWithExpr: boolean;
  24848. var
  24849. Parent: TPasElement;
  24850. begin
  24851. if (Ref=nil) or (Ref.WithExprScope=nil) then exit(false);
  24852. Parent:=El.Parent;
  24853. if (Parent.ClassType=TPasClassType)
  24854. and (TPasClassType(Parent).HelperForType<>nil) then
  24855. begin
  24856. // e.g. with Obj do HelperMethod
  24857. if aResolver.IsHelperForMember(El) then
  24858. // e.g. with Obj do HelperExternalMethod -> Obj.HelperCall
  24859. else
  24860. // e.g. with Obj do HelperMethod -> THelper.HelperCall
  24861. exit(false);
  24862. end;
  24863. Result:=true;
  24864. end;
  24865. function ProcSelfIsInstance(Proc: TPasElement): boolean;
  24866. var
  24867. C: TClass;
  24868. begin
  24869. if Proc=nil then exit(false);
  24870. C:=Proc.ClassType;
  24871. Result:=(C=TPasFunction) or (C=TPasProcedure) or (C=TPasConstructor) or (C=TPasDestructor);
  24872. end;
  24873. procedure Append_GetClass(Member: TPasElement);
  24874. var
  24875. P: TPasElement;
  24876. begin
  24877. P:=Member.Parent;
  24878. if P=nil then
  24879. RaiseNotSupported(Member,AContext,20191018125004);
  24880. if P.ClassType=TPasClassType then
  24881. begin
  24882. if TPasClassType(P).IsExternal then
  24883. exit;
  24884. if Result<>'' then
  24885. Result:=Result+'.'+GetBIName(pbivnPtrClass)
  24886. else
  24887. Result:=GetBIName(pbivnPtrClass);
  24888. end
  24889. else if P.ClassType=TPasRecordType then
  24890. begin
  24891. if Result<>'' then
  24892. Result:=Result+'.'+GetBIName(pbivnPtrRecord)
  24893. else
  24894. Result:=GetBIName(pbivnPtrRecord);
  24895. end
  24896. else
  24897. RaiseNotSupported(Member,AContext,20190106110525);
  24898. end;
  24899. function GetAbsoluteAlias: string;
  24900. var
  24901. AbsolResolved: TPasResolverResult;
  24902. begin
  24903. aResolver.ComputeElement(TPasVariable(El).AbsoluteExpr,AbsolResolved,[rcNoImplicitProc]);
  24904. Result:=CreateReferencePath(AbsolResolved.IdentEl,AContext,Kind,Full,Ref);
  24905. end;
  24906. function ImplToDecl(El: TPasElement): TPasElement;
  24907. var
  24908. ProcScope: TPasProcedureScope;
  24909. begin
  24910. Result:=El;
  24911. if El.CustomData is TPasProcedureScope then
  24912. begin
  24913. // proc: always use the declaration, not the body
  24914. ProcScope:=TPasProcedureScope(El.CustomData);
  24915. if ProcScope.DeclarationProc<>nil then
  24916. Result:=ProcScope.DeclarationProc;
  24917. end;
  24918. end;
  24919. function IsA(SrcType, DstType: TPasType): boolean;
  24920. var
  24921. C: TClass;
  24922. begin
  24923. while SrcType<>nil do
  24924. begin
  24925. if SrcType=DstType then exit(true);
  24926. C:=SrcType.ClassType;
  24927. if C=TPasClassType then
  24928. SrcType:=TPas2JSClassScope(SrcType.CustomData).DirectAncestor
  24929. else if (C=TPasAliasType)
  24930. or (C=TPasTypeAliasType) then
  24931. SrcType:=TPasAliasType(SrcType).DestType
  24932. else if C=TPasSpecializeType then
  24933. begin
  24934. if SrcType.CustomData is TPasSpecializeTypeData then
  24935. SrcType:=TPasSpecializeTypeData(SrcType.CustomData).SpecializedType
  24936. else
  24937. RaiseInconsistency(20191027172642,SrcType);
  24938. end
  24939. else
  24940. exit(false);
  24941. end;
  24942. Result:=false;
  24943. end;
  24944. function ShortRefGlobal: boolean;
  24945. var
  24946. ElClass: TClass;
  24947. Proc: TPasProcedure;
  24948. begin
  24949. ElClass:=El.ClassType;
  24950. if ElClass.InheritsFrom(TPasType) then
  24951. begin
  24952. if El.Parent.ClassType=TProcedureBody then
  24953. exit(false);
  24954. CreateReferencePath:=CreateGlobalTypePath(TPasType(El),AContext);
  24955. exit(true);
  24956. end
  24957. else if ElClass.InheritsFrom(TPasProcedure) then
  24958. begin
  24959. Proc:=TPasProcedure(El);
  24960. if ProcCanHaveShortRef(Proc) then
  24961. begin
  24962. if aResolver.ProcHasSelf(Proc) then
  24963. begin
  24964. {$IFDEF VerbosePas2JS}
  24965. writeln('TPasToJSConverter.CreateReferencePath El=',GetObjName(El),' Parent=',GetObjName(El.Parent),' Kind=',Kind,' Context=',GetObjName(AContext),' SelfContext=',GetObjName(AContext.GetSelfContext));
  24966. {$ENDIF}
  24967. aResolver.RaiseNotYetImplemented(20201030233511,El);
  24968. end;
  24969. CreateReferencePath:=CreateStaticProcPath(Proc,AContext);
  24970. exit(true);
  24971. end;
  24972. end
  24973. else if (ElClass=TPasEnumValue) then
  24974. begin
  24975. CreateReferencePath:=CreateGlobalElPath(El,AContext);
  24976. exit(true);
  24977. end;
  24978. Result:=false;
  24979. end;
  24980. var
  24981. FoundModule: TPasModule;
  24982. ParentEl, CurEl: TPasElement;
  24983. Dot: TDotContext;
  24984. WithData: TPas2JSWithExprScope;
  24985. ShortName: String;
  24986. SelfContext: TFunctionContext;
  24987. ElClass: TClass;
  24988. IsClassRec: Boolean;
  24989. VarKinds: TCtxVarKinds;
  24990. Proc: TPasProcedure;
  24991. begin
  24992. Result:='';
  24993. {$IFDEF VerbosePas2JS}
  24994. //writeln('TPasToJSConverter.CreateReferencePath START El=',GetObjName(El),' Parent=',GetObjName(El.Parent),' Context=',GetObjName(AContext),' SelfContext=',GetObjName(AContext.GetSelfContext));
  24995. //AContext.WriteStack;
  24996. {$ENDIF}
  24997. aResolver:=AContext.Resolver;
  24998. if (El is TPasType) and (AContext<>nil) then
  24999. El:=aResolver.ResolveAliasType(TPasType(El));
  25000. ElClass:=El.ClassType;
  25001. if ElClass.InheritsFrom(TPasVariable) and (TPasVariable(El).AbsoluteExpr<>nil)
  25002. and (AContext.Resolver<>nil) then
  25003. exit(GetAbsoluteAlias);
  25004. if AContext is TDotContext then
  25005. begin
  25006. Dot:=TDotContext(AContext);
  25007. if aResolver<>nil then
  25008. begin
  25009. if ElClass.InheritsFrom(TPasVariable) then
  25010. begin
  25011. //writeln('TPasToJSConverter.CreateReferencePath Left=',GetResolverResultDbg(Dot.LeftResolved),' Right=class var ',GetObjName(El));
  25012. if ([vmClass,vmStatic]*ClassVarModifiersType*TPasVariable(El).VarModifiers<>[])
  25013. and (Dot.Access=caAssign)
  25014. and aResolver.ResolvedElIsClassOrRecordInstance(Dot.LeftResolved) then
  25015. begin
  25016. // writing a class var or class const
  25017. Append_GetClass(El);
  25018. end;
  25019. end
  25020. else if aResolver.IsMethod_SelfIsClass(El)
  25021. and aResolver.ResolvedElIsClassOrRecordInstance(Dot.LeftResolved) then
  25022. // accessing a class method from an object, 'this' must be the class/record
  25023. Append_GetClass(El);
  25024. end;
  25025. end
  25026. else if IsLocalVar then
  25027. begin
  25028. // El is local var -> does not need path
  25029. end
  25030. else if ElClass.InheritsFrom(TPasProcedure)
  25031. and (TPasProcedure(El).LibrarySymbolName<>nil)
  25032. and not (El.Parent is TPasMembersType) then
  25033. begin
  25034. // an external global function -> use the literal
  25035. if Kind=rpkPathAndName then
  25036. Result:=ComputeConstString(TPasProcedure(El).LibrarySymbolName,AContext,true)
  25037. else
  25038. Result:='';
  25039. exit;
  25040. end
  25041. else if ElClass.InheritsFrom(TPasVariable) and (TPasVariable(El).ExportName<>nil)
  25042. and not (El.Parent is TPasMembersType) then
  25043. begin
  25044. // an external global var -> use the literal
  25045. if Kind=rpkPathAndName then
  25046. Result:=ComputeConstString(TPasVariable(El).ExportName,AContext,true)
  25047. else
  25048. Result:='';
  25049. exit;
  25050. end
  25051. else if (ElClass=TPasClassType) and TPasClassType(El).IsExternal then
  25052. begin
  25053. // an external class -> use the literal
  25054. Result:=TPasClassType(El).ExternalName;
  25055. if El.Parent is TPasMembersType then
  25056. PrependClassOrRecName(Result,TPasMembersType(El.Parent));
  25057. exit;
  25058. end
  25059. else if NeedsWithExpr then
  25060. begin
  25061. // using local WITH var
  25062. WithData:=Ref.WithExprScope as TPas2JSWithExprScope;
  25063. if WithData.WithVarName='' then
  25064. RaiseNotSupported(WithData.Expr,AContext,20190209092506,GetObjName(El));
  25065. Prepend(Result,WithData.WithVarName);
  25066. if not (wesfOnlyTypeMembers in WithData.Flags)
  25067. and aResolver.IsMethod_SelfIsClass(El) then
  25068. begin
  25069. // with Obj do NonStaticClassMethod -> append .$class
  25070. Append_GetClass(El);
  25071. end;
  25072. end
  25073. else
  25074. begin
  25075. // neither Dot nor With context, nor local, nor external,
  25076. // -> translate a Pascal identifier to the JS path
  25077. // Examples: this.name, $Self.name, this.sub.name, globalpath.name
  25078. if El.Parent=nil then
  25079. RaiseNotSupported(El,AContext,20170201172141,GetObjName(El));
  25080. if (coShortRefGlobals in Options) and (Kind=rpkPathAndName) then
  25081. begin
  25082. if ShortRefGlobal then exit;
  25083. end;
  25084. El:=ImplToDecl(El);
  25085. CurEl:=El;
  25086. repeat
  25087. ParentEl:=CurEl.Parent;
  25088. if ParentEl=nil then break;
  25089. if ParentEl is TProcedureBody then break;
  25090. ParentEl:=ImplToDecl(ParentEl);
  25091. IsClassRec:=(ParentEl.ClassType=TPasClassType)
  25092. or (ParentEl.ClassType=TPasRecordType);
  25093. if IsClassRec then
  25094. begin
  25095. // Not in a Pascal dotscope and accessing a class member.
  25096. // Possible results: this.v, module.path.path.v, this.$class.v, $Self.v
  25097. // In nested proc 'this' can have another name, e.g. '$Self'
  25098. if (ParentEl.ClassType=TPasClassType)
  25099. and (TPasClassType(ParentEl).HelperForType<>nil) then
  25100. begin
  25101. if (El=CurEl)
  25102. and aResolver.IsHelperForMember(CurEl) then
  25103. begin
  25104. // external helper proc/var -> redirect to helper-for-type
  25105. ParentEl:=aResolver.ResolveAliasType(TPasClassType(ParentEl).HelperForType);
  25106. IsClassRec:=(ParentEl.ClassType=TPasClassType)
  25107. or (ParentEl.ClassType=TPasRecordType);
  25108. if not IsClassRec then
  25109. RaiseNotSupported(El,AContext,20190926091356);
  25110. end
  25111. else
  25112. begin
  25113. // helper members cannot be accessed via "this"
  25114. PrependClassOrRecName(Result,TPasMembersType(ParentEl));
  25115. break;
  25116. end;
  25117. end;
  25118. if Full then
  25119. begin
  25120. PrependClassOrRecName(Result,TPasMembersType(ParentEl));
  25121. break;
  25122. end;
  25123. if El is TPasVariable then
  25124. begin
  25125. if TPasVariable(El).VarModifiers*[vmClass, vmStatic]<>[] then
  25126. VarKinds:=[cvkGlobal,cvkCurType,cvkInstance]
  25127. else
  25128. VarKinds:=[cvkInstance];
  25129. end
  25130. else if El is TPasProcedure then
  25131. begin
  25132. Proc:=TPasProcedure(El);
  25133. if ProcSelfIsInstance(Proc) then
  25134. VarKinds:=[cvkCurType,cvkInstance]
  25135. else
  25136. VarKinds:=[cvkGlobal,cvkCurType,cvkInstance];
  25137. end
  25138. else
  25139. VarKinds:=[cvkGlobal,cvkCurType,cvkInstance];
  25140. if VarKinds<>[cvkGlobal] then
  25141. begin
  25142. // Pascal uses implicit Self -> use "this" if available
  25143. SelfContext:=AContext.GetSelfContext;
  25144. if (SelfContext<>nil)
  25145. and IsA(TPasType(SelfContext.ThisVar.Element),TPasMembersType(ParentEl)) then
  25146. begin
  25147. ShortName:=GetLocalName(SelfContext.ThisVar.Element,VarKinds,AContext);
  25148. if ShortName='' then
  25149. begin
  25150. if not (cvkGlobal in VarKinds) then
  25151. begin
  25152. {$IFDEF VerbosePas2JS}
  25153. {AllowWriteln}
  25154. AContext.WriteStack;
  25155. writeln('TPasToJSConverter.CreateReferencePath SelfContext.ThisVar=',GetObjPath(SelfContext.ThisVar.Element),' El=',GetObjPath(El));
  25156. {AllowWriteln-}
  25157. {$ENDIF}
  25158. RaiseNotSupported(El,AContext,20200920214421);
  25159. end;
  25160. // e.g. inside a static function inside a record accessing a class var of the record
  25161. PrependClassOrRecName(Result,TPasMembersType(ParentEl));
  25162. break;
  25163. end;
  25164. if ProcSelfIsInstance(SelfContext.PasElement) then
  25165. begin
  25166. // inside a method -> Self is a class instance
  25167. if aResolver.IsMethod_SelfIsClass(El) then
  25168. Append_GetClass(El); // accessing a class function -> this.$class.procname
  25169. end;
  25170. Prepend(Result,ShortName);
  25171. break;
  25172. end;
  25173. end;
  25174. ShortName:=GetLocalName(ParentEl,VarKinds,AContext);
  25175. //writeln('TPasToJSConverter.CreateReferencePath NOT USING SELF ',GetObjPath(El),' ShortName=',ShortName);
  25176. if ShortName<>'' then
  25177. begin
  25178. Prepend(Result,ShortName);
  25179. break;
  25180. end
  25181. else if (ParentEl.ClassType=TPasClassType) and TPasClassType(ParentEl).IsExternal then
  25182. begin
  25183. PrependClassOrRecName(Result,TPasClassType(ParentEl));
  25184. break;
  25185. end
  25186. else if coShortRefGlobals in Options then
  25187. begin
  25188. PrependClassOrRecName(Result,TPasMembersType(ParentEl));
  25189. break;
  25190. end
  25191. else
  25192. begin
  25193. ShortName:=TransformElToJSName(ParentEl,AContext);
  25194. Prepend(Result,ShortName);
  25195. end;
  25196. end
  25197. else
  25198. begin
  25199. // check if ParentEl has a JS var
  25200. ShortName:=GetLocalName(ParentEl,[cvkGlobal],AContext);
  25201. if (ShortName<>'') then
  25202. begin
  25203. Prepend(Result,ShortName);
  25204. break;
  25205. end
  25206. else if ParentEl.ClassType=TImplementationSection then
  25207. begin
  25208. // element is in an implementation section (not program/library section)
  25209. // in other unit -> use pas.unitname.$impl
  25210. FoundModule:=ParentEl.GetModule;
  25211. if FoundModule=nil then
  25212. RaiseInconsistency(20161024192755,El);
  25213. Prepend(Result,TransformModuleName(FoundModule,true,AContext)
  25214. +'.'+GetBIName(pbivnImplementation));
  25215. break;
  25216. end
  25217. else if ParentEl is TPasModule then
  25218. begin
  25219. // element is in an unit interface or program/library section
  25220. Prepend(Result,TransformModuleName(TPasModule(ParentEl),true,AContext));
  25221. break;
  25222. end
  25223. else if ParentEl.ClassType=TPasEnumType then
  25224. begin
  25225. Prepend(Result,ParentEl.Name);
  25226. end;
  25227. end;
  25228. CurEl:=ParentEl;
  25229. until false;
  25230. end;
  25231. case Kind of
  25232. rpkPathWithDot:
  25233. if Result<>'' then Result:=Result+'.';
  25234. rpkPathAndName:
  25235. begin
  25236. if (coShortRefGlobals in Options) then
  25237. if ShortRefGlobal then exit;
  25238. ShortName:=TransformElToJSName(El,AContext);
  25239. if Result='' then
  25240. Result:=ShortName
  25241. else if (ShortName<>'') and (ShortName[1] in ['[','(']) then
  25242. Result:=Result+ShortName
  25243. else
  25244. Result:=Result+'.'+ShortName;
  25245. end;
  25246. end;
  25247. end;
  25248. function TPasToJSConverter.CreateReferencePathExpr(El: TPasElement;
  25249. AContext: TConvertContext; Full: boolean; Ref: TResolvedReference
  25250. ): TJSElement;
  25251. var
  25252. Name: String;
  25253. Src: TPasElement;
  25254. begin
  25255. {$IFDEF VerbosePas2JS}
  25256. writeln('TPasToJSConverter.CreateReferencePathExpr El="',GetObjName(El),'" El.Parent=',GetObjName(El.Parent),' ',GetObjName(AContext));
  25257. {$ENDIF}
  25258. Name:=CreateReferencePath(El,AContext,rpkPathAndName,Full,Ref);
  25259. if Ref<>nil then
  25260. Src:=Ref.Element
  25261. else
  25262. Src:=nil;
  25263. Result:=CreatePrimitiveDotExpr(Name,Src);
  25264. end;
  25265. function TPasToJSConverter.CreateGlobalTypePath(El: TPasType;
  25266. AContext: TConvertContext): string;
  25267. var
  25268. aType: TPasType;
  25269. begin
  25270. aType:=AContext.Resolver.ResolveAliasType(El);
  25271. Result:=CreateGlobalElPath(aType,AContext);
  25272. end;
  25273. function TPasToJSConverter.CreateStaticProcPath(El: TPasProcedure;
  25274. AContext: TConvertContext): string;
  25275. begin
  25276. if El.IsAbstract or El.IsExternal then
  25277. RaiseNotSupported(El,AContext,20201101185117)
  25278. else if El.IsStatic
  25279. or (El.Parent is TPasSection)
  25280. or (TPas2JSProcedureScope(El.CustomData).SpecializedFromItem<>nil) then
  25281. Result:=CreateGlobalElPath(El,AContext)
  25282. else
  25283. RaiseNotSupported(El,AContext,20200925104007);
  25284. end;
  25285. function TPasToJSConverter.CreateGlobalElPath(El: TPasElement;
  25286. AContext: TConvertContext): string;
  25287. var
  25288. ShortRefGlobals: Boolean;
  25289. Parent: TPasElement;
  25290. CurModule: TPasModule;
  25291. ElClass: TClass;
  25292. aResolver: TPas2JSResolver;
  25293. begin
  25294. aResolver:=AContext.Resolver;
  25295. Result:=AContext.GetLocalName(El,[cvkGlobal]);
  25296. if Result<>'' then
  25297. begin
  25298. // already exists
  25299. if coStoreImplJS in Options then
  25300. StoreImplJSLocal(El,AContext);
  25301. exit;
  25302. end;
  25303. ShortRefGlobals:=coShortRefGlobals in Options;
  25304. Parent:=El.Parent;
  25305. if Parent<>nil then
  25306. begin
  25307. Result:=AContext.GetLocalName(Parent,[cvkGlobal]);
  25308. if Result='' then
  25309. begin
  25310. ElClass:=Parent.ClassType;
  25311. if ElClass.InheritsFrom(TPasType) then
  25312. Result:=CreateGlobalElPath(Parent,AContext)
  25313. else if ElClass.InheritsFrom(TPasSection) then
  25314. begin
  25315. // element is in foreign unit -> use pas.unitname
  25316. CurModule:=Parent.GetModule;
  25317. Result:=TransformModuleName(CurModule,true,AContext);
  25318. if (Parent.ClassType=TImplementationSection)
  25319. and (CurModule<>AContext.GetRootContext.PasElement.GetModule) then
  25320. begin
  25321. // element is in foreign implementation section (not program/library section)
  25322. // -> use pas.unitname.$impl
  25323. Result:=Result+'.'+GetBIName(pbivnImplementation);
  25324. end;
  25325. end
  25326. else if ElClass.InheritsFrom(TPasModule) then
  25327. Result:=TransformModuleName(TPasModule(Parent),true,AContext)
  25328. else
  25329. RaiseNotSupported(El,AContext,20200609230526,GetObjPath(El));
  25330. end
  25331. else
  25332. begin
  25333. // parent has local var
  25334. if (coStoreImplJS in Options) and (aResolver.GetParentProcBody(Parent)=nil) then
  25335. StoreImplJSLocal(Parent,AContext);
  25336. end;
  25337. Result:=Result+'.'+TransformElToJSName(El,AContext);
  25338. end
  25339. else
  25340. begin
  25341. if El is TPasModule then
  25342. begin
  25343. Result:=TransformModuleName(TPasModule(El),true,AContext);
  25344. exit; // already created a shortrefglobal
  25345. end
  25346. else
  25347. RaiseNotSupported(El,AContext,20201010221704,GetObjPath(El));
  25348. end;
  25349. if ShortRefGlobals then
  25350. Result:=CreateGlobalAliasForeign(El,Result,AContext);
  25351. end;
  25352. function TPasToJSConverter.GetLocalName(El: TPasElement;
  25353. const Filter: TCtxVarKinds; AContext: TConvertContext): string;
  25354. begin
  25355. if coStoreImplJS in Options then
  25356. begin
  25357. if cvkGlobal in Filter then
  25358. begin
  25359. Result:=AContext.GetLocalName(El,[cvkGlobal]);
  25360. if Result<>'' then
  25361. begin
  25362. StoreImplJSLocal(El,AContext);
  25363. exit;
  25364. end
  25365. else if Filter=[cvkGlobal] then
  25366. exit('');
  25367. end;
  25368. end;
  25369. Result:=AContext.GetLocalName(El,Filter);
  25370. end;
  25371. function TPasToJSConverter.ProcCanHaveShortRef(Proc: TPasProcedure): boolean;
  25372. var
  25373. C: TClass;
  25374. begin
  25375. // can not:
  25376. if Proc.IsExternal or Proc.IsVirtual then
  25377. exit(false);
  25378. C:=Proc.Parent.ClassType;
  25379. if C=TProcedureBody then
  25380. exit(false);
  25381. // can:
  25382. if C.InheritsFrom(TPasSection) then
  25383. exit(true);
  25384. if Proc.IsStatic then
  25385. exit(true);
  25386. if TPas2JSProcedureScope(Proc.CustomData).SpecializedFromItem<>nil then
  25387. exit(true);
  25388. Result:=false;
  25389. end;
  25390. procedure TPasToJSConverter.StoreImplJSLocal(El: TPasElement;
  25391. AContext: TConvertContext);
  25392. var
  25393. Ctx: TConvertContext;
  25394. CurEl: TPasElement;
  25395. Data: TObject;
  25396. ImplJS: TPas2JSPrecompiledJS;
  25397. begin
  25398. Ctx:=AContext;
  25399. while Ctx<>nil do
  25400. begin
  25401. CurEl:=Ctx.PasElement;
  25402. if CurEl<>nil then
  25403. begin
  25404. Data:=CurEl.CustomData;
  25405. if Data is TPas2JSProcedureScope then
  25406. begin
  25407. ImplJS:=TPas2JSProcedureScope(Data).ImplJS;
  25408. if ImplJS<>nil then
  25409. ImplJS.AddShortRef(El);
  25410. end
  25411. else if Data is TPas2JSInitialFinalizationScope then
  25412. begin
  25413. ImplJS:=TPas2JSInitialFinalizationScope(Data).ImplJS;
  25414. if ImplJS<>nil then
  25415. ImplJS.AddShortRef(El);
  25416. end;
  25417. end;
  25418. Ctx:=Ctx.Parent;
  25419. end;
  25420. end;
  25421. procedure TPasToJSConverter.StoreImplJSLocals(ModScope: TPas2JSModuleScope;
  25422. IntfContext: TSectionContext);
  25423. var
  25424. i, StoredIndex: Integer;
  25425. CtxVar: TFCLocalIdentifier;
  25426. StoredVar: TPas2JSStoredLocalVar;
  25427. CurName: String;
  25428. begin
  25429. ModScope.ClearStoreJSLocalVars;
  25430. SetLength(ModScope.StoreJSLocalVars,length(IntfContext.LocalVars));
  25431. StoredIndex:=0;
  25432. for i:=0 to length(IntfContext.LocalVars)-1 do
  25433. begin
  25434. CtxVar:=IntfContext.LocalVars[i];
  25435. if (CtxVar.Element=nil) or (CtxVar.Kind<>cvkGlobal) then
  25436. continue;
  25437. if CtxVar.Element.Parent is TProcedureBody then
  25438. continue;
  25439. CurName:=CtxVar.Name;
  25440. if (CurName='') or (CurName='this')
  25441. or (CurName=GetBIName(pbivnModule))
  25442. or (CurName=GetBIName(pbivnImplementation))
  25443. then continue;
  25444. StoredVar:=TPas2JSStoredLocalVar.Create;
  25445. StoredVar.Name:=CurName;
  25446. StoredVar.Element:=CtxVar.Element;
  25447. ModScope.StoreJSLocalVars[StoredIndex]:=StoredVar;
  25448. inc(StoredIndex);
  25449. end;
  25450. SetLength(ModScope.StoreJSLocalVars,StoredIndex);
  25451. end;
  25452. procedure TPasToJSConverter.RestoreImplJSLocals(ModScope: TPas2JSModuleScope;
  25453. IntfContext: TSectionContext);
  25454. begin
  25455. IntfContext.PrecompiledVars:=ModScope.StoreJSLocalVars;
  25456. end;
  25457. procedure TPasToJSConverter.CreateProcedureCall(var Call: TJSCallExpression;
  25458. Args: TParamsExpr; TargetProc: TPasProcedureType; AContext: TConvertContext);
  25459. // create a call, adding call by reference and default values
  25460. begin
  25461. if Call=nil then
  25462. Call:=TJSCallExpression(CreateElement(TJSCallExpression,Args));
  25463. if ((Args=nil) or (length(Args.Params)=0))
  25464. and ((TargetProc=nil) or (TargetProc.Args.Count=0)) then
  25465. exit;
  25466. if Call.Args=nil then
  25467. Call.Args:=TJSArguments(CreateElement(TJSArguments,Args));
  25468. CreateProcedureCallArgs(Call.Args.Elements,Args,TargetProc,AContext);
  25469. end;
  25470. procedure TPasToJSConverter.CreateProcedureCallArgs(
  25471. Elements: TJSArrayLiteralElements; Args: TParamsExpr;
  25472. TargetProc: TPasProcedureType; AContext: TConvertContext);
  25473. // Add call arguments. Handle call by reference and default values
  25474. var
  25475. ArgContext: TConvertContext;
  25476. i: Integer;
  25477. Arg: TJSElement;
  25478. TargetArgs: TFPList;
  25479. TargetArg: TPasArgument;
  25480. OldAccess: TCtxAccess;
  25481. begin
  25482. // get context
  25483. ArgContext:=AContext.GetNonDotContext;
  25484. i:=0;
  25485. OldAccess:=ArgContext.Access;
  25486. if TargetProc<>nil then
  25487. TargetArgs:=TargetProc.Args
  25488. else
  25489. TargetArgs:=nil;
  25490. // add params
  25491. if Args<>nil then
  25492. while i<length(Args.Params) do
  25493. begin
  25494. if (TargetArgs<>nil) and (i<TargetArgs.Count) then
  25495. TargetArg:=TPasArgument(TargetArgs[i])
  25496. else
  25497. TargetArg:=nil;
  25498. Arg:=CreateProcCallArg(Args.Params[i],TargetArg,ArgContext);
  25499. Elements.AddElement.Expr:=Arg;
  25500. inc(i);
  25501. end;
  25502. // fill up default values
  25503. if TargetProc<>nil then
  25504. begin
  25505. while i<TargetArgs.Count do
  25506. begin
  25507. TargetArg:=TPasArgument(TargetArgs[i]);
  25508. if TargetArg.ValueExpr=nil then
  25509. begin
  25510. {$IFDEF VerbosePas2JS}
  25511. writeln('TPasToJSConverter.CreateProcedureCallArgs missing default value: i=',i,' TargetProc=',GetObjPath(TargetProc),' Args=',GetObjPath(Args));
  25512. {$ENDIF}
  25513. if Args=nil then
  25514. RaiseNotSupported(TargetProc,AContext,20201028203457)
  25515. else
  25516. RaiseNotSupported(Args,AContext,20170201193601);
  25517. end;
  25518. AContext.Access:=caRead;
  25519. Arg:=ConvertExpression(TargetArg.ValueExpr,ArgContext);
  25520. Elements.AddElement.Expr:=Arg;
  25521. inc(i);
  25522. end;
  25523. end;
  25524. ArgContext.Access:=OldAccess;
  25525. end;
  25526. function TPasToJSConverter.CreateProcCallArg(El: TPasExpr;
  25527. TargetArg: TPasArgument; AContext: TConvertContext): TJSElement;
  25528. var
  25529. ExprIsTemp, ExprIsTempValid: boolean;
  25530. ExprResolved, ArgResolved: TPasResolverResult;
  25531. function ExprIsTemporaryVar: boolean;
  25532. // returns true if Expr is a temporary variable, e.g. a function result
  25533. begin
  25534. if not ExprIsTempValid then
  25535. begin
  25536. ExprIsTempValid:=true;
  25537. ExprIsTemp:=IsExprTemporaryVar(El);
  25538. end;
  25539. Result:=ExprIsTemp;
  25540. end;
  25541. var
  25542. ExprFlags: TPasResolverComputeFlags;
  25543. IsRecord, NeedVar, ArgTypeIsArray, aManaged: Boolean;
  25544. ArgTypeEl, ExprTypeEl: TPasType;
  25545. Call: TJSCallExpression;
  25546. aResolver: TPas2JSResolver;
  25547. begin
  25548. Result:=nil;
  25549. if TargetArg=nil then
  25550. begin
  25551. // simple conversion
  25552. AContext.Access:=caRead;
  25553. Result:=ConvertExpression(El,AContext);
  25554. exit;
  25555. end;
  25556. if not (TargetArg.Access in [argDefault,argVar,argOut,argConst,argConstRef]) then
  25557. DoError(20170213220927,nPasElementNotSupported,sPasElementNotSupported,
  25558. [AccessNames[TargetArg.Access]],El);
  25559. aResolver:=AContext.Resolver;
  25560. aResolver.ComputeElement(TargetArg,ArgResolved,[]);
  25561. ArgTypeEl:=ArgResolved.LoTypeEl;
  25562. IsRecord:=ArgTypeEl is TPasRecordType;
  25563. ArgTypeIsArray:=ArgTypeEl is TPasArrayType;
  25564. aManaged:=false;
  25565. if ArgTypeIsArray then
  25566. aManaged:=aResolver.IsManagedJSType(ArgTypeEl);
  25567. NeedVar:=(TargetArg.Access in [argVar,argOut]) and not IsRecord;
  25568. ExprFlags:=[];
  25569. if NeedVar then
  25570. Include(ExprFlags,rcNoImplicitProc)
  25571. else if aResolver.IsProcedureType(ArgResolved,true) then
  25572. Include(ExprFlags,rcNoImplicitProcType);
  25573. aResolver.ComputeElement(El,ExprResolved,ExprFlags);
  25574. ExprIsTempValid:=false;
  25575. {$IFDEF VerbosePas2JS}
  25576. writeln('TPasToJSConverter.CreateProcCallArg Arg=',GetResolverResultDbg(ArgResolved),' Expr=',GetResolverResultDbg(ExprResolved));
  25577. {$ENDIF}
  25578. if (TargetArg.ArgType=nil) and (ExprResolved.LoTypeEl is TPasRecordType) then
  25579. NeedVar:=false; // pass aRecord to UntypedArg -> no reference needed
  25580. // consider TargetArg access
  25581. if NeedVar then
  25582. Result:=CreateProcCallArgRef(El,ExprResolved,TargetArg,AContext)
  25583. else
  25584. begin
  25585. // pass as default, const or constref
  25586. AContext.Access:=caRead;
  25587. if ArgTypeIsArray then
  25588. begin
  25589. // array as argument
  25590. if ExprResolved.BaseType=btNil then
  25591. begin
  25592. if aManaged then
  25593. // nil to array of COM interface -> pass null
  25594. Result:=CreateLiteralNull(El)
  25595. else
  25596. // nil to array -> pass []
  25597. Result:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,El));
  25598. exit;
  25599. end
  25600. else if ExprResolved.BaseType in btAllStringAndChars then
  25601. begin
  25602. // pass string to an array
  25603. Result:=ConvertExpression(El,AContext);
  25604. Result:=CreateDotSplit(El,Result);
  25605. end
  25606. else
  25607. Result:=CreateArrayInit(TPasArrayType(ArgTypeEl),El,El,AContext);
  25608. end
  25609. else if ExprResolved.BaseType=btProc then
  25610. begin
  25611. if (ArgTypeEl is TPasProcedureType)
  25612. and (msDelphi in AContext.CurrentModeSwitches)
  25613. and (ExprResolved.IdentEl is TPasProcedure) then
  25614. begin
  25615. // Delphi allows passing a proc address without @
  25616. Result:=CreateCallback(El,ExprResolved,
  25617. TPasProcedureType(ArgTypeEl).CallingConvention=ccSafeCall,
  25618. AContext);
  25619. end;
  25620. end;
  25621. if Result=nil then
  25622. Result:=ConvertExpression(El,AContext);
  25623. if (ExprResolved.BaseType=btSet) and (ExprResolved.IdentEl<>nil) then
  25624. begin
  25625. // pass a set variable
  25626. if TargetArg.Access=argDefault then
  25627. begin
  25628. // pass set with argDefault -> create reference rtl.refSet(right)
  25629. {$IFDEF VerbosePas2JS}
  25630. writeln('TPasToJSConverter.CreateProcCallArg create reference of SET variable Right={',GetResolverResultDbg(ExprResolved),'} AssignContext.RightResolved.IdentEl=',GetObjName(ExprResolved.IdentEl));
  25631. {$ENDIF}
  25632. Result:=CreateReferencedSet(El,Result);
  25633. end;
  25634. end
  25635. else if ArgResolved.BaseType=btCurrency then
  25636. begin
  25637. if ExprResolved.BaseType<>btCurrency then
  25638. begin
  25639. // pass double to currency -> *10000
  25640. Result:=CreateMulNumber(El,Result,10000);
  25641. end;
  25642. end
  25643. else if ExprResolved.BaseType=btCurrency then
  25644. begin
  25645. if ArgResolved.BaseType<>btCurrency then
  25646. begin
  25647. // pass currency to noncurrency
  25648. // e.g. pass currency to double -> /10000
  25649. Result:=CreateDivideNumber(El,Result,10000);
  25650. end;
  25651. end
  25652. else if ExprResolved.BaseType in btAllStrings then
  25653. begin
  25654. if ArgTypeEl=nil then
  25655. // string to untyped
  25656. else if ArgTypeEl.ClassType=TPasRecordType then
  25657. begin
  25658. if aResolver.IsTGUID(TPasRecordType(ArgTypeEl)) then
  25659. begin
  25660. // pass aString to TGuid -> rtl.strToGUIDR(aString)
  25661. Call:=CreateCallExpression(El);
  25662. Call.Expr:=CreatePrimitiveDotExpr(GetBIName(pbivnRTL)+'.'+GetBIName(pbifnIntfStrToGUIDR),El);
  25663. Call.AddArg(Result);
  25664. Result:=Call;
  25665. end;
  25666. end;
  25667. end
  25668. else if ExprResolved.BaseType=btContext then
  25669. begin
  25670. ExprTypeEl:=ExprResolved.LoTypeEl;
  25671. if (ExprTypeEl.ClassType=TPasArrayType) then
  25672. begin
  25673. if length(TPasArrayType(ExprTypeEl).Ranges)>0 then
  25674. begin
  25675. if (TargetArg.Access=argDefault)
  25676. and not ExprIsTemporaryVar then
  25677. begin
  25678. // pass static array with argDefault -> clone
  25679. Result:=CreateCloneStaticArray(El,TPasArrayType(ExprTypeEl),Result,AContext);
  25680. end;
  25681. end
  25682. else
  25683. begin
  25684. // pass dyn or open array
  25685. if (TargetArg.Access=argDefault)
  25686. and (ArgResolved.BaseType=btContext)
  25687. and (ArgResolved.LoTypeEl is TPasArrayType)
  25688. and not (ArgResolved.LoTypeEl.Parent is TPasArgument)
  25689. and not ExprIsTemporaryVar then
  25690. begin
  25691. // pass dyn array to argDefault array -> reference
  25692. if not aManaged then
  25693. Result:=CreateArrayRef(El,Result);
  25694. end;
  25695. end;
  25696. end
  25697. else if ExprTypeEl.ClassType=TPasClassType then
  25698. begin
  25699. if ArgTypeEl=nil then
  25700. // class to untyped
  25701. else if ArgResolved.BaseType in btAllStrings then
  25702. begin
  25703. if TPasClassType(ExprTypeEl).ObjKind=okInterface then
  25704. begin
  25705. // pass IntfVarOrType to string -> IntfVarOrType.$guid
  25706. Result:=CreateDotNameExpr(El,Result,TJSString(GetBIName(pbivnIntfGUID)));
  25707. end;
  25708. end
  25709. else if ArgTypeEl.ClassType=TPasRecordType then
  25710. begin
  25711. if (TPasClassType(ExprTypeEl).ObjKind=okInterface)
  25712. and aResolver.IsTGUID(TPasRecordType(ArgTypeEl)) then
  25713. begin
  25714. // pass IntfTypeOrVar to GUIDRecord -> rtl.getIntfGUIDR(IntfTypeOrVar)
  25715. Call:=CreateCallExpression(El);
  25716. Call.Expr:=CreatePrimitiveDotExpr(GetBIName(pbivnRTL)+'.'+GetBIName(pbifnIntfGetGUIDR),El);
  25717. Call.AddArg(Result);
  25718. Result:=Call;
  25719. if TargetArg.Access=argDefault then
  25720. begin
  25721. // pass record with argDefault -> "TGuid.$clone(RightRecord)"
  25722. {$IFDEF VerbosePas2JS}
  25723. writeln('TPasToJSConverter.CreateProcCallArg clone RECORD TGuid variable Right={',GetResolverResultDbg(ExprResolved),'} AssignContext.RightResolved.IdentEl=',GetObjName(ExprResolved.IdentEl));
  25724. {$ENDIF}
  25725. Result:=CreateRecordCallClone(El,TPasRecordType(ArgTypeEl),Result,AContext);
  25726. end;
  25727. end
  25728. else
  25729. RaiseNotSupported(El,AContext,20180410160008);
  25730. end
  25731. else if ArgTypeEl.ClassType=TPasClassType then
  25732. case TPasClassType(ExprTypeEl).ObjKind of
  25733. okClass:
  25734. case TPasClassType(ArgTypeEl).ObjKind of
  25735. okClass: ; // pass ClassInstVar to ClassType
  25736. okInterface:
  25737. begin
  25738. // pass ClassInstVar to IntfType
  25739. Call:=CreateCallExpression(El);
  25740. case TPasClassType(ArgTypeEl).InterfaceType of
  25741. citCom:
  25742. begin
  25743. // COM: $ir.ref(id,rtl.queryIntfT(Expr,IntfType))
  25744. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnIntfQueryIntfT)]);
  25745. Call.AddArg(Result);
  25746. Result:=Call;
  25747. Call.AddArg(CreateReferencePathExpr(ArgTypeEl,AContext));
  25748. Call:=CreateIntfRef(Call,AContext,El);
  25749. Result:=Call;
  25750. end;
  25751. citCorba:
  25752. begin
  25753. // CORBA: rtl.getIntfT(Expr,IntfType)
  25754. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnIntfGetIntfT)]);
  25755. Call.AddArg(Result);
  25756. Result:=Call;
  25757. Call.AddArg(CreateReferencePathExpr(ArgTypeEl,AContext));
  25758. end;
  25759. else
  25760. RaiseNotSupported(El,AContext,20180401230251,InterfaceTypeNames[TPasClassType(ArgTypeEl).InterfaceType]){%H-};
  25761. end;
  25762. end
  25763. else
  25764. RaiseNotSupported(El,AContext,20180328134244,ObjKindNames[TPasClassType(ArgTypeEl).ObjKind]);
  25765. end;
  25766. okInterface:
  25767. case TPasClassType(ExprTypeEl).ObjKind of
  25768. okInterface: ; // pass IntfVar to IntfType
  25769. else
  25770. RaiseNotSupported(El,AContext,20180328134305,ObjKindNames[TPasClassType(ArgTypeEl).ObjKind]);
  25771. end;
  25772. else
  25773. RaiseNotSupported(El,AContext,20180328134146,ObjKindNames[TPasClassType(ExprTypeEl).ObjKind]);
  25774. end;
  25775. end
  25776. else if ExprTypeEl.ClassType=TPasRecordType then
  25777. begin
  25778. // right side is a record
  25779. if (ArgResolved.BaseType in btAllStrings)
  25780. and aResolver.IsTGUID(TPasRecordType(ExprTypeEl)) then
  25781. begin
  25782. // pass GuidVar to string -> rtl.guidrToStr(GuidVar)
  25783. Call:=CreateCallExpression(El);
  25784. Call.Expr:=CreatePrimitiveDotExpr(GetBIName(pbivnRTL)+'.'+GetBIName(pbifnIntfGuidRToStr),El);
  25785. Call.AddArg(Result);
  25786. Result:=Call;
  25787. exit;
  25788. end;
  25789. if TargetArg.Access=argDefault then
  25790. begin
  25791. // pass record with argDefault -> "RightRecord.$clone(RightRecord)"
  25792. {$IFDEF VerbosePas2JS}
  25793. writeln('TPasToJSConverter.CreateProcCallArg clone RECORD variable Right={',GetResolverResultDbg(ExprResolved),'} AssignContext.RightResolved.IdentEl=',GetObjName(ExprResolved.IdentEl));
  25794. {$ENDIF}
  25795. Result:=CreateRecordCallClone(El,TPasRecordType(ExprTypeEl),Result,AContext);
  25796. end;
  25797. end
  25798. else if (ExprResolved.LoTypeEl is TPasProcedureType)
  25799. and (ArgResolved.LoTypeEl is TPasProcedureType)
  25800. and (TPasProcedureType(ArgResolved.LoTypeEl).CallingConvention=ccSafeCall)
  25801. and (TPasProcedureType(ExprResolved.LoTypeEl).CallingConvention<>ccSafeCall) then
  25802. begin
  25803. // pass non safecall proc to SafeCall proc type -> make safecall
  25804. Result:=CreateSafeCallback(El,Result,AContext);
  25805. end;
  25806. end;
  25807. end;
  25808. end;
  25809. function TPasToJSConverter.CreateProcCallArgRef(El: TPasExpr;
  25810. ResolvedEl: TPasResolverResult; TargetArg: TPasArgument;
  25811. AContext: TConvertContext): TJSElement;
  25812. var
  25813. Obj: TJSObjectLiteral;
  25814. procedure AddVar(const aName: string; var Expr: TJSElement);
  25815. var
  25816. ObjLit: TJSObjectLiteralElement;
  25817. begin
  25818. if Expr=nil then exit;
  25819. ObjLit:=Obj.Elements.AddElement;
  25820. ObjLit.Name:=TJSString(aName);
  25821. ObjLit.Expr:=Expr;
  25822. Expr:=nil;
  25823. end;
  25824. function IfReadOnlyCreateRaiseE(const ParamContext: TParamContext): TJSElement;
  25825. begin
  25826. if not (rrfWritable in ResolvedEl.Flags) then
  25827. begin
  25828. FreeAndNil(ParamContext.Setter);
  25829. ParamContext.Setter:=CreateRaisePropReadOnly(El);
  25830. end;
  25831. Result:=ParamContext.Setter;
  25832. end;
  25833. function CreateRgCheck(const SetterArgName: string): TJSElement;
  25834. function CreateRgCheckSt(aType: TPasType): TJSElement;
  25835. begin
  25836. Result:=CreateRangeCheckCall_TypeRange(aType,
  25837. CreatePrimitiveDotExpr(SetterArgName,El),AContext,El);
  25838. end;
  25839. var
  25840. ArgResolved: TPasResolverResult;
  25841. TypeEl: TPasType;
  25842. begin
  25843. Result:=nil;
  25844. if TargetArg.ArgType=nil then exit;
  25845. AContext.Resolver.ComputeElement(TargetArg,ArgResolved,[]);
  25846. TypeEl:=ArgResolved.LoTypeEl;
  25847. if TypeEl=nil then exit;
  25848. if ArgResolved.BaseType in btAllJSRangeCheckTypes then
  25849. Result:=CreateRgCheckSt(TypeEl)
  25850. else if ArgResolved.BaseType=btContext then
  25851. begin
  25852. if TypeEl.ClassType=TPasEnumType then
  25853. Result:=CreateRgCheckSt(TypeEl);
  25854. end
  25855. else if ArgResolved.BaseType=btRange then
  25856. begin
  25857. if ArgResolved.SubType in btAllJSRangeCheckTypes then
  25858. Result:=CreateRgCheckSt(TypeEl)
  25859. else if ArgResolved.SubType=btContext then
  25860. Result:=CreateRgCheckSt(TypeEl)
  25861. else
  25862. begin
  25863. {$IFDEF VerbosePas2JS}
  25864. writeln('TPasToJSConverter.CreateProcCallArgRef ',GetResolverResultDbg(ArgResolved));
  25865. RaiseNotSupported(El,AContext,20190220014806);
  25866. {$ENDIF}
  25867. end;
  25868. end;
  25869. end;
  25870. var
  25871. ParamContext: TParamContext;
  25872. FullGetter, GetPathExpr, SetPathExpr, GetExpr, SetExpr, ParamExpr,
  25873. RHS, RgCheck: TJSElement;
  25874. AssignSt: TJSSimpleAssignStatement;
  25875. ObjLit: TJSObjectLiteralElement;
  25876. FuncSt: TJSFunctionDeclarationStatement;
  25877. RetSt: TJSReturnStatement;
  25878. GetDotPos, SetDotPos: Integer;
  25879. GetPath, SetPath: String;
  25880. BracketExpr: TJSBracketMemberExpression;
  25881. DotExpr: TJSDotMemberExpression;
  25882. SetterArgName: String;
  25883. TypeEl: TPasType;
  25884. FuncContext: TFunctionContext;
  25885. aManaged, HasCustomSetter: Boolean;
  25886. Call: TJSCallExpression;
  25887. StList: TJSStatementList;
  25888. begin
  25889. // pass reference -> create a temporary JS object with a getter and setter
  25890. Obj:=nil;
  25891. FullGetter:=nil;
  25892. ParamContext:=TParamContext.Create(El,nil,AContext);
  25893. GetPathExpr:=nil;
  25894. SetPathExpr:=nil;
  25895. GetExpr:=nil;
  25896. SetExpr:=nil;
  25897. SetterArgName:=TempRefObjSetterArgName;
  25898. RgCheck:=nil;
  25899. try
  25900. // create FullGetter and setter
  25901. ParamContext.Access:=caByReference;
  25902. ParamContext.Arg:=TargetArg;
  25903. ParamContext.Expr:=El;
  25904. ParamContext.ResolvedExpr:=ResolvedEl;
  25905. FullGetter:=ConvertExpression(El,ParamContext);
  25906. // FullGetter is now a full JS expression to retrieve the value.
  25907. if ParamContext.ReusingReference then
  25908. begin
  25909. // result is already a reference
  25910. Result:=FullGetter;
  25911. exit;
  25912. end;
  25913. // if ParamContext.Getter is set then
  25914. // ParamContext.Getter is the last part of the FullGetter
  25915. // FullSetter is created from FullGetter by replacing the Getter with the Setter
  25916. {$IFDEF VerbosePas2JS}
  25917. writeln('TPasToJSConverter.CreateProcCallArgRef VAR El=',GetObjName(El),' FullGetter=',GetObjName(FullGetter),' Setter=',GetObjName(ParamContext.Setter),' ',GetResolverResultDbg(ResolvedEl));
  25918. {$ENDIF}
  25919. // create "{p:path,get:function(){return this.p.Getter},set:function(v){this.p.Setter(v);}}"
  25920. Obj:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,El));
  25921. if FullGetter.ClassType=TJSPrimaryExpressionIdent then
  25922. begin
  25923. // create "{get:function(){return FullGetter;},set:function(v){FullGetter=v;}}"
  25924. SetExpr:=IfReadOnlyCreateRaiseE(ParamContext);
  25925. HasCustomSetter:=SetExpr<>nil;
  25926. GetPath:=String(TJSPrimaryExpressionIdent(FullGetter).Name);
  25927. GetDotPos:=PosLast('.',GetPath);
  25928. if GetDotPos>0 then
  25929. begin
  25930. // e.g. path1.path2.readvar
  25931. // create
  25932. // GetPathExpr: path1.path2
  25933. // GetExpr: this.p.readvar
  25934. // SetExpr: this.p.readvar
  25935. // Will create "{p:GetPathExpr, get:function(){return GetExpr;},
  25936. // set:function(v){SetExpr = v;}}"
  25937. GetPathExpr:=CreatePrimitiveDotExpr(LeftStr(GetPath,GetDotPos-1),El);
  25938. GetExpr:=CreatePrimitiveDotExpr('this.'+TempRefGetPathName+'.'+copy(GetPath,GetDotPos+1),El);
  25939. if SetExpr=nil then
  25940. SetExpr:=CreatePrimitiveDotExpr('this.'+TempRefGetPathName+'.'+copy(GetPath,GetDotPos+1),El);
  25941. end
  25942. else
  25943. begin
  25944. // local var
  25945. GetExpr:=FullGetter;
  25946. FullGetter:=nil;
  25947. if SetExpr=nil then
  25948. SetExpr:=CreatePrimitiveDotExpr(GetPath,El);
  25949. end;
  25950. if HasCustomSetter then
  25951. begin
  25952. // custom Setter
  25953. ParamContext.Setter:=nil;
  25954. if SetExpr.ClassType=TJSPrimaryExpressionIdent then
  25955. begin
  25956. SetPath:=String(TJSPrimaryExpressionIdent(SetExpr).Name);
  25957. SetDotPos:=PosLast('.',SetPath);
  25958. FreeAndNil(SetExpr);
  25959. if LeftStr(GetPath,GetDotPos)=LeftStr(SetPath,SetDotPos) then
  25960. begin
  25961. // use GetPathExpr for setter
  25962. SetExpr:=CreatePrimitiveDotExpr('this.'+TempRefGetPathName+'.'+copy(SetPath,GetDotPos+1),El);
  25963. end
  25964. else
  25965. begin
  25966. // setter needs its own SetPathExpr
  25967. SetPathExpr:=CreatePrimitiveDotExpr(LeftStr(SetPath,SetDotPos-1),El);
  25968. SetExpr:=CreatePrimitiveDotExpr('this.'+TempRefSetPathName+'.'+copy(SetPath,GetDotPos+1),El);
  25969. end;
  25970. end;
  25971. end;
  25972. end
  25973. else if FullGetter.ClassType=TJSDotMemberExpression then
  25974. begin
  25975. if ParamContext.Setter<>nil then
  25976. RaiseNotSupported(El,AContext,20170214231900);
  25977. // convert this.r.i to
  25978. // {p:this.r,
  25979. // get:function{return this.p.i;},
  25980. // set:function(v){this.p.i=v;}
  25981. // }
  25982. // GetPathExpr: this.r
  25983. // GetExpr: this.p.i
  25984. // SetExpr: this.p.i
  25985. DotExpr:=TJSDotMemberExpression(FullGetter);
  25986. GetPathExpr:=DotExpr.MExpr;
  25987. DotExpr.MExpr:=CreatePrimitiveDotExpr('this.'+TempRefGetPathName,El);
  25988. GetExpr:=DotExpr;
  25989. FullGetter:=nil;
  25990. if (rrfWritable in ResolvedEl.Flags) then
  25991. SetExpr:=CreatePrimitiveDotExpr('this.'+TempRefGetPathName+'.'+String(DotExpr.Name),El)
  25992. else
  25993. SetExpr:=IfReadOnlyCreateRaiseE(ParamContext);
  25994. end
  25995. else if FullGetter.ClassType=TJSBracketMemberExpression then
  25996. begin
  25997. if ParamContext.Setter<>nil then
  25998. RaiseNotSupported(El,AContext,20170214215150);
  25999. // convert path.arr[ParamExpr] to
  26000. // {a:ParamExpr,
  26001. // p:path.arr,
  26002. // get:function{return this.p[this.a];},
  26003. // set:function(v){this.p[this.a]=v;}
  26004. // }
  26005. BracketExpr:=TJSBracketMemberExpression(FullGetter);
  26006. ParamExpr:=BracketExpr.Name;
  26007. // create "a:ParamExpr"
  26008. AddVar(TempRefParamName,ParamExpr);
  26009. // create GetPathExpr "this.arr"
  26010. GetPathExpr:=BracketExpr.MExpr;
  26011. // GetExpr "this.p[this.a]"
  26012. BracketExpr.MExpr:=CreatePrimitiveDotExpr('this.'+TempRefGetPathName,El);
  26013. BracketExpr.Name:=CreatePrimitiveDotExpr('this.'+TempRefParamName,El);
  26014. GetExpr:=BracketExpr;
  26015. FullGetter:=nil;
  26016. // SetExpr "this.p[this.a]"
  26017. BracketExpr:=TJSBracketMemberExpression(CreateElement(TJSBracketMemberExpression,El));
  26018. SetExpr:=BracketExpr;
  26019. BracketExpr.MExpr:=CreatePrimitiveDotExpr('this.'+TempRefGetPathName,El);
  26020. BracketExpr.Name:=CreatePrimitiveDotExpr('this.'+TempRefParamName,El);
  26021. end
  26022. else if FullGetter.ClassType=TJSCallExpression then
  26023. begin
  26024. if ParamContext.Setter<>nil then
  26025. RaiseNotSupported(El,AContext,20190210094430);
  26026. // convert func() to
  26027. // {a:func(),
  26028. // get:function{return this.a;},
  26029. // set:function(v){this.a=v;}
  26030. // }
  26031. // create "p:FullGetter"
  26032. AddVar(TempRefParamName,FullGetter);
  26033. FullGetter:=nil;
  26034. // GetExpr "this.a"
  26035. GetExpr:=CreatePrimitiveDotExpr('this.'+TempRefParamName,El);
  26036. // SetExpr "this.a"
  26037. SetExpr:=CreatePrimitiveDotExpr('this.'+TempRefParamName,El);
  26038. end
  26039. else if FullGetter.ClassType=TJSLiteral then
  26040. begin
  26041. // getter is a const value
  26042. GetExpr:=FullGetter;
  26043. FullGetter:=nil;
  26044. SetExpr:=IfReadOnlyCreateRaiseE(ParamContext);
  26045. ParamContext.Setter:=nil;
  26046. // ToDo: break down SetExpr into path and property
  26047. end
  26048. else
  26049. begin
  26050. // getter is the result of an operation
  26051. // create "p:FullGetter"
  26052. AddVar(TempRefParamName,FullGetter);
  26053. FullGetter:=nil;
  26054. // GetExpr "this.a"
  26055. GetExpr:=CreatePrimitiveDotExpr('this.'+TempRefParamName,El);
  26056. // SetExpr "raise EPropReadOnly"
  26057. SetExpr:=CreateRaisePropReadOnly(El);
  26058. end;
  26059. {$IFDEF VerbosePas2JS}
  26060. //writeln('TPasToJSConverter.CreateProcCallArgRef GetExpr=',GetObjName(GetExpr),' SetExpr=',GetObjName(SetExpr),' SetterArgName=',SetterArgName);
  26061. {$ENDIF}
  26062. if (SetExpr.ClassType=TJSPrimaryExpressionIdent)
  26063. or (SetExpr.ClassType=TJSDotMemberExpression)
  26064. or (SetExpr.ClassType=TJSBracketMemberExpression) then
  26065. begin
  26066. // create setter
  26067. FindAvailableLocalName(SetterArgName,SetExpr);
  26068. RHS:=CreatePrimitiveDotExpr(SetterArgName,El);
  26069. TypeEl:=ResolvedEl.LoTypeEl;
  26070. aManaged:=AContext.Resolver.IsManagedJSType(TypeEl);
  26071. if aManaged and (TargetArg.ArgType<>nil) then
  26072. begin
  26073. // create rtl.setIntfP(path,"IntfVar",v)
  26074. SetExpr:=CreateAssignManagedVar(ResolvedEl,SetExpr,RHS,AContext,El);
  26075. end
  26076. else if (TypeEl is TPasRecordType) then
  26077. begin
  26078. // create SetExpr.$assign(v)
  26079. Call:=CreateCallExpression(El);
  26080. Call.Expr:=CreateDotNameExpr(El,SetExpr,
  26081. TJSString(GetBIName(pbifnRecordAssign)));
  26082. Call.AddArg(RHS);
  26083. SetExpr:=Call;
  26084. end
  26085. else
  26086. begin
  26087. // create SetExpr = v;
  26088. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  26089. AssignSt.LHS:=SetExpr;
  26090. AssignSt.Expr:=RHS;
  26091. SetExpr:=AssignSt;
  26092. if aManaged and (TargetArg.ArgType=nil) then
  26093. begin
  26094. // IntfVar is passed to an untyped parameter
  26095. // This must not call AddRef, but the IntfVar must still be
  26096. // released at the end of the function
  26097. FuncContext:=AContext.GetFunctionContext;
  26098. if ResolvedEl.IdentEl is TPasResultElement then
  26099. FuncContext.ResultNeedsIntfRelease:=true
  26100. else
  26101. FuncContext.Add_InterfaceRelease(ResolvedEl.IdentEl);
  26102. end
  26103. else if (SetExpr is TJSSimpleAssignStatement)
  26104. and (SetterArgName<>'')
  26105. and (bsRangeChecks in AContext.ScannerBoolSwitches) then
  26106. RgCheck:=CreateRgCheck(SetterArgName);
  26107. end;
  26108. end
  26109. else if (SetExpr.ClassType=TJSCallExpression) then
  26110. // has already the form Func(v)
  26111. else
  26112. RaiseInconsistency(20170213225940,El);
  26113. {$IFDEF VerbosePas2JS}
  26114. //writeln('TPasToJSConverter.CreateProcCallArgRef created full SetExpr=',GetObjName(SetExpr),' SetterArgName=',SetterArgName);
  26115. {$ENDIF}
  26116. // add p:GetPathExpr
  26117. AddVar(TempRefGetPathName,GetPathExpr);
  26118. // add get:function(){ return GetExpr; }
  26119. ObjLit:=Obj.Elements.AddElement;
  26120. ObjLit.Name:=TempRefObjGetterName;
  26121. FuncSt:=CreateFunctionSt(El);
  26122. ObjLit.Expr:=FuncSt;
  26123. RetSt:=TJSReturnStatement(CreateElement(TJSReturnStatement,El));
  26124. FuncSt.AFunction.Body.A:=RetSt;
  26125. RetSt.Expr:=GetExpr;
  26126. GetExpr:=nil;
  26127. // add s:SetPathExpr
  26128. AddVar(TempRefSetPathName,SetPathExpr);
  26129. // add set:function(v){ SetExpr }
  26130. ObjLit:=Obj.Elements.AddElement;
  26131. ObjLit.Name:=TempRefObjSetterName;
  26132. FuncSt:=CreateFunctionSt(El);
  26133. ObjLit.Expr:=FuncSt;
  26134. if SetterArgName<>'' then
  26135. FuncSt.AFunction.TypedParams.AddParam(TJSString(SetterArgName));
  26136. if RgCheck<>nil then
  26137. begin
  26138. StList:=TJSStatementList(CreateElement(TJSStatementList,El));
  26139. StList.A:=RgCheck;
  26140. StList.B:=SetExpr;
  26141. SetExpr:=StList;
  26142. end;
  26143. FuncSt.AFunction.Body.A:=SetExpr;
  26144. SetExpr:=nil;
  26145. Result:=Obj;
  26146. finally
  26147. if Result=nil then
  26148. begin
  26149. GetPathExpr.Free;
  26150. SetPathExpr.Free;
  26151. GetExpr.Free;
  26152. SetExpr.Free;
  26153. Obj.Free;
  26154. ParamContext.Setter.Free;
  26155. FullGetter.Free;
  26156. end;
  26157. ParamContext.Free;
  26158. end;
  26159. end;
  26160. function TPasToJSConverter.CreateArrayEl(El: TPasExpr; AContext: TConvertContext
  26161. ): TJSElement;
  26162. var
  26163. JS: TJSElement;
  26164. begin
  26165. JS:=ConvertExpression(El,AContext);
  26166. Result:=CreateArrayEl(El,JS,AContext);
  26167. end;
  26168. function TPasToJSConverter.CreateArrayEl(El: TPasExpr; JS: TJSElement;
  26169. AContext: TConvertContext): TJSElement;
  26170. // call this function for every element of an array literal
  26171. // e.g. [aSet,aStaticArray]
  26172. var
  26173. ResolvedEl: TPasResolverResult;
  26174. ArrayType: TPasArrayType;
  26175. TypeEl: TPasType;
  26176. C: TClass;
  26177. begin
  26178. Result:=JS;
  26179. AContext.Resolver.ComputeElement(El,ResolvedEl,[rcNoImplicitProcType]);
  26180. if ResolvedEl.IdentEl<>nil then
  26181. begin
  26182. // add a variable
  26183. if ResolvedEl.BaseType=btSet then
  26184. begin
  26185. // add a set variable -> create reference rtl.refSet(Expr)
  26186. Result:=CreateReferencedSet(El,Result);
  26187. end
  26188. else if ResolvedEl.BaseType=btContext then
  26189. begin
  26190. TypeEl:=ResolvedEl.LoTypeEl;
  26191. C:=TypeEl.ClassType;
  26192. if C=TPasArrayType then
  26193. begin
  26194. ArrayType:=TPasArrayType(TypeEl);
  26195. if length(ArrayType.Ranges)>0 then
  26196. // add static array variable -> clone
  26197. Result:=CreateCloneStaticArray(El,ArrayType,Result,AContext);
  26198. end
  26199. else if C=TPasRecordType then
  26200. begin
  26201. // add record variable -> clone
  26202. Result:=CreateRecordCallClone(El,TPasRecordType(TypeEl),Result,AContext);
  26203. end;
  26204. end;
  26205. end;
  26206. end;
  26207. function TPasToJSConverter.CreateArgumentAccess(Arg: TPasArgument;
  26208. AContext: TConvertContext; PosEl: TPasElement): TJSElement;
  26209. var
  26210. ArgName: String;
  26211. function CreateSetter(const SetterName: string; AssignContext: TAssignContext): TJSElement;
  26212. var
  26213. Call: TJSCallExpression;
  26214. begin
  26215. Call:=CreateCallExpression(PosEl);
  26216. AssignContext.Call:=Call;
  26217. Call.Expr:=CreateDotNameExpr(PosEl,
  26218. CreatePrimitiveDotExpr(ArgName,PosEl),
  26219. TJSString(SetterName));
  26220. Call.AddArg(AssignContext.RightSide);
  26221. AssignContext.RightSide:=nil;
  26222. Result:=Call;
  26223. end;
  26224. var
  26225. TypeEl: TPasType;
  26226. IsRecord: boolean;
  26227. Call: TJSCallExpression;
  26228. AssignContext: TAssignContext;
  26229. ParamContext: TParamContext;
  26230. begin
  26231. ArgName:=TransformArgName(Arg,AContext);
  26232. TypeEl:=AContext.Resolver.ResolveAliasType(Arg.ArgType);
  26233. IsRecord:=TypeEl is TPasRecordType;
  26234. if AContext.Access=caAssign then
  26235. begin
  26236. AssignContext:=AContext.AccessContext as TAssignContext;
  26237. if IsRecord then
  26238. begin
  26239. // aRecordArg:=right -> "aRecordArg.$assign(right)"
  26240. if AssignContext.Call<>nil then
  26241. RaiseNotSupported(Arg,AContext,20190105174026);
  26242. Result:=CreateSetter(GetBIName(pbifnRecordAssign),AssignContext);
  26243. exit;
  26244. end
  26245. else if (Arg.ArgType=nil)
  26246. and (AssignContext.RightResolved.LoTypeEl is TPasRecordType)
  26247. and (rrfReadable in AssignContext.RightResolved.Flags) then
  26248. begin
  26249. // UntypedArg:=aRecordVar -> "UntypedArg.$assign(right)"
  26250. // Note: records are passed directly to Untyped parameters
  26251. if AssignContext.Call<>nil then
  26252. RaiseNotSupported(Arg,AContext,20190311140048);
  26253. Result:=CreateSetter(GetBIName(pbifnRecordAssign),AssignContext);
  26254. exit;
  26255. end;
  26256. end
  26257. else if IsRecord and (AContext is TParamContext) then
  26258. begin
  26259. ParamContext:=TParamContext(AContext);
  26260. if ParamContext.ResolvedExpr.BaseType=btUntyped then
  26261. begin
  26262. // pass aRecordVar to UntypedArg -> pass aRecordVar directly, no temp ref object
  26263. Result:=CreatePrimitiveDotExpr(ArgName,PosEl);
  26264. exit;
  26265. end;
  26266. end;
  26267. if (Arg.Access in [argVar,argOut]) and not IsRecord then
  26268. begin
  26269. // Arg is a reference object
  26270. case AContext.Access of
  26271. caRead:
  26272. begin
  26273. // create arg.get()
  26274. Call:=CreateCallExpression(PosEl);
  26275. Call.Expr:=CreateDotNameExpr(PosEl,
  26276. CreatePrimitiveDotExpr(ArgName,PosEl),
  26277. TempRefObjGetterName);
  26278. Result:=Call;
  26279. exit;
  26280. end;
  26281. caAssign:
  26282. begin
  26283. // create arg.set(RHS)
  26284. AssignContext:=AContext.AccessContext as TAssignContext;
  26285. if AssignContext.Call<>nil then
  26286. RaiseNotSupported(Arg,AContext,20170214120606);
  26287. Result:=CreateSetter(TempRefObjSetterName,AssignContext);
  26288. exit;
  26289. end;
  26290. caByReference:
  26291. begin
  26292. // simply pass the reference
  26293. ParamContext:=AContext.AccessContext as TParamContext;
  26294. ParamContext.ReusingReference:=true;
  26295. Result:=CreatePrimitiveDotExpr(ArgName,PosEl);
  26296. exit;
  26297. end;
  26298. else
  26299. RaiseNotSupported(Arg,AContext,20170214120739){%H-};
  26300. end;
  26301. end;
  26302. Result:=CreatePrimitiveDotExpr(ArgName,PosEl);
  26303. end;
  26304. function TPasToJSConverter.ConvertExceptOn(El: TPasImplExceptOn;
  26305. AContext: TConvertContext): TJSElement;
  26306. // convert "on T do ;" to "if(T.isPrototypeOf(exceptObject)){}"
  26307. // convert "on E:T do ;" to "if(T.isPrototypeOf(exceptObject)){ var E=exceptObject; }"
  26308. // convert "on TExternal do ;" to "if(rtl.isExt(exceptObject,TExternal)){}"
  26309. Var
  26310. IfSt : TJSIfStatement;
  26311. ListFirst , ListLast: TJSStatementList;
  26312. DotExpr: TJSDotMemberExpression;
  26313. Call: TJSCallExpression;
  26314. V: TJSVariableStatement;
  26315. aResolver: TPas2JSResolver;
  26316. aType: TPasType;
  26317. IsExternal: Boolean;
  26318. begin
  26319. Result:=nil;
  26320. aResolver:=AContext.Resolver;
  26321. aType:=aResolver.ResolveAliasType(El.TypeEl);
  26322. IsExternal:=(aType is TPasClassType) and TPasClassType(aType).IsExternal;
  26323. // create "if()"
  26324. IfSt:=TJSIfStatement(CreateElement(TJSIfStatement,El));
  26325. try
  26326. if IsExternal then
  26327. begin
  26328. // create rtl.isExt(exceptObject,T)
  26329. Call:=CreateCallExpression(El);
  26330. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnIsExt)]);
  26331. Call.AddArg(CreatePrimitiveDotExpr(GetBIName(pbivnExceptObject),El));
  26332. Call.AddArg(CreateReferencePathExpr(El.TypeEl,AContext));
  26333. end
  26334. else
  26335. begin
  26336. // create "T.isPrototypeOf"
  26337. DotExpr:=TJSDotMemberExpression(CreateElement(TJSDotMemberExpression,El));
  26338. DotExpr.MExpr:=CreateReferencePathExpr(El.TypeEl,AContext);
  26339. DotExpr.Name:='isPrototypeOf';
  26340. // create "T.isPrototypeOf(exceptObject)"
  26341. Call:=CreateCallExpression(El);
  26342. Call.Expr:=DotExpr;
  26343. Call.AddArg(CreatePrimitiveDotExpr(GetBIName(pbivnExceptObject),El));
  26344. end;
  26345. IfSt.Cond:=Call;
  26346. if El.VarEl<>nil then
  26347. begin
  26348. // add "var E=exceptObject;"
  26349. ListFirst:=TJSStatementList(CreateElement(TJSStatementList,El.Body));
  26350. ListLast:=ListFirst;
  26351. IfSt.BTrue:=ListFirst;
  26352. V:=CreateVarStatement(TransformElToJSName(El.VarEl,AContext),
  26353. CreatePrimitiveDotExpr(GetBIName(pbivnExceptObject),El),El);
  26354. ListFirst.A:=V;
  26355. // add statements
  26356. if El.Body<>nil then
  26357. AddToStatementList(ListFirst,ListLast,ConvertElement(El.Body,AContext),El);
  26358. end
  26359. else if El.Body<>nil then
  26360. // add statements
  26361. IfSt.BTrue:=ConvertElement(El.Body,AContext);
  26362. Result:=IfSt;
  26363. finally
  26364. if Result=nil then
  26365. IfSt.Free;
  26366. end;
  26367. end;
  26368. function TPasToJSConverter.ConvertStatement(El: TPasImplStatement;
  26369. AContext: TConvertContext): TJSElement;
  26370. begin
  26371. Result:=Nil;
  26372. if (El is TPasImplRaise) then
  26373. Result:=ConvertRaiseStatement(TPasImplRaise(El),AContext)
  26374. else if (El is TPasImplAssign) then
  26375. Result:=ConvertAssignStatement(TPasImplAssign(El),AContext)
  26376. else if (El is TPasImplWhileDo) then
  26377. Result:=ConvertWhileStatement(TPasImplWhileDo(El),AContext)
  26378. else if (El is TPasImplSimple) then
  26379. Result:=ConvertSimpleStatement(TPasImplSimple(El),AContext)
  26380. else if (El is TPasImplWithDo) then
  26381. Result:=ConvertWithStatement(TPasImplWithDo(El),AContext)
  26382. else if (El is TPasImplExceptOn) then
  26383. Result:=ConvertExceptOn(TPasImplExceptOn(El),AContext)
  26384. else if (El is TPasImplForLoop) then
  26385. Result:=ConvertForStatement(TPasImplForLoop(El),AContext)
  26386. else if (El is TPasImplAsmStatement) then
  26387. Result:=ConvertAsmStatement(TPasImplAsmStatement(El),AContext)
  26388. else
  26389. RaiseNotSupported(El,AContext,20161024192759);
  26390. {
  26391. TPasImplCaseStatement = class(TPasImplStatement)
  26392. }
  26393. end;
  26394. function TPasToJSConverter.ConvertConst(El: TPasConst; AContext: TConvertContext
  26395. ): TJSElement;
  26396. // Important: returns nil if const was added to higher context
  26397. Var
  26398. AssignSt: TJSSimpleAssignStatement;
  26399. Obj: TJSObjectLiteral;
  26400. ObjLit: TJSObjectLiteralElement;
  26401. GlobalCtx: TFunctionContext;
  26402. C: TJSElement;
  26403. V: TJSVariableStatement;
  26404. Src: TJSSourceElements;
  26405. Proc: TPasProcedure;
  26406. ProcScope: TPas2JSProcedureScope;
  26407. begin
  26408. Result:=nil;
  26409. if El.AbsoluteExpr<>nil then
  26410. exit; // absolute: do not add a declaration
  26411. if vmExternal in El.VarModifiers then
  26412. exit; // external: do not add a declaration
  26413. if not AContext.IsGlobal then
  26414. begin
  26415. // local const are stored in interface/implementation
  26416. GlobalCtx:=AContext.GetGlobalFunc;
  26417. if not (GlobalCtx.JSElement is TJSSourceElements) then
  26418. begin
  26419. {$IFDEF VerbosePas2JS}
  26420. writeln('TPasToJSConverter.CreateConstDecl GlobalCtx=',GetObjName(GlobalCtx),' JSElement=',GetObjName(GlobalCtx.JSElement));
  26421. {$ENDIF}
  26422. RaiseNotSupported(El,AContext,20170220153216);
  26423. end;
  26424. Src:=TJSSourceElements(GlobalCtx.JSElement);
  26425. C:=ConvertVariable(El,AContext);
  26426. if C=nil then
  26427. RaiseInconsistency(20180501114422,El);
  26428. V:=TJSVariableStatement(CreateElement(TJSVariableStatement,El));
  26429. V.VarDecl:=C;
  26430. AddToSourceElements(Src,V);
  26431. if (coStoreImplJS in Options) and (AContext.Resolver<>nil) then
  26432. begin
  26433. Proc:=AContext.Resolver.GetTopLvlProc(AContext.PasElement);
  26434. if Proc<>nil then
  26435. begin
  26436. ProcScope:=TPas2JSProcedureScope(Proc.CustomData);
  26437. ProcScope.AddGlobalJS(CreatePrecompiledJS(V));
  26438. end;
  26439. end;
  26440. end
  26441. else if AContext is TObjectContext then
  26442. begin
  26443. // create 'A: initvalue'
  26444. Obj:=TObjectContext(AContext).JSElement as TJSObjectLiteral;
  26445. ObjLit:=Obj.Elements.AddElement;
  26446. ObjLit.Name:=TJSString(TransformElToJSName(El,AContext));
  26447. ObjLit.Expr:=CreateVarInit(El,AContext);
  26448. end
  26449. else
  26450. begin
  26451. // create 'this.A=initvalue'
  26452. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  26453. Result:=AssignSt;
  26454. AssignSt.LHS:=CreateSubDeclNameExpr(El,AContext);
  26455. AssignSt.Expr:=CreateVarInit(El,AContext);
  26456. end;
  26457. end;
  26458. function TPasToJSConverter.ConvertLabelMark(El: TPasImplLabelMark;
  26459. AContext: TConvertContext): TJSElement;
  26460. begin
  26461. RaiseNotSupported(El,AContext,20161024192857);
  26462. Result:=Nil;
  26463. // ToDo: TPasImplLabelMark = class(TPasImplLabelMark) then
  26464. end;
  26465. function TPasToJSConverter.ConvertElement(El: TPasElement;
  26466. AContext: TConvertContext): TJSElement;
  26467. var
  26468. C: TClass;
  26469. begin
  26470. {$IFDEF VerbosePas2JS}
  26471. writeln('TPasToJSConverter.ConvertElement El=',GetObjName(El),' Context=',GetObjName(AContext));
  26472. {$ENDIF}
  26473. if El=nil then
  26474. begin
  26475. Result:=nil;
  26476. RaiseInconsistency(20161024190203,El);
  26477. end;
  26478. C:=El.ClassType;
  26479. if C=TPasConst then
  26480. Result:=ConvertConst(TPasConst(El),AContext)
  26481. else if C=TPasProperty then
  26482. Result:=ConvertProperty(TPasProperty(El),AContext)
  26483. else if C=TPasVariable then
  26484. Result:=ConvertVariable(TPasVariable(El),AContext)
  26485. else if C=TPasResString then
  26486. Result:=ConvertResString(TPasResString(El),AContext)
  26487. else if C=TPasExportSymbol then
  26488. Result:=ConvertExportSymbol(TPasExportSymbol(El),AContext)
  26489. else if C=TPasLabels then
  26490. Result:=ConvertLabels(TPasLabels(El),AContext)
  26491. else if C=TPasImplLabelMark then
  26492. Result:=ConvertLabelMark(TPasImplLabelMark(El),AContext)
  26493. else if C.InheritsFrom(TPasExpr) then
  26494. Result:=ConvertExpression(TPasExpr(El),AContext)
  26495. else if C.InheritsFrom(TPasDeclarations) then
  26496. Result:=ConvertDeclarations(TPasDeclarations(El),AContext)
  26497. else if C.InheritsFrom(TPasProcedure) then
  26498. Result:=ConvertProcedure(TPasProcedure(El),AContext)
  26499. else if C.InheritsFrom(TPasImplBlock) then
  26500. Result:=ConvertImplBlock(TPasImplBlock(El),AContext)
  26501. else if C=TPasImplCommand then
  26502. Result:=ConvertImplCommand(TPasImplCommand(El),AContext)
  26503. else if C.InheritsFrom(TPasModule) then
  26504. Result:=ConvertModule(TPasModule(El),AContext)
  26505. else if C=TPasPackage then
  26506. Result:=ConvertPackage(TPasPackage(El),AContext)
  26507. else
  26508. begin
  26509. Result:=nil;
  26510. RaiseNotSupported(El, AContext, 20161024190449);
  26511. end;
  26512. {$IFDEF VerbosePas2JS}
  26513. writeln('TPasToJSConverter.ConvertElement END ',GetObjName(El));
  26514. {$ENDIF}
  26515. end;
  26516. function TPasToJSConverter.ConvertRecordType(El: TPasRecordType;
  26517. AContext: TConvertContext): TJSElement;
  26518. var
  26519. aResolver: TPas2JSResolver;
  26520. DelaySrc: TJSSourceElements;
  26521. DelayFuncContext: TFunctionContext;
  26522. Call: TJSCallExpression;
  26523. JSParentName, JSName: String;
  26524. FunDecl: TJSFunctionDeclarationStatement;
  26525. Src: TJSSourceElements;
  26526. FuncContext: TFunctionContext;
  26527. i: Integer;
  26528. P: TPasElement;
  26529. C: TClass;
  26530. NewEl: TJSElement;
  26531. PasVar: TPasVariable;
  26532. PasVarType: TPasType;
  26533. NewFields, Vars, Methods: TFPList;
  26534. ok, IsComplex, SpecializeDelay: Boolean;
  26535. VarSt: TJSVariableStatement;
  26536. AssignSt: TJSSimpleAssignStatement;
  26537. begin
  26538. Result:=nil;
  26539. if El.Name='' then
  26540. RaiseNotSupported(El,AContext,20190105101258,'anonymous record');
  26541. aResolver:=AContext.Resolver;
  26542. if not aResolver.IsFullySpecialized(El) then exit;
  26543. {$IFDEF VerbosePas2JS}
  26544. writeln('TPasToJSConverter.ConvertRecordType ',GetObjPath(El));
  26545. {$ENDIF}
  26546. FuncContext:=nil;
  26547. NewFields:=nil;
  26548. Vars:=nil;
  26549. Methods:=nil;
  26550. DelaySrc:=nil;
  26551. DelayFuncContext:=nil;
  26552. ok:=false;
  26553. try
  26554. SpecializeDelay:=SpecializeNeedsDelay(El,AContext);
  26555. // rtl.recNewT()
  26556. Call:=CreateCallExpression(El);
  26557. Call.Expr:=CreateMemberExpression([GetBIName(pbivnRTL),GetBIName(pbifnRecordCreateType)]);
  26558. // types are stored in interface/implementation
  26559. if El.Parent is TProcedureBody then
  26560. begin
  26561. // local record type
  26562. if not (AContext.JSElement is TJSSourceElements) then
  26563. RaiseNotSupported(El,AContext,20190105104054);
  26564. // local record type elevated to global scope
  26565. Src:=TJSSourceElements(AContext.JSElement);
  26566. JSName:=TransformElToJSName(El,AContext);
  26567. VarSt:=CreateVarStatement(JSName,Call,El);
  26568. AddToSourceElements(Src,VarSt); // keep Result=nil
  26569. // add parameter: parent = null
  26570. Call.AddArg(CreateLiteralNull(El));
  26571. // add parameter: typename string = ''
  26572. Call.AddArg(CreateLiteralString(El,''));
  26573. end
  26574. else
  26575. begin
  26576. Result:=Call;
  26577. // add parameter: JS parent. For top level record, the module is the JS parent.
  26578. if (El.Parent=nil)
  26579. or ((El.Parent is TPasSection)
  26580. and (El.Parent.ClassType<>TImplementationSection)) then
  26581. JSParentName:=GetLocalName(El.GetModule,[cvkGlobal],AContext)
  26582. else
  26583. JSParentName:=GetLocalName(El.Parent,[cvkGlobal],AContext);
  26584. if JSParentName='' then
  26585. JSParentName:='this';
  26586. Call.AddArg(CreatePrimitiveDotExpr(JSParentName,El));
  26587. // add parameter: typename: string
  26588. Call.AddArg(CreateLiteralString(El,TransformElToJSName(El,AContext)));
  26589. end;
  26590. // add parameter: initialize function 'function(){...}'
  26591. FunDecl:=CreateFunctionSt(El,true,true);
  26592. Call.AddArg(FunDecl);
  26593. Src:=TJSSourceElements(FunDecl.AFunction.Body.A);
  26594. // create context
  26595. FuncContext:=TFunctionContext.Create(El,Src,AContext);
  26596. FuncContext.IsGlobal:=true;
  26597. FuncContext.ThisVar.Element:=El;
  26598. FuncContext.ThisVar.Kind:=cvkGlobal;
  26599. if (coShortRefGlobals in Options) and not (El.Parent is TProcedureBody) then
  26600. begin
  26601. // $lt = this;
  26602. JSName:=AContext.GetLocalName(El,[cvkGlobal]);
  26603. if JSName='' then
  26604. RaiseNotSupported(El,AContext,20200926235501);
  26605. if coStoreImplJS in Options then
  26606. StoreImplJSLocal(El,AContext);
  26607. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  26608. AssignSt.LHS:=CreatePrimitiveDotExpr(JSName,El);
  26609. AssignSt.Expr:=CreatePrimitiveDotExpr('this',El);
  26610. AddToSourceElements(Src,AssignSt);
  26611. end;
  26612. // init fields
  26613. NewFields:=TFPList.Create;
  26614. Vars:=TFPList.Create;
  26615. Methods:=TFPList.Create;
  26616. IsComplex:=false;
  26617. if SpecializeDelay then
  26618. DelayFuncContext:=CreateDelayedInitMembersFunction(El,Src,FuncContext,DelaySrc);
  26619. for i:=0 to El.Members.Count-1 do
  26620. begin
  26621. P:=TPasElement(El.Members[i]);
  26622. //writeln('TPasToJSConverter.ConvertRecordType simple fields El[',i,']=',GetObjName(P));
  26623. if not IsElementUsed(P) then continue;
  26624. C:=P.ClassType;
  26625. NewEl:=nil;
  26626. if C=TPasVariable then
  26627. begin
  26628. PasVar:=TPasVariable(P);
  26629. if PasVar.VarModifiers*[vmClass, vmStatic]<>[] then
  26630. IsComplex:=true
  26631. else if aResolver<>nil then
  26632. begin
  26633. Vars.Add(PasVar);
  26634. PasVarType:=aResolver.ResolveAliasType(PasVar.VarType);
  26635. if PasVarType.ClassType=TPasArrayType then
  26636. begin
  26637. // sub array
  26638. NewFields.Add(PasVar);
  26639. continue;
  26640. end
  26641. else if PasVarType.ClassType=TPasRecordType then
  26642. begin
  26643. // sub record
  26644. NewFields.Add(PasVar);
  26645. continue;
  26646. end
  26647. else if PasVarType.ClassType=TPasSetType then
  26648. begin
  26649. // sub set
  26650. NewFields.Add(PasVar);
  26651. continue;
  26652. end
  26653. else
  26654. begin
  26655. // simple vars are initialized in the record type, no need to initialize them for each instance
  26656. end;
  26657. end;
  26658. NewEl:=CreateVarDecl(PasVar,FuncContext); // can be nil
  26659. end
  26660. else if C=TPasConst then
  26661. begin
  26662. NewEl:=ConvertConst(TPasConst(P),FuncContext);
  26663. IsComplex:=true;
  26664. end
  26665. else if C=TPasProperty then
  26666. NewEl:=ConvertProperty(TPasProperty(P),FuncContext)
  26667. else if C.InheritsFrom(TPasType) then
  26668. begin
  26669. NewEl:=CreateTypeDecl(TPasType(P),FuncContext);
  26670. if (C=TPasRecordType) or (C=TPasClassType) then
  26671. IsComplex:=true;
  26672. end
  26673. else if C.InheritsFrom(TPasProcedure) then
  26674. begin
  26675. if (C=TPasClassConstructor)
  26676. or (C=TPasClassDestructor) then
  26677. AddGlobalClassMethod(FuncContext,TPasProcedure(P))
  26678. else
  26679. Methods.Add(P);
  26680. end
  26681. else if C=TPasAttributes then
  26682. else
  26683. RaiseNotSupported(P,FuncContext,20190105105436);
  26684. if NewEl<>nil then
  26685. begin
  26686. if SpecializeDelay and not (P is TPasProcedure) then
  26687. AddToSourceElements(DelaySrc,NewEl)
  26688. else
  26689. AddToSourceElements(Src,NewEl);
  26690. end;
  26691. end;
  26692. if IsComplex then
  26693. Call.AddArg(CreateLiteralBoolean(El,true)); // needs $record
  26694. // add $new function if needed
  26695. if NewFields.Count>0 then
  26696. AddToSourceElements(Src,CreateRecordFunctionNew(El,FuncContext,NewFields));
  26697. // add $eq function
  26698. AddToSourceElements(Src,CreateRecordFunctionEqual(El,FuncContext,Vars));
  26699. // add $assign function
  26700. AddToSourceElements(Src,CreateRecordFunctionAssign(El,FuncContext,Vars));
  26701. // add methods
  26702. for i:=0 to Methods.Count-1 do
  26703. begin
  26704. P:=TPasProcedure(Methods[i]);
  26705. NewEl:=ConvertProcedure(TPasProcedure(P),FuncContext);
  26706. AddToSourceElements(Src,NewEl);
  26707. end;
  26708. // add RTTI init function
  26709. if (aResolver<>nil) and HasTypeInfo(El,FuncContext) then
  26710. begin
  26711. if SpecializeDelay then
  26712. CreateRecordRTTI(El,Src,FuncContext,DelaySrc,DelayFuncContext)
  26713. else
  26714. CreateRecordRTTI(El,Src,FuncContext,Src,FuncContext);
  26715. end;
  26716. ok:=true;
  26717. finally
  26718. NewFields.Free;
  26719. Vars.Free;
  26720. Methods.Free;
  26721. DelayFuncContext.Free;
  26722. FuncContext.Free;
  26723. if not ok then
  26724. FreeAndNil(Result);
  26725. end;
  26726. end;
  26727. procedure TPasToJSConverter.DoError(Id: TMaxPrecInt; const Msg: String);
  26728. var
  26729. E: EPas2JS;
  26730. begin
  26731. E:=EPas2JS.Create(Msg);
  26732. E.Id:=Id;
  26733. E.MsgType:=mtError;
  26734. Raise E;
  26735. end;
  26736. procedure TPasToJSConverter.DoError(Id: TMaxPrecInt; const Msg: String;
  26737. const Args: array of const);
  26738. var
  26739. E: EPas2JS;
  26740. begin
  26741. E:=EPas2JS.CreateFmt(Msg,Args);
  26742. E.Id:=Id;
  26743. E.MsgType:=mtError;
  26744. Raise E;
  26745. end;
  26746. procedure TPasToJSConverter.DoError(Id: TMaxPrecInt; MsgNumber: integer;
  26747. const MsgPattern: string;
  26748. const Args: array of const;
  26749. El: TPasElement);
  26750. var
  26751. E: EPas2JS;
  26752. begin
  26753. E:=EPas2JS.CreateFmt(MsgPattern,Args);
  26754. {$IFDEF VerbosePas2JS}
  26755. writeln('TPasToJSConverter.DoError ',id,' ',GetElementDbgPath(El),':',El.ClassName,' Msg="',E.Message,'"');
  26756. {$ENDIF}
  26757. E.PasElement:=El;
  26758. E.MsgNumber:=MsgNumber;
  26759. E.Id:=Id;
  26760. E.MsgType:=mtError;
  26761. CreateMsgArgs(E.Args,Args);
  26762. raise E;
  26763. end;
  26764. procedure TPasToJSConverter.RaiseNotSupported(El: TPasElement;
  26765. AContext: TConvertContext; Id: TMaxPrecInt; const Msg: string);
  26766. var
  26767. E: EPas2JS;
  26768. begin
  26769. {$IFDEF VerbosePas2JS}
  26770. writeln('TPasToJSConverter.RaiseNotSupported ',id,' ',GetElementDbgPath(El),':',El.ClassName,' Msg="',Msg,'"');
  26771. {$ENDIF}
  26772. if AContext=nil then ;
  26773. E:=EPas2JS.CreateFmt(sPasElementNotSupported,[GetObjName(El)+' ['+IntToStr(Id)+']']);
  26774. if Msg<>'' then
  26775. E.Message:=E.Message+': '+Msg;
  26776. E.PasElement:=El;
  26777. E.MsgNumber:=nPasElementNotSupported;
  26778. SetLength(E.Args,1);
  26779. E.Args[0]:=El.ClassName;
  26780. E.Id:=Id;
  26781. E.MsgType:=mtError;
  26782. raise E;
  26783. end;
  26784. procedure TPasToJSConverter.RaiseIdentifierNotFound(Identifier: string;
  26785. El: TPasElement; Id: TMaxPrecInt);
  26786. var
  26787. E: EPas2JS;
  26788. begin
  26789. E:=EPas2JS.CreateFmt(sIdentifierNotFound,[Identifier]);
  26790. E.PasElement:=El;
  26791. E.MsgNumber:=nIdentifierNotFound;
  26792. SetLength(E.Args,1);
  26793. E.Args[0]:=Identifier;
  26794. E.Id:=Id;
  26795. E.MsgType:=mtError;
  26796. raise E;
  26797. end;
  26798. procedure TPasToJSConverter.RaiseInconsistency(Id: TMaxPrecInt; El: TPasElement);
  26799. var
  26800. s: String;
  26801. begin
  26802. s:='TPasToJSConverter.RaiseInconsistency['+IntToStr(Id)+']: you found a bug';
  26803. if El<>nil then
  26804. begin
  26805. s:=s+GetElementDbgPath(El);
  26806. if El.Name<>'' then
  26807. s:=s+El.Name
  26808. else
  26809. s:=s+GetElementTypeName(El);
  26810. s:=s+' at '+TPas2JSResolver.GetDbgSourcePosStr(El);
  26811. end;
  26812. raise Exception.Create(s);
  26813. end;
  26814. function TPasToJSConverter.TransformToJSName(ErrorEl: TPasElement;
  26815. const AName: String; CheckGlobal: boolean; AContext: TConvertContext): String;
  26816. // CheckGlobal: check name clashes with global identifiers too
  26817. var
  26818. i: Integer;
  26819. c: AnsiChar;
  26820. begin
  26821. if AContext=nil then ;
  26822. if Pos('.',AName)>0 then
  26823. RaiseInconsistency(20170203164711,ErrorEl);
  26824. if UseLowerCase then
  26825. Result:=LowerCase(AName)
  26826. else
  26827. Result:=AName;
  26828. if not IsReservedWord(Result,CheckGlobal) then
  26829. exit;
  26830. for i:=1 to length(Result) do
  26831. begin
  26832. c:=Result[i];
  26833. case c of
  26834. 'a'..'z','A'..'Z':
  26835. begin
  26836. Result[i]:=chr(ord(c) xor 32);
  26837. if not IsReservedWord(Result,CheckGlobal) then
  26838. exit;
  26839. end;
  26840. end;
  26841. end;
  26842. RaiseNotSupported(ErrorEl,AContext,20170203131832);
  26843. end;
  26844. function TPasToJSConverter.TransformElToJSName(El: TPasElement;
  26845. AContext: TConvertContext): String;
  26846. var
  26847. aType: TPasType;
  26848. begin
  26849. if (El is TPasProcedure) and (TPasProcedure(El).LibrarySymbolName<>nil) then
  26850. Result:=ComputeConstString(TPasProcedure(El).LibrarySymbolName,AContext,true)
  26851. else if (El is TPasVariable) and (TPasVariable(El).ExportName<>nil) then
  26852. Result:=ComputeConstString(TPasVariable(El).ExportName,AContext,true)
  26853. else if (El is TPasType) then
  26854. begin
  26855. if AContext.Resolver<>nil then
  26856. aType:=AContext.Resolver.ResolveAliasType(TPasType(El))
  26857. else
  26858. aType:=TPasType(El);
  26859. if (aType.ClassType=TPasClassType) and TPasClassType(aType).IsExternal then
  26860. Result:=TPasClassType(aType).ExternalName
  26861. else
  26862. Result:=TransformToJSName(El,GetOverloadName(aType,AContext),
  26863. CanClashWithGlobal(aType),AContext);
  26864. end
  26865. else
  26866. Result:=TransformToJSName(El,GetOverloadName(El,AContext),
  26867. CanClashWithGlobal(El),AContext);
  26868. end;
  26869. function TPasToJSConverter.TransformModuleName(El: TPasModule;
  26870. AddModulesPrefix: boolean; AContext: TConvertContext): String;
  26871. var
  26872. p, StartP: Integer;
  26873. aName, Part: String;
  26874. begin
  26875. if AddModulesPrefix then
  26876. begin
  26877. Result:=GetLocalName(El,[cvkGlobal],AContext);
  26878. if Result<>'' then
  26879. exit;
  26880. end;
  26881. if El.ClassType=TPasProgram then
  26882. Result:=GetBIName(pbivnProgram)
  26883. else if El.ClassType=TPasLibrary then
  26884. Result:=GetBIName(pbivnLibrary)
  26885. else
  26886. begin
  26887. Result:='';
  26888. aName:=El.Name;
  26889. p:=1;
  26890. while p<=length(aName) do
  26891. begin
  26892. StartP:=p;
  26893. while (p<=length(aName)) and (aName[p]<>'.') do inc(p);
  26894. Part:=copy(aName,StartP,p-StartP);
  26895. Part:=TransformToJSName(El,Part,false,AContext);
  26896. if Result<>'' then Result:=Result+'.';
  26897. Result:=Result+Part;
  26898. inc(p);
  26899. end;
  26900. end;
  26901. if AddModulesPrefix then
  26902. begin
  26903. if Pos('.',Result)>0 then
  26904. Result:=GetBIName(pbivnModules)+'["'+Result+'"]'
  26905. else
  26906. Result:=GetBIName(pbivnModules)+'.'+Result;
  26907. if coShortRefGlobals in Options then
  26908. Result:=CreateGlobalAliasForeign(El,Result,AContext);
  26909. end;
  26910. end;
  26911. function TPasToJSConverter.IsReservedWord(const aName: string;
  26912. CheckGlobal: boolean): boolean;
  26913. var
  26914. l, r, m, cmp: Integer;
  26915. begin
  26916. Result:=true;
  26917. if aName=GetBIName(pbivnModules) then exit;
  26918. if aName=GetBIName(pbivnRTL) then exit;
  26919. // search default list
  26920. l:=low(JSReservedWords);
  26921. r:=high(JSReservedWords);
  26922. while l<=r do
  26923. begin
  26924. m:=(l+r) div 2;
  26925. cmp:=CompareStr(aName,JSReservedWords[m]);
  26926. //writeln('TPasToJSConverter.IsReservedWord Name="',aName,'" l=',l,' r=',r,' m=',m,' JSReservedWords[m]=',JSReservedWords[m],' cmp=',cmp);
  26927. if cmp>0 then
  26928. l:=m+1
  26929. else if cmp<0 then
  26930. r:=m-1
  26931. else
  26932. exit;
  26933. end;
  26934. // search user list
  26935. l:=0;
  26936. r:=length(FReservedWords)-1;
  26937. while l<=r do
  26938. begin
  26939. m:=(l+r) div 2;
  26940. cmp:=CompareStr(aName,FReservedWords[m]);
  26941. //writeln('TPasToJSConverter.IsReservedWord Name="',aName,'" l=',l,' r=',r,' m=',m,' FReservedWords[m]=',FReservedWords[m],' cmp=',cmp);
  26942. if cmp>0 then
  26943. l:=m+1
  26944. else if cmp<0 then
  26945. r:=m-1
  26946. else
  26947. exit;
  26948. end;
  26949. if CheckGlobal then
  26950. begin
  26951. // search default global list
  26952. l:=low(JSReservedGlobalWords);
  26953. r:=high(JSReservedGlobalWords);
  26954. while l<=r do
  26955. begin
  26956. m:=(l+r) div 2;
  26957. cmp:=CompareStr(aName,JSReservedGlobalWords[m]);
  26958. //writeln('TPasToJSConverter.IsReservedWord Name="',aName,'" l=',l,' r=',r,' m=',m,' JSReservedGlobalWords[m]=',JSReservedGlobalWords[m],' cmp=',cmp);
  26959. if cmp>0 then
  26960. l:=m+1
  26961. else if cmp<0 then
  26962. r:=m-1
  26963. else
  26964. exit;
  26965. end;
  26966. end;
  26967. Result:=false;
  26968. end;
  26969. function TPasToJSConverter.GetTypeInfoName(El: TPasType;
  26970. AContext: TConvertContext; ErrorEl: TPasElement; Full: boolean): String;
  26971. var
  26972. C: TClass;
  26973. bt: TResolverBaseType;
  26974. jbt: TPas2jsBaseType;
  26975. CurEl: TPasElement;
  26976. aName: String;
  26977. begin
  26978. Result:='';
  26979. El:=ResolveSimpleAliasType(El);
  26980. if El=nil then
  26981. RaiseInconsistency(20170409172756,El);
  26982. C:=El.ClassType;
  26983. if C=TPasSpecializeType then
  26984. begin
  26985. if not (El.CustomData is TPasSpecializeTypeData) then
  26986. RaiseInconsistency(20200220113319,El);
  26987. El:=TPasSpecializeTypeData(El.CustomData).SpecializedType;
  26988. C:=El.ClassType;
  26989. end;
  26990. if (El=AContext.PasElement) and not Full then
  26991. begin
  26992. // referring to itself
  26993. if El is TPasMembersType then
  26994. begin
  26995. // use this
  26996. Result:=GetBIName(pbivnRTTILocal);
  26997. exit;
  26998. end
  26999. else
  27000. RaiseNotSupported(ErrorEl,AContext,20170905150746,'cannot typeinfo itself');
  27001. end;
  27002. if C=TPasUnresolvedSymbolRef then
  27003. begin
  27004. if El.Name='' then
  27005. DoError(20170905150752,nTypeXCannotBePublished,sTypeXCannotBePublished,
  27006. ['typeinfo of anonymous '+El.ElementTypeName],ErrorEl);
  27007. if El.CustomData is TResElDataBaseType then
  27008. begin
  27009. bt:=TResElDataBaseType(El.CustomData).BaseType;
  27010. case bt of
  27011. btWideChar: bt:=btChar;
  27012. btUnicodeString: bt:=btString;
  27013. btCurrency: bt:=btIntDouble;
  27014. end;
  27015. case bt of
  27016. btShortInt,btByte,
  27017. btSmallInt,btWord,
  27018. btLongint,btLongWord,
  27019. btIntDouble,btUIntDouble,
  27020. btString,btChar,
  27021. btDouble,
  27022. btBoolean,
  27023. btPointer:
  27024. begin
  27025. // create rtl.basename
  27026. Result:=GetBIName(pbivnRTL)+'.'+lowercase(AContext.Resolver.BaseTypeNames[bt]);
  27027. exit;
  27028. end;
  27029. btCustom:
  27030. if El.CustomData is TResElDataPas2JSBaseType then
  27031. begin
  27032. jbt:=TResElDataPas2JSBaseType(El.CustomData).JSBaseType;
  27033. case jbt of
  27034. pbtJSValue:
  27035. begin
  27036. // create rtl.basename
  27037. Result:=GetBIName(pbivnRTL)+'.'+lowercase(Pas2jsBaseTypeNames[jbt]);
  27038. exit;
  27039. end;
  27040. else
  27041. {$IFDEF VerbosePas2JS}
  27042. writeln('TPasToJSConverter.CreateTypeInfoRef [20170905150833] El=',GetObjName(El),' El.CustomData=',GetObjName(El.CustomData),' jbt=',Pas2jsBaseTypeNames[jbt]);
  27043. {$ENDIF}
  27044. end;
  27045. end
  27046. else
  27047. begin
  27048. {$IFDEF VerbosePas2JS}
  27049. writeln('TPasToJSConverter.CreateTypeInfoRef [20170905150840] El=',GetObjName(El),' El.CustomData=',GetObjName(El.CustomData),' bt=',AContext.Resolver.BaseTypeNames[bt]);
  27050. {$ENDIF}
  27051. end
  27052. else
  27053. {$IFDEF VerbosePas2JS}
  27054. writeln('TPasToJSConverter.CreateTypeInfoRef [20170905150842] El=',GetObjName(El),' El.CustomData=',GetObjName(El.CustomData),' bt=',AContext.Resolver.BaseTypeNames[bt]);
  27055. {$ENDIF}
  27056. end;
  27057. end
  27058. else
  27059. begin
  27060. {$IFDEF VerbosePas2JS}
  27061. writeln('TPasToJSConverter.CreateTypeInfoRef [20170905150844] El=',GetObjName(El),' El.CustomData=',GetObjName(El.CustomData));
  27062. {$ENDIF}
  27063. end;
  27064. end
  27065. else if (C=TPasEnumType)
  27066. or (C=TPasSetType)
  27067. or (C=TPasClassType)
  27068. or (C=TPasClassOfType)
  27069. or (C=TPasArrayType)
  27070. or (C=TPasProcedureType)
  27071. or (C=TPasFunctionType)
  27072. or (C=TPasPointerType)
  27073. or (C=TPasTypeAliasType)
  27074. or (C=TPasRecordType)
  27075. or (C=TPasRangeType)
  27076. then
  27077. begin
  27078. // user type -> module.$rtti["pascalname"]
  27079. // Notes:
  27080. // a nested type gets the parent types prepended: classnameA.ElName
  27081. // an anonymous type gets for each level '$a' prepended
  27082. // an anonymous type of a variable/argument gets the variable name prepended
  27083. CurEl:=ResolveSimpleAliasType(TPasType(El));
  27084. repeat
  27085. if CurEl.Name<>'' then
  27086. begin
  27087. // RTTI uses Pascal name
  27088. Result:=CurEl.Name+Result;
  27089. end
  27090. else
  27091. begin
  27092. // anonymous type -> prepend '$a'
  27093. // for example:
  27094. // "var AnArray: array of array of char;" becomes AnArray$a$a
  27095. Result:=GetBIName(pbitnAnonymousPostfix)+Result;
  27096. end;
  27097. CurEl:=CurEl.Parent;
  27098. if CurEl=nil then
  27099. break;
  27100. C:=CurEl.ClassType;
  27101. if (C=TPasClassType)
  27102. or (C=TPasRecordType) then
  27103. // nested
  27104. Result:='.'+Result
  27105. else if C.InheritsFrom(TPasType)
  27106. or (C=TPasVariable)
  27107. or (C=TPasConst)
  27108. or (C=TPasArgument)
  27109. or (C=TPasProperty) then
  27110. begin
  27111. // for example: var a: array of longint;
  27112. end
  27113. else
  27114. break;
  27115. until false;
  27116. if CurEl is TPasSection then
  27117. exit;
  27118. end;
  27119. aName:=El.Name;
  27120. if aName='' then aName:=El.ClassName;
  27121. DoError(20170409173329,nTypeXCannotBePublished,sTypeXCannotBePublished,
  27122. [aName],ErrorEl);
  27123. end;
  27124. function TPasToJSConverter.TransformArgName(Arg: TPasArgument;
  27125. AContext: TConvertContext): string;
  27126. begin
  27127. Result:=Arg.Name;
  27128. if (CompareText(Result,'Self')=0) and (Arg.Parent is TPasProcedure) then
  27129. begin
  27130. // hidden self argument
  27131. Result:=AContext.GetLocalName(Arg,cvkAll);
  27132. if Result='' then
  27133. begin
  27134. {$IFDEF VerbosePas2JS}
  27135. writeln('TPasToJSConverter.TransformArgName Arg=',GetObjPath(Arg));
  27136. AContext.WriteStack;
  27137. {$ENDIF}
  27138. RaiseNotSupported(Arg,AContext,20190205190114,GetObjName(Arg.Parent));
  27139. end;
  27140. end
  27141. else
  27142. Result:=TransformToJSName(Arg,Result,true,AContext);
  27143. end;
  27144. function TPasToJSConverter.CreateGlobalAliasForeign(El: TPasElement; JSPath: string;
  27145. AContext: TConvertContext): string;
  27146. var
  27147. ElModule, MyModule: TPasModule;
  27148. aResolver: TPas2JSResolver;
  27149. SectionContext: TSectionContext;
  27150. FuncContext: TFunctionContext;
  27151. Expr: TJSElement;
  27152. V: TJSVariableStatement;
  27153. AssignSt: TJSSimpleAssignStatement;
  27154. ElClass: TClass;
  27155. begin
  27156. Result:=JSPath;
  27157. if El is TPasUnresolvedSymbolRef then
  27158. exit; // built-in element
  27159. ElModule:=El.GetModule;
  27160. aResolver:=AContext.Resolver;
  27161. MyModule:=aResolver.RootElement;
  27162. if ElModule=MyModule then
  27163. begin
  27164. // El is in this module
  27165. exit;
  27166. end
  27167. else
  27168. begin
  27169. // El is from another unit
  27170. SectionContext:=TSectionContext(AContext.GetMainSectionContext);
  27171. FuncContext:=AContext.GetFunctionContext;
  27172. ElClass:=El.ClassType;
  27173. if ElClass.InheritsFrom(TPasType) then
  27174. Result:=GetBIName(pbivnLocalTypeRef)
  27175. else if ElClass.InheritsFrom(TPasProcedure) then
  27176. Result:=GetBIName(pbivnLocalProcRef)
  27177. else if ElClass=TPasEnumValue then
  27178. Result:=GetBIName(pbivnLocalTypeRef)
  27179. else if ElClass.InheritsFrom(TPasModule) then
  27180. Result:=GetBIName(pbivnLocalModuleRef)
  27181. else
  27182. RaiseNotSupported(El,AContext,20200608160225);
  27183. Result:=FuncContext.CreateLocalIdentifier(Result,El,cvkGlobal);
  27184. SectionContext.AddLocalVar(Result,El,cvkGlobal,true);
  27185. if coStoreImplJS in Options then
  27186. StoreImplJSLocal(El,AContext);
  27187. if aResolver.ImplementationUsesUnit(ElModule) then
  27188. begin
  27189. // insert var $lm = null;
  27190. Expr:=CreateLiteralNull(El);
  27191. V:=CreateVarStatement(Result,Expr,El);
  27192. AddHeaderStatement(V,El,SectionContext);
  27193. // insert impl $lm = JSPath;
  27194. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  27195. AssignSt.LHS:=CreatePrimitiveDotExpr(Result,El);
  27196. AssignSt.Expr:=CreatePrimitiveDotExpr(JSPath,El);
  27197. AddImplHeaderStatement(AssignSt,El,AContext);
  27198. end
  27199. else
  27200. begin
  27201. // insert var $lm = JSPath;
  27202. Expr:=CreatePrimitiveDotExpr(JSPath,El);
  27203. V:=CreateVarStatement(Result,Expr,El);
  27204. AddHeaderStatement(V,El,SectionContext);
  27205. end;
  27206. end;
  27207. end;
  27208. function TPasToJSConverter.CreateGlobalAliasNull(El: TPasElement;
  27209. Prefix: TPas2JSBuiltInName; SectionContext: TSectionContext
  27210. ): TFCLocalIdentifier;
  27211. var
  27212. V: TJSVariableStatement;
  27213. begin
  27214. // insert var $lt = null;
  27215. Result:=SectionContext.AddLocalVar(GetBIName(Prefix),El,cvkGlobal,true);
  27216. V:=CreateVarStatement(Result.Name,CreateLiteralNull(El),El);
  27217. AddHeaderStatement(V,El,SectionContext);
  27218. end;
  27219. procedure TPasToJSConverter.CreateGlobalAlias_List(ElRefList: TFPList;
  27220. AContext: TConvertContext);
  27221. var
  27222. i: Integer;
  27223. SectionContext: TSectionContext;
  27224. El: TPasElement;
  27225. begin
  27226. if ElRefList=nil then exit;
  27227. if ElRefList.Count=0 then exit;
  27228. SectionContext:=TSectionContext(AContext.GetMainSectionContext);
  27229. for i:=0 to ElRefList.Count-1 do
  27230. begin
  27231. El:=TPasElement(ElRefList[i]);
  27232. // Note: they are all needed by precompiled code, do not check ElNeedsGlobalAlias
  27233. CreateGlobalElPath(El,SectionContext);
  27234. end;
  27235. end;
  27236. function TPasToJSConverter.ElNeedsGlobalAlias(El: TPasElement): boolean;
  27237. var
  27238. C: TClass;
  27239. begin
  27240. Result:=false;
  27241. if El=nil then exit;
  27242. if not (coShortRefGlobals in Options) then
  27243. exit;
  27244. C:=El.ClassType;
  27245. if El.CustomData is TResElDataBuiltInSymbol then
  27246. exit(false)
  27247. else if C.InheritsFrom(TPasType) then
  27248. exit(true)
  27249. else if C.InheritsFrom(TPasProcedure) then
  27250. exit(ProcCanHaveShortRef(TPasProcedure(El)))
  27251. else if C=TPasEnumValue then
  27252. begin
  27253. if not (coEnumNumbers in Options) then
  27254. exit(true);
  27255. end
  27256. else if C.InheritsFrom(TPasModule) then
  27257. exit(true);
  27258. end;
  27259. function TPasToJSConverter.ConvertPasElement(El: TPasElement;
  27260. Resolver: TPas2JSResolver): TJSElement;
  27261. var
  27262. aContext: TRootContext;
  27263. Scanner: TPas2jsPasScanner;
  27264. begin
  27265. if FGlobals=nil then
  27266. FGlobals:=TPasToJSConverterGlobals.Create(Self);
  27267. if (Resolver<>nil)
  27268. and (Resolver.CurrentParser<>nil)
  27269. and (Resolver.CurrentParser.Scanner is TPas2jsPasScanner) then
  27270. begin
  27271. Scanner:=TPas2jsPasScanner(Resolver.CurrentParser.Scanner);
  27272. Options:=Options+Scanner.GlobalConvOptsEnabled-Scanner.GlobalConvOptsDisabled;
  27273. end;
  27274. aContext:=TRootContext.Create(El,nil,nil);
  27275. try
  27276. aContext.Resolver:=Resolver;
  27277. if (El.ClassType=TPasImplBeginBlock) then
  27278. Result:=ConvertBeginEndStatement(TPasImplBeginBlock(El),AContext,false)
  27279. else
  27280. Result:=ConvertElement(El,aContext);
  27281. finally
  27282. FreeAndNil(aContext);
  27283. end;
  27284. end;
  27285. end.