fppas2js.pp 642 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871987298739874987598769877987898799880988198829883988498859886988798889889989098919892989398949895989698979898989999009901990299039904990599069907990899099910991199129913991499159916991799189919992099219922992399249925992699279928992999309931993299339934993599369937993899399940994199429943994499459946994799489949995099519952995399549955995699579958995999609961996299639964996599669967996899699970997199729973997499759976997799789979998099819982998399849985998699879988998999909991999299939994999599969997999899991000010001100021000310004100051000610007100081000910010100111001210013100141001510016100171001810019100201002110022100231002410025100261002710028100291003010031100321003310034100351003610037100381003910040100411004210043100441004510046100471004810049100501005110052100531005410055100561005710058100591006010061100621006310064100651006610067100681006910070100711007210073100741007510076100771007810079100801008110082100831008410085100861008710088100891009010091100921009310094100951009610097100981009910100101011010210103101041010510106101071010810109101101011110112101131011410115101161011710118101191012010121101221012310124101251012610127101281012910130101311013210133101341013510136101371013810139101401014110142101431014410145101461014710148101491015010151101521015310154101551015610157101581015910160101611016210163101641016510166101671016810169101701017110172101731017410175101761017710178101791018010181101821018310184101851018610187101881018910190101911019210193101941019510196101971019810199102001020110202102031020410205102061020710208102091021010211102121021310214102151021610217102181021910220102211022210223102241022510226102271022810229102301023110232102331023410235102361023710238102391024010241102421024310244102451024610247102481024910250102511025210253102541025510256102571025810259102601026110262102631026410265102661026710268102691027010271102721027310274102751027610277102781027910280102811028210283102841028510286102871028810289102901029110292102931029410295102961029710298102991030010301103021030310304103051030610307103081030910310103111031210313103141031510316103171031810319103201032110322103231032410325103261032710328103291033010331103321033310334103351033610337103381033910340103411034210343103441034510346103471034810349103501035110352103531035410355103561035710358103591036010361103621036310364103651036610367103681036910370103711037210373103741037510376103771037810379103801038110382103831038410385103861038710388103891039010391103921039310394103951039610397103981039910400104011040210403104041040510406104071040810409104101041110412104131041410415104161041710418104191042010421104221042310424104251042610427104281042910430104311043210433104341043510436104371043810439104401044110442104431044410445104461044710448104491045010451104521045310454104551045610457104581045910460104611046210463104641046510466104671046810469104701047110472104731047410475104761047710478104791048010481104821048310484104851048610487104881048910490104911049210493104941049510496104971049810499105001050110502105031050410505105061050710508105091051010511105121051310514105151051610517105181051910520105211052210523105241052510526105271052810529105301053110532105331053410535105361053710538105391054010541105421054310544105451054610547105481054910550105511055210553105541055510556105571055810559105601056110562105631056410565105661056710568105691057010571105721057310574105751057610577105781057910580105811058210583105841058510586105871058810589105901059110592105931059410595105961059710598105991060010601106021060310604106051060610607106081060910610106111061210613106141061510616106171061810619106201062110622106231062410625106261062710628106291063010631106321063310634106351063610637106381063910640106411064210643106441064510646106471064810649106501065110652106531065410655106561065710658106591066010661106621066310664106651066610667106681066910670106711067210673106741067510676106771067810679106801068110682106831068410685106861068710688106891069010691106921069310694106951069610697106981069910700107011070210703107041070510706107071070810709107101071110712107131071410715107161071710718107191072010721107221072310724107251072610727107281072910730107311073210733107341073510736107371073810739107401074110742107431074410745107461074710748107491075010751107521075310754107551075610757107581075910760107611076210763107641076510766107671076810769107701077110772107731077410775107761077710778107791078010781107821078310784107851078610787107881078910790107911079210793107941079510796107971079810799108001080110802108031080410805108061080710808108091081010811108121081310814108151081610817108181081910820108211082210823108241082510826108271082810829108301083110832108331083410835108361083710838108391084010841108421084310844108451084610847108481084910850108511085210853108541085510856108571085810859108601086110862108631086410865108661086710868108691087010871108721087310874108751087610877108781087910880108811088210883108841088510886108871088810889108901089110892108931089410895108961089710898108991090010901109021090310904109051090610907109081090910910109111091210913109141091510916109171091810919109201092110922109231092410925109261092710928109291093010931109321093310934109351093610937109381093910940109411094210943109441094510946109471094810949109501095110952109531095410955109561095710958109591096010961109621096310964109651096610967109681096910970109711097210973109741097510976109771097810979109801098110982109831098410985109861098710988109891099010991109921099310994109951099610997109981099911000110011100211003110041100511006110071100811009110101101111012110131101411015110161101711018110191102011021110221102311024110251102611027110281102911030110311103211033110341103511036110371103811039110401104111042110431104411045110461104711048110491105011051110521105311054110551105611057110581105911060110611106211063110641106511066110671106811069110701107111072110731107411075110761107711078110791108011081110821108311084110851108611087110881108911090110911109211093110941109511096110971109811099111001110111102111031110411105111061110711108111091111011111111121111311114111151111611117111181111911120111211112211123111241112511126111271112811129111301113111132111331113411135111361113711138111391114011141111421114311144111451114611147111481114911150111511115211153111541115511156111571115811159111601116111162111631116411165111661116711168111691117011171111721117311174111751117611177111781117911180111811118211183111841118511186111871118811189111901119111192111931119411195111961119711198111991120011201112021120311204112051120611207112081120911210112111121211213112141121511216112171121811219112201122111222112231122411225112261122711228112291123011231112321123311234112351123611237112381123911240112411124211243112441124511246112471124811249112501125111252112531125411255112561125711258112591126011261112621126311264112651126611267112681126911270112711127211273112741127511276112771127811279112801128111282112831128411285112861128711288112891129011291112921129311294112951129611297112981129911300113011130211303113041130511306113071130811309113101131111312113131131411315113161131711318113191132011321113221132311324113251132611327113281132911330113311133211333113341133511336113371133811339113401134111342113431134411345113461134711348113491135011351113521135311354113551135611357113581135911360113611136211363113641136511366113671136811369113701137111372113731137411375113761137711378113791138011381113821138311384113851138611387113881138911390113911139211393113941139511396113971139811399114001140111402114031140411405114061140711408114091141011411114121141311414114151141611417114181141911420114211142211423114241142511426114271142811429114301143111432114331143411435114361143711438114391144011441114421144311444114451144611447114481144911450114511145211453114541145511456114571145811459114601146111462114631146411465114661146711468114691147011471114721147311474114751147611477114781147911480114811148211483114841148511486114871148811489114901149111492114931149411495114961149711498114991150011501115021150311504115051150611507115081150911510115111151211513115141151511516115171151811519115201152111522115231152411525115261152711528115291153011531115321153311534115351153611537115381153911540115411154211543115441154511546115471154811549115501155111552115531155411555115561155711558115591156011561115621156311564115651156611567115681156911570115711157211573115741157511576115771157811579115801158111582115831158411585115861158711588115891159011591115921159311594115951159611597115981159911600116011160211603116041160511606116071160811609116101161111612116131161411615116161161711618116191162011621116221162311624116251162611627116281162911630116311163211633116341163511636116371163811639116401164111642116431164411645116461164711648116491165011651116521165311654116551165611657116581165911660116611166211663116641166511666116671166811669116701167111672116731167411675116761167711678116791168011681116821168311684116851168611687116881168911690116911169211693116941169511696116971169811699117001170111702117031170411705117061170711708117091171011711117121171311714117151171611717117181171911720117211172211723117241172511726117271172811729117301173111732117331173411735117361173711738117391174011741117421174311744117451174611747117481174911750117511175211753117541175511756117571175811759117601176111762117631176411765117661176711768117691177011771117721177311774117751177611777117781177911780117811178211783117841178511786117871178811789117901179111792117931179411795117961179711798117991180011801118021180311804118051180611807118081180911810118111181211813118141181511816118171181811819118201182111822118231182411825118261182711828118291183011831118321183311834118351183611837118381183911840118411184211843118441184511846118471184811849118501185111852118531185411855118561185711858118591186011861118621186311864118651186611867118681186911870118711187211873118741187511876118771187811879118801188111882118831188411885118861188711888118891189011891118921189311894118951189611897118981189911900119011190211903119041190511906119071190811909119101191111912119131191411915119161191711918119191192011921119221192311924119251192611927119281192911930119311193211933119341193511936119371193811939119401194111942119431194411945119461194711948119491195011951119521195311954119551195611957119581195911960119611196211963119641196511966119671196811969119701197111972119731197411975119761197711978119791198011981119821198311984119851198611987119881198911990119911199211993119941199511996119971199811999120001200112002120031200412005120061200712008120091201012011120121201312014120151201612017120181201912020120211202212023120241202512026120271202812029120301203112032120331203412035120361203712038120391204012041120421204312044120451204612047120481204912050120511205212053120541205512056120571205812059120601206112062120631206412065120661206712068120691207012071120721207312074120751207612077120781207912080120811208212083120841208512086120871208812089120901209112092120931209412095120961209712098120991210012101121021210312104121051210612107121081210912110121111211212113121141211512116121171211812119121201212112122121231212412125121261212712128121291213012131121321213312134121351213612137121381213912140121411214212143121441214512146121471214812149121501215112152121531215412155121561215712158121591216012161121621216312164121651216612167121681216912170121711217212173121741217512176121771217812179121801218112182121831218412185121861218712188121891219012191121921219312194121951219612197121981219912200122011220212203122041220512206122071220812209122101221112212122131221412215122161221712218122191222012221122221222312224122251222612227122281222912230122311223212233122341223512236122371223812239122401224112242122431224412245122461224712248122491225012251122521225312254122551225612257122581225912260122611226212263122641226512266122671226812269122701227112272122731227412275122761227712278122791228012281122821228312284122851228612287122881228912290122911229212293122941229512296122971229812299123001230112302123031230412305123061230712308123091231012311123121231312314123151231612317123181231912320123211232212323123241232512326123271232812329123301233112332123331233412335123361233712338123391234012341123421234312344123451234612347123481234912350123511235212353123541235512356123571235812359123601236112362123631236412365123661236712368123691237012371123721237312374123751237612377123781237912380123811238212383123841238512386123871238812389123901239112392123931239412395123961239712398123991240012401124021240312404124051240612407124081240912410124111241212413124141241512416124171241812419124201242112422124231242412425124261242712428124291243012431124321243312434124351243612437124381243912440124411244212443124441244512446124471244812449124501245112452124531245412455124561245712458124591246012461124621246312464124651246612467124681246912470124711247212473124741247512476124771247812479124801248112482124831248412485124861248712488124891249012491124921249312494124951249612497124981249912500125011250212503125041250512506125071250812509125101251112512125131251412515125161251712518125191252012521125221252312524125251252612527125281252912530125311253212533125341253512536125371253812539125401254112542125431254412545125461254712548125491255012551125521255312554125551255612557125581255912560125611256212563125641256512566125671256812569125701257112572125731257412575125761257712578125791258012581125821258312584125851258612587125881258912590125911259212593125941259512596125971259812599126001260112602126031260412605126061260712608126091261012611126121261312614126151261612617126181261912620126211262212623126241262512626126271262812629126301263112632126331263412635126361263712638126391264012641126421264312644126451264612647126481264912650126511265212653126541265512656126571265812659126601266112662126631266412665126661266712668126691267012671126721267312674126751267612677126781267912680126811268212683126841268512686126871268812689126901269112692126931269412695126961269712698126991270012701127021270312704127051270612707127081270912710127111271212713127141271512716127171271812719127201272112722127231272412725127261272712728127291273012731127321273312734127351273612737127381273912740127411274212743127441274512746127471274812749127501275112752127531275412755127561275712758127591276012761127621276312764127651276612767127681276912770127711277212773127741277512776127771277812779127801278112782127831278412785127861278712788127891279012791127921279312794127951279612797127981279912800128011280212803128041280512806128071280812809128101281112812128131281412815128161281712818128191282012821128221282312824128251282612827128281282912830128311283212833128341283512836128371283812839128401284112842128431284412845128461284712848128491285012851128521285312854128551285612857128581285912860128611286212863128641286512866128671286812869128701287112872128731287412875128761287712878128791288012881128821288312884128851288612887128881288912890128911289212893128941289512896128971289812899129001290112902129031290412905129061290712908129091291012911129121291312914129151291612917129181291912920129211292212923129241292512926129271292812929129301293112932129331293412935129361293712938129391294012941129421294312944129451294612947129481294912950129511295212953129541295512956129571295812959129601296112962129631296412965129661296712968129691297012971129721297312974129751297612977129781297912980129811298212983129841298512986129871298812989129901299112992129931299412995129961299712998129991300013001130021300313004130051300613007130081300913010130111301213013130141301513016130171301813019130201302113022130231302413025130261302713028130291303013031130321303313034130351303613037130381303913040130411304213043130441304513046130471304813049130501305113052130531305413055130561305713058130591306013061130621306313064130651306613067130681306913070130711307213073130741307513076130771307813079130801308113082130831308413085130861308713088130891309013091130921309313094130951309613097130981309913100131011310213103131041310513106131071310813109131101311113112131131311413115131161311713118131191312013121131221312313124131251312613127131281312913130131311313213133131341313513136131371313813139131401314113142131431314413145131461314713148131491315013151131521315313154131551315613157131581315913160131611316213163131641316513166131671316813169131701317113172131731317413175131761317713178131791318013181131821318313184131851318613187131881318913190131911319213193131941319513196131971319813199132001320113202132031320413205132061320713208132091321013211132121321313214132151321613217132181321913220132211322213223132241322513226132271322813229132301323113232132331323413235132361323713238132391324013241132421324313244132451324613247132481324913250132511325213253132541325513256132571325813259132601326113262132631326413265132661326713268132691327013271132721327313274132751327613277132781327913280132811328213283132841328513286132871328813289132901329113292132931329413295132961329713298132991330013301133021330313304133051330613307133081330913310133111331213313133141331513316133171331813319133201332113322133231332413325133261332713328133291333013331133321333313334133351333613337133381333913340133411334213343133441334513346133471334813349133501335113352133531335413355133561335713358133591336013361133621336313364133651336613367133681336913370133711337213373133741337513376133771337813379133801338113382133831338413385133861338713388133891339013391133921339313394133951339613397133981339913400134011340213403134041340513406134071340813409134101341113412134131341413415134161341713418134191342013421134221342313424134251342613427134281342913430134311343213433134341343513436134371343813439134401344113442134431344413445134461344713448134491345013451134521345313454134551345613457134581345913460134611346213463134641346513466134671346813469134701347113472134731347413475134761347713478134791348013481134821348313484134851348613487134881348913490134911349213493134941349513496134971349813499135001350113502135031350413505135061350713508135091351013511135121351313514135151351613517135181351913520135211352213523135241352513526135271352813529135301353113532135331353413535135361353713538135391354013541135421354313544135451354613547135481354913550135511355213553135541355513556135571355813559135601356113562135631356413565135661356713568135691357013571135721357313574135751357613577135781357913580135811358213583135841358513586135871358813589135901359113592135931359413595135961359713598135991360013601136021360313604136051360613607136081360913610136111361213613136141361513616136171361813619136201362113622136231362413625136261362713628136291363013631136321363313634136351363613637136381363913640136411364213643136441364513646136471364813649136501365113652136531365413655136561365713658136591366013661136621366313664136651366613667136681366913670136711367213673136741367513676136771367813679136801368113682136831368413685136861368713688136891369013691136921369313694136951369613697136981369913700137011370213703137041370513706137071370813709137101371113712137131371413715137161371713718137191372013721137221372313724137251372613727137281372913730137311373213733137341373513736137371373813739137401374113742137431374413745137461374713748137491375013751137521375313754137551375613757137581375913760137611376213763137641376513766137671376813769137701377113772137731377413775137761377713778137791378013781137821378313784137851378613787137881378913790137911379213793137941379513796137971379813799138001380113802138031380413805138061380713808138091381013811138121381313814138151381613817138181381913820138211382213823138241382513826138271382813829138301383113832138331383413835138361383713838138391384013841138421384313844138451384613847138481384913850138511385213853138541385513856138571385813859138601386113862138631386413865138661386713868138691387013871138721387313874138751387613877138781387913880138811388213883138841388513886138871388813889138901389113892138931389413895138961389713898138991390013901139021390313904139051390613907139081390913910139111391213913139141391513916139171391813919139201392113922139231392413925139261392713928139291393013931139321393313934139351393613937139381393913940139411394213943139441394513946139471394813949139501395113952139531395413955139561395713958139591396013961139621396313964139651396613967139681396913970139711397213973139741397513976139771397813979139801398113982139831398413985139861398713988139891399013991139921399313994139951399613997139981399914000140011400214003140041400514006140071400814009140101401114012140131401414015140161401714018140191402014021140221402314024140251402614027140281402914030140311403214033140341403514036140371403814039140401404114042140431404414045140461404714048140491405014051140521405314054140551405614057140581405914060140611406214063140641406514066140671406814069140701407114072140731407414075140761407714078140791408014081140821408314084140851408614087140881408914090140911409214093140941409514096140971409814099141001410114102141031410414105141061410714108141091411014111141121411314114141151411614117141181411914120141211412214123141241412514126141271412814129141301413114132141331413414135141361413714138141391414014141141421414314144141451414614147141481414914150141511415214153141541415514156141571415814159141601416114162141631416414165141661416714168141691417014171141721417314174141751417614177141781417914180141811418214183141841418514186141871418814189141901419114192141931419414195141961419714198141991420014201142021420314204142051420614207142081420914210142111421214213142141421514216142171421814219142201422114222142231422414225142261422714228142291423014231142321423314234142351423614237142381423914240142411424214243142441424514246142471424814249142501425114252142531425414255142561425714258142591426014261142621426314264142651426614267142681426914270142711427214273142741427514276142771427814279142801428114282142831428414285142861428714288142891429014291142921429314294142951429614297142981429914300143011430214303143041430514306143071430814309143101431114312143131431414315143161431714318143191432014321143221432314324143251432614327143281432914330143311433214333143341433514336143371433814339143401434114342143431434414345143461434714348143491435014351143521435314354143551435614357143581435914360143611436214363143641436514366143671436814369143701437114372143731437414375143761437714378143791438014381143821438314384143851438614387143881438914390143911439214393143941439514396143971439814399144001440114402144031440414405144061440714408144091441014411144121441314414144151441614417144181441914420144211442214423144241442514426144271442814429144301443114432144331443414435144361443714438144391444014441144421444314444144451444614447144481444914450144511445214453144541445514456144571445814459144601446114462144631446414465144661446714468144691447014471144721447314474144751447614477144781447914480144811448214483144841448514486144871448814489144901449114492144931449414495144961449714498144991450014501145021450314504145051450614507145081450914510145111451214513145141451514516145171451814519145201452114522145231452414525145261452714528145291453014531145321453314534145351453614537145381453914540145411454214543145441454514546145471454814549145501455114552145531455414555145561455714558145591456014561145621456314564145651456614567145681456914570145711457214573145741457514576145771457814579145801458114582145831458414585145861458714588145891459014591145921459314594145951459614597145981459914600146011460214603146041460514606146071460814609146101461114612146131461414615146161461714618146191462014621146221462314624146251462614627146281462914630146311463214633146341463514636146371463814639146401464114642146431464414645146461464714648146491465014651146521465314654146551465614657146581465914660146611466214663146641466514666146671466814669146701467114672146731467414675146761467714678146791468014681146821468314684146851468614687146881468914690146911469214693146941469514696146971469814699147001470114702147031470414705147061470714708147091471014711147121471314714147151471614717147181471914720147211472214723147241472514726147271472814729147301473114732147331473414735147361473714738147391474014741147421474314744147451474614747147481474914750147511475214753147541475514756147571475814759147601476114762147631476414765147661476714768147691477014771147721477314774147751477614777147781477914780147811478214783147841478514786147871478814789147901479114792147931479414795147961479714798147991480014801148021480314804148051480614807148081480914810148111481214813148141481514816148171481814819148201482114822148231482414825148261482714828148291483014831148321483314834148351483614837148381483914840148411484214843148441484514846148471484814849148501485114852148531485414855148561485714858148591486014861148621486314864148651486614867148681486914870148711487214873148741487514876148771487814879148801488114882148831488414885148861488714888148891489014891148921489314894148951489614897148981489914900149011490214903149041490514906149071490814909149101491114912149131491414915149161491714918149191492014921149221492314924149251492614927149281492914930149311493214933149341493514936149371493814939149401494114942149431494414945149461494714948149491495014951149521495314954149551495614957149581495914960149611496214963149641496514966149671496814969149701497114972149731497414975149761497714978149791498014981149821498314984149851498614987149881498914990149911499214993149941499514996149971499814999150001500115002150031500415005150061500715008150091501015011150121501315014150151501615017150181501915020150211502215023150241502515026150271502815029150301503115032150331503415035150361503715038150391504015041150421504315044150451504615047150481504915050150511505215053150541505515056150571505815059150601506115062150631506415065150661506715068150691507015071150721507315074150751507615077150781507915080150811508215083150841508515086150871508815089150901509115092150931509415095150961509715098150991510015101151021510315104151051510615107151081510915110151111511215113151141511515116151171511815119151201512115122151231512415125151261512715128151291513015131151321513315134151351513615137151381513915140151411514215143151441514515146151471514815149151501515115152151531515415155151561515715158151591516015161151621516315164151651516615167151681516915170151711517215173151741517515176151771517815179151801518115182151831518415185151861518715188151891519015191151921519315194151951519615197151981519915200152011520215203152041520515206152071520815209152101521115212152131521415215152161521715218152191522015221152221522315224152251522615227152281522915230152311523215233152341523515236152371523815239152401524115242152431524415245152461524715248152491525015251152521525315254152551525615257152581525915260152611526215263152641526515266152671526815269152701527115272152731527415275152761527715278152791528015281152821528315284152851528615287152881528915290152911529215293152941529515296152971529815299153001530115302153031530415305153061530715308153091531015311153121531315314153151531615317153181531915320153211532215323153241532515326153271532815329153301533115332153331533415335153361533715338153391534015341153421534315344153451534615347153481534915350153511535215353153541535515356153571535815359153601536115362153631536415365153661536715368153691537015371153721537315374153751537615377153781537915380153811538215383153841538515386153871538815389153901539115392153931539415395153961539715398153991540015401154021540315404154051540615407154081540915410154111541215413154141541515416154171541815419154201542115422154231542415425154261542715428154291543015431154321543315434154351543615437154381543915440154411544215443154441544515446154471544815449154501545115452154531545415455154561545715458154591546015461154621546315464154651546615467154681546915470154711547215473154741547515476154771547815479154801548115482154831548415485154861548715488154891549015491154921549315494154951549615497154981549915500155011550215503155041550515506155071550815509155101551115512155131551415515155161551715518155191552015521155221552315524155251552615527155281552915530155311553215533155341553515536155371553815539155401554115542155431554415545155461554715548155491555015551155521555315554155551555615557155581555915560155611556215563155641556515566155671556815569155701557115572155731557415575155761557715578155791558015581155821558315584155851558615587155881558915590155911559215593155941559515596155971559815599156001560115602156031560415605156061560715608156091561015611156121561315614156151561615617156181561915620156211562215623156241562515626156271562815629156301563115632156331563415635156361563715638156391564015641156421564315644156451564615647156481564915650156511565215653156541565515656156571565815659156601566115662156631566415665156661566715668156691567015671156721567315674156751567615677156781567915680156811568215683156841568515686156871568815689156901569115692156931569415695156961569715698156991570015701157021570315704157051570615707157081570915710157111571215713157141571515716157171571815719157201572115722157231572415725157261572715728157291573015731157321573315734157351573615737157381573915740157411574215743157441574515746157471574815749157501575115752157531575415755157561575715758157591576015761157621576315764157651576615767157681576915770157711577215773157741577515776157771577815779157801578115782157831578415785157861578715788157891579015791157921579315794157951579615797157981579915800158011580215803158041580515806158071580815809158101581115812158131581415815158161581715818158191582015821158221582315824158251582615827158281582915830158311583215833158341583515836158371583815839158401584115842158431584415845158461584715848158491585015851158521585315854158551585615857158581585915860158611586215863158641586515866158671586815869158701587115872158731587415875158761587715878158791588015881158821588315884158851588615887158881588915890158911589215893158941589515896158971589815899159001590115902159031590415905159061590715908159091591015911159121591315914159151591615917159181591915920159211592215923159241592515926159271592815929159301593115932159331593415935159361593715938159391594015941159421594315944159451594615947159481594915950159511595215953159541595515956159571595815959159601596115962159631596415965159661596715968159691597015971159721597315974159751597615977159781597915980159811598215983159841598515986159871598815989159901599115992159931599415995159961599715998159991600016001160021600316004160051600616007160081600916010160111601216013160141601516016160171601816019160201602116022160231602416025160261602716028160291603016031160321603316034160351603616037160381603916040160411604216043160441604516046160471604816049160501605116052160531605416055160561605716058160591606016061160621606316064160651606616067160681606916070160711607216073160741607516076160771607816079160801608116082160831608416085160861608716088160891609016091160921609316094160951609616097160981609916100161011610216103161041610516106161071610816109161101611116112161131611416115161161611716118161191612016121161221612316124161251612616127161281612916130161311613216133161341613516136161371613816139161401614116142161431614416145161461614716148161491615016151161521615316154161551615616157161581615916160161611616216163161641616516166161671616816169161701617116172161731617416175161761617716178161791618016181161821618316184161851618616187161881618916190161911619216193161941619516196161971619816199162001620116202162031620416205162061620716208162091621016211162121621316214162151621616217162181621916220162211622216223162241622516226162271622816229162301623116232162331623416235162361623716238162391624016241162421624316244162451624616247162481624916250162511625216253162541625516256162571625816259162601626116262162631626416265162661626716268162691627016271162721627316274162751627616277162781627916280162811628216283162841628516286162871628816289162901629116292162931629416295162961629716298162991630016301163021630316304163051630616307163081630916310163111631216313163141631516316163171631816319163201632116322163231632416325163261632716328163291633016331163321633316334163351633616337163381633916340163411634216343163441634516346163471634816349163501635116352163531635416355163561635716358163591636016361163621636316364163651636616367163681636916370163711637216373163741637516376163771637816379163801638116382163831638416385163861638716388163891639016391163921639316394163951639616397163981639916400164011640216403164041640516406164071640816409164101641116412164131641416415164161641716418164191642016421164221642316424164251642616427164281642916430164311643216433164341643516436164371643816439164401644116442164431644416445164461644716448164491645016451164521645316454164551645616457164581645916460164611646216463164641646516466164671646816469164701647116472164731647416475164761647716478164791648016481164821648316484164851648616487164881648916490164911649216493164941649516496164971649816499165001650116502165031650416505165061650716508165091651016511165121651316514165151651616517165181651916520165211652216523165241652516526165271652816529165301653116532165331653416535165361653716538165391654016541165421654316544165451654616547165481654916550165511655216553165541655516556165571655816559165601656116562165631656416565165661656716568165691657016571165721657316574165751657616577165781657916580165811658216583165841658516586165871658816589165901659116592165931659416595165961659716598165991660016601166021660316604166051660616607166081660916610166111661216613166141661516616166171661816619166201662116622166231662416625166261662716628166291663016631166321663316634166351663616637166381663916640166411664216643166441664516646166471664816649166501665116652166531665416655166561665716658166591666016661166621666316664166651666616667166681666916670166711667216673166741667516676166771667816679166801668116682166831668416685166861668716688166891669016691166921669316694166951669616697166981669916700167011670216703167041670516706167071670816709167101671116712167131671416715167161671716718167191672016721167221672316724167251672616727167281672916730167311673216733167341673516736167371673816739167401674116742167431674416745167461674716748167491675016751167521675316754167551675616757167581675916760167611676216763167641676516766167671676816769167701677116772167731677416775167761677716778167791678016781167821678316784167851678616787167881678916790167911679216793167941679516796167971679816799168001680116802168031680416805168061680716808168091681016811168121681316814168151681616817168181681916820168211682216823168241682516826168271682816829168301683116832168331683416835168361683716838168391684016841168421684316844168451684616847168481684916850168511685216853168541685516856168571685816859168601686116862168631686416865168661686716868168691687016871168721687316874168751687616877168781687916880168811688216883168841688516886168871688816889168901689116892168931689416895168961689716898168991690016901169021690316904169051690616907169081690916910169111691216913169141691516916169171691816919169201692116922169231692416925169261692716928169291693016931169321693316934169351693616937169381693916940169411694216943169441694516946169471694816949169501695116952169531695416955169561695716958169591696016961169621696316964169651696616967169681696916970169711697216973169741697516976169771697816979169801698116982169831698416985169861698716988169891699016991169921699316994169951699616997169981699917000170011700217003170041700517006170071700817009170101701117012170131701417015170161701717018170191702017021170221702317024170251702617027170281702917030170311703217033170341703517036170371703817039170401704117042170431704417045170461704717048170491705017051170521705317054170551705617057170581705917060170611706217063170641706517066170671706817069170701707117072170731707417075170761707717078170791708017081170821708317084170851708617087170881708917090170911709217093170941709517096170971709817099171001710117102171031710417105171061710717108171091711017111171121711317114171151711617117171181711917120171211712217123171241712517126171271712817129171301713117132171331713417135171361713717138171391714017141171421714317144171451714617147171481714917150171511715217153171541715517156171571715817159171601716117162171631716417165171661716717168171691717017171171721717317174171751717617177171781717917180171811718217183171841718517186171871718817189171901719117192171931719417195171961719717198171991720017201172021720317204172051720617207172081720917210172111721217213172141721517216172171721817219172201722117222172231722417225172261722717228172291723017231172321723317234172351723617237172381723917240172411724217243172441724517246172471724817249172501725117252172531725417255172561725717258172591726017261172621726317264172651726617267172681726917270172711727217273172741727517276172771727817279172801728117282172831728417285172861728717288172891729017291172921729317294172951729617297172981729917300173011730217303173041730517306173071730817309173101731117312173131731417315173161731717318173191732017321173221732317324173251732617327173281732917330173311733217333173341733517336173371733817339173401734117342173431734417345173461734717348173491735017351173521735317354173551735617357173581735917360173611736217363173641736517366173671736817369173701737117372173731737417375173761737717378173791738017381173821738317384173851738617387173881738917390173911739217393173941739517396173971739817399174001740117402174031740417405174061740717408174091741017411174121741317414174151741617417174181741917420174211742217423174241742517426174271742817429174301743117432174331743417435174361743717438174391744017441174421744317444174451744617447174481744917450174511745217453174541745517456174571745817459174601746117462174631746417465174661746717468174691747017471174721747317474174751747617477174781747917480174811748217483174841748517486174871748817489174901749117492174931749417495174961749717498174991750017501175021750317504175051750617507175081750917510175111751217513175141751517516175171751817519175201752117522175231752417525175261752717528175291753017531175321753317534175351753617537175381753917540175411754217543175441754517546175471754817549175501755117552175531755417555175561755717558175591756017561175621756317564175651756617567175681756917570175711757217573175741757517576175771757817579175801758117582175831758417585175861758717588175891759017591175921759317594175951759617597175981759917600176011760217603176041760517606176071760817609176101761117612176131761417615176161761717618176191762017621176221762317624176251762617627176281762917630176311763217633176341763517636176371763817639176401764117642176431764417645176461764717648176491765017651176521765317654176551765617657176581765917660176611766217663176641766517666176671766817669176701767117672176731767417675176761767717678176791768017681176821768317684176851768617687176881768917690176911769217693176941769517696176971769817699177001770117702177031770417705177061770717708177091771017711177121771317714177151771617717177181771917720177211772217723177241772517726177271772817729177301773117732177331773417735177361773717738177391774017741177421774317744177451774617747177481774917750177511775217753177541775517756177571775817759177601776117762177631776417765177661776717768177691777017771177721777317774177751777617777177781777917780177811778217783177841778517786177871778817789177901779117792177931779417795177961779717798177991780017801178021780317804178051780617807178081780917810178111781217813178141781517816178171781817819178201782117822178231782417825178261782717828178291783017831178321783317834178351783617837178381783917840178411784217843178441784517846178471784817849178501785117852178531785417855178561785717858178591786017861178621786317864178651786617867178681786917870178711787217873178741787517876178771787817879178801788117882178831788417885178861788717888178891789017891178921789317894178951789617897178981789917900179011790217903179041790517906179071790817909179101791117912179131791417915179161791717918179191792017921179221792317924179251792617927179281792917930179311793217933179341793517936179371793817939179401794117942179431794417945179461794717948179491795017951179521795317954179551795617957179581795917960179611796217963179641796517966179671796817969179701797117972179731797417975179761797717978179791798017981179821798317984179851798617987179881798917990179911799217993179941799517996179971799817999180001800118002180031800418005180061800718008180091801018011180121801318014180151801618017180181801918020180211802218023180241802518026180271802818029180301803118032180331803418035180361803718038180391804018041180421804318044180451804618047180481804918050180511805218053180541805518056180571805818059180601806118062180631806418065180661806718068180691807018071180721807318074180751807618077180781807918080180811808218083180841808518086180871808818089180901809118092180931809418095180961809718098180991810018101181021810318104181051810618107181081810918110181111811218113181141811518116181171811818119181201812118122181231812418125181261812718128181291813018131181321813318134181351813618137181381813918140181411814218143181441814518146181471814818149181501815118152181531815418155181561815718158181591816018161181621816318164181651816618167181681816918170181711817218173181741817518176181771817818179181801818118182181831818418185181861818718188181891819018191181921819318194181951819618197181981819918200182011820218203182041820518206182071820818209182101821118212182131821418215182161821718218182191822018221182221822318224182251822618227182281822918230182311823218233182341823518236182371823818239182401824118242182431824418245182461824718248182491825018251182521825318254182551825618257182581825918260182611826218263182641826518266182671826818269182701827118272182731827418275182761827718278182791828018281182821828318284182851828618287182881828918290182911829218293182941829518296182971829818299183001830118302183031830418305183061830718308183091831018311183121831318314183151831618317183181831918320183211832218323183241832518326183271832818329183301833118332183331833418335183361833718338183391834018341183421834318344183451834618347183481834918350183511835218353183541835518356183571835818359183601836118362183631836418365183661836718368183691837018371183721837318374183751837618377183781837918380183811838218383183841838518386183871838818389183901839118392183931839418395183961839718398183991840018401184021840318404184051840618407184081840918410184111841218413184141841518416184171841818419184201842118422184231842418425184261842718428184291843018431184321843318434184351843618437184381843918440184411844218443184441844518446184471844818449184501845118452184531845418455184561845718458184591846018461184621846318464184651846618467184681846918470184711847218473184741847518476184771847818479184801848118482184831848418485184861848718488184891849018491184921849318494184951849618497184981849918500185011850218503185041850518506185071850818509185101851118512185131851418515185161851718518185191852018521185221852318524185251852618527185281852918530185311853218533185341853518536185371853818539185401854118542185431854418545185461854718548185491855018551185521855318554185551855618557185581855918560185611856218563185641856518566185671856818569185701857118572185731857418575185761857718578185791858018581185821858318584185851858618587185881858918590185911859218593185941859518596185971859818599186001860118602186031860418605186061860718608186091861018611186121861318614186151861618617186181861918620186211862218623186241862518626186271862818629186301863118632186331863418635186361863718638186391864018641186421864318644186451864618647186481864918650186511865218653186541865518656186571865818659186601866118662186631866418665186661866718668186691867018671186721867318674186751867618677186781867918680186811868218683186841868518686186871868818689186901869118692186931869418695186961869718698186991870018701187021870318704187051870618707187081870918710187111871218713187141871518716187171871818719187201872118722187231872418725187261872718728187291873018731187321873318734187351873618737187381873918740187411874218743187441874518746187471874818749187501875118752187531875418755187561875718758187591876018761187621876318764187651876618767187681876918770187711877218773187741877518776187771877818779187801878118782187831878418785187861878718788187891879018791187921879318794187951879618797187981879918800188011880218803188041880518806188071880818809188101881118812188131881418815188161881718818188191882018821188221882318824188251882618827188281882918830188311883218833188341883518836188371883818839188401884118842188431884418845188461884718848188491885018851188521885318854188551885618857188581885918860188611886218863188641886518866188671886818869188701887118872188731887418875188761887718878188791888018881188821888318884188851888618887188881888918890188911889218893188941889518896188971889818899189001890118902189031890418905189061890718908189091891018911189121891318914189151891618917189181891918920189211892218923189241892518926189271892818929189301893118932189331893418935189361893718938189391894018941189421894318944189451894618947189481894918950189511895218953189541895518956189571895818959189601896118962189631896418965189661896718968189691897018971189721897318974189751897618977189781897918980189811898218983189841898518986189871898818989189901899118992189931899418995189961899718998189991900019001190021900319004190051900619007190081900919010190111901219013190141901519016190171901819019190201902119022190231902419025190261902719028190291903019031190321903319034190351903619037190381903919040190411904219043190441904519046190471904819049190501905119052190531905419055190561905719058190591906019061190621906319064190651906619067190681906919070190711907219073190741907519076190771907819079190801908119082190831908419085190861908719088190891909019091190921909319094190951909619097190981909919100191011910219103191041910519106191071910819109191101911119112191131911419115191161911719118191191912019121191221912319124191251912619127191281912919130191311913219133191341913519136191371913819139191401914119142191431914419145191461914719148191491915019151191521915319154191551915619157191581915919160191611916219163191641916519166191671916819169191701917119172191731917419175191761917719178191791918019181191821918319184191851918619187191881918919190191911919219193191941919519196191971919819199192001920119202192031920419205192061920719208192091921019211192121921319214192151921619217192181921919220192211922219223192241922519226192271922819229192301923119232192331923419235192361923719238192391924019241192421924319244192451924619247192481924919250192511925219253192541925519256192571925819259192601926119262192631926419265192661926719268192691927019271192721927319274192751927619277192781927919280192811928219283192841928519286192871928819289192901929119292192931929419295192961929719298192991930019301193021930319304193051930619307193081930919310193111931219313193141931519316193171931819319193201932119322193231932419325193261932719328193291933019331193321933319334193351933619337193381933919340193411934219343193441934519346193471934819349193501935119352193531935419355193561935719358193591936019361193621936319364193651936619367193681936919370193711937219373193741937519376193771937819379193801938119382193831938419385193861938719388193891939019391193921939319394193951939619397193981939919400194011940219403194041940519406194071940819409194101941119412194131941419415194161941719418194191942019421194221942319424194251942619427194281942919430194311943219433194341943519436194371943819439194401944119442194431944419445194461944719448194491945019451194521945319454194551945619457194581945919460194611946219463194641946519466194671946819469194701947119472194731947419475194761947719478194791948019481194821948319484194851948619487194881948919490194911949219493194941949519496194971949819499195001950119502195031950419505195061950719508195091951019511195121951319514195151951619517195181951919520195211952219523195241952519526195271952819529195301953119532195331953419535195361953719538195391954019541195421954319544195451954619547195481954919550195511955219553195541955519556195571955819559195601956119562195631956419565195661956719568195691957019571195721957319574195751957619577195781957919580195811958219583195841958519586195871958819589195901959119592195931959419595195961959719598195991960019601196021960319604196051960619607196081960919610196111961219613196141961519616196171961819619196201962119622196231962419625196261962719628196291963019631196321963319634196351963619637196381963919640196411964219643196441964519646196471964819649196501965119652196531965419655196561965719658196591966019661196621966319664196651966619667196681966919670196711967219673196741967519676196771967819679196801968119682196831968419685196861968719688196891969019691196921969319694196951969619697196981969919700197011970219703197041970519706197071970819709197101971119712197131971419715197161971719718197191972019721197221972319724197251972619727197281972919730197311973219733197341973519736197371973819739197401974119742197431974419745197461974719748197491975019751197521975319754197551975619757197581975919760197611976219763197641976519766197671976819769197701977119772197731977419775197761977719778197791978019781197821978319784197851978619787197881978919790197911979219793197941979519796197971979819799198001980119802198031980419805198061980719808198091981019811198121981319814198151981619817198181981919820198211982219823198241982519826198271982819829198301983119832198331983419835198361983719838198391984019841198421984319844198451984619847198481984919850198511985219853198541985519856198571985819859198601986119862198631986419865198661986719868198691987019871198721987319874198751987619877198781987919880198811988219883198841988519886198871988819889198901989119892198931989419895198961989719898198991990019901199021990319904199051990619907199081990919910
  1. {
  2. This file is part of the Free Component Library (FCL)
  3. Copyright (c) 2018 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(char) -> 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
  75. - clone record member
  76. - clone set member
  77. - clone when passing as argument
  78. - equal, not equal
  79. - const
  80. - array of record-const
  81. - skip clone record of new record
  82. - classes
  83. - declare using createClass
  84. - constructor
  85. - destructor
  86. - vars, init on create, clear references on destroy
  87. - class vars
  88. - ancestor
  89. - virtual, override, abstract
  90. - "is" operator
  91. - "as" operator
  92. - call inherited
  93. - "inherited;",
  94. - "inherited funcname(params);"
  95. - in nested proc
  96. - call class method
  97. - read/write class var
  98. - property
  99. - param list
  100. - property of type array
  101. - class property
  102. - accessors non static
  103. - Assigned()
  104. - default property
  105. - type casts
  106. - overloads, reintroduce append $1, $2, ...
  107. - reintroduced variables
  108. - external vars and methods
  109. - const
  110. - bracket accessor, getter/setter has external name '[]'
  111. - TObject.Free sets variable to nil
  112. - property stored and index modifier
  113. - option verify method calls -CR, bsObjectChecks
  114. - dynamic arrays
  115. - arrays can be null
  116. - init as "arr = []" so typeof works
  117. - SetLength(arr,dim1,...) becomes arr = rtl.arraySetLength(arr,defaultvalue,dim1,dim2,...)
  118. - length(), low(), high(), assigned(), concat()
  119. - assign nil -> [] so typeof works
  120. - read, write element arr[index]
  121. - multi dimensional [index1,index2] -> [index1][index2]
  122. - array of record
  123. - equal, unequal nil -> rtl.length(array)==0 or >0
  124. - when passing nil to an array argument, pass []
  125. - allow type casting array to external class name 'Array'
  126. - type cast array to array of same dimensions and compatible element type
  127. - function copy(array,start=0,count=max): array
  128. - procedure insert(item,var array,const position)
  129. - procedure delete(var array,const start,count)
  130. - const c: dynarray = (a,b,...)
  131. - mode delphi: var B: TBytes = [1,2,3]; // square bracket initialization
  132. - a:=[];
  133. - a:=[1,2,3]; // assignation using constant array
  134. - a:=[[],[]] // nested constant array
  135. - string like operations: modeswitch arrayoperators a:=A+[4,5];
  136. - Insert(Arr,MultiDimArr,0-based-pos);
  137. - a := Concat([1,2,3],[4,5,6]);
  138. - copy, concat for static arrays, creating dynamic arrays
  139. - static arrays
  140. - range: enumtype, boolean, int, char, custom int
  141. - init as arr = rtl.arraySetLength(null,value,dim1,dim2,...)
  142. - init with expression
  143. - length(1-dim array)
  144. - low(1-dim array), high(1-dim array)
  145. - "=" operator for records with static array fields
  146. - of record
  147. - open arrays
  148. - as dynamic arrays
  149. - enums
  150. - type with values and names
  151. - option to write numbers instead of variables
  152. - ord(), low(), high(), pred(), succ(), str(), writestr()
  153. - type cast alias to enumtype
  154. - type cast number to enumtype, enumtype to number
  155. - const aliasname = enumvalue
  156. - sets
  157. - set of enum
  158. - include, exclude, clone when referenced
  159. - assign := set state referenced
  160. - constant set: enums, enum vars, ranges
  161. - set operators +, -, *, ><, =, <>, >=, <=
  162. - in-operator
  163. - low(), high()
  164. - when passing as argument set state referenced
  165. - set of (enum,enum2) - anonymous enumtype
  166. - with-do using local var
  167. - with record do i:=v;
  168. - with classinstance do begin create; i:=v; f(); i:=a[]; end;
  169. - pass by reference
  170. - pass local var to a var/out parameter
  171. - pass variable to a var/out parameter
  172. - pass reference to a var/out parameter
  173. - pass array element to a var/out parameter
  174. - procedure types
  175. - implemented as immutable wrapper function
  176. - assign := nil, proctype (not clone), @function, @method
  177. - call explicit and implicit
  178. - compare equal and notequal with nil, proctype, address, function
  179. - assigned(proctype)
  180. - pass as argument
  181. - methods
  182. - mode delphi: proctype:=proc
  183. - mode delphi: functype=funcresulttype
  184. - nested functions
  185. - reference to
  186. - @@ compare method in delphi mode
  187. - class-of
  188. - assign := nil, var
  189. - call class method
  190. - call constructor
  191. - operators =, <>
  192. - class var, property, method
  193. - Self in class method
  194. - typecast
  195. - class external
  196. - JS object or function as ancestor
  197. - does not descend from TObject
  198. - all members become external. case sensitive
  199. - has no hidden values like $class, $ancestor, $unitname, $init, $final
  200. - can be ancestor of a pascal class (not descend from TObject).
  201. - pascal class descendant can override methods
  202. - property works as normal, replaced by getter and setter
  203. - class-of
  204. - class var/function: works as in JS.
  205. - is and as operators
  206. - destructor forbidden
  207. - constructor must not be virtual
  208. - constructor 'new' -> new extclass(params)
  209. - identifiers are renamed to avoid clashes with external names
  210. - call inherited
  211. - Pascal descendant can override newinstance
  212. - any class can be typecasted to any root class
  213. - class instances cannot access external class members (e.g. static class functions)
  214. - external class 'Array' bracket operator [integer] type jsvalue
  215. - external class 'Object' bracket operator [string] type jsvalue
  216. - typecast class type to JS Object, e.g. TJSObject(TObject)
  217. - typecast record type to JS Object, e.g. TJSObject(TPoint)
  218. - typecast interface type to JS Object, e.g. TJSObject(IUnknown)
  219. - for i in tjsobject do
  220. - nested classes
  221. - jsvalue
  222. - init as undefined
  223. - assign to jsvalue := integer, string, boolean, double, char
  224. - type cast base types to jsvalue
  225. - type cast jsvalue to base type
  226. integer: Math.floor(jsvalue) may return NaN
  227. boolean: !(jsvalue == false) works for numbers too 0==false
  228. double: rtl.getNumber(jsvalue) typeof(n)=="number"?n:NaN;
  229. string: ""+jsvalue
  230. char: rtl.getChar(jsvalue) ((typeof(c)!="string") && (c.length==1)) ? c : ""
  231. - enums: assign to jsvalue, typecast jsvalue to enum
  232. - class instance: assign to jsvalue, typecast jsvalue to a class
  233. - class of: assign to jsvalue, typecast jsvalue to a class-of
  234. - array of jsvalue,
  235. allow to assign any array to an array of jsvalue
  236. allow type casting to any array
  237. - parameter, result type, assign from/to untyped
  238. - operators equal, not equal
  239. - callback: assign to jsvalue, equal, not equal
  240. - jsvalue is class-type, jsvalue is class-of-type
  241. - for i in jsvalue do
  242. - RTTI
  243. - base types
  244. - $mod.$rtti
  245. - enum type tkEnumeration
  246. - set type tkSet
  247. - procedure type tkProcVar, tkMethod
  248. - class type tkClass
  249. - fields,
  250. - methods,
  251. - properties no params, no index, no defaultvalue
  252. - class forward
  253. - class-of type tkClassRef
  254. - dyn array type tkDynArray
  255. - static array type tkArray
  256. - record type tkRecord
  257. - no typeinfo for local types
  258. - built-in function typeinfo(): Pointer/TTypeInfo/...;
  259. - typeinfo(class) -> class.$rtti
  260. - WPO skip not used typeinfo
  261. - open array param
  262. - property stored and index modifier
  263. - property default value, nodefault
  264. - pointer
  265. - compare with and assign nil
  266. - typecast class, class-of, interface, array
  267. - ECMAScript6:
  268. - use 0b for binary literals
  269. - use 0o for octal literals
  270. - dotted unit names, namespaces
  271. - resourcestring
  272. - custom ranges
  273. - enum, int, char
  274. - low(), high(), pred(), succ(), ord(),
  275. - rg(int), int(rg), enum:=rg,
  276. - rg:=rg, rg1:=rg2, rg:=enum, =, <>,
  277. - set of int/enum/char range, in
  278. - array[rg], low(array), high(array), length(array)
  279. - enumeration for..in..do
  280. - enum, enum range, set of enum, set of enum range
  281. - int, int range, set of int, set of int range
  282. - char, char range, set of char, set of char range
  283. - array
  284. - class
  285. - for key in JSObject do
  286. - for value in JSArray do
  287. - Assert(bool[,string])
  288. - without sysutils: if(!bool) throw string
  289. - with sysutils: if(!bool) throw pas.sysutils.EAssertionFailed.$create("Create",[string])
  290. - Object checks:
  291. - Method call EInvalidCast, rtl.checkMethodCall
  292. - type cast to class-type and class-of-type, rtl.asExt, EInvalidCast
  293. - Range checks:
  294. - compile time: warnings to errors
  295. - assign int:=, int+=, enum:=, enum+=, intrange:=, intrange+=,
  296. enumrange:=, enumrange+=, char:=, char+=, charrange:=, charrange+=
  297. - procedure argument int, enum, intrange, enumrange, char, charrange
  298. - array[index1,index2,...] read and assign
  299. - string[index] read and assign
  300. - Interfaces:
  301. - autogenerate GUID
  302. - method resolution
  303. - delegation, property implements: intf or object, field or function,
  304. class field, class function
  305. - default property
  306. - Assigned(intfvar)
  307. - TGUID record
  308. - GuidVar:='{guid}', StringVar:=GuidVar, GuidVar:=IntfTypeOrVar,
  309. - GuidVar=IntfTypeOrVar, GuidVar=s
  310. - pass IntfTypeOrVar to GuidVar parameter
  311. - TGUIDString
  312. - GuidString:=IntfTypeOrVar, GuidString=IntfTypeOrVar
  313. - pass IntfTypeOrVar to GuidString parameter
  314. - CORBA: IntfVar:=nil, IntfVar:=IntfVar, IntfVar:=ObjVar;
  315. - CORBA: IntfVar=IntfVar2, IntfVar<>IntfVar2,
  316. - CORBA: IntfVar is IBird, IntfVar is TBird, ObjVar is IBird
  317. - CORBA: IntfVar2 as IBird, IntfVar2 as TBird, ObjVar as IBird
  318. - CORBA: IntfVar:=IBird(IntfVar2);',
  319. - CORBA: pass IntfVar as argument, pass classinstvar to intf argument
  320. - CORBA: IEnumerable
  321. - COM: IntfVar:=nil, IntfVar:=IntfVar, IntfVar:=ObjVar, IntfArg:=, IntfLocalVar:=
  322. - COM: IntfVar=IntfVar2, IntfVar<>IntfVar2,
  323. - COM: IntfVar is IBird, IntfVar is TBird, ObjVar is IBird
  324. - COM: IntfVar2 as IBird, IntfVar2 as TBird, ObjVar as IBird
  325. - COM: IntfVar:=IBird(IntfVar2);',
  326. - COM: pass IntfVar as argument, pass classinstvar to intf argument
  327. - COM: function result, release on exception
  328. - COM: addref/release for function call in expression
  329. - COM: delegation
  330. - COM: property in class, property in interface
  331. - COM: with interface do
  332. - COM: for interface in ... do
  333. - COM: pass IntfVar to untyped parameter
  334. - currency:
  335. - as nativeint*10000
  336. - CurA+CurB -> CurA+CurB
  337. - CurA-CurB -> CurA-CurB
  338. - CurA*CurB -> CurA*CurB/10000
  339. - CurA/CurB -> Math.floor(CurA/CurB*10000)
  340. - CurA^^CurB -> Math.floor(Math.pow(CurA/10000,CurB/10000)*10000)
  341. - Double:=Currency -> Double:=Currency/10000
  342. - Currency:=Double -> Currency:=Math.floor(Double*10000)
  343. - jsvalue := currency -> jsvalue:=currency/10000
  344. - simplify Math.floor(constnumber) to truncated constnumber
  345. - Pointer of record
  346. - p:=@r, p^:=r
  347. - p^.x, p.x
  348. - dispose, new
  349. - typecast byte(longword) -> value & $ff
  350. - typecast TJSFunction(func)
  351. - modeswitch OmitRTTI
  352. - debugger;
  353. - anonymous functions
  354. ToDos:
  355. - do not rename property Date
  356. - cmd line param to set modeswitch
  357. - bug: DoIt(typeinfo(i)) where DoIt is in another unit and has TTypeInfo
  358. - bug:
  359. v:=a[0] gives Local variable "a" is assigned but never used
  360. - bug:
  361. exit(something) gives function result not set
  362. - constructor does not need reintroduce
  363. - double utf8bom at start must give error pscanner 4259
  364. - setlength(dynarray) modeswitch to not create a copy
  365. - 'new', 'Function' -> class var use .prototype
  366. - static arrays
  367. - clone multi dim static array
  368. - RTTI
  369. - class property
  370. - asm: pas() - useful for overloads and protect an identifier from optimization
  371. - interfaces
  372. - array of interface
  373. - record member interface
  374. - range check o.arr[i] o.astring[i]
  375. - record field external name
  376. - make records more lightweight
  377. - 1 as TEnum, ERangeError
  378. - ifthen<T>
  379. - stdcall of methods: pass original 'this' as first parameter
  380. - move local types to unit scope
  381. - property read Arr[0] https://bugs.freepascal.org/view.php?id=33416
  382. - write, writeln
  383. - array of const
  384. - Result:=inherited;
  385. - sets
  386. - set of char, boolean, integer range, char range, enum range
  387. - call array of proc element without ()
  388. - enums with custom values
  389. - library
  390. - constref
  391. - option overflow checking -Co
  392. +, -, *, Succ, Pred, Inc, Dec
  393. -Co : Overflow checking of integer operations
  394. -CO : Check for possible overflow of integer operations
  395. -C3 : Turn on ieee error checking for constants
  396. - optimizations:
  397. - move rtl.js functions to system.pp
  398. - less brackets on logical and/or/xor, add
  399. - add $mod only if needed
  400. - add Self only if needed
  401. - use a number for small sets
  402. - put set literals into constants
  403. - shortcut for test set is empty a=[] a<>[]
  404. - set operators on literals without temporary arrays, a in [b], [a]*b<>[]
  405. - combine multiple var a=0,b=0
  406. - skip clone array for new array and arraysetlength
  407. - SetLength(scope.a,l) -> read scope only once, same for
  408. Include, Exclude, Inc, Dec, +=, -=, *=, /=
  409. - inline -Si
  410. - autoinline
  411. -O1 insert local/unit vars for global type references:
  412. at start of intf var $r1=null;
  413. at end of impl: $r1=path;
  414. -O1 insert unit vars for complex literals
  415. -O1 no function Result var when assigned only once
  416. -O1 replace constant expression with result
  417. -O1 pass array element by ref: when index is constant, use that directly
  418. -O1 case-of with 6+ elements as binary tree
  419. -O2 removeemptyprocs
  420. -O2 CSE
  421. -O3 DFA
  422. - objects
  423. - advanced records
  424. - TPasClassRecordType as ancestor
  425. - class helpers, type helpers, record helpers, array helpers
  426. - generics
  427. - operator overloading
  428. - operator enumerator
  429. - inline
  430. - anonymous functions
  431. - extended RTTI
  432. - attributes
  433. Debugging this unit: -d<x>
  434. VerbosePas2JS
  435. *)
  436. unit FPPas2Js;
  437. {$mode objfpc}{$H+}
  438. {$inline on}
  439. {$ifdef fpc}
  440. {$define UsePChar}
  441. {$define HasInt64}
  442. {$endif}
  443. interface
  444. uses
  445. Classes, SysUtils, math, contnrs,
  446. jsbase, jstree, jswriter,
  447. PasTree, PScanner, PasResolveEval, PasResolver;
  448. // message numbers
  449. const
  450. nPasElementNotSupported = 4001;
  451. nNotSupportedX = 4002;
  452. nUnaryOpcodeNotSupported = 4003;
  453. nBinaryOpcodeNotSupported = 4004;
  454. nInvalidNumber = 4005;
  455. nInitializedArraysNotSupported = 4006;
  456. nMemberExprMustBeIdentifier = 4007;
  457. nCantWriteSetLiteral = 4008;
  458. nInvalidAbsoluteLocation = 4009;
  459. nForInJSArrDefaultGetterNotExtBracketAccessor = 4010;
  460. nInvalidFunctionReference = 4011;
  461. nMissingExternalName = 4012;
  462. nVirtualMethodNameMustMatchExternal = 4013;
  463. nPublishedNameMustMatchExternal = 4014;
  464. nInvalidVariableModifier = 4015;
  465. nNoArgumentsAllowedForExternalObjectConstructor = 4016;
  466. nNewInstanceFunctionMustBeVirtual = 4017;
  467. nNewInstanceFunctionMustHaveTwoParameters = 4018;
  468. nNewInstanceFunctionMustNotHaveOverloadAtX = 4019;
  469. nBracketAccessorOfExternalClassMustHaveOneParameter = 4020;
  470. nTypeXCannotBePublished = 4021;
  471. nNestedInheritedNeedsParameters = 4022;
  472. nFreeNeedsVar = 4023;
  473. nDuplicateGUIDXInYZ = 4024;
  474. nCantCallExtBracketAccessor = 4025;
  475. nJSNewNotSupported = 4026;
  476. // resourcestring patterns of messages
  477. resourcestring
  478. sPasElementNotSupported = 'Pascal element not supported: %s';
  479. sNotSupportedX = 'Not supported: %s';
  480. sUnaryOpcodeNotSupported = 'Unary OpCode not yet supported "%s"';
  481. sBinaryOpcodeNotSupported = 'Binary OpCode not yet supported "%s"';
  482. sInvalidNumber = 'Invalid number "%s"';
  483. sInitializedArraysNotSupported = 'Initialized array variables not yet supported';
  484. sMemberExprMustBeIdentifier = 'Member expression must be an identifier';
  485. sCantWriteSetLiteral = 'Cannot write set literal';
  486. sInvalidAbsoluteLocation = 'Invalid absolute location';
  487. sForInJSArrDefaultGetterNotExtBracketAccessor = 'for-in-JS-array needs as default getter an external bracket accessor';
  488. sInvalidFunctionReference = 'Invalid function reference';
  489. sMissingExternalName = 'Missing external name';
  490. sVirtualMethodNameMustMatchExternal = 'Virtual method name must match external';
  491. sInvalidVariableModifier = 'Invalid variable modifier "%s"';
  492. sPublishedNameMustMatchExternal = 'Published name must match external';
  493. sNoArgumentsAllowedForExternalObjectConstructor = 'no arguments allowed for external object constructor';
  494. sNewInstanceFunctionMustBeVirtual = 'NewInstance function must be virtual';
  495. sNewInstanceFunctionMustHaveTwoParameters = 'NewInstance function must have two parameters';
  496. sNewInstanceFunctionMustNotHaveOverloadAtX = 'NewInstance function must not have overload at %s';
  497. sBracketAccessorOfExternalClassMustHaveOneParameter = 'Bracket accessor of external class must have one parameter';
  498. sTypeXCannotBePublished = 'Type "%s" cannot be published';
  499. sNestedInheritedNeedsParameters = 'nested inherited needs parameters';
  500. sFreeNeedsVar = 'Free needs a variable';
  501. sDuplicateGUIDXInYZ = 'Duplicate GUID %s in %s and %s';
  502. sCantCallExtBracketAccessor = 'cannot call external bracket accessor, use a property instead';
  503. sJSNewNotSupported = 'Pascal class does not support the "new" constructor';
  504. const
  505. ExtClassBracketAccessor = '[]'; // external name '[]' marks the array param getter/setter
  506. IsExtModePasClassInstance = 1;
  507. IsExtModePasClass = 2;
  508. type
  509. TPas2JSBuiltInName = (
  510. pbifnArray_Concat,
  511. pbifnArray_ConcatN,
  512. pbifnArray_Copy,
  513. pbifnArray_Equal,
  514. pbifnArray_Length,
  515. pbifnArray_SetLength,
  516. pbifnArray_Static_Clone,
  517. pbifnAs,
  518. pbifnAsExt,
  519. pbifnCheckMethodCall,
  520. pbifnCheckVersion,
  521. pbifnClassInstanceFree,
  522. pbifnClassInstanceNew,
  523. pbifnCreateClass,
  524. pbifnCreateClassExt,
  525. pbifnGetChar,
  526. pbifnGetNumber,
  527. pbifnGetObject,
  528. pbifnGetResourcestring,
  529. pbifnIntf_AddRef,
  530. pbifnIntf_Release,
  531. pbifnIntfAddMap,
  532. pbifnIntfAsClass,
  533. pbifnIntfCreate,
  534. pbifnIntfCreateTGUID,
  535. pbifnIntfExprRefsAdd,
  536. pbifnIntfExprRefsCreate,
  537. pbifnIntfExprRefsFree,
  538. pbifnIntfGetGUIDR,
  539. pbifnIntfGetIntfT,
  540. pbifnIntfGuidRToStr,
  541. pbifnIntfIsClass,
  542. pbifnIntfToClass,
  543. pbifnIntfSetIntfL,
  544. pbifnIntfSetIntfP,
  545. pbifnIntfStrToGUIDR,
  546. pbifnIntfQueryIntfIsT,
  547. pbifnIntfQueryIntfT,
  548. pbifnIs,
  549. pbifnIsExt,
  550. pbifnFloatToStr,
  551. pbifnFreeLocalVar,
  552. pbifnFreeVar,
  553. pbifnProcType_Create,
  554. pbifnProcType_Equal,
  555. pbifnProgramMain,
  556. pbifnRangeCheckArrayRead,
  557. pbifnRangeCheckArrayWrite,
  558. pbifnRangeCheckChar,
  559. pbifnRangeCheckInt,
  560. pbifnRangeCheckGetCharAt,
  561. pbifnRangeCheckSetCharAt,
  562. pbifnRecordEqual,
  563. pbifnRTTIAddField, // typeinfos of tkclass and tkrecord have addField
  564. pbifnRTTIAddFields, // typeinfos of tkclass and tkrecord have addFields
  565. pbifnRTTIAddMethod,// " "
  566. pbifnRTTIAddProperty,// " "
  567. pbifnRTTIInherited, // typeinfo for type alias type $inherited
  568. pbifnRTTINewClass,// typeinfo creator of tkClass $Class
  569. pbifnRTTINewClassRef,// typeinfo of tkClassRef $ClassRef
  570. pbifnRTTINewDynArray,// typeinfo of tkDynArray $DynArray
  571. pbifnRTTINewEnum,// typeinfo of tkEnumeration $Enum
  572. pbifnRTTINewInt,// typeinfo of tkInt $Int
  573. pbifnRTTINewInterface,// typeinfo creator of tkInterface $Interface
  574. pbifnRTTINewMethodVar,// typeinfo of tkMethod $MethodVar
  575. pbifnRTTINewPointer,// typeinfo of tkPointer $Pointer
  576. pbifnRTTINewProcSig,// rtl.newTIProcSig
  577. pbifnRTTINewProcVar,// typeinfo of tkProcVar $ProcVar
  578. pbifnRTTINewRecord,// typeinfo creator of tkRecord $Record
  579. pbifnRTTINewRefToProcVar,// typeinfo of tkRefToProcVar $RefToProcVar
  580. pbifnRTTINewSet,// typeinfo of tkSet $Set
  581. pbifnRTTINewStaticArray,// typeinfo of tkArray $StaticArray
  582. pbifnSetCharAt,
  583. pbifnSet_Clone,
  584. pbifnSet_Create,
  585. pbifnSet_Difference,
  586. pbifnSet_Equal,
  587. pbifnSet_Exclude,
  588. pbifnSet_GreaterEqual,
  589. pbifnSet_Include,
  590. pbifnSet_Intersect,
  591. pbifnSet_LowerEqual,
  592. pbifnSet_NotEqual,
  593. pbifnSet_Reference,
  594. pbifnSet_SymDiffSet,
  595. pbifnSet_Union,
  596. pbifnSpaceLeft,
  597. pbifnStringSetLength,
  598. pbifnUnitInit,
  599. pbivnExceptObject,
  600. pbivnIntfExprRefs,
  601. pbivnIntfGUID,
  602. pbivnIntfKind,
  603. pbivnIntfMaps,
  604. pbivnImplementation,
  605. pbivnLoop,
  606. pbivnLoopEnd,
  607. pbivnLoopIn,
  608. pbivnModule,
  609. pbivnModules,
  610. pbivnPtrClass,
  611. pbivnProcOk,
  612. pbivnResourceStrings,
  613. pbivnResourceStringOrg,
  614. pbivnRTL,
  615. pbivnRTTI, // $rtti
  616. pbivnRTTIArray_Dims,
  617. pbivnRTTIArray_ElType,
  618. pbivnRTTIClassRef_InstanceType,
  619. pbivnRTTIEnum_EnumType,
  620. pbivnRTTIInt_MaxValue,
  621. pbivnRTTIInt_MinValue,
  622. pbivnRTTIInt_OrdType,
  623. pbivnRTTILocal, // $r
  624. pbivnRTTIMethodKind, // tTypeInfoMethodVar has methodkind
  625. pbivnRTTIPointer_RefType,
  626. pbivnRTTIProcFlags,
  627. pbivnRTTIProcVar_ProcSig,
  628. pbivnRTTIPropDefault,
  629. pbivnRTTIPropIndex,
  630. pbivnRTTIPropStored,
  631. pbivnRTTISet_CompType,
  632. pbivnSelf,
  633. pbivnTObjectDestroy,
  634. pbivnWith,
  635. pbitnAnonymousPostfix,
  636. pbitnIntDouble,
  637. pbitnTI,
  638. pbitnTIClass,
  639. pbitnTIClassRef,
  640. pbitnTIDynArray,
  641. pbitnTIEnum,
  642. pbitnTIInteger,
  643. pbitnTIInterface,
  644. pbitnTIMethodVar,
  645. pbitnTIPointer,
  646. pbitnTIProcVar,
  647. pbitnTIRecord,
  648. pbitnTIRefToProcVar,
  649. pbitnTISet,
  650. pbitnTIStaticArray,
  651. pbitnUIntDouble
  652. );
  653. const
  654. Pas2JSBuiltInNames: array[TPas2JSBuiltInName] of string = (
  655. 'arrayConcat', // rtl.arrayConcat
  656. 'arrayConcatN', // rtl.arrayConcatN
  657. 'arrayCopy', // rtl.arrayCopy
  658. 'arrayEq', // rtl.arrayEq
  659. 'length', // rtl.length
  660. 'arraySetLength', // rtl.arraySetLength
  661. '$clone',
  662. 'as', // rtl.as
  663. 'asExt', // rtl.asExt
  664. 'checkMethodCall',
  665. 'checkVersion',
  666. '$destroy',
  667. '$create',
  668. 'createClass', // rtl.createClass
  669. 'createClassExt', // rtl.createClassExt
  670. 'getChar', // rtl.getChar
  671. 'getNumber', // rtl.getNumber
  672. 'getObject', // rtl.getObject
  673. 'getResStr', // rtl.getResStr
  674. '_AddRef', // rtl._AddRef
  675. '_Release', // rtl._Release
  676. 'addIntf', // rtl.addIntf
  677. 'intfAsClass', // rtl.intfAsClass
  678. 'createInterface', // rtl.createInterface
  679. 'createTGUID', // rtl.createTGUID
  680. 'ref', // $ir.ref
  681. 'createIntfRefs', // rtl.createIntfRefs
  682. 'free', // $ir.free
  683. 'getIntfGUIDR', // rtl.getIntfGUIDR
  684. 'getIntfT', // rtl.getIntfT
  685. 'guidrToStr', // rtl.guidrToStr
  686. 'intfIsClass', // rtl.intfIsClass
  687. 'intfToClass', // rtl.intfToClass
  688. 'setIntfL', // rtl.setIntfL
  689. 'setIntfP', // rtl.setIntfP
  690. 'strToGUIDR', // rtl.strToGUIDR
  691. 'queryIntfIsT', // rtl.queryIntfIsT
  692. 'queryIntfT', // rtl.queryIntfT
  693. 'is', // rtl.is
  694. 'isExt', // rtl.isExt
  695. 'floatToStr', // rtl.floatToStr
  696. 'freeLoc', // rtl.freeLoc
  697. 'free', // rtl.free
  698. 'createCallback', // rtl.createCallback
  699. 'eqCallback', // rtl.eqCallback
  700. '$main',
  701. 'rcArrR', // rtl.rcArrR
  702. 'rcArrW', // rtl.rcArrW
  703. 'rcc', // rtl.rcc
  704. 'rc', // rtl.rc
  705. 'rcCharAt', // rtl.rcCharAt
  706. 'rcSetCharAt', // rtl.rcSetCharAt
  707. '$equal',
  708. 'addField',
  709. 'addFields',
  710. 'addMethod',
  711. 'addProperty',
  712. '$inherited',
  713. '$Class',
  714. '$ClassRef',
  715. '$DynArray',
  716. '$Enum',
  717. '$Int',
  718. '$Interface',
  719. '$MethodVar',
  720. '$Pointer',
  721. 'newTIProcSig',
  722. '$ProcVar',
  723. '$Record',
  724. '$RefToProcVar',
  725. '$Set',
  726. '$StaticArray',
  727. 'setCharAt', // rtl.setCharAt
  728. 'cloneSet', // rtl.cloneSet
  729. 'createSet', // rtl.createSet [...]
  730. 'diffSet', // rtl.diffSet -
  731. 'eqSet', // rtl.eqSet =
  732. 'excludeSet', // rtl.excludeSet
  733. 'geSet', // rtl.geSet superset >=
  734. 'includeSet', // rtl.includeSet
  735. 'intersectSet', // rtl.intersectSet *
  736. 'leSet', // rtl.leSet subset <=
  737. 'neSet', // rtl.neSet <>
  738. 'refSet', // rtl.refSet
  739. 'symDiffSet', // rtl.symDiffSet >< (symmetrical difference)
  740. 'unionSet', // rtl.unionSet +
  741. 'spaceLeft', // rtl.spaceLeft
  742. 'strSetLength', // rtl.strSetLength
  743. '$init',
  744. '$e',
  745. '$ir',
  746. '$guid',
  747. '$kind',
  748. '$intfmaps',
  749. '$impl',
  750. '$l',
  751. '$end',
  752. '$in',
  753. '$mod',
  754. 'pas',
  755. '$class',
  756. '$ok',
  757. '$resourcestrings',
  758. 'org',
  759. 'rtl',
  760. '$rtti',
  761. 'dims',
  762. 'eltype',
  763. 'instancetype',
  764. 'enumtype',
  765. 'maxvalue',
  766. 'minvalue',
  767. 'ordtype',
  768. '$r',
  769. 'methodkind',
  770. 'reftype',
  771. 'flags',
  772. 'procsig',
  773. 'Default',
  774. 'index',
  775. 'stored',
  776. 'comptype',
  777. 'Self',
  778. 'tObjectDestroy', // rtl.tObjectDestroy
  779. '$with',
  780. '$a',
  781. 'NativeInt',
  782. 'tTypeInfo', // rtl.
  783. 'tTypeInfoClass', // rtl.
  784. 'tTypeInfoClassRef', // rtl.
  785. 'tTypeInfoDynArray', // rtl.
  786. 'tTypeInfoEnum', // rtl.
  787. 'tTypeInfoInteger', // rtl.
  788. 'tTypeInfoInterface', // rtl.
  789. 'tTypeInfoMethodVar', // rtl.
  790. 'tTypeInfoPointer', // rtl.
  791. 'tTypeInfoProcVar', // rtl.
  792. 'tTypeInfoRecord', // rtl.
  793. 'tTypeInfoRefToProcVar', // rtl.
  794. 'tTypeInfoSet', // rtl.
  795. 'tTypeInfoStaticArray', // rtl.
  796. 'NativeUInt'
  797. );
  798. // reserved words, not usable as identifiers, not even as sub identifiers
  799. JSReservedWords: array[0..59] of string = (
  800. // keep sorted, first uppercase, then lowercase !
  801. '__extends',
  802. '_super',
  803. 'anonymous',
  804. 'apply',
  805. 'array',
  806. 'await',
  807. 'bind',
  808. 'break',
  809. 'call',
  810. 'case',
  811. 'catch',
  812. 'class',
  813. 'constructor',
  814. 'continue',
  815. 'default',
  816. 'delete',
  817. 'do',
  818. 'each',
  819. 'else',
  820. 'enum',
  821. 'escape',
  822. 'eval',
  823. 'export',
  824. 'extends',
  825. 'false',
  826. 'for',
  827. 'function',
  828. 'getPrototypeOf',
  829. 'hasOwnProperty',
  830. 'if',
  831. 'implements',
  832. 'import',
  833. 'in',
  834. 'instanceof',
  835. 'interface',
  836. 'isPrototypeOf',
  837. 'let',
  838. 'new',
  839. 'null',
  840. 'package',
  841. 'private',
  842. 'propertyIsEnumerable',
  843. 'protected',
  844. 'prototype',
  845. 'public',
  846. 'return',
  847. 'static',
  848. 'super',
  849. 'switch',
  850. 'this',
  851. 'throw',
  852. 'toLocaleString',
  853. 'toString',
  854. 'true',
  855. 'try',
  856. 'undefined',
  857. 'var',
  858. 'while',
  859. 'with',
  860. 'yield'
  861. );
  862. // reserved words, not usable as global identifiers, can be used as sub identifiers
  863. JSReservedGlobalWords: array[0..51] of string = (
  864. // keep sorted, first uppercase, then lowercase !
  865. 'Array',
  866. 'ArrayBuffer',
  867. 'Boolean',
  868. 'DataView',
  869. 'Date',
  870. 'Error',
  871. 'EvalError',
  872. 'Float32Array',
  873. 'Float64Array',
  874. 'Generator',
  875. 'GeneratorFunction',
  876. 'Infinity',
  877. 'Int16Array',
  878. 'Int32Array',
  879. 'Int8Array',
  880. 'InternalError',
  881. 'JSON',
  882. 'Map',
  883. 'Math',
  884. 'NaN',
  885. 'Number',
  886. 'Object',
  887. 'Promise',
  888. 'Proxy',
  889. 'RangeError',
  890. 'ReferenceError',
  891. 'Reflect',
  892. 'RegExp',
  893. 'Set',
  894. 'String',
  895. 'Symbol',
  896. 'SyntaxError',
  897. 'TypeError',
  898. 'URIError',
  899. 'Uint16Array',
  900. 'Uint32Array',
  901. 'Uint8Array',
  902. 'Uint8ClampedArray',
  903. 'WeakMap',
  904. 'WeakSet',
  905. 'arguments',
  906. 'decodeURI',
  907. 'decodeURIComponent',
  908. 'encodeURI',
  909. 'encodeURIComponent',
  910. 'isFinite',
  911. 'isNaN',
  912. 'parseFloat',
  913. 'parseInt',
  914. 'unescape',
  915. 'uneval',
  916. 'valueOf'
  917. );
  918. type
  919. { EPas2JS }
  920. EPas2JS = Class(Exception)
  921. public
  922. PasElement: TPasElement;
  923. MsgNumber: integer;
  924. Args: TMessageArgs;
  925. Id: TMaxPrecInt;
  926. MsgType: TMessageType;
  927. end;
  928. type
  929. TPasToJsPlatform = (
  930. PlatformBrowser,
  931. PlatformNodeJS
  932. );
  933. TPasToJsPlatforms = set of TPasToJsPlatform;
  934. const
  935. PasToJsPlatformNames: array[TPasToJsPlatform] of string = (
  936. 'Browser',
  937. 'NodeJS'
  938. );
  939. type
  940. TPasToJsProcessor = (
  941. ProcessorECMAScript5,
  942. ProcessorECMAScript6
  943. );
  944. TPasToJsProcessors = set of TPasToJsProcessor;
  945. const
  946. PasToJsProcessorNames: array[TPasToJsProcessor] of string = (
  947. 'ECMAScript5',
  948. 'ECMAScript6'
  949. );
  950. //------------------------------------------------------------------------------
  951. // Pas2js built-in types
  952. type
  953. TPas2jsBaseType = (
  954. pbtNone,
  955. pbtJSValue
  956. );
  957. TPas2jsBaseTypes = set of TPas2jsBaseType;
  958. const
  959. Pas2jsBaseTypeNames: array[TPas2jsBaseType] of string = (
  960. 'None',
  961. 'JSValue'
  962. );
  963. const
  964. ClassVarModifiersType = [vmClass,vmStatic];
  965. LowJSNativeInt = MinSafeIntDouble;
  966. HighJSNativeInt = MaxSafeIntDouble;
  967. LowJSBoolean = false;
  968. HighJSBoolean = true;
  969. //------------------------------------------------------------------------------
  970. // Element CustomData
  971. type
  972. { TPas2JsElementData }
  973. TPas2JsElementData = Class(TPasElementBase)
  974. private
  975. FElement: TPasElement;
  976. procedure SetElement(const AValue: TPasElement);
  977. public
  978. Owner: TObject; // e.g. a TPasToJSConverter
  979. Next: TPas2JsElementData; // TPasToJSConverter uses this for its memory chain
  980. constructor Create; virtual;
  981. destructor Destroy; override;
  982. property Element: TPasElement read FElement write SetElement; // can be TPasElement
  983. end;
  984. TPas2JsElementDataClass = class of TPas2JsElementData;
  985. { TPas2JSModuleScope }
  986. TPas2JSModuleScope = class(TPasModuleScope)
  987. public
  988. end;
  989. { TPas2JSSectionScope }
  990. TPas2JSSectionScope = class(TPasSectionScope)
  991. private
  992. FElevatedLocals: TPasResHashList; // list of TPasIdentifier, case insensitive
  993. procedure InternalAddElevatedLocal(Item: TPasIdentifier);
  994. procedure OnClearElevatedLocal(Item, Dummy: pointer);
  995. public
  996. constructor Create; override;
  997. destructor Destroy; override;
  998. function FindElevatedLocal(const Identifier: String): TPasIdentifier; inline;
  999. function AddElevatedLocal(const Identifier: String; El: TPasElement): TPasIdentifier; virtual;
  1000. procedure WriteElevatedLocals(Prefix: string); virtual;
  1001. end;
  1002. { TPas2JSInitialFinalizationScope }
  1003. TPas2JSInitialFinalizationScope = class(TPasInitialFinalizationScope)
  1004. public
  1005. JS: string; // Option coStoreProcJS
  1006. end;
  1007. { TPas2JSClassScope }
  1008. TPas2JSClassScope = class(TPasClassScope)
  1009. public
  1010. NewInstanceFunction: TPasClassFunction;
  1011. GUID: string;
  1012. end;
  1013. { TPas2JSProcedureScope }
  1014. TPas2JSProcedureScope = class(TPasProcedureScope)
  1015. public
  1016. OverloadName: string;
  1017. ResultVarName: string; // valid in implementation ProcScope, empty means use ResolverResultVar
  1018. BodyJS: string; // Option coStoreProcJS: stored in ImplScope
  1019. GlobalJS: TStringList; // Option coStoreProcJS: stored in ImplScope
  1020. EmptyJS: boolean; // Option coStoreProcJS: stored in ImplScope, true if Body.Body=nil
  1021. procedure AddGlobalJS(const JS: string);
  1022. destructor Destroy; override;
  1023. end;
  1024. { TPas2JSWithExprScope }
  1025. TPas2JSWithExprScope = class(TPasWithExprScope)
  1026. public
  1027. WithVarName: string;
  1028. end;
  1029. { TResElDataPas2JSBaseType - CustomData for compiler built-in types (TPasUnresolvedSymbolRef), e.g. jsvalue }
  1030. TResElDataPas2JSBaseType = class(TResElDataBaseType)
  1031. public
  1032. JSBaseType: TPas2jsBaseType;
  1033. end;
  1034. //------------------------------------------------------------------------------
  1035. // TPas2JSResolver
  1036. const
  1037. msAllPas2jsModeSwitchesReadOnly = [
  1038. msClass,
  1039. msResult,
  1040. msRepeatForward,
  1041. msInitFinal,
  1042. msOut,
  1043. msDefaultPara,
  1044. msProperty,
  1045. msExcept,
  1046. msDefaultUnicodestring,
  1047. msCBlocks
  1048. ];
  1049. msAllPas2jsModeSwitches = msAllPas2jsModeSwitchesReadOnly+[
  1050. msDelphi,msObjfpc,
  1051. msAutoDeref,
  1052. msHintDirective,
  1053. msNestedComment,
  1054. msExternalClass,
  1055. msArrayOperators,
  1056. msIgnoreAttributes,
  1057. msOmitRTTI];
  1058. msAllPas2jsBoolSwitchesReadOnly = [
  1059. bsLongStrings
  1060. ];
  1061. msAllPas2jsBoolSwitches = msAllPas2jsBoolSwitchesReadOnly+[
  1062. bsAssertions,
  1063. bsRangeChecks,
  1064. bsWriteableConst,
  1065. bsTypeInfo,
  1066. bsOverflowChecks,
  1067. bsHints,
  1068. bsNotes,
  1069. bsWarnings,
  1070. bsMacro,
  1071. bsScopedEnums,
  1072. bsObjectChecks
  1073. ];
  1074. // default parser+scanner options
  1075. po_Pas2js = po_Resolver+[
  1076. po_AsmWhole,
  1077. po_ResolveStandardTypes,
  1078. po_ExtConstWithoutExpr,
  1079. po_StopOnUnitInterface];
  1080. btAllJSBaseTypes = [
  1081. btChar,
  1082. btWideChar,
  1083. btString,
  1084. btUnicodeString,
  1085. btDouble,
  1086. btCurrency, // nativeint*10000 truncated
  1087. btBoolean,
  1088. btByteBool,
  1089. btWordBool,
  1090. btLongBool,
  1091. btByte,
  1092. btShortInt,
  1093. btWord,
  1094. btSmallInt,
  1095. btLongWord,
  1096. btLongint,
  1097. btUIntDouble,
  1098. btIntDouble,
  1099. btPointer
  1100. ];
  1101. bfAllJSBaseProcs = bfAllStandardProcs;
  1102. btAllJSStrings = [btString];
  1103. btAllJSChars = [btChar];
  1104. btAllJSStringAndChars = btAllJSStrings+btAllJSChars;
  1105. btAllJSFloats = [btDouble];
  1106. btAllJSBooleans = [btBoolean];
  1107. btAllJSInteger = [btByte,btShortInt,btWord,btSmallInt,btLongWord,btLongint,
  1108. btIntDouble,btUIntDouble,
  1109. btCurrency // in pas2js currency is more like an integer, instead of float
  1110. ];
  1111. btAllJSValueSrcTypes = [btNil,btUntyped,btPointer]+btAllJSInteger
  1112. +btAllJSStringAndChars+btAllJSFloats+btAllJSBooleans;
  1113. btAllJSValueTypeCastTo = btAllJSInteger
  1114. +btAllJSStringAndChars+btAllJSFloats+btAllJSBooleans+[btPointer];
  1115. DefaultPasResolverOptions = [
  1116. proFixCaseOfOverrides,
  1117. proClassPropertyNonStatic,
  1118. proPropertyAsVarParam,
  1119. proClassOfIs,
  1120. proExtClassInstanceNoTypeMembers,
  1121. proOpenAsDynArrays,
  1122. proProcTypeWithoutIsNested,
  1123. proMethodAddrAsPointer
  1124. ];
  1125. type
  1126. TPas2JSResolver = class;
  1127. { TPas2jsPasScanner }
  1128. TPas2jsPasScanner = class(TPascalScanner)
  1129. private
  1130. FCompilerVersion: string;
  1131. FResolver: TPas2JSResolver;
  1132. FTargetPlatform: TPasToJsPlatform;
  1133. FTargetProcessor: TPasToJsProcessor;
  1134. protected
  1135. function HandleInclude(const Param: String): TToken; override;
  1136. public
  1137. function ReadNonPascalTillEndToken(StopAtLineEnd: boolean): TToken;
  1138. override;
  1139. property CompilerVersion: string read FCompilerVersion write FCompilerVersion;
  1140. property Resolver: TPas2JSResolver read FResolver write FResolver;
  1141. property TargetPlatform: TPasToJsPlatform read FTargetPlatform write FTargetPlatform;
  1142. property TargetProcessor: TPasToJsProcessor read FTargetProcessor write FTargetProcessor;
  1143. end;
  1144. { TPas2JSResolver }
  1145. TPas2JSResolver = class(TPasResolver)
  1146. private
  1147. FJSBaseTypes: array[TPas2jsBaseType] of TPasUnresolvedSymbolRef;
  1148. FExternalNames: TPasResHashList; // list of TPasIdentifier, case sensitive
  1149. FFirstElementData, FLastElementData: TPas2JsElementData;
  1150. function GetJSBaseTypes(aBaseType: TPas2jsBaseType): TPasUnresolvedSymbolRef; inline;
  1151. procedure InternalAdd(Item: TPasIdentifier);
  1152. procedure OnClearHashItem(Item, Dummy: pointer);
  1153. protected
  1154. FOverloadScopes: TFPList; // list of TPasIdentifierScope
  1155. function HasOverloadIndex(El: TPasElement; WithElevatedLocal: boolean = false): boolean; virtual;
  1156. function GetOverloadIndex(Identifier: TPasIdentifier;
  1157. StopAt: TPasElement): integer;
  1158. function GetOverloadAt(Identifier: TPasIdentifier; var Index: integer): TPasIdentifier;
  1159. function GetOverloadIndex(El: TPasElement): integer;
  1160. function GetOverloadAt(const aName: String; Index: integer): TPasIdentifier;
  1161. function RenameOverload(El: TPasElement): boolean;
  1162. procedure RenameOverloadsInSection(aSection: TPasSection);
  1163. procedure RenameOverloads(DeclEl: TPasElement; Declarations: TFPList);
  1164. procedure RenameSubOverloads(Declarations: TFPList);
  1165. procedure PushOverloadScope(Scope: TPasIdentifierScope);
  1166. procedure PopOverloadScope;
  1167. procedure AddType(El: TPasType); override;
  1168. procedure ResolveImplAsm(El: TPasImplAsmStatement); override;
  1169. procedure ResolveNameExpr(El: TPasExpr; const aName: string;
  1170. Access: TResolvedRefAccess); override;
  1171. procedure ResolveFuncParamsExpr(Params: TParamsExpr;
  1172. Access: TResolvedRefAccess); override;
  1173. procedure FinishInterfaceSection(Section: TPasSection); override;
  1174. procedure FinishTypeSection(El: TPasDeclarations); override;
  1175. procedure FinishModule(CurModule: TPasModule); override;
  1176. procedure FinishEnumType(El: TPasEnumType); override;
  1177. procedure FinishSetType(El: TPasSetType); override;
  1178. procedure FinishRecordType(El: TPasRecordType); override;
  1179. procedure FinishClassType(El: TPasClassType); override;
  1180. procedure FinishArrayType(El: TPasArrayType); override;
  1181. procedure FinishAncestors(aClass: TPasClassType); override;
  1182. procedure FinishVariable(El: TPasVariable); override;
  1183. procedure FinishArgument(El: TPasArgument); override;
  1184. procedure FinishProcedureType(El: TPasProcedureType); override;
  1185. procedure FinishPropertyOfClass(PropEl: TPasProperty); override;
  1186. procedure CheckExternalClassConstructor(Ref: TResolvedReference); virtual;
  1187. procedure CheckConditionExpr(El: TPasExpr;
  1188. const ResolvedEl: TPasResolverResult); override;
  1189. procedure CheckNewInstanceFunction(ClassScope: TPas2JSClassScope); virtual;
  1190. function AddExternalName(const aName: string; El: TPasElement): TPasIdentifier; virtual;
  1191. function FindExternalName(const aName: String): TPasIdentifier; virtual;
  1192. procedure AddExternalPath(aName: string; El: TPasElement);
  1193. procedure ClearElementData; virtual;
  1194. function GenerateGUID(El: TPasClassType): string; virtual;
  1195. protected
  1196. const
  1197. cJSValueConversion = 2*cTypeConversion;
  1198. // additional base types
  1199. function AddJSBaseType(const aName: string; Typ: TPas2jsBaseType): TResElDataPas2JSBaseType;
  1200. function CheckAssignCompatibilityCustom(const LHS,
  1201. RHS: TPasResolverResult; ErrorEl: TPasElement;
  1202. RaiseOnIncompatible: boolean; var Handled: boolean): integer; override;
  1203. function CheckTypeCastClassInstanceToClass(const FromClassRes,
  1204. ToClassRes: TPasResolverResult; ErrorEl: TPasElement): integer; override;
  1205. function CheckEqualCompatibilityCustomType(const LHS,
  1206. RHS: TPasResolverResult; ErrorEl: TPasElement;
  1207. RaiseOnIncompatible: boolean): integer; override;
  1208. function CheckForIn(Loop: TPasImplForLoop; const VarResolved,
  1209. InResolved: TPasResolverResult): boolean; override;
  1210. procedure ComputeUnaryNot(El: TUnaryExpr;
  1211. var ResolvedEl: TPasResolverResult; Flags: TPasResolverComputeFlags);
  1212. override;
  1213. procedure ComputeBinaryExprRes(Bin: TBinaryExpr; out
  1214. ResolvedEl: TPasResolverResult; Flags: TPasResolverComputeFlags;
  1215. var LeftResolved, RightResolved: TPasResolverResult); override;
  1216. // built-in functions
  1217. procedure BI_TypeInfo_OnGetCallResult(Proc: TResElDataBuiltInProc;
  1218. Params: TParamsExpr; out ResolvedEl: TPasResolverResult); override;
  1219. function BI_Debugger_OnGetCallCompatibility(Proc: TResElDataBuiltInProc;
  1220. Expr: TPasExpr; RaiseOnError: boolean): integer; virtual;
  1221. public
  1222. constructor Create; reintroduce;
  1223. destructor Destroy; override;
  1224. procedure ClearBuiltInIdentifiers; override;
  1225. // base types
  1226. function IsJSBaseType(TypeEl: TPasType; Typ: TPas2jsBaseType): boolean;
  1227. function IsJSBaseType(const TypeResolved: TPasResolverResult;
  1228. Typ: TPas2jsBaseType; HasValue: boolean = false): boolean;
  1229. procedure AddObjFPCBuiltInIdentifiers(
  1230. const TheBaseTypes: TResolveBaseTypes;
  1231. const TheBaseProcs: TResolverBuiltInProcs); override;
  1232. function CheckTypeCastRes(const FromResolved,
  1233. ToResolved: TPasResolverResult; ErrorEl: TPasElement;
  1234. RaiseOnError: boolean): integer; override;
  1235. function FindLocalBuiltInSymbol(El: TPasElement): TPasElement; override;
  1236. property JSBaseTypes[aBaseType: TPas2jsBaseType]: TPasUnresolvedSymbolRef read GetJSBaseTypes;
  1237. // compute literals and constants
  1238. function ExtractPasStringLiteral(El: TPasElement; const S: String): TJSString; virtual;
  1239. function ResolverToJSValue(Value: TResEvalValue; ErrorEl: TPasElement): TJSValue; virtual;
  1240. function ComputeConstString(Expr: TPasExpr; StoreCustomData, NotEmpty: boolean): String; virtual;
  1241. procedure CheckAssignExprRangeToCustom(
  1242. const LeftResolved: TPasResolverResult; RValue: TResEvalValue;
  1243. RHS: TPasExpr); override;
  1244. function HasStaticArrayCloneFunc(Arr: TPasArrayType): boolean;
  1245. function IsTGUID(TypeEl: TPasRecordType): boolean; override;
  1246. function GetAssignGUIDString(TypeEl: TPasRecordType; Expr: TPasExpr; out GUID: TGuid): boolean;
  1247. // CustomData
  1248. function GetElementData(El: TPasElementBase;
  1249. DataClass: TPas2JsElementDataClass): TPas2JsElementData; virtual;
  1250. procedure AddElementData(Data: TPas2JsElementData); virtual;
  1251. function CreateElementData(DataClass: TPas2JsElementDataClass;
  1252. El: TPasElement): TPas2JsElementData; virtual;
  1253. // utility
  1254. procedure RaiseMsg(const Id: TMaxPrecInt; MsgNumber: integer; const Fmt: String;
  1255. Args: array of {$IFDEF pas2js}jsvalue{$ELSE}const{$ENDIF}; ErrorPosEl: TPasElement); override;
  1256. function GetOverloadName(El: TPasElement): string;
  1257. function GetBaseDescription(const R: TPasResolverResult; AddPath: boolean=
  1258. false): string; override;
  1259. function HasTypeInfo(El: TPasType): boolean; override;
  1260. function ProcHasImplElements(Proc: TPasProcedure): boolean; override;
  1261. function IsTObjectFreeMethod(El: TPasExpr): boolean; virtual;
  1262. function IsExternalBracketAccessor(El: TPasElement): boolean;
  1263. function IsExternalClassConstructor(El: TPasElement): boolean;
  1264. function IsForInExtArray(Loop: TPasImplForLoop; const VarResolved,
  1265. InResolved: TPasResolverResult; out ArgResolved, LengthResolved,
  1266. PropResultResolved: TPasResolverResult): boolean;
  1267. end;
  1268. //------------------------------------------------------------------------------
  1269. // TConvertContext
  1270. type
  1271. TCtxAccess = (
  1272. caRead, // normal read
  1273. caAssign, // needs setter
  1274. caByReference // needs path, getter and setter
  1275. );
  1276. TFunctionContext = Class;
  1277. { TConvertContext }
  1278. TConvertContextClass = Class of TConvertContext;
  1279. TConvertContext = Class(TObject)
  1280. public
  1281. PasElement: TPasElement;
  1282. JSElement: TJSElement;
  1283. Resolver: TPas2JSResolver;
  1284. Parent: TConvertContext;
  1285. IsGlobal: boolean; // can hold constants and types
  1286. Access: TCtxAccess;
  1287. AccessContext: TConvertContext;
  1288. TmpVarCount: integer;
  1289. ScannerBoolSwitches: TBoolSwitches;
  1290. ScannerModeSwitches: TModeSwitches;
  1291. constructor Create(PasEl: TPasElement; JSEl: TJSElement; aParent: TConvertContext); virtual;
  1292. function GetRootModule: TPasModule;
  1293. function GetNonDotContext: TConvertContext;
  1294. function GetFunctionContext: TFunctionContext;
  1295. function GetLocalName(El: TPasElement): string; virtual;
  1296. function GetSelfContext: TFunctionContext;
  1297. function GetContextOfPasElement(El: TPasElement): TConvertContext;
  1298. function GetFuncContextOfPasElement(El: TPasElement): TFunctionContext;
  1299. function GetContextOfType(aType: TConvertContextClass): TConvertContext;
  1300. function CreateLocalIdentifier(const Prefix: string): string;
  1301. function CurrentModeSwitches: TModeSwitches;
  1302. function GetGlobalFunc: TFunctionContext;
  1303. procedure WriteStack;
  1304. procedure DoWriteStack(Index: integer); virtual;
  1305. function ToString: string; override;
  1306. end;
  1307. { TRootContext }
  1308. TRootContext = Class(TConvertContext)
  1309. public
  1310. ResourceStrings: TJSVarDeclaration;
  1311. end;
  1312. { TFCLocalIdentifier }
  1313. TFCLocalIdentifier = class
  1314. public
  1315. Element: TPasElement;
  1316. Name: string;
  1317. constructor Create(const aName: string; TheEl: TPasElement);
  1318. end;
  1319. TFCLocalVars = array of TFCLocalIdentifier;
  1320. { TFunctionContext
  1321. Module Function: PasElement is TPasProcedure (ImplProc), ThisPas=nil
  1322. Method: PasElement is TPasProcedure (ImplProc), ThisPas is TPasClassType }
  1323. TFunctionContext = Class(TConvertContext)
  1324. public
  1325. LocalVars: TFCLocalVars;
  1326. ThisPas: TPasElement;
  1327. IntfElReleases: TFPList; // list of TPasElement, that needs rtl._Release(<El>)
  1328. ResultNeedsIntfRelease: boolean;
  1329. IntfExprReleaseCount: integer; // >0 means needs $ir
  1330. BodySt: TJSElement;
  1331. TrySt: TJSTryFinallyStatement;
  1332. FinallyFirst, FinallyLast: TJSStatementList;
  1333. destructor Destroy; override;
  1334. procedure AddLocalVar(const aName: string; El: TPasElement);
  1335. procedure Add_InterfaceRelease(El: TPasElement);
  1336. function ToString: string; override;
  1337. function GetLocalName(El: TPasElement): string; override;
  1338. function IndexOfLocalVar(const aName: string): integer;
  1339. function IndexOfLocalVar(El: TPasElement): integer;
  1340. function FindLocalVar(const aName: string): TFCLocalIdentifier;
  1341. function FindLocalIdentifier(El: TPasElement): TFCLocalIdentifier;
  1342. procedure DoWriteStack(Index: integer); override;
  1343. end;
  1344. { TObjectContext }
  1345. TObjectContext = Class(TConvertContext)
  1346. end;
  1347. { TSectionContext - interface/implementation/program/library
  1348. interface/program/library: PasElement is TPasModule, ThisPas is TPasModule
  1349. implementation: PasElement is TImplementationSection, ThisPas is TPasModule }
  1350. TSectionContext = Class(TFunctionContext)
  1351. public
  1352. constructor Create(PasEl: TPasElement; JSEl: TJSElement; aParent: TConvertContext); override;
  1353. end;
  1354. { TDotContext - used for converting eopSubIdent }
  1355. TDotContext = Class(TConvertContext)
  1356. public
  1357. LeftResolved: TPasResolverResult;
  1358. // created by ConvertElement if subident needs special translation:
  1359. JS: TJSElement;
  1360. end;
  1361. { TAssignContext - used for left side of an assign statement }
  1362. TAssignContext = Class(TConvertContext)
  1363. public
  1364. // set when creating:
  1365. LeftResolved: TPasResolverResult;
  1366. RightResolved: TPasResolverResult;
  1367. RightSide: TJSElement;
  1368. // created by ConvertElement if assign needs a call:
  1369. PropertyEl: TPasProperty;
  1370. Setter: TPasElement;
  1371. Call: TJSCallExpression;
  1372. constructor Create(PasEl: TPasElement; JSEl: TJSElement; aParent: TConvertContext); override;
  1373. end;
  1374. { TParamContext }
  1375. TParamContext = Class(TConvertContext)
  1376. public
  1377. // set when creating:
  1378. Arg: TPasArgument;
  1379. Expr: TPasExpr;
  1380. ResolvedExpr: TPasResolverResult;
  1381. // created by ConvertElement:
  1382. Getter: TJSElement;
  1383. Setter: TJSElement;
  1384. ReusingReference: boolean; // true = result is a reference, do not create another
  1385. constructor Create(PasEl: TPasElement; JSEl: TJSElement; aParent: TConvertContext); override;
  1386. end;
  1387. //------------------------------------------------------------------------------
  1388. // TPasToJSConverter
  1389. type
  1390. TPasToJsConverterOption = (
  1391. coLowerCase, // lowercase all identifiers, except conflicts with JS reserved words
  1392. coSwitchStatement, // convert case-of into switch instead of if-then-else
  1393. coEnumNumbers, // use enum numbers instead of names
  1394. coUseStrict, // insert 'use strict'
  1395. coNoTypeInfo, // do not generate RTTI
  1396. coEliminateDeadCode, // skip code that is never executed
  1397. coStoreImplJS, // store references to JS code in procscopes
  1398. coRTLVersionCheckMain, // insert rtl version check into main
  1399. coRTLVersionCheckSystem, // insert rtl version check into system unit init
  1400. coRTLVersionCheckUnit // insert rtl version check into every unit init
  1401. );
  1402. TPasToJsConverterOptions = set of TPasToJsConverterOption;
  1403. const
  1404. DefaultPasToJSOptions = [coLowerCase];
  1405. DefaultJSWriterOptions = [
  1406. {$IFDEF FPC_HAS_CPSTRING}
  1407. woUseUTF8,
  1408. {$ENDIF}
  1409. woCompactArrayLiterals,
  1410. woCompactObjectLiterals,
  1411. woCompactArguments];
  1412. type
  1413. TPas2JSIsElementUsedEvent = function(Sender: TObject; El: TPasElement): boolean of object;
  1414. TJSReservedWordList = array of String;
  1415. TRefPathKind = (
  1416. rpkPath, // e.g. "TObject"
  1417. rpkPathWithDot, // e.g. "TObject."
  1418. rpkPathAndName // e.g. "TObject.ClassName"
  1419. );
  1420. { TPasToJSConverter }
  1421. TPasToJSConverter = Class(TObject)
  1422. private
  1423. // inline at ttop, because fpc 3.1 requires inline implementation in front of use
  1424. function GetUseEnumNumbers: boolean; inline;
  1425. function GetUseLowerCase: boolean; inline;
  1426. function GetUseSwitchStatement: boolean; inline;
  1427. private
  1428. {$IFDEF EnableForLoopRunnerCheck}
  1429. type
  1430. TForLoopFindData = record
  1431. ForLoop: TPasImplForLoop;
  1432. LoopVar: TPasElement;
  1433. FoundLoop: boolean;
  1434. LoopVarWrite: boolean; // true if first access of LoopVar after loop is a write
  1435. LoopVarRead: boolean; // true if first access of LoopVar after loop is a read
  1436. end;
  1437. PForLoopFindData = ^TForLoopFindData;
  1438. procedure ForLoop_OnProcBodyElement(El: TPasElement; arg: pointer);
  1439. {$ENDIF}
  1440. private
  1441. FBuiltInNames: array[TPas2JSBuiltInName] of string;
  1442. FOnIsElementUsed: TPas2JSIsElementUsedEvent;
  1443. FOnIsTypeInfoUsed: TPas2JSIsElementUsedEvent;
  1444. FOptions: TPasToJsConverterOptions;
  1445. FReservedWords: TJSReservedWordList; // sorted with CompareStr
  1446. FRTLVersion: TJSNumber;
  1447. FTargetPlatform: TPasToJsPlatform;
  1448. FTargetProcessor: TPasToJsProcessor;
  1449. Function CreatePrimitiveDotExpr(AName: string; Src: TPasElement): TJSElement;
  1450. Function CreateSubDeclNameExpr(El: TPasElement; const Name: string;
  1451. AContext: TConvertContext; PosEl: TPasElement = nil): TJSElement;
  1452. Function CreateSubDeclNameExpr(El: TPasElement;
  1453. AContext: TConvertContext; PosEl: TPasElement = nil): TJSElement;
  1454. Function CreateIdentifierExpr(El: TPasElement; AContext: TConvertContext): TJSElement;
  1455. Function CreateIdentifierExpr(AName: string; CheckGlobal: boolean; PosEl: TPasElement; AContext: TConvertContext): TJSElement;
  1456. Function CreateSwitchStatement(El: TPasImplCaseOf; AContext: TConvertContext): TJSElement;
  1457. Function CreateTypeDecl(El: TPasType; AContext: TConvertContext): TJSElement;
  1458. Function CreateVarDecl(El: TPasVariable; AContext: TConvertContext): TJSElement;
  1459. Procedure AddToSourceElements(Src: TJSSourceElements; El: TJSElement);
  1460. procedure RemoveFromSourceElements(Src: TJSSourceElements;
  1461. El: TJSElement);
  1462. function GetBuildInNames(bin: TPas2JSBuiltInName): string;
  1463. procedure SetBuildInNames(bin: TPas2JSBuiltInName; const AValue: string);
  1464. procedure SetReservedWords(const AValue: TJSReservedWordList);
  1465. procedure SetUseEnumNumbers(const AValue: boolean);
  1466. procedure SetUseLowerCase(const AValue: boolean);
  1467. procedure SetUseSwitchStatement(const AValue: boolean);
  1468. protected
  1469. // Error functions
  1470. Procedure DoError(Id: TMaxPrecInt; Const Msg : String);
  1471. Procedure DoError(Id: TMaxPrecInt; Const Msg : String;
  1472. const Args: array of {$IFDEF pas2js}jsvalue{$ELSE}const{$ENDIF});
  1473. Procedure DoError(Id: TMaxPrecInt; MsgNumber: integer; const MsgPattern: string;
  1474. const Args: array of {$IFDEF pas2js}jsvalue{$ELSE}const{$ENDIF}; El: TPasElement);
  1475. procedure RaiseNotSupported(El: TPasElement; AContext: TConvertContext; Id: TMaxPrecInt; const Msg: string = '');
  1476. procedure RaiseIdentifierNotFound(Identifier: string; El: TPasElement; Id: TMaxPrecInt);
  1477. procedure RaiseInconsistency(Id: TMaxPrecInt; El: TPasElement);
  1478. // Computation, value conversions
  1479. Function GetExpressionValueType(El: TPasExpr; AContext: TConvertContext ): TJSType; virtual;
  1480. Function GetPasIdentValueType(AName: String; AContext: TConvertContext): TJSType; virtual;
  1481. Function ComputeConstString(Expr: TPasExpr; AContext: TConvertContext; NotEmpty: boolean): String; virtual;
  1482. Function IsLiteralInteger(El: TJSElement; out Number: TMaxPrecInt): boolean;
  1483. Function IsLiteralNumber(El: TJSElement; out n: TJSNumber): boolean;
  1484. // Name mangling
  1485. Function GetOverloadName(El: TPasElement; AContext: TConvertContext): string;
  1486. Function CanClashWithGlobal(El: TPasElement): boolean;
  1487. Function TransformVariableName(ErrorEl: TPasElement; Const AName: String; CheckGlobal: boolean; AContext : TConvertContext): String; virtual;
  1488. Function TransformVariableName(El: TPasElement; AContext : TConvertContext) : String; virtual;
  1489. Function TransformModuleName(El: TPasModule; AddModulesPrefix: boolean; AContext : TConvertContext) : String; virtual;
  1490. Function IsReservedWord(const aName: string; CheckGlobal: boolean): boolean; virtual;
  1491. Function GetTypeInfoName(El: TPasType; AContext: TConvertContext;
  1492. ErrorEl: TPasElement): String; virtual;
  1493. // utility functions for creating stuff
  1494. Function IsElementUsed(El: TPasElement): boolean; virtual;
  1495. Function IsSystemUnit(aModule: TPasModule): boolean; virtual;
  1496. Function HasTypeInfo(El: TPasType; AContext: TConvertContext): boolean; virtual;
  1497. Function IsClassRTTICreatedBefore(aClass: TPasClassType; Before: TPasElement; AConText: TConvertContext): boolean;
  1498. Procedure FindAvailableLocalName(var aName: string; JSExpr: TJSElement);
  1499. // Never create an element manually, always use the below functions
  1500. Function CreateElement(C: TJSElementClass; Src: TPasElement): TJSElement; virtual;
  1501. Function CreateFreeOrNewInstanceExpr(Ref: TResolvedReference;
  1502. AContext : TConvertContext): TJSCallExpression; virtual;
  1503. Function CreateFunctionSt(El: TPasElement; WithBody: boolean = true;
  1504. WithSrc: boolean = false): TJSFunctionDeclarationStatement;
  1505. Function CreateFunctionDef(El: TPasElement; WithBody: boolean = true;
  1506. WithSrc: boolean = false): TJSFuncDef;
  1507. Procedure CreateProcedureCall(var Call: TJSCallExpression; Args: TParamsExpr;
  1508. TargetProc: TPasProcedureType; AContext: TConvertContext); virtual;
  1509. Procedure CreateProcedureCallArgs(Elements: TJSArrayLiteralElements;
  1510. Args: TParamsExpr; TargetProc: TPasProcedureType; AContext: TConvertContext); virtual;
  1511. Function CreateProcCallArg(El: TPasExpr; TargetArg: TPasArgument;
  1512. AContext: TConvertContext): TJSElement; virtual;
  1513. Function CreateProcCallArgRef(El: TPasExpr; ResolvedEl: TPasResolverResult;
  1514. TargetArg: TPasArgument; AContext: TConvertContext): TJSElement; virtual;
  1515. Function CreateArrayEl(El: TPasExpr; JS: TJSElement; AContext: TConvertContext): TJSElement; virtual;
  1516. Function CreateArgumentAccess(Arg: TPasArgument; AContext: TConvertContext;
  1517. PosEl: TPasElement): TJSElement; virtual;
  1518. Function CreateUnary(Members: array of string; E: TJSElement): TJSUnary;
  1519. Function CreateUnaryPlus(Expr: TJSElement; El: TPasElement): TJSUnaryPlusExpression;
  1520. Function CreateMemberExpression(Members: array of string): TJSDotMemberExpression;
  1521. Function CreateCallExpression(El: TPasElement): TJSCallExpression;
  1522. Function CreateCallCharCodeAt(Arg: TJSElement; aNumber: integer; El: TPasElement): TJSCallExpression; virtual;
  1523. Function CreateCallFromCharCode(Arg: TJSElement; El: TPasElement): TJSCallExpression; virtual;
  1524. Function CreateUsesList(UsesSection: TPasSection; AContext : TConvertContext): TJSArrayLiteral;
  1525. Procedure AddToStatementList(var First, Last: TJSStatementList;
  1526. Add: TJSElement; Src: TPasElement); overload;
  1527. Procedure AddToStatementList(St: TJSStatementList; Add: TJSElement; Src: TPasElement); overload;
  1528. Procedure AddToVarStatement(VarStat: TJSVariableStatement; Add: TJSElement;
  1529. Src: TPasElement);
  1530. Function CreateValInit(PasType: TPasType; Expr: TPasExpr; El: TPasElement;
  1531. AContext: TConvertContext): TJSElement; virtual;
  1532. Function CreateVarInit(El: TPasVariable; AContext: TConvertContext): TJSElement; virtual;
  1533. Function CreateVarStatement(const aName: String; Init: TJSElement;
  1534. El: TPasElement): TJSVariableStatement; virtual;
  1535. Function CreateVarDecl(const aName: String; Init: TJSElement; El: TPasElement): TJSVarDeclaration; virtual;
  1536. // JS literals
  1537. Function CreateLiteralNumber(El: TPasElement; const n: TJSNumber): TJSLiteral; virtual;
  1538. Function CreateLiteralHexNumber(El: TPasElement; const n: TMaxPrecInt; Digits: byte): TJSLiteral; virtual;
  1539. Function CreateLiteralString(El: TPasElement; const s: string): TJSLiteral; virtual;
  1540. Function CreateLiteralJSString(El: TPasElement; const s: TJSString): TJSLiteral; virtual;
  1541. Function CreateLiteralBoolean(El: TPasElement; b: boolean): TJSLiteral; virtual;
  1542. Function CreateLiteralNull(El: TPasElement): TJSLiteral; virtual;
  1543. Function CreateLiteralUndefined(El: TPasElement): TJSLiteral; virtual;
  1544. Function CreateLiteralCustomValue(El: TPasElement; const s: TJSString): TJSLiteral; virtual;
  1545. Function CreateSetLiteralElement(Expr: TPasExpr; AContext: TConvertContext): TJSElement; virtual;
  1546. Function CreateUnaryNot(El: TJSElement; Src: TPasElement): TJSUnaryNotExpression; virtual;
  1547. Procedure ConvertCharLiteralToInt(Lit: TJSLiteral; ErrorEl: TPasElement; AContext: TConvertContext); virtual;
  1548. Function ClonePrimaryExpression(El: TJSPrimaryExpression; Src: TPasElement): TJSPrimaryExpression;
  1549. // simple JS expressions
  1550. Function CreateMulNumber(El: TPasElement; JS: TJSElement; n: TMaxPrecInt): TJSElement; virtual;
  1551. Function CreateDivideNumber(El: TPasElement; JS: TJSElement; n: TMaxPrecInt): TJSElement; virtual;
  1552. Function CreateMathFloor(El: TPasElement; JS: TJSElement): TJSElement; virtual;
  1553. Function CreateDotExpression(aParent: TPasElement; Left, Right: TJSElement;
  1554. CheckRightIntfRef: boolean = false): TJSElement; virtual;
  1555. Function CreateReferencePath(El: TPasElement; AContext : TConvertContext;
  1556. Kind: TRefPathKind; Full: boolean = false; Ref: TResolvedReference = nil): string; virtual;
  1557. Function CreateReferencePathExpr(El: TPasElement; AContext : TConvertContext;
  1558. Full: boolean = false; Ref: TResolvedReference = nil): TJSElement; virtual;
  1559. Function CreateImplementationSection(El: TPasModule; AContext: TConvertContext): TJSFunctionDeclarationStatement;
  1560. Procedure CreateInitSection(El: TPasModule; Src: TJSSourceElements; AContext: TConvertContext);
  1561. Function CreateReferencedSet(El: TPasElement; SetExpr: TJSElement): TJSElement; virtual;
  1562. // record
  1563. Function CreateRecordInit(aRecord: TPasRecordType; Expr: TPasExpr;
  1564. El: TPasElement; AContext: TConvertContext): TJSElement; virtual;
  1565. Function CreateNewRecord(El: TPasElement; RecTypeEl: TPasRecordType;
  1566. AContext: TConvertContext): TJSNewMemberExpression; virtual;
  1567. Function CreateCloneRecord(El: TPasElement; RecTypeEl: TPasRecordType;
  1568. RecordExpr: TJSElement; AContext: TConvertContext): TJSElement; virtual;
  1569. // array
  1570. Function CreateArrayConcat(ElTypeResolved: TPasResolverResult; PosEl: TPasElement;
  1571. AContext: TConvertContext): TJSCallExpression; overload; virtual;
  1572. Function CreateArrayConcat(ArrayType: TPasArrayType; PosEl: TPasElement;
  1573. AContext: TConvertContext): TJSCallExpression; overload; virtual;
  1574. Function CreateCallback(El: TPasElement; ResolvedEl: TPasResolverResult;
  1575. AContext: TConvertContext): TJSElement; virtual;
  1576. Function ConvertExternalBracketAccessorCall(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  1577. Function CreateAssignStatement(LeftEl: TPasElement; AssignContext: TAssignContext): TJSElement; virtual;
  1578. Function CreateGetEnumeratorLoop(El: TPasImplForLoop;
  1579. AContext: TConvertContext): TJSElement; virtual;
  1580. Function CreateCallRTLFreeLoc(Setter, Getter: TJSElement; Src: TPasElement): TJSElement; virtual;
  1581. Function CreatePropertyGet(Prop: TPasProperty; Ref: TResolvedReference;
  1582. AContext: TConvertContext; PosEl: TPasElement): TJSElement; virtual;
  1583. Function CreatePrecompiledJS(El: TJSElement): string; virtual;
  1584. // create elements for array
  1585. Function CreateArrayInit(ArrayType: TPasArrayType; Expr: TPasExpr;
  1586. El: TPasElement; AContext: TConvertContext): TJSElement; virtual;
  1587. Function CreateCmpArrayWithNil(El: TPasElement; JSArray: TJSElement;
  1588. OpCode: TExprOpCode): TJSElement; virtual;
  1589. Function CreateCloneStaticArray(El: TPasElement; ArrTypeEl: TPasArrayType;
  1590. ArrayExpr: TJSElement; AContext: TConvertContext): TJSElement; virtual;
  1591. // create elements for RTTI
  1592. Function CreateTypeInfoRef(El: TPasType; AContext: TConvertContext;
  1593. ErrorEl: TPasElement): TJSElement; virtual;
  1594. Function CreateRTTIArgList(Parent: TPasElement; Args: TFPList;
  1595. AContext: TConvertContext): TJSElement; virtual;
  1596. Procedure AddRTTIArgument(Arg: TPasArgument; TargetParams: TJSArrayLiteral;
  1597. AContext: TConvertContext); virtual;
  1598. Function CreateRTTINewType(El: TPasType; const CallFuncName: string;
  1599. IsForward: boolean; AContext: TConvertContext; out ObjLit: TJSObjectLiteral): TJSCallExpression; virtual;
  1600. Function CreateRTTIClassField(V: TPasVariable; AContext: TConvertContext): TJSElement; virtual;
  1601. Function CreateRTTIClassMethod(Proc: TPasProcedure; AContext: TConvertContext): TJSElement; virtual;
  1602. Function CreateRTTIClassProperty(Prop: TPasProperty; AContext: TConvertContext): TJSElement; virtual;
  1603. Procedure CreateRTTIAnonymous(El: TPasType; AContext: TConvertContext;
  1604. var First, Last: TJSStatementList); virtual;
  1605. // create elements for interfaces
  1606. Procedure AddIntfDelegations(ClassEl: TPasElement; Prop: TPasProperty;
  1607. FinishedGUIDs: TStringList; ObjLit: TJSObjectLiteral; aContext: TFunctionContext);
  1608. Function CreateGUIDObjLit(aTGUIDRecord: TPasRecordType; const GUID: TGUID;
  1609. PosEl: TPasElement; AContext: TConvertContext): TJSObjectLiteral;
  1610. Function CreateAssignComIntfVar(const LeftResolved: TPasResolverResult;
  1611. var LHS, RHS: TJSElement; AContext: TConvertContext; PosEl: TPasElement): TJSElement; virtual;
  1612. Function IsInterfaceRef(Expr: TJSElement): boolean;
  1613. Function CreateIntfRef(Expr: TJSElement; aContext: TConvertContext;
  1614. PosEl: TPasElement): TJSCallExpression; virtual;
  1615. Function RemoveIntfRef(Call: TJSCallExpression; AContext: TConvertContext): TJSElement;
  1616. Procedure CreateFunctionTryFinally(FuncContext: TFunctionContext);
  1617. Procedure AddFunctionFinallySt(NewEl: TJSElement; PosEl: TPasElement;
  1618. FuncContext: TFunctionContext);
  1619. Procedure AddFunctionFinallyRelease(SubEl: TPasElement; FuncContext: TFunctionContext);
  1620. Procedure AddInFrontOfFunctionTry(NewEl: TJSElement; PosEl: TPasElement;
  1621. FuncContext: TFunctionContext);
  1622. Procedure AddInterfaceReleases(FuncContext: TFunctionContext; PosEl: TPasElement);
  1623. Procedure AddRTLVersionCheck(FuncContext: TFunctionContext; PosEl: TPasElement);
  1624. // Statements
  1625. Function ConvertImplBlockElements(El: TPasImplBlock; AContext: TConvertContext; NilIfEmpty: boolean): TJSElement; virtual;
  1626. Function ConvertBeginEndStatement(El: TPasImplBeginBlock; AContext: TConvertContext; NilIfEmpty: boolean): TJSElement; virtual;
  1627. Function ConvertStatement(El: TPasImplStatement; AContext: TConvertContext ): TJSElement; virtual;
  1628. Function ConvertAssignStatement(El: TPasImplAssign; AContext: TConvertContext): TJSElement; virtual;
  1629. Function ConvertRaiseStatement(El: TPasImplRaise; AContext: TConvertContext ): TJSElement; virtual;
  1630. Function ConvertIfStatement(El: TPasImplIfElse; AContext: TConvertContext ): TJSElement; virtual;
  1631. Function ConvertWhileStatement(El: TPasImplWhileDo; AContext: TConvertContext): TJSElement; virtual;
  1632. Function ConvertRepeatStatement(El: TPasImplRepeatUntil; AContext: TConvertContext): TJSElement; virtual;
  1633. Function ConvertForStatement(El: TPasImplForLoop; AContext: TConvertContext): TJSElement; virtual;
  1634. Function ConvertFinalizationSection(El: TFinalizationSection; AContext: TConvertContext): TJSElement; virtual;
  1635. Function ConvertInitializationSection(El: TInitializationSection; AContext: TConvertContext): TJSElement; virtual;
  1636. Function ConvertSimpleStatement(El: TPasImplSimple; AContext: TConvertContext): TJSElement; virtual;
  1637. Function ConvertWithStatement(El: TPasImplWithDo; AContext: TConvertContext): TJSElement; virtual;
  1638. Function ConvertTryStatement(El: TPasImplTry; AContext: TConvertContext ): TJSElement; virtual;
  1639. Function ConvertExceptOn(El: TPasImplExceptOn; AContext: TConvertContext): TJSElement;
  1640. Function ConvertCaseOfStatement(El: TPasImplCaseOf; AContext: TConvertContext): TJSElement;
  1641. Function ConvertAsmStatement(El: TPasImplAsmStatement; AContext: TConvertContext): TJSElement;
  1642. // Expressions
  1643. Function ConvertConstValue(Value: TResEvalValue; AContext: TConvertContext; El: TPasElement): TJSElement; virtual;
  1644. Function ConvertArrayValues(El: TArrayValues; AContext: TConvertContext): TJSElement; virtual;
  1645. Function ConvertInheritedExpr(El: TInheritedExpr; AContext: TConvertContext): TJSElement; virtual;
  1646. Function ConvertNilExpr(El: TNilExpr; AContext: TConvertContext): TJSElement; virtual;
  1647. Function ConvertParamsExpr(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  1648. Function ConvertArrayParams(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  1649. Function ConvertFuncParams(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  1650. Function ConvertExternalConstructor(Left: TPasElement; Ref: TResolvedReference;
  1651. ParamsExpr: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  1652. Function ConvertTObjectFree_Bin(Bin: TBinaryExpr; NameExpr: TPasExpr; AContext: TConvertContext): TJSElement; virtual;
  1653. Function ConvertTObjectFree_With(NameExpr: TPasExpr; AContext: TConvertContext): TJSElement; virtual;
  1654. Function ConvertTypeCastToBaseType(El: TParamsExpr; AContext: TConvertContext; ToBaseTypeData: TResElDataBaseType): TJSElement; virtual;
  1655. Function ConvertArrayOrSetLiteral(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  1656. Function ConvertBuiltIn_Length(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  1657. Function ConvertBuiltIn_SetLength(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  1658. Function ConvertBuiltIn_ExcludeInclude(El: TParamsExpr; AContext: TConvertContext; IsInclude: boolean): TJSElement; virtual;
  1659. Function ConvertBuiltInContinue(El: TPasExpr; AContext: TConvertContext): TJSElement; virtual;
  1660. Function ConvertBuiltInBreak(El: TPasExpr; AContext: TConvertContext): TJSElement; virtual;
  1661. Function ConvertBuiltIn_Exit(El: TPasExpr; AContext: TConvertContext): TJSElement; virtual;
  1662. Function ConvertBuiltIn_IncDec(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  1663. Function ConvertBuiltIn_Assigned(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  1664. Function ConvertBuiltIn_Chr(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  1665. Function ConvertBuiltIn_Ord(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  1666. Function ConvertBuiltIn_LowHigh(El: TParamsExpr; AContext: TConvertContext; IsLow: boolean): TJSElement; virtual;
  1667. Function ConvertBuiltIn_PredSucc(El: TParamsExpr; AContext: TConvertContext; IsPred: boolean): TJSElement; virtual;
  1668. Function ConvertBuiltIn_StrProc(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  1669. Function ConvertBuiltIn_StrFunc(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  1670. Function ConvertBuiltInStrParam(El: TPasExpr; AContext: TConvertContext; IsStrFunc, IsFirst: boolean): TJSElement; virtual;
  1671. Function ConvertBuiltIn_WriteStr(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  1672. Function ConvertBuiltIn_ConcatArray(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  1673. Function ConvertBuiltIn_CopyArray(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  1674. Function ConvertBuiltIn_InsertArray(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  1675. Function ConvertBuiltIn_DeleteArray(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  1676. Function ConvertBuiltIn_TypeInfo(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  1677. Function ConvertBuiltIn_Assert(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  1678. Function ConvertBuiltIn_New(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  1679. Function ConvertBuiltIn_Dispose(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  1680. Function ConvertBuiltIn_Default(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
  1681. Function ConvertBuiltIn_Debugger(El: TPasExpr; AContext: TConvertContext): TJSElement; virtual;
  1682. Function ConvertRecordValues(El: TRecordValues; AContext: TConvertContext): TJSElement; virtual;
  1683. Function ConvertSelfExpression(El: TSelfExpr; AContext: TConvertContext): TJSElement; virtual;
  1684. Function ConvertBinaryExpression(El: TBinaryExpr; AContext: TConvertContext): TJSElement; virtual;
  1685. Function ConvertBinaryExpressionRes(El: TBinaryExpr; AContext: TConvertContext;
  1686. const LeftResolved, RightResolved: TPasResolverResult; var A,B: TJSElement): TJSElement; virtual;
  1687. Function ConvertSubIdentExpression(El: TBinaryExpr; AContext: TConvertContext): TJSElement; virtual;
  1688. Function ConvertBoolConstExpression(El: TBoolConstExpr; AContext: TConvertContext): TJSElement; virtual;
  1689. Function ConvertPrimitiveExpression(El: TPrimitiveExpr; AContext: TConvertContext): TJSElement; virtual;
  1690. Function ConvertIdentifierExpr(El: TPasExpr; const aName: string; AContext : TConvertContext): TJSElement; virtual;
  1691. Function ConvertUnaryExpression(El: TUnaryExpr; AContext: TConvertContext): TJSElement; virtual;
  1692. // Convert declarations
  1693. Function ConvertElement(El : TPasElement; AContext: TConvertContext) : TJSElement; virtual;
  1694. Function ConvertProperty(El: TPasProperty; AContext: TConvertContext ): TJSElement; virtual;
  1695. Function ConvertConst(El: TPasConst; AContext: TConvertContext): TJSElement; virtual;
  1696. Function ConvertDeclarations(El: TPasDeclarations; AContext: TConvertContext): TJSElement; virtual;
  1697. Function ConvertExportSymbol(El: TPasExportSymbol; AContext: TConvertContext): TJSElement; virtual;
  1698. Function ConvertExpression(El: TPasExpr; AContext: TConvertContext): TJSElement; virtual;
  1699. Function ConvertImplBlock(El: TPasImplBlock; AContext: TConvertContext ): TJSElement; virtual;
  1700. Function ConvertImplCommand(El: TPasImplCommand; AContext: TConvertContext ): TJSElement; virtual;
  1701. Function ConvertLabelMark(El: TPasImplLabelMark; AContext: TConvertContext): TJSElement; virtual;
  1702. Function ConvertLabels(El: TPasLabels; AContext: TConvertContext): TJSElement; virtual;
  1703. Function ConvertModule(El: TPasModule; AContext: TConvertContext): TJSElement; virtual;
  1704. Function ConvertPackage(El: TPasPackage; AContext: TConvertContext): TJSElement; virtual;
  1705. Function ConvertProcedure(El: TPasProcedure; AContext: TConvertContext): TJSElement; virtual;
  1706. Function ConvertResString(El: TPasResString; AContext: TConvertContext): TJSElement; virtual;
  1707. Function ConvertVariable(El: TPasVariable; AContext: TConvertContext): TJSElement; virtual;
  1708. Function ConvertRecordType(El: TPasRecordType; AContext: TConvertContext): TJSElement; virtual;
  1709. Function ConvertClassType(El: TPasClassType; AContext: TConvertContext): TJSElement; virtual;
  1710. Function ConvertClassForwardType(El: TPasClassType; AContext: TConvertContext): TJSElement; virtual;
  1711. Function ConvertClassExternalType(El: TPasClassType; AContext: TConvertContext): TJSElement; virtual;
  1712. Function ConvertClassOfType(El: TPasClassOfType; AContext: TConvertContext): TJSElement; virtual;
  1713. Function ConvertEnumType(El: TPasEnumType; AContext: TConvertContext): TJSElement; virtual;
  1714. Function ConvertSetType(El: TPasSetType; AContext: TConvertContext): TJSElement; virtual;
  1715. Function ConvertRangeType(El: TPasRangeType; AContext: TConvertContext): TJSElement; virtual;
  1716. Function ConvertTypeAliasType(El: TPasTypeAliasType; AContext: TConvertContext): TJSElement; virtual;
  1717. Function ConvertPointerType(El: TPasPointerType; AContext: TConvertContext): TJSElement; virtual;
  1718. Function ConvertProcedureType(El: TPasProcedureType; AContext: TConvertContext): TJSElement; virtual;
  1719. Function ConvertArrayType(El: TPasArrayType; AContext: TConvertContext): TJSElement; virtual;
  1720. Public
  1721. // RTTI, TypeInfo constants
  1722. const
  1723. // TParamFlag
  1724. pfVar = 1;
  1725. pfConst = 2;
  1726. pfOut = 4;
  1727. pfArray = 8;
  1728. // TProcedureFlag
  1729. pfStatic = 1;
  1730. pfVarargs = 2;
  1731. pfExternal = 4;
  1732. // PropertyFlag
  1733. pfGetFunction = 1; // getter is a function
  1734. pfSetProcedure = 2; // setter is a function
  1735. pfStoredTrue = 0; // stored true, always
  1736. pfStoredFalse = 4; // stored false, never
  1737. pfStoredField = 8; // stored field, field name is in Stored
  1738. pfStoredFunction = 12; // stored function, function name is in Stored
  1739. pfHasIndex = 16; { if getter is function, append Index as last param
  1740. if setter is function, append Index as second last param }
  1741. type
  1742. TMethodKind = (
  1743. mkProcedure, // 0 default
  1744. mkFunction, // 1
  1745. mkConstructor, // 2
  1746. mkDestructor, // 3
  1747. mkClassProcedure, // 4
  1748. mkClassFunction // 5
  1749. );
  1750. TOrdType = (
  1751. otSByte, // 0
  1752. otUByte, // 1
  1753. otSWord, // 2
  1754. otUWord, // 3
  1755. otSLong, // 4
  1756. otULong, // 5
  1757. otSIntDouble, // 6 NativeInt
  1758. otUIntDouble // 7 NativeUInt
  1759. );
  1760. Function GetOrdType(MinValue, MaxValue: TMaxPrecInt; ErrorEl: TPasElement): TOrdType; virtual;
  1761. Public
  1762. Constructor Create;
  1763. destructor Destroy; override;
  1764. Function ConvertPasElement(El: TPasElement; Resolver: TPas2JSResolver) : TJSElement;
  1765. // options
  1766. Property Options: TPasToJsConverterOptions read FOptions write FOptions default DefaultPasToJSOptions;
  1767. Property RTLVersion: TJSNumber read FRTLVersion write FRTLVersion;
  1768. Property TargetPlatform: TPasToJsPlatform read FTargetPlatform write FTargetPlatform;
  1769. Property TargetProcessor: TPasToJsProcessor read FTargetProcessor write FTargetProcessor;
  1770. Property UseLowerCase: boolean read GetUseLowerCase write SetUseLowerCase default true;
  1771. Property UseSwitchStatement: boolean read GetUseSwitchStatement write SetUseSwitchStatement;// default false, because slower than "if" in many engines
  1772. Property UseEnumNumbers: boolean read GetUseEnumNumbers write SetUseEnumNumbers; // default false
  1773. Property OnIsElementUsed: TPas2JSIsElementUsedEvent read FOnIsElementUsed write FOnIsElementUsed;
  1774. Property OnIsTypeInfoUsed: TPas2JSIsElementUsedEvent read FOnIsTypeInfoUsed write FOnIsTypeInfoUsed;
  1775. Property ReservedWords: TJSReservedWordList read FReservedWords write SetReservedWords;
  1776. // names
  1777. Property BuildInNames[bin: TPas2JSBuiltInName]: string read GetBuildInNames write SetBuildInNames;
  1778. end;
  1779. var
  1780. JSTypeCaptions: array[TJSType] of string = (
  1781. 'undefined',
  1782. 'null',
  1783. 'boolean',
  1784. 'number',
  1785. 'string',
  1786. 'object',
  1787. 'reference',
  1788. 'completion'
  1789. );
  1790. function CodePointToJSString(u: longword): TJSString;
  1791. function PosLast(c: char; const s: string): integer;
  1792. function JSEquals(A, B: TJSElement): boolean;
  1793. function dbgs(opts: TPasToJsConverterOptions): string; overload;
  1794. implementation
  1795. const
  1796. TempRefObjGetterName = 'get';
  1797. TempRefObjSetterName = 'set';
  1798. TempRefObjSetterArgName = 'v';
  1799. IdentChars = ['0'..'9', 'A'..'Z', 'a'..'z','_'];
  1800. function CodePointToJSString(u: longword): TJSString;
  1801. begin
  1802. if u < $10000 then
  1803. // Note: codepoints $D800 - $DFFF are reserved
  1804. Result:=WideChar(u)
  1805. else
  1806. Result:=WideChar($D800+((u - $10000) shr 10))+WideChar($DC00+((u - $10000) and $3ff));
  1807. end;
  1808. function PosLast(c: char; const s: string): integer;
  1809. begin
  1810. Result:=length(s);
  1811. while (Result>0) and (s[Result]<>c) do dec(Result);
  1812. end;
  1813. function JSEquals(A, B: TJSElement): boolean;
  1814. begin
  1815. if A=nil then
  1816. exit(B=nil)
  1817. else if B=nil then
  1818. exit(false)
  1819. else if A.ClassType<>B.ClassType then
  1820. exit(false);
  1821. if A.ClassType=TJSPrimaryExpressionIdent then
  1822. exit(TJSPrimaryExpressionIdent(A).Name=TJSPrimaryExpressionIdent(B).Name)
  1823. else if A.ClassType=TJSPrimaryExpressionThis then
  1824. else if A.ClassType=TJSDotMemberExpression then
  1825. Result:=JSEquals(TJSDotMemberExpression(A).MExpr,TJSDotMemberExpression(B).MExpr)
  1826. and (TJSDotMemberExpression(A).Name=TJSDotMemberExpression(B).Name)
  1827. else if A.ClassType=TJSBracketMemberExpression then
  1828. Result:=JSEquals(TJSBracketMemberExpression(A).MExpr,TJSBracketMemberExpression(B).MExpr)
  1829. and (TJSBracketMemberExpression(A).Name=TJSBracketMemberExpression(B).Name)
  1830. else
  1831. exit(false);
  1832. end;
  1833. function dbgs(opts: TPasToJsConverterOptions): string;
  1834. var
  1835. o: TPasToJsConverterOption;
  1836. h: string;
  1837. begin
  1838. Result:='';
  1839. for o in opts do
  1840. begin
  1841. if Result<>'' then Result:=Result+',';
  1842. str(o,h);
  1843. Result:=Result+h;
  1844. end;
  1845. Result:='['+Result+']';
  1846. end;
  1847. { TPas2JSSectionScope }
  1848. procedure TPas2JSSectionScope.InternalAddElevatedLocal(Item: TPasIdentifier);
  1849. var
  1850. {$IFDEF fpc}
  1851. Index: Integer;
  1852. {$ENDIF}
  1853. OldItem: TPasIdentifier;
  1854. LoName: string;
  1855. begin
  1856. LoName:=lowercase(Item.Identifier);
  1857. {$IFDEF VerbosePasResolver}
  1858. if Item.Owner<>nil then
  1859. raise Exception.Create('20160925184110');
  1860. Item.Owner:=Self;
  1861. {$ENDIF}
  1862. {$IFDEF pas2js}
  1863. OldItem:=TPasIdentifier(FElevatedLocals.Find(LoName));
  1864. if OldItem<>nil then
  1865. begin
  1866. // insert LIFO - last in, first out
  1867. {$IFDEF VerbosePasResolver}
  1868. if lowercase(OldItem.Identifier)<>LoName then
  1869. raise Exception.Create('20181025113922');
  1870. {$ENDIF}
  1871. Item.NextSameIdentifier:=OldItem;
  1872. FElevatedLocals.Remove(LoName);
  1873. end;
  1874. FElevatedLocals.Add(LoName, Item);
  1875. {$ELSE}
  1876. Index:=FElevatedLocals.FindIndexOf(LoName);
  1877. //writeln(' Index=',Index);
  1878. if Index>=0 then
  1879. begin
  1880. // insert LIFO - last in, first out
  1881. OldItem:=TPasIdentifier(FElevatedLocals.List^[Index].Data);
  1882. {$IFDEF VerbosePasResolver}
  1883. if lowercase(OldItem.Identifier)<>LoName then
  1884. raise Exception.Create('20160925183438');
  1885. {$ENDIF}
  1886. Item.NextSameIdentifier:=OldItem;
  1887. FElevatedLocals.List^[Index].Data:=Item;
  1888. end
  1889. else
  1890. begin
  1891. FElevatedLocals.Add(LoName, Item);
  1892. end;
  1893. {$ENDIF}
  1894. {$IFDEF VerbosePasResolver}
  1895. if FindElevatedLocal(Item.Identifier)<>Item then
  1896. raise Exception.Create('20160925183849');
  1897. {$ENDIF}
  1898. end;
  1899. procedure TPas2JSSectionScope.OnClearElevatedLocal(Item, Dummy: pointer);
  1900. var
  1901. PasIdentifier: TPasIdentifier absolute Item;
  1902. Ident: TPasIdentifier;
  1903. begin
  1904. if Dummy=nil then ;
  1905. //writeln('TPasIdentifierScope.OnClearItem ',PasIdentifier.Identifier+':'+PasIdentifier.ClassName);
  1906. while PasIdentifier<>nil do
  1907. begin
  1908. Ident:=PasIdentifier;
  1909. PasIdentifier:=PasIdentifier.NextSameIdentifier;
  1910. Ident.Free;
  1911. end;
  1912. end;
  1913. constructor TPas2JSSectionScope.Create;
  1914. begin
  1915. inherited Create;
  1916. FElevatedLocals:=TPasResHashList.Create;
  1917. end;
  1918. destructor TPas2JSSectionScope.Destroy;
  1919. begin
  1920. FElevatedLocals.ForEachCall(@OnClearElevatedLocal,nil);
  1921. {$IFDEF pas2js}
  1922. FElevatedLocals:=nil;
  1923. {$ELSE}
  1924. FreeAndNil(FElevatedLocals);
  1925. {$ENDIF}
  1926. inherited Destroy;
  1927. end;
  1928. // inline
  1929. function TPas2JSSectionScope.FindElevatedLocal(const Identifier: String
  1930. ): TPasIdentifier;
  1931. begin
  1932. Result:=TPasIdentifier(FElevatedLocals.Find(lowercase(Identifier)));
  1933. end;
  1934. function TPas2JSSectionScope.AddElevatedLocal(const Identifier: String;
  1935. El: TPasElement): TPasIdentifier;
  1936. var
  1937. Item: TPasIdentifier;
  1938. begin
  1939. //writeln('TPasIdentifierScope.AddIdentifier Identifier="',Identifier,'" El=',GetObjName(El));
  1940. Item:=TPasIdentifier.Create;
  1941. Item.Identifier:=Identifier;
  1942. Item.Element:=El;
  1943. InternalAddElevatedLocal(Item);
  1944. //writeln('TPasIdentifierScope.AddIdentifier END');
  1945. Result:=Item;
  1946. end;
  1947. procedure TPas2JSSectionScope.WriteElevatedLocals(Prefix: string);
  1948. begin
  1949. Prefix:=Prefix+' ';
  1950. FElevatedLocals.ForEachCall(@OnWriteItem,Pointer(Prefix));
  1951. end;
  1952. { TPas2JSProcedureScope }
  1953. procedure TPas2JSProcedureScope.AddGlobalJS(const JS: string);
  1954. begin
  1955. if GlobalJS=nil then
  1956. GlobalJS:=TStringList.Create;
  1957. GlobalJS.Add(Js);
  1958. end;
  1959. destructor TPas2JSProcedureScope.Destroy;
  1960. begin
  1961. FreeAndNil(GlobalJS);
  1962. inherited Destroy;
  1963. end;
  1964. { TFCLocalIdentifier }
  1965. constructor TFCLocalIdentifier.Create(const aName: string; TheEl: TPasElement);
  1966. begin
  1967. Name:=aName;
  1968. Element:=TheEl;
  1969. end;
  1970. { TPas2jsPasScanner }
  1971. function TPas2jsPasScanner.HandleInclude(const Param: String): TToken;
  1972. procedure SetStr(s: string);
  1973. var
  1974. i: Integer;
  1975. h: String;
  1976. begin
  1977. Result:=tkString;
  1978. if s='' then
  1979. s:=''''''
  1980. else
  1981. for i:=length(s) downto 1 do
  1982. case s[i] of
  1983. #0..#31,#127:
  1984. begin
  1985. h:='#'+IntToStr(ord(s[i]));
  1986. if i>1 then h:=''''+h;
  1987. if (i<length(s)) and (s[i+1]<>'#') then
  1988. h:=h+'''';
  1989. s:=LeftStr(s,i-1)+h+copy(s,i+1,length(s));
  1990. end;
  1991. else
  1992. if i=length(s) then
  1993. s:=s+'''';
  1994. if s[i]='''' then
  1995. Insert('''',s,i);
  1996. if i=1 then
  1997. s:=''''+s;
  1998. end;
  1999. SetCurTokenString(s);
  2000. end;
  2001. procedure SetInteger(const i: TMaxPrecInt);
  2002. begin
  2003. Result:=tkNumber;
  2004. SetCurTokenString(IntToStr(i));
  2005. end;
  2006. var
  2007. Year, Month, Day, Hour, Minute, Second, MilliSecond: word;
  2008. i: Integer;
  2009. Scope: TPasScope;
  2010. begin
  2011. if (Param<>'') and (Param[1]='%') then
  2012. begin
  2013. if (length(Param)<3) or (Param[length(Param)]<>'%') then
  2014. begin
  2015. SetStr('');
  2016. DoLog(mtWarning,nWarnIllegalCompilerDirectiveX,SWarnIllegalCompilerDirectiveX,
  2017. ['$i '+Param]);
  2018. exit;
  2019. end;
  2020. if length(Param)>255 then
  2021. begin
  2022. SetStr('');
  2023. DoLog(mtWarning,nWarnIllegalCompilerDirectiveX,SWarnIllegalCompilerDirectiveX,
  2024. ['$i '+copy(Param,1,255)+'...']);
  2025. exit;
  2026. end;
  2027. case lowercase(Param) of
  2028. '%date%':
  2029. begin
  2030. // 'Y/M/D'
  2031. DecodeDate(Now,Year,Month,Day);
  2032. SetStr(IntToStr(Year)+'/'+IntToStr(Month)+'/'+IntToStr(Day));
  2033. exit;
  2034. end;
  2035. '%time%':
  2036. begin
  2037. // 'hh:mm:ss'
  2038. DecodeTime(Now,Hour,Minute,Second,MilliSecond);
  2039. SetStr(Format('%2d:%2d:%2d',[Hour,Minute,Second]));
  2040. exit;
  2041. end;
  2042. '%pas2jstarget%','%fpctarget%',
  2043. '%pas2jstargetos%','%fpctargetos%':
  2044. begin
  2045. SetStr(PasToJsPlatformNames[TargetPlatform]);
  2046. exit;
  2047. end;
  2048. '%pas2jstargetcpu%','%fpctargetcpu%':
  2049. begin
  2050. SetStr(PasToJsProcessorNames[TargetProcessor]);
  2051. exit;
  2052. end;
  2053. '%pas2jsversion%','%fpcversion%':
  2054. begin
  2055. SetStr(CompilerVersion);
  2056. exit;
  2057. end;
  2058. '%file%':
  2059. begin
  2060. SetStr(CurFilename);
  2061. exit;
  2062. end;
  2063. '%line%':
  2064. begin
  2065. SetStr(IntToStr(CurRow));
  2066. exit;
  2067. end;
  2068. '%linenum%':
  2069. begin
  2070. SetInteger(CurRow);
  2071. exit;
  2072. end;
  2073. '%currentroutine%':
  2074. begin
  2075. if Resolver<>nil then
  2076. for i:=Resolver.ScopeCount-1 downto 0 do
  2077. begin
  2078. Scope:=Resolver.Scopes[i];
  2079. if (Scope.Element is TPasProcedure)
  2080. and (Scope.Element.Name<>'') then
  2081. begin
  2082. SetStr(Scope.Element.Name);
  2083. exit;
  2084. end;
  2085. end;
  2086. SetStr('<anonymous>');
  2087. exit;
  2088. end;
  2089. else
  2090. SetStr(GetEnvironmentVariable(copy(Param,2,length(Param)-2)));
  2091. exit;
  2092. end;
  2093. end;
  2094. Result:=inherited HandleInclude(Param);
  2095. end;
  2096. function TPas2jsPasScanner.ReadNonPascalTillEndToken(StopAtLineEnd: boolean
  2097. ): TToken;
  2098. var
  2099. StartPos, MyTokenPos: integer;
  2100. s: string;
  2101. l: integer;
  2102. Procedure CommitTokenPos;
  2103. begin
  2104. {$IFDEF Pas2js}
  2105. TokenPos:=MyTokenPos;
  2106. {$ELSE}
  2107. TokenPos:=PChar(s)+MyTokenPos-1;
  2108. {$ENDIF}
  2109. end;
  2110. Procedure Add;
  2111. var
  2112. AddLen: PtrInt;
  2113. begin
  2114. AddLen:=MyTokenPos-StartPos;
  2115. if AddLen=0 then
  2116. SetCurTokenString('')
  2117. else
  2118. begin
  2119. SetCurTokenString(CurTokenString+copy(CurLine,StartPos,AddLen));
  2120. StartPos:=MyTokenPos;
  2121. end;
  2122. end;
  2123. function DoEndOfLine: boolean;
  2124. begin
  2125. Add;
  2126. if StopAtLineEnd then
  2127. begin
  2128. ReadNonPascalTillEndToken := tkLineEnding;
  2129. CommitTokenPos;
  2130. SetCurToken(tkLineEnding);
  2131. FetchLine;
  2132. exit(true);
  2133. end;
  2134. if not FetchLine then
  2135. begin
  2136. ReadNonPascalTillEndToken := tkEOF;
  2137. SetCurToken(tkEOF);
  2138. exit(true);
  2139. end;
  2140. s:=CurLine;
  2141. l:=length(s);
  2142. MyTokenPos:=1;
  2143. StartPos:=MyTokenPos;
  2144. Result:=false;
  2145. end;
  2146. begin
  2147. SetCurTokenString('');
  2148. s:=CurLine;
  2149. l:=length(s);
  2150. {$IFDEF Pas2js}
  2151. MyTokenPos:=TokenPos;
  2152. {$ELSE}
  2153. {$IFDEF VerbosePas2JS}
  2154. if (TokenPos<PChar(s)) or (TokenPos>PChar(s)+length(s)) then
  2155. Error(nErrRangeCheck,'[20181109104812]');
  2156. {$ENDIF}
  2157. MyTokenPos:=TokenPos-PChar(s)+1;
  2158. {$ENDIF}
  2159. StartPos:=MyTokenPos;
  2160. repeat
  2161. if MyTokenPos>l then
  2162. if DoEndOfLine then exit;
  2163. case s[MyTokenPos] of
  2164. '''':
  2165. begin
  2166. inc(MyTokenPos);
  2167. repeat
  2168. if MyTokenPos>l then
  2169. Error(nErrOpenString,SErrOpenString);
  2170. case s[MyTokenPos] of
  2171. '''':
  2172. begin
  2173. inc(MyTokenPos);
  2174. break;
  2175. end;
  2176. #10,#13:
  2177. begin
  2178. // string literal missing closing apostroph
  2179. break;
  2180. end
  2181. else
  2182. inc(MyTokenPos);
  2183. end;
  2184. until false;
  2185. end;
  2186. '"':
  2187. begin
  2188. inc(MyTokenPos);
  2189. repeat
  2190. if MyTokenPos>l then
  2191. Error(nErrOpenString,SErrOpenString);
  2192. case s[MyTokenPos] of
  2193. '"':
  2194. begin
  2195. inc(MyTokenPos);
  2196. break;
  2197. end;
  2198. #10,#13:
  2199. begin
  2200. // string literal missing closing quote
  2201. break;
  2202. end
  2203. else
  2204. inc(MyTokenPos);
  2205. end;
  2206. until false;
  2207. end;
  2208. '/':
  2209. begin
  2210. inc(MyTokenPos);
  2211. if (MyTokenPos<=l) and (s[MyTokenPos]='/') then
  2212. begin
  2213. // skip Delphi comment //, see Note above
  2214. repeat
  2215. inc(MyTokenPos);
  2216. until (MyTokenPos>l) or (s[MyTokenPos] in [#10,#13]);
  2217. end;
  2218. end;
  2219. '0'..'9', 'A'..'Z', 'a'..'z','_':
  2220. begin
  2221. // number or identifier
  2222. if (CompareText(copy(s,MyTokenPos,3),'end')=0)
  2223. and ((MyTokenPos+3>l) or not (s[MyTokenPos+3] in IdentChars)) then
  2224. begin
  2225. // 'end' found
  2226. Add;
  2227. if CurTokenString<>'' then
  2228. begin
  2229. // return characters in front of 'end'
  2230. Result:=tkWhitespace;
  2231. CommitTokenPos;
  2232. SetCurToken(Result);
  2233. exit;
  2234. end;
  2235. // return 'end'
  2236. Result := tkend;
  2237. SetCurTokenString(copy(s,MyTokenPos,3));
  2238. inc(MyTokenPos,3);
  2239. CommitTokenPos;
  2240. SetCurToken(Result);
  2241. exit;
  2242. end
  2243. else
  2244. begin
  2245. // skip identifier
  2246. while (MyTokenPos<=l) and (s[MyTokenPos] in IdentChars) do
  2247. inc(MyTokenPos);
  2248. end;
  2249. end;
  2250. else
  2251. inc(MyTokenPos);
  2252. end;
  2253. until false;
  2254. end;
  2255. { TPas2JSResolver }
  2256. // inline
  2257. function TPas2JSResolver.GetJSBaseTypes(aBaseType: TPas2jsBaseType
  2258. ): TPasUnresolvedSymbolRef;
  2259. begin
  2260. Result:=TPasUnresolvedSymbolRef(FJSBaseTypes[aBaseType]);
  2261. end;
  2262. procedure TPas2JSResolver.InternalAdd(Item: TPasIdentifier);
  2263. var
  2264. {$IFDEF fpc}
  2265. Index: Integer;
  2266. {$ENDIF}
  2267. OldItem: TPasIdentifier;
  2268. aName: String;
  2269. begin
  2270. aName:=Item.Identifier;
  2271. {$IFDEF VerbosePasResolver}
  2272. if Item.Owner<>nil then
  2273. raise Exception.Create('20170322235419');
  2274. Item.Owner:=Self;
  2275. {$ENDIF}
  2276. {$IFDEF pas2js}
  2277. OldItem:=TPasIdentifier(FExternalNames.Find(aName));
  2278. if OldItem<>nil then
  2279. begin
  2280. // insert LIFO - last in, first out
  2281. {$IFDEF VerbosePasResolver}
  2282. if OldItem.Identifier<>aName then
  2283. raise Exception.Create('20181025114714');
  2284. {$ENDIF}
  2285. Item.NextSameIdentifier:=OldItem;
  2286. FExternalNames.Remove(aName);
  2287. end;
  2288. FExternalNames.Add(aName,Item);
  2289. {$ELSE}
  2290. Index:=FExternalNames.FindIndexOf(aName);
  2291. //writeln(' Index=',Index);
  2292. if Index>=0 then
  2293. begin
  2294. // insert LIFO - last in, first out
  2295. OldItem:=TPasIdentifier(FExternalNames.List^[Index].Data);
  2296. {$IFDEF VerbosePasResolver}
  2297. if OldItem.Identifier<>aName then
  2298. raise Exception.Create('20170322235429');
  2299. {$ENDIF}
  2300. Item.NextSameIdentifier:=OldItem;
  2301. FExternalNames.List^[Index].Data:=Item;
  2302. end
  2303. else
  2304. FExternalNames.Add(aName, Item);
  2305. {$ENDIF}
  2306. {$IFDEF VerbosePasResolver}
  2307. if FindExternalName(Item.Identifier)<>Item then
  2308. raise Exception.Create('20170322235433');
  2309. {$ENDIF}
  2310. end;
  2311. procedure TPas2JSResolver.OnClearHashItem(Item, Dummy: pointer);
  2312. var
  2313. PasIdentifier: TPasIdentifier absolute Item;
  2314. Ident: TPasIdentifier;
  2315. begin
  2316. if Dummy=nil then ;
  2317. //writeln('TPas2JSResolver.OnClearItem ',PasIdentifier.Identifier+':'+PasIdentifier.ClassName);
  2318. while PasIdentifier<>nil do
  2319. begin
  2320. Ident:=PasIdentifier;
  2321. PasIdentifier:=PasIdentifier.NextSameIdentifier;
  2322. Ident.Free;
  2323. end;
  2324. end;
  2325. function TPas2JSResolver.HasOverloadIndex(El: TPasElement;
  2326. WithElevatedLocal: boolean): boolean;
  2327. var
  2328. C: TClass;
  2329. ProcScope: TPasProcedureScope;
  2330. begin
  2331. C:=El.ClassType;
  2332. if C=TPasProperty then
  2333. exit(false)
  2334. else if C=TPasConst then
  2335. begin
  2336. if (not WithElevatedLocal) and (El.Parent is TProcedureBody) then
  2337. exit(false); // local const counted via TPas2JSSectionScope.FElevatedLocals
  2338. end
  2339. else if C=TPasClassType then
  2340. begin
  2341. if TPasClassType(El).IsForward then
  2342. exit(false);
  2343. end
  2344. else if C.InheritsFrom(TPasProcedure) then
  2345. begin
  2346. if TPasProcedure(El).IsOverride then
  2347. exit(true);
  2348. // Note: external proc pollutes the name space
  2349. ProcScope:=TPasProcedureScope(El.CustomData);
  2350. if ProcScope.DeclarationProc<>nil then
  2351. // implementation proc -> only count the header -> skip
  2352. exit(false);
  2353. end;
  2354. Result:=true;
  2355. end;
  2356. function TPas2JSResolver.GetOverloadIndex(Identifier: TPasIdentifier;
  2357. StopAt: TPasElement): integer;
  2358. // if not found return number of overloads
  2359. // if found return index in overloads
  2360. var
  2361. El: TPasElement;
  2362. begin
  2363. Result:=0;
  2364. // iterate from last added to first added
  2365. // Note: the first added has Index=0
  2366. while Identifier<>nil do
  2367. begin
  2368. El:=Identifier.Element;
  2369. Identifier:=Identifier.NextSameIdentifier;
  2370. if El=StopAt then
  2371. Result:=0
  2372. else if HasOverloadIndex(El) then
  2373. inc(Result);
  2374. end;
  2375. end;
  2376. function TPas2JSResolver.GetOverloadAt(Identifier: TPasIdentifier;
  2377. var Index: integer): TPasIdentifier;
  2378. // if found Result<>nil and Index=0
  2379. // if not found Result=nil and Index is reduced by number of overloads
  2380. var
  2381. El: TPasElement;
  2382. CurIdent: TPasIdentifier;
  2383. Count: Integer;
  2384. begin
  2385. if Identifier=nil then exit(nil);
  2386. // Note: the Identifier chain is from last added to first added
  2387. // -> get length of chain
  2388. Count:=0;
  2389. CurIdent:=Identifier;
  2390. while CurIdent<>nil do
  2391. begin
  2392. El:=CurIdent.Element;
  2393. CurIdent:=CurIdent.NextSameIdentifier;
  2394. if HasOverloadIndex(El) then
  2395. inc(Count);
  2396. end;
  2397. if Count<=Index then
  2398. begin
  2399. // Index is not in this scope
  2400. dec(Index);
  2401. exit(nil);
  2402. end;
  2403. // Index is in this scope -> find it
  2404. CurIdent:=Identifier;
  2405. while CurIdent<>nil do
  2406. begin
  2407. if HasOverloadIndex(CurIdent.Element) then
  2408. begin
  2409. dec(Count);
  2410. if (Index=Count) then
  2411. begin
  2412. Index:=0;
  2413. Result:=CurIdent;
  2414. exit;
  2415. end;
  2416. end;
  2417. CurIdent:=CurIdent.NextSameIdentifier;
  2418. end;
  2419. end;
  2420. function TPas2JSResolver.GetOverloadIndex(El: TPasElement): integer;
  2421. var
  2422. i, j: Integer;
  2423. Identifier: TPasIdentifier;
  2424. Scope: TPasIdentifierScope;
  2425. CurEl: TPasElement;
  2426. begin
  2427. Result:=0;
  2428. if not HasOverloadIndex(El,true) then exit;
  2429. for i:=FOverloadScopes.Count-1 downto 0 do
  2430. begin
  2431. Scope:=TPasIdentifierScope(FOverloadScopes[i]);
  2432. if (Scope.ClassType=TPas2JSSectionScope) and (i<FOverloadScopes.Count-1) then
  2433. begin
  2434. // Note: the elevated locals are after the section scope and before the next deeper scope
  2435. // check elevated locals
  2436. Identifier:=TPas2JSSectionScope(Scope).FindElevatedLocal(El.Name);
  2437. j:=0;
  2438. // add count or index
  2439. while Identifier<>nil do
  2440. begin
  2441. CurEl:=Identifier.Element;
  2442. Identifier:=Identifier.NextSameIdentifier;
  2443. if CurEl=El then
  2444. j:=0
  2445. else
  2446. inc(j);
  2447. end;
  2448. inc(Result,j);
  2449. end;
  2450. // find last added
  2451. Identifier:=Scope.FindLocalIdentifier(El.Name);
  2452. // add count or index
  2453. inc(Result,GetOverloadIndex(Identifier,El));
  2454. end;
  2455. // find in external names
  2456. Identifier:=FindExternalName(El.Name);
  2457. // add count or index
  2458. inc(Result,GetOverloadIndex(Identifier,El));
  2459. end;
  2460. function TPas2JSResolver.GetOverloadAt(const aName: String; Index: integer
  2461. ): TPasIdentifier;
  2462. var
  2463. i: Integer;
  2464. Scope: TPasIdentifierScope;
  2465. begin
  2466. Result:=nil;
  2467. for i:=FOverloadScopes.Count-1 downto 0 do
  2468. begin
  2469. // find last added
  2470. Scope:=TPasIdentifierScope(FOverloadScopes[i]);
  2471. if (Scope.ClassType=TPas2JSSectionScope) and (i<FOverloadScopes.Count-1) then
  2472. begin
  2473. // Note: the elevated locals are after the section scope and before the next deeper scope
  2474. // check elevated locals
  2475. Result:=TPas2JSSectionScope(Scope).FindElevatedLocal(aName);
  2476. Result:=GetOverloadAt(Result,Index);
  2477. if Result<>nil then
  2478. exit;
  2479. end;
  2480. Result:=Scope.FindLocalIdentifier(aName);
  2481. Result:=GetOverloadAt(Result,Index);
  2482. if Result<>nil then
  2483. exit;
  2484. end;
  2485. // find in external names
  2486. Result:=FindExternalName(aName);
  2487. Result:=GetOverloadAt(Result,Index);
  2488. end;
  2489. function TPas2JSResolver.RenameOverload(El: TPasElement): boolean;
  2490. var
  2491. OverloadIndex: Integer;
  2492. function GetDuplicate: TPasElement;
  2493. var
  2494. Duplicate: TPasIdentifier;
  2495. begin
  2496. Duplicate:=GetOverloadAt(El.Name,0);
  2497. Result:=Duplicate.Element;
  2498. end;
  2499. var
  2500. NewName: String;
  2501. Duplicate: TPasElement;
  2502. ProcScope: TPas2JSProcedureScope;
  2503. begin
  2504. // => count overloads in this section
  2505. OverloadIndex:=GetOverloadIndex(El);
  2506. if OverloadIndex=0 then
  2507. exit(false); // there is no overload
  2508. if (El.ClassType=TPasClassFunction)
  2509. and (TPas2JSClassScope(TPasClassType(El.Parent).CustomData).NewInstanceFunction=El) then
  2510. begin
  2511. Duplicate:=GetDuplicate;
  2512. RaiseMsg(20170324234324,nNewInstanceFunctionMustNotHaveOverloadAtX,
  2513. sNewInstanceFunctionMustNotHaveOverloadAtX,[GetElementSourcePosStr(Duplicate)],El);
  2514. end;
  2515. if El.Visibility=visPublished then
  2516. begin
  2517. Duplicate:=GetDuplicate;
  2518. RaiseMsg(20170413220924,nDuplicateIdentifier,sDuplicateIdentifier,
  2519. [Duplicate.Name,GetElementSourcePosStr(Duplicate)],El);
  2520. end;
  2521. NewName:=El.Name+'$'+IntToStr(OverloadIndex);
  2522. {$IFDEF VerbosePas2JS}
  2523. writeln('TPas2JSResolver.RenameOverload "',El.Name,'" has overload. NewName="',NewName,'"');
  2524. {$ENDIF}
  2525. if (El.CustomData is TPas2JSProcedureScope) then
  2526. begin
  2527. ProcScope:=TPas2JSProcedureScope(El.CustomData);
  2528. ProcScope.OverloadName:=NewName;
  2529. if ProcScope.DeclarationProc<>nil then
  2530. RaiseInternalError(20180322233222,GetElementDbgPath(El));
  2531. if ProcScope.ImplProc<>nil then
  2532. TPas2JSProcedureScope(ProcScope.ImplProc.CustomData).OverloadName:=NewName;
  2533. end
  2534. else
  2535. El.Name:=NewName;
  2536. Result:=true;
  2537. end;
  2538. procedure TPas2JSResolver.RenameOverloadsInSection(aSection: TPasSection);
  2539. var
  2540. IntfSection: TInterfaceSection;
  2541. begin
  2542. if aSection=nil then exit;
  2543. IntfSection:=nil;
  2544. if aSection.ClassType=TImplementationSection then
  2545. begin
  2546. IntfSection:=RootElement.InterfaceSection;
  2547. PushOverloadScope(IntfSection.CustomData as TPasIdentifierScope);
  2548. end;
  2549. PushOverloadScope(aSection.CustomData as TPasIdentifierScope);
  2550. RenameOverloads(aSection,aSection.Declarations);
  2551. RenameSubOverloads(aSection.Declarations);
  2552. PopOverloadScope;
  2553. if IntfSection<>nil then
  2554. PopOverloadScope;
  2555. {$IFDEF VerbosePas2JS}
  2556. //writeln('TPas2JSResolver.RenameOverloadsInSection END ',GetObjName(aSection));
  2557. {$ENDIF}
  2558. end;
  2559. procedure TPas2JSResolver.RenameOverloads(DeclEl: TPasElement;
  2560. Declarations: TFPList);
  2561. var
  2562. i: Integer;
  2563. El: TPasElement;
  2564. Proc: TPasProcedure;
  2565. ProcScope, OvrProcScope, ImplProcScope: TPas2JSProcedureScope;
  2566. begin
  2567. //IsExternalClass:=(DeclEl is TPasClassType) and (TPasClassType(DeclEl).IsExternal);
  2568. if DeclEl=nil then;
  2569. for i:=0 to Declarations.Count-1 do
  2570. begin
  2571. El:=TPasElement(Declarations[i]);
  2572. if (El is TPasProcedure) then
  2573. begin
  2574. Proc:=TPasProcedure(El);
  2575. ProcScope:=Proc.CustomData as TPas2JSProcedureScope;
  2576. //writeln('TPas2JSResolver.RenameOverloads Proc=',Proc.Name,' DeclarationProc=',GetObjName(ProcScope.DeclarationProc),' ImplProc=',GetObjName(ProcScope.ImplProc),' ClassScope=',GetObjName(ProcScope.ClassScope));
  2577. if ProcScope.DeclarationProc<>nil then
  2578. continue
  2579. else if Proc.IsOverride then
  2580. begin
  2581. // override -> copy name from overridden proc
  2582. if ProcScope.OverriddenProc=nil then
  2583. RaiseInternalError(20171205183502);
  2584. OvrProcScope:=TPas2JSProcedureScope(ProcScope.OverriddenProc.CustomData);
  2585. if OvrProcScope.OverloadName<>'' then
  2586. begin
  2587. ProcScope.OverloadName:=OvrProcScope.OverloadName;
  2588. if ProcScope.ImplProc<>nil then
  2589. begin
  2590. ImplProcScope:=TPas2JSProcedureScope(ProcScope.ImplProc.CustomData);
  2591. ImplProcScope.OverloadName:=ProcScope.OverloadName;
  2592. end;
  2593. end;
  2594. continue;
  2595. end
  2596. else if Proc.IsExternal then
  2597. begin
  2598. // Note: Pascal names of external procs are not in the generated JS,
  2599. // so no need to rename them
  2600. continue;
  2601. end;
  2602. // proc declaration (header, not body)
  2603. RenameOverload(Proc);
  2604. end;
  2605. end;
  2606. {$IFDEF VerbosePas2JS}
  2607. //writeln('TPas2JSResolver.RenameOverloads END ',GetObjName(DeclEl));
  2608. {$ENDIF}
  2609. end;
  2610. procedure TPas2JSResolver.RenameSubOverloads(Declarations: TFPList);
  2611. var
  2612. i, OldScopeCount: Integer;
  2613. El: TPasElement;
  2614. Proc: TPasProcedure;
  2615. ProcScope: TPasProcedureScope;
  2616. ClassScope, aScope: TPasClassScope;
  2617. ClassEl: TPasClassType;
  2618. C: TClass;
  2619. begin
  2620. for i:=0 to Declarations.Count-1 do
  2621. begin
  2622. El:=TPasElement(Declarations[i]);
  2623. C:=El.ClassType;
  2624. if C.InheritsFrom(TPasProcedure) then
  2625. begin
  2626. Proc:=TPasProcedure(El);
  2627. ProcScope:=Proc.CustomData as TPasProcedureScope;
  2628. {$IFDEF VerbosePas2JS}
  2629. writeln('TPas2JSResolver.RenameSubOverloads Proc=',Proc.Name,' DeclarationProc=',GetObjName(ProcScope.DeclarationProc),' ImplProc=',GetObjName(ProcScope.ImplProc),' ClassScope=',GetObjName(ProcScope.ClassScope));
  2630. {$ENDIF}
  2631. if Proc.Body<>nil then
  2632. begin
  2633. PushOverloadScope(ProcScope);
  2634. // first rename all overloads on this level
  2635. RenameOverloads(Proc.Body,Proc.Body.Declarations);
  2636. // then process nested procedures
  2637. RenameSubOverloads(Proc.Body.Declarations);
  2638. PopOverloadScope;
  2639. end;
  2640. end
  2641. else if C=TPasClassType then
  2642. begin
  2643. ClassEl:=TPasClassType(El);
  2644. if ClassEl.IsForward then continue;
  2645. ClassScope:=El.CustomData as TPas2JSClassScope;
  2646. OldScopeCount:=FOverloadScopes.Count;
  2647. // add class and ancestor scopes
  2648. aScope:=ClassScope;
  2649. repeat
  2650. PushOverloadScope(aScope);
  2651. aScope:=aScope.AncestorScope;
  2652. until aScope=nil;
  2653. // first rename all overloads on this level
  2654. RenameOverloads(ClassEl,ClassEl.Members);
  2655. // then process nested procedures
  2656. RenameSubOverloads(ClassEl.Members);
  2657. while FOverloadScopes.Count>OldScopeCount do
  2658. PopOverloadScope;
  2659. end
  2660. else if C=TPasConst then
  2661. RenameOverload(El)
  2662. else if C.InheritsFrom(TPasVariable) and (El.Parent.ClassType=TPasClassType) then
  2663. RenameOverload(El);
  2664. end;
  2665. {$IFDEF VerbosePas2JS}
  2666. //writeln('TPas2JSResolver.RenameSubOverloads END');
  2667. {$ENDIF}
  2668. end;
  2669. procedure TPas2JSResolver.PushOverloadScope(Scope: TPasIdentifierScope);
  2670. begin
  2671. FOverloadScopes.Add(Scope);
  2672. end;
  2673. procedure TPas2JSResolver.PopOverloadScope;
  2674. begin
  2675. FOverloadScopes.Delete(FOverloadScopes.Count-1);
  2676. end;
  2677. procedure TPas2JSResolver.AddType(El: TPasType);
  2678. begin
  2679. inherited AddType(El);
  2680. end;
  2681. procedure TPas2JSResolver.ResolveImplAsm(El: TPasImplAsmStatement);
  2682. {type
  2683. TAsmToken = (
  2684. atNone,
  2685. atWord,
  2686. atDot,
  2687. atRoundBracketOpen,
  2688. atRoundBracketClose
  2689. );
  2690. procedure Next;
  2691. begin
  2692. end;}
  2693. var
  2694. Lines: TStrings;
  2695. begin
  2696. Lines:=El.Tokens;
  2697. if Lines=nil then exit;
  2698. end;
  2699. procedure TPas2JSResolver.ResolveNameExpr(El: TPasExpr; const aName: string;
  2700. Access: TResolvedRefAccess);
  2701. procedure CheckTObjectFree(Ref: TResolvedReference);
  2702. var
  2703. Bin: TBinaryExpr;
  2704. Left: TPasExpr;
  2705. LeftResolved: TPasResolverResult;
  2706. IdentEl: TPasElement;
  2707. C: TClass;
  2708. begin
  2709. if not IsTObjectFreeMethod(El) then exit;
  2710. if Ref.WithExprScope<>nil then
  2711. begin
  2712. // with expr do free
  2713. if GetNewInstanceExpr(Ref.WithExprScope.Expr)<>nil then
  2714. exit; // with TSomeClass.Free do Free -> ok
  2715. RaiseMsg(20170517092407,nFreeNeedsVar,sFreeNeedsVar,[],El);
  2716. end;
  2717. C:=El.Parent.ClassType;
  2718. if (C=TBinaryExpr) then
  2719. begin
  2720. // expr.Free
  2721. Bin:=TBinaryExpr(El.Parent);
  2722. if (Bin.right<>El) or (Bin.OpCode<>eopSubIdent) then
  2723. RaiseMsg(20170516151950,nFreeNeedsVar,sFreeNeedsVar,[],El);
  2724. if rrfImplicitCallWithoutParams in Ref.Flags then
  2725. // ".Free;" -> ok
  2726. else if Bin.Parent is TParamsExpr then
  2727. begin
  2728. if Bin.Parent.Parent is TPasExpr then
  2729. RaiseMsg(20170516161345,nFreeNeedsVar,sFreeNeedsVar,[],El);
  2730. // ".Free();" -> ok
  2731. end
  2732. else if Bin.Parent is TPasImplElement then
  2733. // ok
  2734. else
  2735. begin
  2736. {$IFDEF VerbosePas2JS}
  2737. writeln('TPas2JSResolver.ResolveNameExpr.CheckTObjectFree Bin.Parent=',GetObjName(Bin.Parent));
  2738. {$ENDIF}
  2739. RaiseMsg(20170516160347,nFreeNeedsVar,sFreeNeedsVar,[],El);
  2740. end;
  2741. Left:=Bin.left;
  2742. ComputeElement(Left,LeftResolved,[]);
  2743. if not (rrfReadable in LeftResolved.Flags) then
  2744. RaiseMsg(20170516152300,nFreeNeedsVar,sFreeNeedsVar,[],El);
  2745. if not (rrfWritable in LeftResolved.Flags) then
  2746. RaiseMsg(20170516152307,nFreeNeedsVar,sFreeNeedsVar,[],El);
  2747. IdentEl:=LeftResolved.IdentEl;
  2748. if IdentEl=nil then
  2749. RaiseMsg(20170516152401,nFreeNeedsVar,sFreeNeedsVar,[],El);
  2750. if IdentEl.ClassType=TPasArgument then
  2751. exit; // readable and writable argument -> ok
  2752. if (IdentEl.ClassType=TPasVariable)
  2753. or (IdentEl.ClassType=TPasConst) then
  2754. exit; // readable and writable variable -> ok
  2755. if IdentEl.ClassType=TPasResultElement then
  2756. exit; // readable and writable function result -> ok
  2757. RaiseMsg(20170516152455,nFreeNeedsVar,sFreeNeedsVar,[],El);
  2758. end
  2759. else if C.InheritsFrom(TPasImplBlock) then
  2760. begin
  2761. // e.g. "begin Free end;" OR "if expr then Free;" -> ok
  2762. exit;
  2763. end;
  2764. RaiseMsg(20170516152454,nFreeNeedsVar,sFreeNeedsVar,[],El);
  2765. end;
  2766. procedure CheckResultEl(Ref: TResolvedReference);
  2767. // Ref.Declaration is TPasResultElement
  2768. var
  2769. CurEl: TPasElement;
  2770. Lvl: Integer;
  2771. ProcScope, CurProcScope: TPas2JSProcedureScope;
  2772. FuncType: TPasFunctionType;
  2773. begin
  2774. // result refers to a function result
  2775. // -> check if it is referring to a parent function result
  2776. Lvl:=0;
  2777. CurEl:=El;
  2778. CurProcScope:=nil;
  2779. while CurEl<>nil do
  2780. begin
  2781. if (CurEl is TPasProcedure)
  2782. and (TPasProcedure(CurEl).ProcType is TPasFunctionType) then
  2783. begin
  2784. inc(Lvl);
  2785. if not (CurEl.CustomData is TPas2JSProcedureScope) then
  2786. RaiseInternalError(20181210231858);
  2787. ProcScope:=TPas2JSProcedureScope(CurEl.CustomData);
  2788. if ProcScope.DeclarationProc is TPasFunction then
  2789. FuncType:=TPasFunctionType(ProcScope.DeclarationProc.ProcType)
  2790. else
  2791. FuncType:=TPasFunctionType(TPasProcedure(CurEl).ProcType);
  2792. if Lvl=1 then
  2793. begin
  2794. // current function (where the statement of El is)
  2795. if (FuncType.ResultEl=Ref.Declaration) then
  2796. exit; // accessing current function -> ok
  2797. // accessing Result variable of higher function -> need rename
  2798. // Note: ProcScope.ResultVarName only valid in implementation ProcScope
  2799. if ProcScope.ResultVarName<>'' then
  2800. exit; // is already renamed
  2801. CurProcScope:=ProcScope;
  2802. end;
  2803. end;
  2804. CurEl:=CurEl.Parent;
  2805. end;
  2806. if Lvl<2 then
  2807. RaiseNotYetImplemented(20171003112020,El);
  2808. // El refers to a higher Result variable
  2809. // -> current function needs another name for its Result variable
  2810. CurProcScope.ResultVarName:=ResolverResultVar+'$'+IntToStr(Lvl-1);
  2811. end;
  2812. var
  2813. Ref: TResolvedReference;
  2814. begin
  2815. inherited ResolveNameExpr(El, aName, Access);
  2816. if El.CustomData is TResolvedReference then
  2817. begin
  2818. Ref:=TResolvedReference(El.CustomData);
  2819. if (CompareText(aName,'free')=0) then
  2820. CheckTObjectFree(Ref)
  2821. else if (Ref.Declaration is TPasResultElement) then
  2822. CheckResultEl(Ref)
  2823. else if IsExternalClassConstructor(Ref.Declaration) then
  2824. CheckExternalClassConstructor(Ref);
  2825. end;
  2826. end;
  2827. procedure TPas2JSResolver.ResolveFuncParamsExpr(Params: TParamsExpr;
  2828. Access: TResolvedRefAccess);
  2829. var
  2830. Value: TPasExpr;
  2831. Ref: TResolvedReference;
  2832. begin
  2833. inherited ResolveFuncParamsExpr(Params, Access);
  2834. Value:=Params.Value;
  2835. if Value.CustomData is TResolvedReference then
  2836. begin
  2837. Ref:=TResolvedReference(Value.CustomData);
  2838. if IsExternalClassConstructor(Ref.Declaration) then
  2839. CheckExternalClassConstructor(Ref);
  2840. end;
  2841. end;
  2842. procedure TPas2JSResolver.FinishInterfaceSection(Section: TPasSection);
  2843. begin
  2844. inherited FinishInterfaceSection(Section);
  2845. if FOverloadScopes=nil then
  2846. begin
  2847. FOverloadScopes:=TFPList.Create;
  2848. RenameOverloadsInSection(Section);
  2849. end;
  2850. end;
  2851. procedure TPas2JSResolver.FinishTypeSection(El: TPasDeclarations);
  2852. var
  2853. i: Integer;
  2854. Decl: TPasElement;
  2855. C: TClass;
  2856. TypeEl: TPasType;
  2857. begin
  2858. inherited FinishTypeSection(El);
  2859. for i:=0 to El.Declarations.Count-1 do
  2860. begin
  2861. Decl:=TPasElement(El.Declarations[i]);
  2862. C:=Decl.ClassType;
  2863. if C=TPasPointerType then
  2864. begin
  2865. TypeEl:=ResolveAliasType(TPasPointerType(Decl).DestType);
  2866. if TypeEl.ClassType=TPasRecordType then
  2867. // ^record
  2868. else
  2869. RaiseMsg(20180423105726,nNotSupportedX,sNotSupportedX,['pointer of '+TPasPointerType(Decl).DestType.Name],Decl);
  2870. end;
  2871. end;
  2872. end;
  2873. procedure TPas2JSResolver.FinishModule(CurModule: TPasModule);
  2874. var
  2875. ModuleClass: TClass;
  2876. begin
  2877. inherited FinishModule(CurModule);
  2878. if FOverloadScopes=nil then
  2879. FOverloadScopes:=TFPList.Create;
  2880. try
  2881. ModuleClass:=CurModule.ClassType;
  2882. if ModuleClass=TPasModule then
  2883. RenameOverloadsInSection(CurModule.ImplementationSection)
  2884. else if ModuleClass=TPasProgram then
  2885. RenameOverloadsInSection(TPasProgram(CurModule).ProgramSection)
  2886. else if CurModule.ClassType=TPasLibrary then
  2887. RenameOverloadsInSection(TPasLibrary(CurModule).LibrarySection)
  2888. else
  2889. RaiseNotYetImplemented(20170221000032,CurModule);
  2890. finally
  2891. FreeAndNil(FOverloadScopes);
  2892. end;
  2893. end;
  2894. procedure TPas2JSResolver.FinishEnumType(El: TPasEnumType);
  2895. var
  2896. i: Integer;
  2897. EnumValue: TPasEnumValue;
  2898. begin
  2899. inherited FinishEnumType(El);
  2900. for i:=0 to El.Values.Count-1 do
  2901. begin
  2902. EnumValue:=TPasEnumValue(El.Values[i]);
  2903. if EnumValue.Value<>nil then
  2904. RaiseNotYetImplemented(20180126202434,EnumValue,'enum const');
  2905. end;
  2906. end;
  2907. procedure TPas2JSResolver.FinishSetType(El: TPasSetType);
  2908. var
  2909. TypeEl: TPasType;
  2910. C: TClass;
  2911. RangeValue: TResEvalValue;
  2912. bt: TResolverBaseType;
  2913. begin
  2914. inherited FinishSetType(El);
  2915. TypeEl:=ResolveAliasType(El.EnumType);
  2916. C:=TypeEl.ClassType;
  2917. if C=TPasEnumType then
  2918. exit
  2919. else if C=TPasUnresolvedSymbolRef then
  2920. begin
  2921. if TypeEl.CustomData is TResElDataBaseType then
  2922. begin
  2923. bt:=TResElDataBaseType(TypeEl.CustomData).BaseType;
  2924. if bt in [btBoolean,btByte,btShortInt,btSmallInt,btWord,btChar,btWideChar] then
  2925. exit; // ok
  2926. {$IFDEF VerbosePas2JS}
  2927. writeln('TPas2JSResolver.FinishSetType El='+GetObjName(El)+' TypeEl=',GetObjName(TypeEl),' ',bt);
  2928. {$ENDIF}
  2929. RaiseMsg(20171110150000,nNotSupportedX,sNotSupportedX,['set of '+TypeEl.Name],El);
  2930. end;
  2931. end
  2932. else if C=TPasRangeType then
  2933. begin
  2934. RangeValue:=Eval(TPasRangeType(TypeEl).RangeExpr,[refConst]);
  2935. try
  2936. case RangeValue.Kind of
  2937. revkRangeInt:
  2938. begin
  2939. if TResEvalRangeInt(RangeValue).RangeEnd-TResEvalRangeInt(RangeValue).RangeStart>$ffff then
  2940. begin
  2941. {$IFDEF VerbosePas2JS}
  2942. writeln('TPas2JSResolver.FinishSetType El='+GetObjName(El)+' Range='+RangeValue.AsDebugString,' ',bt);
  2943. {$ENDIF}
  2944. RaiseMsg(20171110150159,nNotSupportedX,sNotSupportedX,['set of '+TypeEl.Name],El);
  2945. end;
  2946. exit;
  2947. end;
  2948. else
  2949. begin
  2950. {$IFDEF VerbosePas2JS}
  2951. writeln('TPas2JSResolver.FinishSetType El='+GetObjName(El)+' Range='+RangeValue.AsDebugString);
  2952. {$ENDIF}
  2953. RaiseMsg(20171110145211,nNotSupportedX,sNotSupportedX,['set of '+TypeEl.Name],El);
  2954. end;
  2955. end;
  2956. finally
  2957. ReleaseEvalValue(RangeValue);
  2958. end;
  2959. end;
  2960. {$IFDEF VerbosePas2JS}
  2961. writeln('TPas2JSResolver.FinishSetType El='+GetObjName(El)+' TypeEl=',GetObjName(TypeEl));
  2962. {$ENDIF}
  2963. RaiseMsg(20170415182320,nNotSupportedX,sNotSupportedX,['set of '+TypeEl.Name],El);
  2964. end;
  2965. procedure TPas2JSResolver.FinishRecordType(El: TPasRecordType);
  2966. begin
  2967. if (El.Variants<>nil) and (El.Variants.Count>0) then
  2968. RaiseMsg(20180104205309,nXIsNotSupported,sXIsNotSupported,['variant record'],TPasElement(El.Variants[0]));
  2969. inherited FinishRecordType(El);
  2970. end;
  2971. procedure TPas2JSResolver.FinishClassType(El: TPasClassType);
  2972. var
  2973. Scope, CurScope: TPas2JSClassScope;
  2974. Value: TResEvalValue;
  2975. begin
  2976. inherited FinishClassType(El);
  2977. if El.IsExternal then
  2978. begin
  2979. if El.ExternalName='' then
  2980. RaiseMsg(20170321151109,nMissingExternalName,sMissingExternalName,[],El);
  2981. AddExternalPath(El.ExternalName,El);
  2982. end;
  2983. if El.IsPacked then
  2984. RaiseMsg(20180326155616,nPasElementNotSupported,sPasElementNotSupported,
  2985. ['packed'],El);
  2986. if El.IsForward then
  2987. exit;
  2988. //writeln('TPas2JSResolver.FinishClassType START ',GetObjName(El));
  2989. Scope:=El.CustomData as TPas2JSClassScope;
  2990. case El.ObjKind of
  2991. okInterface:
  2992. begin
  2993. if not (El.InterfaceType in [citCom,citCorba]) then
  2994. RaiseMsg(20180326155612,nPasElementNotSupported,sPasElementNotSupported,
  2995. [InterfaceTypeNames[El.InterfaceType]],El);
  2996. if El.GUIDExpr<>nil then
  2997. begin
  2998. Value:=Eval(El.GUIDExpr,[refConst]);
  2999. try
  3000. case Value.Kind of
  3001. {$IFDEF FPC_HAS_CPSTRING}
  3002. revkString:
  3003. Scope.GUID:=TResEvalString(Value).S;
  3004. revkUnicodeString:
  3005. Scope.GUID:=UTF8Encode(TResEvalUTF16(Value).S);
  3006. {$ELSE}
  3007. revkUnicodeString:
  3008. Scope.GUID:=TResEvalUTF16(Value).S;
  3009. {$ENDIF}
  3010. else
  3011. RaiseXExpectedButYFound(20180326160602,'string literal',El.GUIDExpr.ElementTypeName,El.GUIDExpr);
  3012. end;
  3013. // test format?
  3014. finally
  3015. ReleaseEvalValue(Value);
  3016. end;
  3017. end
  3018. else
  3019. begin
  3020. // autogenerate GUID
  3021. Scope.GUID:=GenerateGUID(El);
  3022. end;
  3023. CurScope:=Scope;
  3024. repeat
  3025. CurScope:=TPas2JSClassScope(CurScope.AncestorScope);
  3026. if CurScope=nil then break;
  3027. if SameText(CurScope.GUID,Scope.GUID) then
  3028. RaiseMsg(20180330232206,nDuplicateGUIDXInYZ,sDuplicateGUIDXInYZ,
  3029. [Scope.GUID,El.Name,CurScope.Element.Name],El);
  3030. until false;
  3031. end;
  3032. end;
  3033. //writeln('TPas2JSResolver.FinishClassType END ',GetObjName(El));
  3034. end;
  3035. procedure TPas2JSResolver.FinishArrayType(El: TPasArrayType);
  3036. var
  3037. ElType: TPasType;
  3038. begin
  3039. inherited FinishArrayType(El);
  3040. ElType:=ResolveAliasType(El.ElType);
  3041. while ElType is TPasArrayType do
  3042. ElType:=ResolveAliasType(TPasArrayType(ElType).ElType);
  3043. if IsInterfaceType(ElType,citCom) then
  3044. RaiseMsg(20180404134515,nNotSupportedX,sNotSupportedX,['array of COM-interface'],El);
  3045. end;
  3046. procedure TPas2JSResolver.FinishAncestors(aClass: TPasClassType);
  3047. var
  3048. IntfList: TFPList;
  3049. i, j: Integer;
  3050. Scope, IntfScope: TPas2JSClassScope;
  3051. IntfType, OrigIntfType: TPasType;
  3052. GUIDs: TStringList;
  3053. begin
  3054. inherited FinishAncestors(aClass);
  3055. Scope:=TPas2JSClassScope(aClass.CustomData);
  3056. if Scope=nil then exit;
  3057. IntfList:=aClass.Interfaces;
  3058. GUIDs:=TStringList.Create;
  3059. try
  3060. for i:=0 to IntfList.Count-1 do
  3061. begin
  3062. OrigIntfType:=TPasType(IntfList[i]);
  3063. IntfType:=ResolveAliasType(OrigIntfType);
  3064. IntfScope:=TPas2JSClassScope(IntfType.CustomData);
  3065. j:=GUIDs.IndexOf(IntfScope.GUID);
  3066. if j>=0 then
  3067. RaiseMsg(20180330231220,nDuplicateGUIDXInYZ,sDuplicateGUIDXInYZ,
  3068. [IntfScope.GUID,OrigIntfType.Name,TpasElement(GUIDs.Objects[j]).Name],aClass); // ToDo: jump to interface expr
  3069. GUIDs.AddObject(IntfScope.GUID,OrigIntfType);
  3070. end;
  3071. finally
  3072. GUIDs.Free;
  3073. end;
  3074. end;
  3075. procedure TPas2JSResolver.FinishVariable(El: TPasVariable);
  3076. const
  3077. ClassFieldModifiersAllowed = [vmClass,vmStatic,vmExternal,vmPublic];
  3078. RecordVarModifiersAllowed = [vmExternal];
  3079. LocalVarModifiersAllowed = [];
  3080. ImplementationVarModifiersAllowed = [vmExternal];
  3081. SectionVarModifiersAllowed = [vmExternal,vmPublic];
  3082. procedure RaiseVarModifierNotSupported(const Allowed: TVariableModifiers);
  3083. var
  3084. s: String;
  3085. m: TVariableModifier;
  3086. begin
  3087. s:='';
  3088. for m in TVariableModifiers do
  3089. if (m in El.VarModifiers) and not (m in Allowed) then
  3090. begin
  3091. str(m,s);
  3092. RaiseMsg(20170322134418,nInvalidVariableModifier,
  3093. sInvalidVariableModifier,[VariableModifierNames[m]],El);
  3094. end;
  3095. end;
  3096. var
  3097. ExtName: String;
  3098. ParentC: TClass;
  3099. AbsExpr: TPasExpr;
  3100. ResolvedAbsol: TPasResolverResult;
  3101. AbsIdent: TPasElement;
  3102. TypeEl, ElTypeEl: TPasType;
  3103. GUID: TGUID;
  3104. i: Integer;
  3105. SectionScope: TPas2JSSectionScope;
  3106. begin
  3107. inherited FinishVariable(El);
  3108. ParentC:=El.Parent.ClassType;
  3109. if El.AbsoluteExpr<>nil then
  3110. begin
  3111. // check 'absolute' alias
  3112. if vmExternal in El.VarModifiers then
  3113. RaiseMsg(20171226105002,nXModifierMismatchY,sXModifierMismatchY,
  3114. ['absolute','external'],El.AbsoluteExpr);
  3115. AbsExpr:=El.AbsoluteExpr;
  3116. ComputeElement(AbsExpr,ResolvedAbsol,[rcNoImplicitProc]);
  3117. AbsIdent:=ResolvedAbsol.IdentEl;
  3118. if ParentC=TProcedureBody then
  3119. begin
  3120. // local var
  3121. if (AbsIdent.Parent is TProcedureBody)
  3122. or (AbsIdent is TPasArgument) then
  3123. // ok
  3124. else
  3125. begin
  3126. {$IFDEF VerbosePas2JS}
  3127. writeln('TPas2JSResolver.FinishVariable absolute: El.Parent=',GetObjName(El.Parent),'.Parent=',GetObjName(El.Parent.Parent),' AbsParent=',GetObjName(AbsIdent.Parent),'.Parent=',GetObjName(AbsIdent.Parent.Parent));
  3128. {$ENDIF}
  3129. RaiseMsg(20171226102424,nInvalidAbsoluteLocation,sInvalidAbsoluteLocation,[],El.AbsoluteExpr);
  3130. end;
  3131. end
  3132. else
  3133. begin
  3134. RaiseMsg(20170728133340,nInvalidVariableModifier,
  3135. sInvalidVariableModifier,['absolute'],El);
  3136. end;
  3137. end;
  3138. if (ParentC=TPasClassType) then
  3139. begin
  3140. // class member
  3141. RaiseVarModifierNotSupported(ClassFieldModifiersAllowed);
  3142. if TPasClassType(El.Parent).IsExternal then
  3143. begin
  3144. // external class
  3145. if El.Visibility=visPublished then
  3146. // Note: an external class has no typeinfo
  3147. RaiseMsg(20170413221516,nSymbolCannotBePublished,sSymbolCannotBePublished,
  3148. [],El);
  3149. if not (vmExternal in El.VarModifiers) then
  3150. begin
  3151. // make variable external
  3152. if (El.ClassType=TPasVariable) or (El.ClassType=TPasConst) then
  3153. begin
  3154. if El.ExportName<>nil then
  3155. RaiseMsg(20170322134321,nInvalidVariableModifier,
  3156. sInvalidVariableModifier,['export name'],El.ExportName);
  3157. El.ExportName:=TPrimitiveExpr.Create(El,pekString,''''+El.Name+'''');
  3158. end;
  3159. Include(El.VarModifiers,vmExternal);
  3160. end;
  3161. if (El.ClassType=TPasConst) and (TPasConst(El).Expr<>nil) then
  3162. // external const with expression is not writable
  3163. TPasConst(El).IsConst:=true;
  3164. end;
  3165. end
  3166. else if ParentC=TPasRecordType then
  3167. begin
  3168. // record member
  3169. RaiseVarModifierNotSupported(RecordVarModifiersAllowed);
  3170. if IsInterfaceType(El.VarType,citCom) then
  3171. RaiseMsg(20180404135105,nNotSupportedX,sNotSupportedX,['COM-interface as record member'],El);
  3172. if (El.ClassType=TPasConst) and (TPasConst(El).Expr<>nil) then
  3173. // external const with expression is not writable
  3174. TPasConst(El).IsConst:=true;
  3175. end
  3176. else if ParentC=TProcedureBody then
  3177. begin
  3178. // local var
  3179. RaiseVarModifierNotSupported(LocalVarModifiersAllowed);
  3180. if (El.ClassType=TPasConst) and TPasConst(El).IsConst then
  3181. begin
  3182. // local const
  3183. i:=ScopeCount-1;
  3184. while (i>=0) and not (Scopes[i] is TPas2JSSectionScope) do dec(i);
  3185. if i<0 then
  3186. RaiseNotYetImplemented(20180420131358,El);
  3187. SectionScope:=TPas2JSSectionScope(Scopes[i]);
  3188. SectionScope.AddElevatedLocal(El.Name,El);
  3189. end;
  3190. end
  3191. else if ParentC=TImplementationSection then
  3192. // implementation var
  3193. RaiseVarModifierNotSupported(ImplementationVarModifiersAllowed)
  3194. else if ParentC.InheritsFrom(TPasSection) then
  3195. begin
  3196. // interface/program/library var
  3197. RaiseVarModifierNotSupported(SectionVarModifiersAllowed);
  3198. end
  3199. else
  3200. begin
  3201. {$IFDEF VerbosePas2JS}
  3202. writeln('TPas2JSResolver.FinishVariable ',GetObjName(El),' Parent=',GetObjName(El.Parent));
  3203. {$ENDIF}
  3204. RaiseNotYetImplemented(20170324151259,El);
  3205. end;
  3206. if vmExternal in El.VarModifiers then
  3207. begin
  3208. // compute constant
  3209. if El.LibraryName<>nil then
  3210. RaiseMsg(20170227094227,nPasElementNotSupported,sPasElementNotSupported,
  3211. ['library'],El.ExportName);
  3212. if El.ExportName=nil then
  3213. RaiseMsg(20170227100750,nMissingExternalName,sMissingExternalName,[],El);
  3214. ExtName:=ComputeConstString(El.ExportName,true,true);
  3215. if (El.Visibility=visPublished) and (ExtName<>El.Name) then
  3216. RaiseMsg(20170407002940,nPublishedNameMustMatchExternal,
  3217. sPublishedNameMustMatchExternal,[],El.ExportName);
  3218. // add external name to FExternalNames
  3219. if (El.Parent is TPasSection)
  3220. or ((El.ClassType=TPasConst) and (El.Parent is TPasProcedure)) then
  3221. AddExternalPath(ExtName,El.ExportName);
  3222. end;
  3223. if El.VarType<>nil then
  3224. begin
  3225. TypeEl:=ResolveAliasType(El.VarType);
  3226. if TypeEl.ClassType=TPasPointerType then
  3227. begin
  3228. ElTypeEl:=ResolveAliasType(TPasPointerType(TypeEl).DestType);
  3229. if ElTypeEl.ClassType=TPasRecordType then
  3230. // ^record
  3231. else
  3232. RaiseMsg(20180423110113,nNotSupportedX,sNotSupportedX,['pointer'],El);
  3233. end;
  3234. if El.Expr<>nil then
  3235. begin
  3236. if (TypeEl.ClassType=TPasRecordType) then
  3237. begin
  3238. if GetAssignGUIDString(TPasRecordType(TypeEl),El.Expr,GUID) then
  3239. // e.g. IObjectInstance: TGuid = '{D91C9AF4-3C93-420F-A303-BF5BA82BFD23}'
  3240. else
  3241. ;
  3242. end;
  3243. end;
  3244. end;
  3245. end;
  3246. procedure TPas2JSResolver.FinishArgument(El: TPasArgument);
  3247. var
  3248. TypeEl, ElTypeEl: TPasType;
  3249. begin
  3250. inherited FinishArgument(El);
  3251. if El.ArgType<>nil then
  3252. begin
  3253. TypeEl:=ResolveAliasType(El.ArgType);
  3254. if TypeEl.ClassType=TPasPointerType then
  3255. begin
  3256. ElTypeEl:=ResolveAliasType(TPasPointerType(TypeEl).DestType);
  3257. if ElTypeEl.ClassType=TPasRecordType then
  3258. // ^record
  3259. else
  3260. RaiseMsg(20180423110239,nNotSupportedX,sNotSupportedX,['pointer'],El);
  3261. end;
  3262. end;
  3263. end;
  3264. procedure TPas2JSResolver.FinishProcedureType(El: TPasProcedureType);
  3265. var
  3266. Proc: TPasProcedure;
  3267. pm: TProcedureModifier;
  3268. ExtName: String;
  3269. C: TClass;
  3270. AClass: TPasClassType;
  3271. ClassScope: TPas2JSClassScope;
  3272. ptm: TProcTypeModifier;
  3273. TypeEl, ElTypeEl: TPasType;
  3274. begin
  3275. if El.Parent.Parent is TPasRecordType then
  3276. RaiseNotYetImplemented(20181107183603,El,'methods in records');
  3277. inherited FinishProcedureType(El);
  3278. if El is TPasFunctionType then
  3279. begin
  3280. TypeEl:=ResolveAliasType(TPasFunctionType(El).ResultEl.ResultType);
  3281. if TypeEl.ClassType=TPasPointerType then
  3282. begin
  3283. ElTypeEl:=ResolveAliasType(TPasPointerType(TypeEl).DestType);
  3284. if ElTypeEl.ClassType=TPasRecordType then
  3285. // ^record
  3286. else
  3287. RaiseMsg(20180423110824,nNotSupportedX,sNotSupportedX,['pointer'],El);
  3288. end;
  3289. end;
  3290. if El.Parent is TPasProcedure then
  3291. begin
  3292. Proc:=TPasProcedure(El.Parent);
  3293. // calling convention
  3294. if Proc.CallingConvention<>ccDefault then
  3295. RaiseMsg(20170211214731,nPasElementNotSupported,sPasElementNotSupported,
  3296. [cCallingConventions[Proc.CallingConvention]],Proc);
  3297. for pm in TProcedureModifiers do
  3298. if (pm in Proc.Modifiers)
  3299. and (not (pm in [pmVirtual, pmAbstract, pmOverride,
  3300. pmOverload, pmReintroduce,
  3301. pmInline, pmAssembler, pmPublic,
  3302. pmExternal, pmForward])) then
  3303. RaiseNotYetImplemented(20170208142159,El,'modifier '+ModifierNames[pm]);
  3304. for ptm in TProcTypeModifiers do
  3305. if (ptm in Proc.ProcType.Modifiers)
  3306. and (not (ptm in [ptmOfObject,ptmVarargs])) then
  3307. RaiseNotYetImplemented(20170411171454,El,'modifier '+ProcTypeModifiers[ptm]);
  3308. // check pmPublic
  3309. if [pmPublic,pmExternal]<=Proc.Modifiers then
  3310. RaiseMsg(20170324150149,nInvalidXModifierY,
  3311. sInvalidXModifierY,[Proc.ElementTypeName,'public, external'],Proc);
  3312. if (Proc.PublicName<>nil) then
  3313. RaiseMsg(20170324150417,nPasElementNotSupported,sPasElementNotSupported,
  3314. ['public name'],Proc.PublicName);
  3315. if (Proc.Parent.ClassType=TPasClassType) then
  3316. begin
  3317. // class member
  3318. AClass:=TPasClassType(Proc.Parent);
  3319. ClassScope:=AClass.CustomData as TPas2JSClassScope;
  3320. if AClass.IsExternal then
  3321. begin
  3322. // external class -> make method external
  3323. if not (pmExternal in Proc.Modifiers) then
  3324. begin
  3325. if Proc.LibrarySymbolName<>nil then
  3326. RaiseMsg(20170322142158,nInvalidXModifierY,
  3327. sInvalidXModifierY,[Proc.ElementTypeName,'symbol name'],Proc.LibrarySymbolName);
  3328. Proc.Modifiers:=Proc.Modifiers+[pmExternal];
  3329. Proc.LibrarySymbolName:=TPrimitiveExpr.Create(Proc,pekString,''''+Proc.Name+'''');
  3330. end;
  3331. if Proc.Visibility=visPublished then
  3332. // Note: an external class has no typeinfo
  3333. RaiseMsg(20170413221327,nSymbolCannotBePublished,sSymbolCannotBePublished,
  3334. [],Proc);
  3335. C:=Proc.ClassType;
  3336. if (C=TPasProcedure) or (C=TPasFunction)
  3337. or (C=TPasClassProcedure) or (C=TPasClassFunction) then
  3338. // ok
  3339. else if C=TPasConstructor then
  3340. begin
  3341. if Proc.IsVirtual then
  3342. // constructor of external class can't be overriden -> forbid virtual
  3343. RaiseMsg(20170323100447,nInvalidXModifierY,sInvalidXModifierY,
  3344. [Proc.ElementTypeName,'virtual,external'],Proc);
  3345. if CompareText(Proc.Name,'new')=0 then
  3346. begin
  3347. ExtName:=ComputeConstString(Proc.LibrarySymbolName,true,true);
  3348. if ExtName<>Proc.Name then
  3349. RaiseMsg(20170323083511,nVirtualMethodNameMustMatchExternal,
  3350. sVirtualMethodNameMustMatchExternal,[],Proc.LibrarySymbolName);
  3351. end
  3352. else if El.Args.Count>0 then
  3353. RaiseMsg(20170322164357,nNoArgumentsAllowedForExternalObjectConstructor,
  3354. sNoArgumentsAllowedForExternalObjectConstructor,[],TPasArgument(El.Args[0]));
  3355. if pmVirtual in Proc.Modifiers then
  3356. RaiseMsg(20170322183141,nInvalidXModifierY,sInvalidXModifierY,
  3357. [Proc.ElementTypeName,'virtual'],Proc.ProcType);
  3358. end
  3359. else
  3360. RaiseMsg(20170322163210,nPasElementNotSupported,sPasElementNotSupported,
  3361. [Proc.ElementTypeName],Proc);
  3362. end
  3363. else
  3364. // Pascal class, not external
  3365. case AClass.ObjKind of
  3366. okClass:
  3367. begin
  3368. if (ClassScope.NewInstanceFunction=nil)
  3369. and (ClassScope.AncestorScope<>nil)
  3370. and (TPasClassType(ClassScope.AncestorScope.Element).IsExternal)
  3371. and (Proc.ClassType=TPasClassFunction)
  3372. and (Proc.Visibility in [visProtected,visPublic,visPublished])
  3373. and (TPasClassFunction(Proc).FuncType.ResultEl.ResultType=AClass)
  3374. and ([pmOverride,pmExternal]*Proc.Modifiers=[]) then
  3375. begin
  3376. // The first non private class function in a Pascal class descending
  3377. // from an external class
  3378. // -> this is the NewInstance function
  3379. ClassScope.NewInstanceFunction:=TPasClassFunction(Proc);
  3380. CheckNewInstanceFunction(ClassScope);
  3381. end;
  3382. end;
  3383. okInterface:
  3384. begin
  3385. for pm in Proc.Modifiers do
  3386. if not (pm in [pmOverload, pmReintroduce]) then
  3387. RaiseMsg(20180329141108,nInvalidXModifierY,
  3388. sInvalidXModifierY,[Proc.ElementTypeName,ModifierNames[pm]],Proc);
  3389. end;
  3390. end;
  3391. end;
  3392. if pmExternal in Proc.Modifiers then
  3393. begin
  3394. // external proc
  3395. // external override -> unneeded information, probably a bug
  3396. if Proc.IsOverride then
  3397. RaiseMsg(20170321101715,nInvalidXModifierY,sInvalidXModifierY,
  3398. [Proc.ElementTypeName,'override,external'],Proc);
  3399. if Proc.LibraryExpr<>nil then
  3400. RaiseMsg(20170211220712,nPasElementNotSupported,sPasElementNotSupported,
  3401. ['external library name'],Proc.LibraryExpr);
  3402. if Proc.LibrarySymbolName=nil then
  3403. RaiseMsg(20170227095454,nMissingExternalName,sMissingExternalName,
  3404. ['missing external name'],Proc);
  3405. for pm in [pmAssembler,pmForward,pmNoReturn,pmInline] do
  3406. if pm in Proc.Modifiers then
  3407. RaiseMsg(20170323100842,nInvalidXModifierY,sInvalidXModifierY,
  3408. [Proc.ElementTypeName,ModifierNames[pm]],Proc);
  3409. // compute external name
  3410. ExtName:=ComputeConstString(Proc.LibrarySymbolName,true,true);
  3411. // a virtual must have the external name, so that override works
  3412. if Proc.IsVirtual and (Proc.Name<>ExtName) then
  3413. RaiseMsg(20170321090049,nVirtualMethodNameMustMatchExternal,
  3414. sVirtualMethodNameMustMatchExternal,[],Proc.LibrarySymbolName);
  3415. // a published must have the external name, so that streaming works
  3416. if (Proc.Visibility=visPublished) then
  3417. begin
  3418. if (Proc.Name<>ExtName) then
  3419. RaiseMsg(20170407002940,nPublishedNameMustMatchExternal,
  3420. sPublishedNameMustMatchExternal,[],Proc.LibrarySymbolName);
  3421. if ExtName=ExtClassBracketAccessor then
  3422. RaiseMsg(20170409211805,nSymbolCannotBePublished,
  3423. sSymbolCannotBePublished,[],Proc.LibrarySymbolName);
  3424. end;
  3425. if Proc.Parent is TPasSection then
  3426. AddExternalPath(ExtName,Proc.LibrarySymbolName);
  3427. end;
  3428. end;
  3429. end;
  3430. procedure TPas2JSResolver.FinishPropertyOfClass(PropEl: TPasProperty);
  3431. var
  3432. Getter, Setter: TPasElement;
  3433. GetterIsBracketAccessor, SetterIsBracketAccessor: Boolean;
  3434. Arg: TPasArgument;
  3435. ArgResolved: TPasResolverResult;
  3436. ParentC: TClass;
  3437. IndexExpr: TPasExpr;
  3438. PropArgs: TFPList;
  3439. begin
  3440. inherited FinishPropertyOfClass(PropEl);
  3441. ParentC:=PropEl.Parent.ClassType;
  3442. if (ParentC=TPasClassType) then
  3443. begin
  3444. // class member
  3445. if TPasClassType(PropEl.Parent).IsExternal then
  3446. begin
  3447. // external class
  3448. if PropEl.Visibility=visPublished then
  3449. // Note: an external class has no typeinfo
  3450. RaiseMsg(20170413221703,nSymbolCannotBePublished,sSymbolCannotBePublished,
  3451. [],PropEl);
  3452. end;
  3453. end;
  3454. Getter:=GetPasPropertyGetter(PropEl);
  3455. GetterIsBracketAccessor:=IsExternalBracketAccessor(Getter);
  3456. Setter:=GetPasPropertySetter(PropEl);
  3457. SetterIsBracketAccessor:=IsExternalBracketAccessor(Setter);
  3458. IndexExpr:=GetPasPropertyIndex(PropEl);
  3459. PropArgs:=GetPasPropertyArgs(PropEl);
  3460. if GetterIsBracketAccessor then
  3461. begin
  3462. if (PropArgs.Count<>1) or (IndexExpr<>nil) then
  3463. RaiseMsg(20170403001743,nBracketAccessorOfExternalClassMustHaveOneParameter,
  3464. sBracketAccessorOfExternalClassMustHaveOneParameter,
  3465. [],PropEl);
  3466. end;
  3467. if SetterIsBracketAccessor then
  3468. begin
  3469. if (PropArgs.Count<>1) or (IndexExpr<>nil) then
  3470. RaiseMsg(20170403001806,nBracketAccessorOfExternalClassMustHaveOneParameter,
  3471. sBracketAccessorOfExternalClassMustHaveOneParameter,
  3472. [],PropEl);
  3473. end;
  3474. if GetterIsBracketAccessor or SetterIsBracketAccessor then
  3475. begin
  3476. Arg:=TPasArgument(PropArgs[0]);
  3477. if not (Arg.Access in [argDefault,argConst]) then
  3478. RaiseMsg(20170403090225,nXExpectedButYFound,sXExpectedButYFound,
  3479. ['default or "const"',AccessNames[Arg.Access]],PropEl);
  3480. ComputeElement(Arg,ArgResolved,[rcType],Arg);
  3481. if not (ArgResolved.BaseType in (btAllJSInteger+btAllJSStringAndChars+btAllJSBooleans+btAllJSFloats)) then
  3482. RaiseMsg(20170403090628,nIncompatibleTypesGotExpected,
  3483. sIncompatibleTypesGotExpected,
  3484. [GetResolverResultDescription(ArgResolved,true),'string'],Arg);
  3485. end;
  3486. end;
  3487. procedure TPas2JSResolver.CheckExternalClassConstructor(Ref: TResolvedReference
  3488. );
  3489. var
  3490. TypeEl: TPasType;
  3491. begin
  3492. if not (Ref.Context is TResolvedRefCtxConstructor) then
  3493. RaiseMsg(20180511165144,nJSNewNotSupported,sJSNewNotSupported,[],Ref.Element);
  3494. TypeEl:=TResolvedRefCtxConstructor(Ref.Context).Typ;
  3495. if TypeEl.ClassType=TPasClassType then
  3496. begin
  3497. // ClassType.new
  3498. if not TPasClassType(TypeEl).IsExternal then
  3499. RaiseMsg(20180511165316,nJSNewNotSupported,sJSNewNotSupported,[],Ref.Element);
  3500. end
  3501. else if TypeEl.ClassType=TPasClassOfType then
  3502. begin
  3503. TypeEl:=ResolveAliasType(TPasClassOfType(TypeEl).DestType);
  3504. if TypeEl.ClassType=TPasClassType then
  3505. begin
  3506. // ClassOfVar.new
  3507. if not TPasClassType(TypeEl).IsExternal then
  3508. RaiseMsg(20180511175309,nJSNewNotSupported,sJSNewNotSupported,[],Ref.Element);
  3509. end;
  3510. end;
  3511. end;
  3512. procedure TPas2JSResolver.CheckConditionExpr(El: TPasExpr;
  3513. const ResolvedEl: TPasResolverResult);
  3514. begin
  3515. if (ResolvedEl.BaseType=btCustom) and (IsJSBaseType(ResolvedEl,pbtJSValue)) then
  3516. exit;
  3517. inherited CheckConditionExpr(El, ResolvedEl);
  3518. end;
  3519. procedure TPas2JSResolver.CheckNewInstanceFunction(ClassScope: TPas2JSClassScope
  3520. );
  3521. var
  3522. Proc: TPasClassFunction;
  3523. Args: TFPList;
  3524. Arg: TPasArgument;
  3525. ResolvedArg: TPasResolverResult;
  3526. begin
  3527. Proc:=ClassScope.NewInstanceFunction;
  3528. // proc modifiers override and external were already checked
  3529. // visibility was already checked
  3530. // function result type was already checked
  3531. if not Proc.IsVirtual then
  3532. RaiseMsg(20170324231040,nNewInstanceFunctionMustBeVirtual,
  3533. sNewInstanceFunctionMustBeVirtual,[],Proc);
  3534. Args:=Proc.ProcType.Args;
  3535. if Args.Count<2 then
  3536. RaiseMsg(20170324232247,nNewInstanceFunctionMustHaveTwoParameters,
  3537. sNewInstanceFunctionMustHaveTwoParameters,[],Proc.ProcType);
  3538. // first param must be a string
  3539. Arg:=TPasArgument(Args[0]);
  3540. if Arg.Access<>argDefault then
  3541. RaiseMsg(20170324232655,nIncompatibleTypeArgNo,sIncompatibleTypeArgNo,
  3542. ['1',AccessNames[Arg.Access],'default (none)'],Arg);
  3543. if Arg.ArgType=nil then
  3544. RaiseMsg(20170324233201,nIncompatibleTypeArgNo,sIncompatibleTypeArgNo,
  3545. ['1','untyped','String'],Arg);
  3546. ComputeElement(Arg.ArgType,ResolvedArg,[rcType]);
  3547. if ResolvedArg.BaseType<>btString then
  3548. RaiseMsg(20170324233348,nIncompatibleTypeArgNo,sIncompatibleTypeArgNo,
  3549. ['1',GetResolverResultDescription(ResolvedArg),'String'],Arg);
  3550. // second param must be const untyped
  3551. Arg:=TPasArgument(Args[1]);
  3552. if Arg.Access<>argConst then
  3553. RaiseMsg(20170324233457,nIncompatibleTypeArgNo,sIncompatibleTypeArgNo,
  3554. ['2',AccessNames[Arg.Access],'const'],Arg);
  3555. if Arg.ArgType<>nil then
  3556. RaiseMsg(20170324233508,nIncompatibleTypeArgNo,sIncompatibleTypeArgNo,
  3557. ['2','type','untyped'],Arg);
  3558. end;
  3559. function TPas2JSResolver.AddExternalName(const aName: string; El: TPasElement
  3560. ): TPasIdentifier;
  3561. var
  3562. Item: TPasIdentifier;
  3563. begin
  3564. //writeln('TPas2JSResolver.AddExternalIdentifier Name="',aName,'" El=',GetObjName(El));
  3565. Item:=TPasIdentifier.Create;
  3566. Item.Identifier:=aName;
  3567. Item.Element:=El;
  3568. InternalAdd(Item);
  3569. //writeln('TPas2JSResolver.AddExternalIdentifier END');
  3570. Result:=Item;
  3571. end;
  3572. function TPas2JSResolver.FindExternalName(const aName: String
  3573. ): TPasIdentifier;
  3574. begin
  3575. Result:=TPasIdentifier(FExternalNames.Find(aName));
  3576. {$IFDEF VerbosePasResolver}
  3577. {AllowWriteln}
  3578. if (Result<>nil) and (Result.Owner<>Self) then
  3579. begin
  3580. writeln('TPas2JSResolver.FindExternalName Result.Owner<>Self Owner='+GetObjName(Result.Owner));
  3581. raise Exception.Create('20170322235814');
  3582. end;
  3583. {AllowWriteln-}
  3584. {$ENDIF}
  3585. end;
  3586. procedure TPas2JSResolver.AddExternalPath(aName: string; El: TPasElement);
  3587. // add aName and the first identifier of aName
  3588. var
  3589. p: integer;
  3590. begin
  3591. aName:=Trim(aName);
  3592. if aName='' then exit;
  3593. AddExternalName(aName,El);
  3594. p:=1;
  3595. while (p<=length(aName)) and (aName[p] in ['a'..'z','A'..'Z','0'..'9','_','$']) do
  3596. inc(p);
  3597. if p>length(aName) then exit;
  3598. AddExternalName(LeftStr(aName,p-1),El);
  3599. end;
  3600. procedure TPas2JSResolver.ClearElementData;
  3601. var
  3602. Data, Next: TPas2JsElementData;
  3603. begin
  3604. Data:=FFirstElementData;
  3605. while Data<>nil do
  3606. begin
  3607. Next:=Data.Next;
  3608. Data.Free;
  3609. Data:=Next;
  3610. end;
  3611. FFirstElementData:=nil;
  3612. FLastElementData:=nil;
  3613. FExternalNames.ForEachCall(@OnClearHashItem,nil);
  3614. FExternalNames.Clear;
  3615. end;
  3616. function TPas2JSResolver.GenerateGUID(El: TPasClassType): string;
  3617. var
  3618. Name: String;
  3619. i, BytePos, BitPos, v: Integer;
  3620. Member: TPasElement;
  3621. Bytes: array[0..15] of byte;
  3622. List: TStringList;
  3623. Scope: TPas2JSClassScope;
  3624. begin
  3625. Name:=El.PathName;
  3626. Scope:=TPas2JSClassScope(El.CustomData);
  3627. if Scope.AncestorScope<>nil then
  3628. begin
  3629. // use ancestor GUID as start
  3630. Name:=TPas2JSClassScope(Scope.AncestorScope).GUID+Name;
  3631. end;
  3632. List:=TStringList.Create;
  3633. for i:=0 to El.Members.Count-1 do
  3634. begin
  3635. Member:=TPasElement(El.Members[i]);
  3636. if Member is TPasProcedure then
  3637. List.Add(Member.Name);
  3638. end;
  3639. List.Sort;
  3640. for i:=0 to List.Count-1 do
  3641. Name:=Name+','+List[i];
  3642. List.Free;
  3643. BytePos:=0;
  3644. BitPos:=0;
  3645. {$IFDEF fpc}
  3646. FillByte({%H-}Bytes[0],16,0);
  3647. {$ENDIF}
  3648. for i:=1 to length(Name) do
  3649. begin
  3650. // read 16-bit
  3651. v:=(Bytes[BytePos] shl 8)+Bytes[(BytePos+1) and 15];
  3652. // change some bits
  3653. v:=v+(ord(Name[i]) shl (11-BitPos));
  3654. // write 16 bit
  3655. Bytes[BytePos]:=(v shr 8) and $ff;
  3656. Bytes[(BytePos+1) and 15]:=v and $ff;
  3657. inc(BitPos,5);
  3658. if BitPos>7 then
  3659. begin
  3660. dec(BitPos,8);
  3661. BytePos:=(BytePos+1) and 15;
  3662. end;
  3663. end;
  3664. // set version 3
  3665. Bytes[6]:=(Bytes[6] and $f)+(3 shl 4);
  3666. // set variant 2
  3667. Bytes[8]:=(Bytes[8] and $3f)+(2 shl 6);
  3668. Result:='{';
  3669. for i:=0 to 3 do Result:=Result+HexStr(Bytes[i],2);
  3670. Result:=Result+'-';
  3671. for i:=4 to 5 do Result:=Result+HexStr(Bytes[i],2);
  3672. Result:=Result+'-';
  3673. for i:=6 to 7 do Result:=Result+HexStr(Bytes[i],2);
  3674. Result:=Result+'-';
  3675. for i:=8 to 9 do Result:=Result+HexStr(Bytes[i],2);
  3676. Result:=Result+'-';
  3677. for i:=10 to 15 do Result:=Result+HexStr(Bytes[i],2);
  3678. Result:=Result+'}';
  3679. end;
  3680. function TPas2JSResolver.AddJSBaseType(const aName: string; Typ: TPas2jsBaseType
  3681. ): TResElDataPas2JSBaseType;
  3682. var
  3683. El: TPasUnresolvedSymbolRef;
  3684. begin
  3685. El:=AddCustomBaseType(aName,TResElDataPas2JSBaseType);
  3686. if Typ<>pbtNone then
  3687. FJSBaseTypes[Typ]:=El;
  3688. Result:=TResElDataPas2JSBaseType(El.CustomData);
  3689. Result.JSBaseType:=Typ;
  3690. end;
  3691. function TPas2JSResolver.CheckAssignCompatibilityCustom(const LHS,
  3692. RHS: TPasResolverResult; ErrorEl: TPasElement; RaiseOnIncompatible: boolean;
  3693. var Handled: boolean): integer;
  3694. var
  3695. LeftBaseType: TPas2jsBaseType;
  3696. LArray: TPasArrayType;
  3697. ElTypeResolved: TPasResolverResult;
  3698. LTypeEl, RTypeEl: TPasType;
  3699. TIName: String;
  3700. begin
  3701. Result:=cIncompatible;
  3702. //writeln('TPas2JSResolver.CheckAssignCompatibilityCustom ',GetResolverResultDbg(LHS));
  3703. if LHS.BaseType=btCustom then
  3704. begin
  3705. if not (LHS.LoTypeEl is TPasUnresolvedSymbolRef) then
  3706. begin
  3707. {$IFDEF VerbosePas2JS}
  3708. writeln('TPas2JSResolver.CheckAssignCompatibilityCustomBaseType LHS=',GetResolverResultDbg(LHS));
  3709. {$ENDIF}
  3710. RaiseInternalError(20170325114554);
  3711. end;
  3712. if not (LHS.LoTypeEl.CustomData is TResElDataPas2JSBaseType) then
  3713. exit;
  3714. Handled:=true;
  3715. LeftBaseType:=TResElDataPas2JSBaseType(LHS.LoTypeEl.CustomData).JSBaseType;
  3716. if LeftBaseType=pbtJSValue then
  3717. begin
  3718. // assign to a JSValue
  3719. if rrfReadable in RHS.Flags then
  3720. begin
  3721. // RHS is a value
  3722. if (RHS.BaseType in btAllJSValueSrcTypes) then
  3723. Result:=cJSValueConversion // type cast to JSValue
  3724. else if RHS.BaseType=btCustom then
  3725. begin
  3726. if IsJSBaseType(RHS,pbtJSValue) then
  3727. Result:=cExact;
  3728. end
  3729. else if RHS.BaseType=btContext then
  3730. Result:=cJSValueConversion;
  3731. end
  3732. else if RHS.BaseType=btContext then
  3733. begin
  3734. // RHS is not a value
  3735. if RHS.IdentEl<>nil then
  3736. begin
  3737. if RHS.IdentEl.ClassType=TPasClassType then
  3738. Result:=cJSValueConversion; // RHS is a class type
  3739. end;
  3740. end;
  3741. end;
  3742. end
  3743. else if (LHS.BaseType=btContext) then
  3744. begin
  3745. LTypeEl:=LHS.LoTypeEl;
  3746. RTypeEl:=RHS.LoTypeEl;
  3747. if (LTypeEl.ClassType=TPasArrayType)
  3748. and (rrfReadable in RHS.Flags) then
  3749. begin
  3750. LArray:=TPasArrayType(LTypeEl);
  3751. if length(LArray.Ranges)>0 then
  3752. exit;
  3753. if (RHS.BaseType<>btContext) or (RTypeEl.ClassType<>TPasArrayType) then
  3754. exit;
  3755. ComputeElement(LArray.ElType,ElTypeResolved,[rcType]);
  3756. if IsJSBaseType(ElTypeResolved,pbtJSValue) then
  3757. begin
  3758. // array of jsvalue := array
  3759. Handled:=true;
  3760. Result:=cJSValueConversion;
  3761. end;
  3762. end
  3763. else if (LTypeEl.ClassType=TPasClassType)
  3764. and (rrfReadable in RHS.Flags)
  3765. and (RHS.BaseType=btPointer)
  3766. and IsSameType(RTypeEl,BaseTypes[btPointer],prraNone)
  3767. then
  3768. begin
  3769. TIName:=Pas2JSBuiltInNames[pbivnRTL]+'.'+Pas2JSBuiltInNames[pbitnTI];
  3770. if IsExternalClass_Name(TPasClassType(LTypeEl),TIName) then
  3771. begin
  3772. // aTTypeInfo:=aPointer
  3773. Handled:=true;
  3774. Result:=cTypeConversion;
  3775. end;
  3776. end;
  3777. end;
  3778. if RaiseOnIncompatible then ;
  3779. if ErrorEl=nil then ;
  3780. end;
  3781. function TPas2JSResolver.CheckTypeCastClassInstanceToClass(const FromClassRes,
  3782. ToClassRes: TPasResolverResult; ErrorEl: TPasElement): integer;
  3783. var
  3784. ToClass: TPasClassType;
  3785. ClassScope: TPasClassScope;
  3786. begin
  3787. if FromClassRes.BaseType=btNil then exit(cExact);
  3788. ToClass:=ToClassRes.LoTypeEl as TPasClassType;
  3789. ClassScope:=ToClass.CustomData as TPasClassScope;
  3790. if ClassScope.AncestorScope=nil then
  3791. // type cast to root class
  3792. Result:=cTypeConversion+1
  3793. else
  3794. Result:=cIncompatible;
  3795. if ErrorEl=nil then ;
  3796. end;
  3797. function TPas2JSResolver.CheckEqualCompatibilityCustomType(const LHS,
  3798. RHS: TPasResolverResult; ErrorEl: TPasElement; RaiseOnIncompatible: boolean
  3799. ): integer;
  3800. var
  3801. LeftBaseType: TPas2jsBaseType;
  3802. begin
  3803. Result:=cIncompatible;
  3804. if LHS.BaseType=btCustom then
  3805. begin
  3806. if not (LHS.LoTypeEl is TPasUnresolvedSymbolRef) then
  3807. begin
  3808. {$IFDEF VerbosePas2JS}
  3809. writeln('TPas2JSResolver.CheckEqualCompatibilityCustomType LHS=',GetResolverResultDbg(LHS));
  3810. {$ENDIF}
  3811. RaiseInternalError(20170330005841);
  3812. end;
  3813. if not (LHS.LoTypeEl.CustomData is TResElDataPas2JSBaseType) then
  3814. exit;
  3815. LeftBaseType:=TResElDataPas2JSBaseType(LHS.LoTypeEl.CustomData).JSBaseType;
  3816. if LeftBaseType=pbtJSValue then
  3817. begin
  3818. if (rrfReadable in LHS.Flags) then
  3819. begin
  3820. if (rrfReadable in RHS.Flags) then
  3821. begin
  3822. if RHS.BaseType in btAllJSValueSrcTypes then
  3823. Result:=cJSValueConversion
  3824. else if RHS.BaseType=btCustom then
  3825. begin
  3826. if IsJSBaseType(RHS,pbtJSValue) then
  3827. Result:=cExact;
  3828. end
  3829. else if RHS.BaseType=btContext then
  3830. Result:=cJSValueConversion;
  3831. end
  3832. else if RHS.BaseType=btContext then
  3833. begin
  3834. // right side is not a value
  3835. if RHS.IdentEl<>nil then
  3836. begin
  3837. if RHS.IdentEl.ClassType=TPasClassType then
  3838. Result:=cJSValueConversion; // RHS is a class
  3839. end;
  3840. end;
  3841. end;
  3842. end;
  3843. end
  3844. else if RHS.BaseType=btCustom then
  3845. exit(CheckEqualCompatibilityCustomType(RHS,LHS,ErrorEl,RaiseOnIncompatible))
  3846. else
  3847. RaiseInternalError(20170330005725);
  3848. end;
  3849. function TPas2JSResolver.CheckForIn(Loop: TPasImplForLoop; const VarResolved,
  3850. InResolved: TPasResolverResult): boolean;
  3851. var
  3852. TypeEl: TPasType;
  3853. ArgResolved, LengthResolved, PropResultResolved: TPasResolverResult;
  3854. begin
  3855. if InResolved.BaseType=btCustom then
  3856. begin
  3857. if IsJSBaseType(InResolved,pbtJSValue,true) then
  3858. begin
  3859. // for string in jsvalue do ...
  3860. if not (VarResolved.BaseType in btAllStrings) then
  3861. RaiseXExpectedButYFound(20180423185800,'string',GetResolverResultDescription(VarResolved,true),Loop.StartExpr);
  3862. exit(true);
  3863. end;
  3864. end
  3865. else if InResolved.BaseType=btContext then
  3866. begin
  3867. TypeEl:=InResolved.LoTypeEl;
  3868. if (TypeEl.ClassType=TPasClassType) and TPasClassType(TypeEl).IsExternal then
  3869. begin
  3870. // for key in JSClass do ...
  3871. if IsForInExtArray(Loop,VarResolved,InResolved,ArgResolved,
  3872. LengthResolved,PropResultResolved) then
  3873. exit(true);
  3874. // for key in JSObject do
  3875. if not (VarResolved.BaseType in btAllStrings) then
  3876. RaiseXExpectedButYFound(20180423191611,'string',GetResolverResultDescription(VarResolved,true),Loop.StartExpr);
  3877. exit(true);
  3878. end;
  3879. end;
  3880. Result:=false;
  3881. end;
  3882. procedure TPas2JSResolver.ComputeUnaryNot(El: TUnaryExpr;
  3883. var ResolvedEl: TPasResolverResult; Flags: TPasResolverComputeFlags);
  3884. begin
  3885. if ResolvedEl.BaseType=btCustom then
  3886. begin
  3887. if IsJSBaseType(ResolvedEl,pbtJSValue,true) then
  3888. begin
  3889. SetResolverValueExpr(ResolvedEl,btBoolean,BaseTypes[btBoolean],BaseTypes[btBoolean],
  3890. El,[rrfReadable]);
  3891. exit;
  3892. end;
  3893. end;
  3894. inherited ComputeUnaryNot(El, ResolvedEl, Flags);
  3895. end;
  3896. procedure TPas2JSResolver.ComputeBinaryExprRes(Bin: TBinaryExpr; out
  3897. ResolvedEl: TPasResolverResult; Flags: TPasResolverComputeFlags;
  3898. var LeftResolved, RightResolved: TPasResolverResult);
  3899. procedure SetBaseType(BaseType: TResolverBaseType);
  3900. begin
  3901. SetResolverValueExpr(ResolvedEl,BaseType,BaseTypes[BaseType],BaseTypes[BaseType],
  3902. Bin,[rrfReadable]);
  3903. end;
  3904. var
  3905. RightTypeEl: TPasType;
  3906. begin
  3907. if (LeftResolved.BaseType=btCustom)
  3908. or (RightResolved.BaseType=btCustom) then
  3909. case Bin.OpCode of
  3910. eopIs:
  3911. if IsJSBaseType(LeftResolved,pbtJSValue,true) then
  3912. begin
  3913. // aJSValue is x
  3914. if (RightResolved.IdentEl is TPasType)
  3915. and (ResolveAliasType(TPasType(RightResolved.IdentEl)) is TPasClassType) then
  3916. begin
  3917. // e.g. if aJSValue is TObject then ;
  3918. SetBaseType(btBoolean);
  3919. exit;
  3920. end;
  3921. RightTypeEl:=RightResolved.LoTypeEl;
  3922. if (RightTypeEl is TPasClassOfType) then
  3923. begin
  3924. // e.g. if aJSValue is TClass then ;
  3925. // or if aJSValue is ImageClass then ;
  3926. SetBaseType(btBoolean);
  3927. exit;
  3928. end;
  3929. end;
  3930. end;
  3931. inherited ComputeBinaryExprRes(Bin, ResolvedEl, Flags, LeftResolved,
  3932. RightResolved);
  3933. end;
  3934. procedure TPas2JSResolver.BI_TypeInfo_OnGetCallResult(
  3935. Proc: TResElDataBuiltInProc; Params: TParamsExpr; out
  3936. ResolvedEl: TPasResolverResult);
  3937. // if an external type with the right name and external name is in scope return
  3938. // that, otherwise btPointer
  3939. var
  3940. Param: TPasExpr;
  3941. ParamResolved: TPasResolverResult;
  3942. C: TClass;
  3943. TIName: String;
  3944. FindData: TPRFindData;
  3945. Abort: boolean;
  3946. bt: TResolverBaseType;
  3947. jbt: TPas2jsBaseType;
  3948. TypeEl: TPasType;
  3949. FoundClass: TPasClassType;
  3950. ScopeDepth: Integer;
  3951. begin
  3952. Param:=Params.Params[0];
  3953. ComputeElement(Param,ParamResolved,[rcNoImplicitProc]);
  3954. if ParamResolved.LoTypeEl=nil then
  3955. RaiseInternalError(20170413090726);
  3956. if (ParamResolved.BaseType=btProc) and (ParamResolved.IdentEl is TPasFunction) then
  3957. begin
  3958. // typeinfo of function result -> resolve once
  3959. TypeEl:=TPasFunction(ParamResolved.IdentEl).FuncType.ResultEl.ResultType;
  3960. ComputeElement(TypeEl,ParamResolved,[rcNoImplicitProc]);
  3961. Include(ParamResolved.Flags,rrfReadable);
  3962. if ParamResolved.LoTypeEl=nil then
  3963. RaiseInternalError(20170421124923);
  3964. end;
  3965. TypeEl:=ParamResolved.LoTypeEl;
  3966. C:=TypeEl.ClassType;
  3967. TIName:='';
  3968. //writeln('TPas2JSResolver.BI_TypeInfo_OnGetCallResult TypeEl=',GetObjName(TypeEl));
  3969. if C=TPasUnresolvedSymbolRef then
  3970. begin
  3971. if TypeEl.CustomData is TResElDataPas2JSBaseType then
  3972. begin
  3973. jbt:=TResElDataPas2JSBaseType(TypeEl.CustomData).JSBaseType;
  3974. if jbt=pbtJSValue then
  3975. TIName:=Pas2JSBuiltInNames[pbitnTI];
  3976. end
  3977. else if TypeEl.CustomData is TResElDataBaseType then
  3978. begin
  3979. bt:=TResElDataBaseType(TypeEl.CustomData).BaseType;
  3980. if bt in (btAllJSInteger+[btCurrency]) then
  3981. TIName:=Pas2JSBuiltInNames[pbitnTIInteger]
  3982. else if bt in [btString,btChar,btDouble,btBoolean] then
  3983. TIName:=Pas2JSBuiltInNames[pbitnTI]
  3984. else if bt=btPointer then
  3985. TIName:=Pas2JSBuiltInNames[pbitnTIPointer];
  3986. end;
  3987. end
  3988. else if ParamResolved.BaseType=btContext then
  3989. begin
  3990. if C=TPasEnumType then
  3991. TIName:=Pas2JSBuiltInNames[pbitnTIEnum]
  3992. else if C=TPasSetType then
  3993. TIName:=Pas2JSBuiltInNames[pbitnTISet]
  3994. else if C.InheritsFrom(TPasProcedureType) then
  3995. begin
  3996. if TPasProcedureType(TypeEl).IsReferenceTo then
  3997. TIName:=Pas2JSBuiltInNames[pbitnTIRefToProcVar]
  3998. else if TPasProcedureType(TypeEl).IsOfObject then
  3999. TIName:=Pas2JSBuiltInNames[pbitnTIMethodVar]
  4000. else
  4001. TIName:=Pas2JSBuiltInNames[pbitnTIProcVar];
  4002. end
  4003. else if C=TPasRecordType then
  4004. TIName:=Pas2JSBuiltInNames[pbitnTIRecord]
  4005. else if C=TPasClassType then
  4006. case TPasClassType(TypeEl).ObjKind of
  4007. okClass: TIName:=Pas2JSBuiltInNames[pbitnTIClass];
  4008. okInterface: TIName:=Pas2JSBuiltInNames[pbitnTIInterface];
  4009. else
  4010. RaiseNotYetImplemented(20180328195807,Param);
  4011. end
  4012. else if C=TPasClassOfType then
  4013. begin
  4014. if rrfReadable in ParamResolved.Flags then
  4015. TIName:=Pas2JSBuiltInNames[pbitnTIClass]
  4016. else
  4017. TIName:=Pas2JSBuiltInNames[pbitnTIClassRef];
  4018. end
  4019. else if C=TPasArrayType then
  4020. begin
  4021. if length(TPasArrayType(TypeEl).Ranges)>0 then
  4022. TIName:=Pas2JSBuiltInNames[pbitnTIStaticArray]
  4023. else
  4024. TIName:=Pas2JSBuiltInNames[pbitnTIDynArray];
  4025. end
  4026. else if C=TPasPointerType then
  4027. TIName:=Pas2JSBuiltInNames[pbitnTIPointer];
  4028. end
  4029. else if ParamResolved.BaseType=btSet then
  4030. begin
  4031. if ParamResolved.IdentEl is TPasSetType then
  4032. TIName:=Pas2JSBuiltInNames[pbitnTISet];
  4033. end
  4034. else if ParamResolved.BaseType=btRange then
  4035. begin
  4036. ConvertRangeToElement(ParamResolved);
  4037. if ParamResolved.BaseType in btAllJSInteger then
  4038. TIName:=Pas2JSBuiltInNames[pbitnTIInteger]
  4039. else if ParamResolved.BaseType in [btChar,btBoolean] then
  4040. TIName:=Pas2JSBuiltInNames[pbitnTI]
  4041. else if ParamResolved.BaseType=btContext then
  4042. begin
  4043. TypeEl:=ParamResolved.LoTypeEl;
  4044. C:=TypeEl.ClassType;
  4045. if C=TPasEnumType then
  4046. TIName:=Pas2JSBuiltInNames[pbitnTIEnum];
  4047. end;
  4048. end
  4049. else if C=TPasRangeType then
  4050. begin
  4051. if ParamResolved.BaseType in btAllJSInteger then
  4052. TIName:=Pas2JSBuiltInNames[pbitnTIInteger]
  4053. else if ParamResolved.BaseType in [btChar,btBoolean] then
  4054. TIName:=Pas2JSBuiltInNames[pbitnTI]
  4055. end;
  4056. //writeln('TPas2JSResolver.BI_TypeInfo_OnGetCallResult TIName=',TIName);
  4057. if TIName='' then
  4058. begin
  4059. {$IFDEF VerbosePas2JS}
  4060. writeln('TPas2JSResolver.BI_TypeInfo_OnGetCallResult ',GetResolverResultDbg(ParamResolved));
  4061. {$ENDIF}
  4062. RaiseNotYetImplemented(20170413091852,Param);
  4063. end;
  4064. // search for TIName
  4065. ResetSubScopes(ScopeDepth);
  4066. FindData:=Default(TPRFindData);
  4067. FindData.ErrorPosEl:=Params;
  4068. Abort:=false;
  4069. IterateElements(TIName,@OnFindFirstElement,@FindData,Abort);
  4070. RestoreSubScopes(ScopeDepth);
  4071. {$IFDEF VerbosePas2JS}
  4072. writeln('TPas2JSResolver.BI_TypeInfo_OnGetCallResult TIName="',TIName,'" FindData.Found="',GetObjName(FindData.Found),'"');
  4073. {$ENDIF}
  4074. if FindData.Found is TPasType then
  4075. begin
  4076. TypeEl:=ResolveAliasType(TPasType(FindData.Found));
  4077. if TypeEl.ClassType=TPasClassType then
  4078. begin
  4079. FoundClass:=TPasClassType(FindData.Found);
  4080. if FoundClass.IsExternal
  4081. and (FoundClass.ExternalName=Pas2JSBuiltInNames[pbivnRTL]+'.'+TIName) then
  4082. begin
  4083. // use external class definition
  4084. {$IFDEF VerbosePas2JS}
  4085. writeln('TPas2JSResolver.BI_TypeInfo_OnGetCallResult FindData.Found="',FindData.Found.ParentPath,'"');
  4086. {$ENDIF}
  4087. SetResolverTypeExpr(ResolvedEl,btContext,FoundClass,TPasType(FindData.Found),[rrfReadable]);
  4088. exit;
  4089. end;
  4090. end;
  4091. end;
  4092. // default: btPointer
  4093. SetResolverTypeExpr(ResolvedEl,btPointer,BaseTypes[btPointer],BaseTypes[btPointer],[rrfReadable]);
  4094. if Proc=nil then ;
  4095. end;
  4096. function TPas2JSResolver.BI_Debugger_OnGetCallCompatibility(
  4097. Proc: TResElDataBuiltInProc; Expr: TPasExpr; RaiseOnError: boolean): integer;
  4098. // debugger;
  4099. begin
  4100. if Expr is TParamsExpr then
  4101. Result:=CheckBuiltInMaxParamCount(Proc,TParamsExpr(Expr),0,RaiseOnError)
  4102. else
  4103. Result:=cExact;
  4104. end;
  4105. constructor TPas2JSResolver.Create;
  4106. var
  4107. bt: TPas2jsBaseType;
  4108. begin
  4109. inherited;
  4110. // prefer overloads of GUID with string
  4111. cInterfaceToTGUID:=cTypeConversion+2;
  4112. cInterfaceToString:=cTypeConversion+1;
  4113. {$IFDEF FPC_HAS_CPSTRING}
  4114. ExprEvaluator.DefaultStringCodePage:=CP_UTF8;
  4115. {$ENDIF}
  4116. FExternalNames:=TPasResHashList.Create;
  4117. StoreSrcColumns:=true;
  4118. Options:=Options+DefaultPasResolverOptions;
  4119. ScopeClass_Class:=TPas2JSClassScope;
  4120. ScopeClass_InitialFinalization:=TPas2JSInitialFinalizationScope;
  4121. ScopeClass_Module:=TPas2JSModuleScope;
  4122. ScopeClass_Procedure:=TPas2JSProcedureScope;
  4123. ScopeClass_Section:=TPas2JSSectionScope;
  4124. ScopeClass_WithExpr:=TPas2JSWithExprScope;
  4125. for bt in [pbtJSValue] do
  4126. AddJSBaseType(Pas2jsBaseTypeNames[bt],bt);
  4127. AnonymousElTypePostfix:=Pas2JSBuiltInNames[pbitnAnonymousPostfix];
  4128. BaseTypeChar:=btWideChar;
  4129. BaseTypeString:=btUnicodeString;
  4130. BaseTypeLength:=btIntDouble;
  4131. end;
  4132. destructor TPas2JSResolver.Destroy;
  4133. begin
  4134. ClearElementData;
  4135. {$IFDEF pas2js}
  4136. FExternalNames:=nil;
  4137. {$ELSE}
  4138. FreeAndNil(FExternalNames);
  4139. {$ENDIF}
  4140. FreeAndNil(FOverloadScopes);
  4141. inherited Destroy;
  4142. end;
  4143. procedure TPas2JSResolver.ClearBuiltInIdentifiers;
  4144. var
  4145. bt: TPas2jsBaseType;
  4146. begin
  4147. inherited ClearBuiltInIdentifiers;
  4148. for bt in TPas2jsBaseType do
  4149. ReleaseAndNil(TPasElement(FJSBaseTypes[bt]){$IFDEF CheckPasTreeRefCount},'TPasResolver.AddCustomBaseType'{$ENDIF});
  4150. end;
  4151. function TPas2JSResolver.IsJSBaseType(TypeEl: TPasType; Typ: TPas2jsBaseType
  4152. ): boolean;
  4153. begin
  4154. Result:=(TypeEl is TPasUnresolvedSymbolRef)
  4155. and (CompareText(TypeEl.Name,Pas2jsBaseTypeNames[Typ])=0)
  4156. and (TypeEl.CustomData is TResElDataPas2JSBaseType);
  4157. end;
  4158. function TPas2JSResolver.IsJSBaseType(const TypeResolved: TPasResolverResult;
  4159. Typ: TPas2jsBaseType; HasValue: boolean): boolean;
  4160. begin
  4161. if (TypeResolved.BaseType<>btCustom) or not IsJSBaseType(TypeResolved.LoTypeEl,Typ) then
  4162. exit(false);
  4163. if HasValue and not (rrfReadable in TypeResolved.Flags) then
  4164. exit(false);
  4165. Result:=true;
  4166. end;
  4167. procedure TPas2JSResolver.AddObjFPCBuiltInIdentifiers(
  4168. const TheBaseTypes: TResolveBaseTypes;
  4169. const TheBaseProcs: TResolverBuiltInProcs);
  4170. var
  4171. InvalidTypes: TResolveBaseTypes;
  4172. bt: TResolverBaseType;
  4173. InvalidProcs: TResolverBuiltInProcs;
  4174. bf: TResolverBuiltInProc;
  4175. begin
  4176. InvalidTypes:=TheBaseTypes-btAllJSBaseTypes;
  4177. if InvalidTypes<>[] then
  4178. for bt in InvalidTypes do
  4179. RaiseInternalError(20170409180202,BaseTypeNames[bt]);
  4180. InvalidProcs:=TheBaseProcs-bfAllJSBaseProcs;
  4181. if InvalidProcs<>[] then
  4182. for bf in InvalidProcs do
  4183. RaiseInternalError(20170409180246,ResolverBuiltInProcNames[bf]);
  4184. inherited AddObjFPCBuiltInIdentifiers(TheBaseTypes-[btUIntDouble,btIntDouble],TheBaseProcs);
  4185. if btUIntDouble in TheBaseTypes then
  4186. AddBaseType(Pas2JSBuiltInNames[pbitnUIntDouble],btUIntDouble);
  4187. if btIntDouble in TheBaseTypes then
  4188. AddBaseType(Pas2JSBuiltInNames[pbitnIntDouble],btIntDouble);
  4189. AddBuiltInProc('Debugger','procedure Debugger',
  4190. @BI_Debugger_OnGetCallCompatibility,nil,
  4191. nil,nil,bfCustom,[bipfCanBeStatement]);
  4192. end;
  4193. function TPas2JSResolver.CheckTypeCastRes(const FromResolved,
  4194. ToResolved: TPasResolverResult; ErrorEl: TPasElement; RaiseOnError: boolean
  4195. ): integer;
  4196. function Incompatible(Id: TMaxPrecInt): integer;
  4197. begin
  4198. if RaiseOnError then
  4199. RaiseIncompatibleTypeRes(Id,nIllegalTypeConversionTo,
  4200. [],FromResolved,ToResolved,ErrorEl);
  4201. Result:=cIncompatible;
  4202. end;
  4203. var
  4204. JSBaseType: TPas2jsBaseType;
  4205. C: TClass;
  4206. ToClass: TPasClassType;
  4207. ToTypeEl, FromTypeEl: TPasType;
  4208. begin
  4209. Result:=cIncompatible;
  4210. {$IFDEF VerbosePas2JS}
  4211. writeln('TPas2JSResolver.CheckTypeCastRes To=',GetResolverResultDbg(ToResolved),' From=',GetResolverResultDbg(FromResolved));
  4212. {$ENDIF}
  4213. if rrfReadable in FromResolved.Flags then
  4214. begin
  4215. if (ToResolved.BaseType=btCustom) then
  4216. begin
  4217. ToTypeEl:=ToResolved.LoTypeEl;
  4218. if not (ToTypeEl is TPasUnresolvedSymbolRef) then
  4219. RaiseInternalError(20170325142826);
  4220. if (ToTypeEl.CustomData is TResElDataPas2JSBaseType) then
  4221. begin
  4222. // type cast to pas2js type, e.g. JSValue(V)
  4223. JSBaseType:=TResElDataPas2JSBaseType(ToTypeEl.CustomData).JSBaseType;
  4224. if JSBaseType=pbtJSValue then
  4225. begin
  4226. if (FromResolved.BaseType in btAllJSValueSrcTypes) then
  4227. Result:=cCompatible // type cast to JSValue
  4228. else if FromResolved.BaseType=btCustom then
  4229. begin
  4230. if IsJSBaseType(FromResolved,pbtJSValue) then
  4231. Result:=cExact;
  4232. end
  4233. else if FromResolved.BaseType=btContext then
  4234. Result:=cCompatible;
  4235. end;
  4236. exit;
  4237. end;
  4238. end
  4239. else if FromResolved.BaseType=btCustom then
  4240. begin
  4241. FromTypeEl:=FromResolved.LoTypeEl;
  4242. if not (FromTypeEl is TPasUnresolvedSymbolRef) then
  4243. RaiseInternalError(20170325143016);
  4244. if (FromTypeEl.CustomData is TResElDataPas2JSBaseType) then
  4245. begin
  4246. // type cast a pas2js value, e.g. T(jsvalue)
  4247. JSBaseType:=TResElDataPas2JSBaseType(FromTypeEl.CustomData).JSBaseType;
  4248. if JSBaseType=pbtJSValue then
  4249. begin
  4250. if (ToResolved.BaseType in btAllJSValueTypeCastTo) then
  4251. Result:=cCompatible // type cast JSValue to simple base type
  4252. else if ToResolved.BaseType=btContext then
  4253. begin
  4254. // typecast JSValue to user type
  4255. Result:=cCompatible;
  4256. end;
  4257. end;
  4258. exit;
  4259. end;
  4260. end
  4261. else if ToResolved.BaseType=btContext then
  4262. begin
  4263. ToTypeEl:=ToResolved.LoTypeEl;
  4264. C:=ToTypeEl.ClassType;
  4265. if C=TPasClassType then
  4266. begin
  4267. ToClass:=TPasClassType(ToTypeEl);
  4268. if ToClass.IsExternal then
  4269. begin
  4270. if (FromResolved.BaseType in btAllJSStringAndChars) then
  4271. begin
  4272. if IsExternalClass_Name(ToClass,'String') then
  4273. // TJSString(aString)
  4274. exit(cExact);
  4275. end
  4276. else if (FromResolved.BaseType=btContext) then
  4277. begin
  4278. FromTypeEl:=FromResolved.LoTypeEl;
  4279. if FromTypeEl.ClassType=TPasArrayType then
  4280. begin
  4281. if IsExternalClass_Name(ToClass,'Array')
  4282. or IsExternalClass_Name(ToClass,'Object') then
  4283. // TJSArray(AnArray) or TJSObject(AnArray)
  4284. exit(cExact);
  4285. end
  4286. else if FromTypeEl.ClassType=TPasRecordType then
  4287. begin
  4288. if IsExternalClass_Name(ToClass,'Object') then
  4289. // TJSObject(aRecord)
  4290. exit(cExact);
  4291. end
  4292. else if FromTypeEl.ClassType=TPasClassOfType then
  4293. begin
  4294. if IsExternalClass_Name(ToClass,'Object') then
  4295. // TJSObject(ImgClass)
  4296. exit(cExact);
  4297. end
  4298. else if FromTypeEl.InheritsFrom(TPasProcedureType) then
  4299. begin
  4300. if IsExternalClass_Name(ToClass,'Function')
  4301. or IsExternalClass_Name(ToClass,'Object') then
  4302. // TJSFunction(@Proc) or TJSFunction(ProcVar)
  4303. exit(cExact);
  4304. end;
  4305. end;
  4306. end;
  4307. end
  4308. else if C=TPasArrayType then
  4309. begin
  4310. if (FromResolved.BaseType=btContext) then
  4311. begin
  4312. FromTypeEl:=FromResolved.LoTypeEl;
  4313. if (FromTypeEl.ClassType=TPasClassType)
  4314. and TPasClassType(FromTypeEl).IsExternal
  4315. and (IsExternalClass_Name(TPasClassType(FromTypeEl),'Array')
  4316. or IsExternalClass_Name(TPasClassType(FromTypeEl),'Object')) then
  4317. begin
  4318. // type cast external Array/Object to an array
  4319. exit(cCompatible);
  4320. end;
  4321. end;
  4322. end
  4323. else if C=TPasRecordType then
  4324. begin
  4325. // typecast to recordtype
  4326. if FromResolved.BaseType=btNone then
  4327. // recordtype(untyped) -> ok
  4328. else if FromResolved.BaseType=btContext then
  4329. begin
  4330. FromTypeEl:=FromResolved.LoTypeEl;
  4331. if FromTypeEl=ToTypeEl then
  4332. exit(cAliasExact)
  4333. else
  4334. // FPC/Delphi allow typecasting records of same size, pas2js does not
  4335. exit(Incompatible(20180503134526));
  4336. end
  4337. else
  4338. exit(Incompatible(20180503134528));
  4339. end
  4340. else if C.InheritsFrom(TPasProcedureType) then
  4341. begin
  4342. // typecast to proctype
  4343. if FromResolved.BaseType=btContext then
  4344. begin
  4345. FromTypeEl:=FromResolved.LoTypeEl;
  4346. if FromTypeEl.ClassType=TPasClassType then
  4347. begin
  4348. if IsExternalClass_Name(TPasClassType(FromTypeEl),'Function') then
  4349. // TProcType(aJSFunction)
  4350. exit(cCompatible);
  4351. end;
  4352. end;
  4353. end;
  4354. end;
  4355. end
  4356. else if FromResolved.IdentEl is TPasType then
  4357. begin
  4358. // FromResolved is a type
  4359. FromTypeEl:=ResolveAliasType(TPasType(FromResolved.IdentEl));
  4360. if ToResolved.BaseType=btContext then
  4361. begin
  4362. ToTypeEl:=ToResolved.LoTypeEl;
  4363. if (ToTypeEl.ClassType=TPasClassType)
  4364. and TPasClassType(ToTypeEl).IsExternal
  4365. and (TPasClassType(ToTypeEl).ExternalName='Object') // do not allow typecast to a descendant!
  4366. then
  4367. begin
  4368. // type cast to JS Object, not a descendant
  4369. if (FromTypeEl.ClassType=TPasClassType)
  4370. or (FromTypeEl.ClassType=TPasRecordType) then
  4371. // e.g. TJSObject(TObject)
  4372. exit(cTypeConversion+1);
  4373. end;
  4374. end;
  4375. end;
  4376. Result:=inherited CheckTypeCastRes(FromResolved,ToResolved,ErrorEl,RaiseOnError);
  4377. end;
  4378. function TPas2JSResolver.FindLocalBuiltInSymbol(El: TPasElement): TPasElement;
  4379. begin
  4380. Result:=inherited FindLocalBuiltInSymbol(El);
  4381. if Result<>nil then exit;
  4382. if El.CustomData is TResElDataPas2JSBaseType then
  4383. Result:=JSBaseTypes[TResElDataPas2JSBaseType(El.CustomData).JSBaseType];
  4384. end;
  4385. function TPas2JSResolver.ExtractPasStringLiteral(El: TPasElement;
  4386. const S: String): TJSString;
  4387. { Extracts the value from a Pascal string literal
  4388. S is a Pascal string literal e.g. 'Line'#10
  4389. '' empty string
  4390. '''' => "'"
  4391. #decimal
  4392. #$hex
  4393. ^l l is a letter a-z
  4394. }
  4395. var
  4396. p, StartP, i, l: integer;
  4397. c: Char;
  4398. begin
  4399. Result:='';
  4400. {$IFDEF VerbosePas2JS}
  4401. writeln('TPasToJSConverter.ExtractPasStringLiteral S="',S,'" ',{$IFDEF pas2js}copy(s,100){$ELSE}RawStrToCaption(S,100){$ENDIF},' ',length(S));
  4402. {$ENDIF}
  4403. if S='' then
  4404. RaiseInternalError(20170207154543);
  4405. p:=1;
  4406. l:=length(S);
  4407. while p<=l do
  4408. case S[p] of
  4409. '''':
  4410. begin
  4411. inc(p);
  4412. StartP:=p;
  4413. repeat
  4414. if p>l then
  4415. RaiseInternalError(20170207155120);
  4416. c:=S[p];
  4417. case c of
  4418. '''':
  4419. begin
  4420. if p>StartP then
  4421. Result:=Result+StrToJSString(copy(S,StartP,p-StartP));
  4422. inc(p);
  4423. StartP:=p;
  4424. if (p>l) or (S[p]<>'''') then
  4425. break;
  4426. Result:=Result+'''';
  4427. inc(p);
  4428. StartP:=p;
  4429. end;
  4430. else
  4431. inc(p);
  4432. end;
  4433. until false;
  4434. if p>StartP then
  4435. Result:=Result+StrToJSString(copy(S,StartP,p-StartP));
  4436. end;
  4437. '#':
  4438. begin
  4439. inc(p);
  4440. if p>l then
  4441. RaiseInternalError(20170207155121);
  4442. if S[p]='$' then
  4443. begin
  4444. // #$hexnumber
  4445. inc(p);
  4446. StartP:=p;
  4447. i:=0;
  4448. while p<=l do
  4449. begin
  4450. c:=S[p];
  4451. case c of
  4452. '0'..'9': i:=i*16+ord(c)-ord('0');
  4453. 'a'..'f': i:=i*16+ord(c)-ord('a')+10;
  4454. 'A'..'F': i:=i*16+ord(c)-ord('A')+10;
  4455. else break;
  4456. end;
  4457. if i>$10ffff then
  4458. RaiseNotYetImplemented(20170207164657,El,'maximum codepoint is $10ffff');
  4459. inc(p);
  4460. end;
  4461. if p=StartP then
  4462. RaiseInternalError(20170207164956);
  4463. Result:=Result+CodePointToJSString(i);
  4464. end
  4465. else
  4466. begin
  4467. // #decimalnumber
  4468. StartP:=p;
  4469. i:=0;
  4470. while p<=l do
  4471. begin
  4472. c:=S[p];
  4473. case c of
  4474. '0'..'9': i:=i*10+ord(c)-ord('0');
  4475. else break;
  4476. end;
  4477. if i>$10ffff then
  4478. RaiseNotYetImplemented(20170207171140,El,'maximum codepoint is $10ffff');
  4479. inc(p);
  4480. end;
  4481. if p=StartP then
  4482. RaiseInternalError(20170207171148);
  4483. Result:=Result+CodePointToJSString(i);
  4484. end;
  4485. end;
  4486. '^':
  4487. begin
  4488. // ^A is #1
  4489. inc(p);
  4490. if p>l then
  4491. RaiseInternalError(20181025125920);
  4492. c:=S[p];
  4493. case c of
  4494. 'a'..'z': Result:=Result+TJSChar(ord(c)-ord('a')+1);
  4495. 'A'..'Z': Result:=Result+TJSChar(ord(c)-ord('A')+1);
  4496. else RaiseInternalError(20170207160412);
  4497. end;
  4498. inc(p);
  4499. end;
  4500. else
  4501. RaiseNotYetImplemented(20170207154653,El,'ord='+IntToStr(ord(S[p])));
  4502. end;
  4503. {$IFDEF VerbosePas2JS}
  4504. {AllowWriteln}
  4505. writeln('TPasToJSConverter.ExtractPasStringLiteral Result="',Result,'"');
  4506. //for i:=1 to length(Result) do
  4507. // writeln(' Result[',i,']',HexStr(ord(Result[i]),4));
  4508. {AllowWriteln-}
  4509. {$ENDIF}
  4510. end;
  4511. function TPas2JSResolver.ResolverToJSValue(Value: TResEvalValue;
  4512. ErrorEl: TPasElement): TJSValue;
  4513. begin
  4514. Result:=nil;
  4515. if Value=nil then exit;
  4516. case Value.Kind of
  4517. revkBool: Result:=TJSValue.Create(TResEvalBool(Value).B);
  4518. revkInt: Result:=TJSValue.Create(TJSNumber(TResEvalInt(Value).Int));
  4519. revkUInt: Result:=TJSValue.Create(TJSNumber(TResEvalUInt(Value).UInt));
  4520. revkFloat: Result:=TJSValue.Create(TJSNumber(TResEvalFloat(Value).FloatValue));
  4521. {$IFDEF FPC_HAS_CPSTRING}
  4522. revkString: Result:=TJSValue.Create(TJSString(
  4523. ExprEvaluator.GetUnicodeStr(TResEvalString(Value).S,ErrorEl)));
  4524. {$ENDIF}
  4525. revkUnicodeString: Result:=TJSValue.Create(TJSString(TResEvalUTF16(Value).S));
  4526. else
  4527. {$IFDEF VerbosePas2JS}
  4528. writeln('TPas2JSResolver.ResolverToJSValue ',Value.AsDebugString);
  4529. {$ENDIF}
  4530. RaiseNotYetImplemented(20170914092413,ErrorEl,'');
  4531. end;
  4532. end;
  4533. function TPas2JSResolver.ComputeConstString(Expr: TPasExpr; StoreCustomData,
  4534. NotEmpty: boolean): String;
  4535. var
  4536. Value: TResEvalValue;
  4537. begin
  4538. Result:='';
  4539. if Expr=nil then
  4540. RaiseInternalError(20170215123600);
  4541. Value:=Eval(Expr,[refAutoConst],StoreCustomData);
  4542. try
  4543. case Value.Kind of
  4544. {$IFDEF FPC_HAS_CPSTRING}
  4545. revkString: Result:=ExprEvaluator.GetUTF8Str(TResEvalString(Value).S,Expr);
  4546. revkUnicodeString: Result:=UTF8Encode(TResEvalUTF16(Value).S);
  4547. {$ELSE}
  4548. revkUnicodeString: Result:=TResEvalUTF16(Value).S;
  4549. {$ENDIF}
  4550. else
  4551. str(Value.Kind,Result);
  4552. RaiseXExpectedButYFound(20170211221121,'string literal',Result,Expr);
  4553. end;
  4554. finally
  4555. ReleaseEvalValue(Value);
  4556. end;
  4557. if NotEmpty and (Result='') then
  4558. RaiseXExpectedButYFound(20170321085318,'string literal','empty',Expr);
  4559. end;
  4560. procedure TPas2JSResolver.CheckAssignExprRangeToCustom(
  4561. const LeftResolved: TPasResolverResult; RValue: TResEvalValue; RHS: TPasExpr);
  4562. var
  4563. LeftBaseType: TPas2jsBaseType;
  4564. begin
  4565. if (LeftResolved.BaseType<>btCustom) then
  4566. exit;
  4567. if not (LeftResolved.LoTypeEl is TPasUnresolvedSymbolRef) then
  4568. begin
  4569. {$IFDEF VerbosePas2JS}
  4570. writeln('TPas2JSResolver.CheckAssignExprRangeToCustom LeftResolved=',GetResolverResultDbg(LeftResolved));
  4571. {$ENDIF}
  4572. RaiseInternalError(20170902165913);
  4573. end;
  4574. if not (LeftResolved.LoTypeEl.CustomData is TResElDataPas2JSBaseType) then
  4575. exit;
  4576. LeftBaseType:=TResElDataPas2JSBaseType(LeftResolved.LoTypeEl.CustomData).JSBaseType;
  4577. if LeftBaseType=pbtJSValue then
  4578. // jsvalue:=someconst -> ok
  4579. else
  4580. RaiseNotYetImplemented(20170902170153,RHS);
  4581. if RHS=nil then ;
  4582. if RValue=nil then ;
  4583. end;
  4584. function TPas2JSResolver.HasStaticArrayCloneFunc(Arr: TPasArrayType): boolean;
  4585. var
  4586. l: Integer;
  4587. ElType: TPasType;
  4588. begin
  4589. l:=length(Arr.Ranges);
  4590. if l=0 then exit(false);
  4591. if l>1 then exit(false ); // ToDo: return true when cloning multi dims is implemented
  4592. ElType:=ResolveAliasType(Arr.ElType);
  4593. if ElType is TPasArrayType then
  4594. Result:=length(TPasArrayType(ElType).Ranges)>0
  4595. else if ElType is TPasRecordType then
  4596. Result:=true
  4597. else if ElType is TPasSetType then
  4598. Result:=true
  4599. else
  4600. Result:=false;
  4601. end;
  4602. function TPas2JSResolver.IsTGUID(TypeEl: TPasRecordType): boolean;
  4603. var
  4604. Members: TFPList;
  4605. El: TPasElement;
  4606. begin
  4607. Result:=false;
  4608. if not SameText(TypeEl.Name,'TGUID') then exit;
  4609. Members:=TypeEl.Members;
  4610. if Members.Count<4 then exit;
  4611. El:=TPasElement(Members[0]);
  4612. if not SameText(El.Name,'D1') then exit;
  4613. El:=TPasElement(Members[1]);
  4614. if not SameText(El.Name,'D2') then exit;
  4615. El:=TPasElement(Members[2]);
  4616. if not SameText(El.Name,'D3') then exit;
  4617. El:=TPasElement(Members[3]);
  4618. if not SameText(El.Name,'D4') then exit;
  4619. Result:=true;
  4620. end;
  4621. function TPas2JSResolver.GetAssignGUIDString(TypeEl: TPasRecordType;
  4622. Expr: TPasExpr; out GUID: TGuid): boolean;
  4623. var
  4624. Value: TResEvalValue;
  4625. GUIDStr: String;
  4626. begin
  4627. Result:=false;
  4628. if Expr=nil then exit;
  4629. if not IsTGUID(TypeEl) then exit;
  4630. Value:=Eval(Expr,[refAutoConst]);
  4631. try
  4632. case Value.Kind of
  4633. {$IFDEF FPC_HAS_CPSTRING}
  4634. revkString: GUIDStr:=ExprEvaluator.GetUTF8Str(TResEvalString(Value).S,Expr);
  4635. revkUnicodeString: GUIDStr:=UTF8Encode(TResEvalUTF16(Value).S);
  4636. {$ELSE}
  4637. revkUnicodeString: GUIDStr:=TResEvalUTF16(Value).S;
  4638. {$ENDIF}
  4639. else
  4640. RaiseXExpectedButYFound(20180415092350,'GUID string literal',Value.AsString,Expr);
  4641. end;
  4642. if not TryStringToGUID(GUIDStr,GUID) then
  4643. RaiseXExpectedButYFound(20180415092351,'GUID string literal',Value.AsString,Expr);
  4644. Result:=true;
  4645. finally
  4646. ReleaseEvalValue(Value);
  4647. end;
  4648. end;
  4649. function TPas2JSResolver.GetElementData(El: TPasElementBase;
  4650. DataClass: TPas2JsElementDataClass): TPas2JsElementData;
  4651. begin
  4652. Result:=nil;
  4653. repeat
  4654. if El.InheritsFrom(DataClass) then
  4655. exit(TPas2JsElementData(El));
  4656. if El.CustomData=nil then exit;
  4657. El:=El.CustomData as TPasElementBase;
  4658. until false;
  4659. end;
  4660. procedure TPas2JSResolver.AddElementData(Data: TPas2JsElementData);
  4661. begin
  4662. Data.Owner:=Self;
  4663. if FFirstElementData<>nil then
  4664. begin
  4665. FLastElementData.Next:=Data;
  4666. FLastElementData:=Data;
  4667. end
  4668. else
  4669. begin
  4670. FFirstElementData:=Data;
  4671. FLastElementData:=Data;
  4672. end;
  4673. end;
  4674. function TPas2JSResolver.CreateElementData(DataClass: TPas2JsElementDataClass;
  4675. El: TPasElement): TPas2JsElementData;
  4676. begin
  4677. Result:=DataClass.Create;
  4678. Result.Element:=El;
  4679. AddElementData(Result);
  4680. end;
  4681. procedure TPas2JSResolver.RaiseMsg(const Id: TMaxPrecInt; MsgNumber: integer;
  4682. const Fmt: String; Args: array of {$IFDEF pas2js}jsvalue{$ELSE}const{$ENDIF};
  4683. ErrorPosEl: TPasElement);
  4684. begin
  4685. {$IFDEF VerbosePas2JS}
  4686. writeln('TPas2JSResolver.RaiseMsg [',Id,']');
  4687. {$ENDIF}
  4688. inherited RaiseMsg(Id, MsgNumber, Fmt, Args, ErrorPosEl);
  4689. end;
  4690. function TPas2JSResolver.GetOverloadName(El: TPasElement): string;
  4691. var
  4692. Data: TObject;
  4693. begin
  4694. Data:=El.CustomData;
  4695. if Data is TPas2JSProcedureScope then
  4696. begin
  4697. Result:=TPas2JSProcedureScope(Data).OverloadName;
  4698. if Result<>'' then exit;
  4699. end;
  4700. Result:=El.Name;
  4701. end;
  4702. function TPas2JSResolver.GetBaseDescription(const R: TPasResolverResult;
  4703. AddPath: boolean): string;
  4704. begin
  4705. if (R.BaseType=btCustom) and (R.LoTypeEl.CustomData is TResElDataPas2JSBaseType) then
  4706. Result:=Pas2jsBaseTypeNames[TResElDataPas2JSBaseType(R.LoTypeEl.CustomData).JSBaseType]
  4707. else
  4708. Result:=inherited GetBaseDescription(R, AddPath);
  4709. end;
  4710. function TPas2JSResolver.HasTypeInfo(El: TPasType): boolean;
  4711. begin
  4712. Result:=inherited HasTypeInfo(El);
  4713. if not Result then exit;
  4714. if (El.ClassType=TPasClassType) and TPasClassType(El).IsExternal then
  4715. exit(false);
  4716. if El.Parent is TProcedureBody then
  4717. Result:=false;
  4718. end;
  4719. function TPas2JSResolver.ProcHasImplElements(Proc: TPasProcedure): boolean;
  4720. var
  4721. Scope: TPas2JSProcedureScope;
  4722. begin
  4723. Result:=inherited ProcHasImplElements(Proc);
  4724. if Result then exit;
  4725. // no body elements found -> check precompiled
  4726. Scope:=Proc.CustomData as TPas2JSProcedureScope;
  4727. if Scope.ImplProc<>nil then
  4728. Scope:=Scope.ImplProc.CustomData as TPas2JSProcedureScope;
  4729. if Scope.BodyJS<>'' then
  4730. Result:=not Scope.EmptyJS;
  4731. end;
  4732. function TPas2JSResolver.IsTObjectFreeMethod(El: TPasExpr): boolean;
  4733. var
  4734. Ref: TResolvedReference;
  4735. Decl: TPasElement;
  4736. begin
  4737. Result:=false;
  4738. if El=nil then exit;
  4739. if El.ClassType<>TPrimitiveExpr then exit;
  4740. if not (El.CustomData is TResolvedReference) then exit;
  4741. Ref:=TResolvedReference(El.CustomData);
  4742. if CompareText(TPrimitiveExpr(El).Value,'free')<>0 then exit;
  4743. Decl:=Ref.Declaration;
  4744. if not (Decl.ClassType=TPasProcedure)
  4745. or (Decl.Parent.ClassType<>TPasClassType)
  4746. or (CompareText(Decl.Parent.Name,'tobject')<>0)
  4747. or (pmExternal in TPasProcedure(Decl).Modifiers)
  4748. or (TPasProcedure(Decl).ProcType.Args.Count>0) then
  4749. exit;
  4750. Result:=true;
  4751. end;
  4752. function TPas2JSResolver.IsExternalBracketAccessor(El: TPasElement): boolean;
  4753. var
  4754. ExtName: String;
  4755. begin
  4756. if (not (El is TPasProcedure)) or (TPasProcedure(El).LibrarySymbolName=nil) then
  4757. exit(false);
  4758. ExtName:=ComputeConstString(TPasProcedure(El).LibrarySymbolName,false,false);
  4759. Result:=ExtName=ExtClassBracketAccessor;
  4760. end;
  4761. function TPas2JSResolver.IsExternalClassConstructor(El: TPasElement): boolean;
  4762. var
  4763. P: TPasElement;
  4764. begin
  4765. if (El.ClassType=TPasConstructor)
  4766. and (pmExternal in TPasConstructor(El).Modifiers) then
  4767. begin
  4768. P:=El.Parent;
  4769. if (P<>nil) and (P.ClassType=TPasClassType) and TPasClassType(P).IsExternal then
  4770. exit(true);
  4771. end;
  4772. Result:=false;
  4773. end;
  4774. function TPas2JSResolver.IsForInExtArray(Loop: TPasImplForLoop;
  4775. const VarResolved, InResolved: TPasResolverResult; out ArgResolved,
  4776. LengthResolved, PropResultResolved: TPasResolverResult): boolean;
  4777. var
  4778. TypeEl: TPasType;
  4779. aClass: TPasClassType;
  4780. ClassScope: TPas2JSClassScope;
  4781. DefProp: TPasProperty;
  4782. Arg0: TPasArgument;
  4783. Getter: TPasElement;
  4784. ClassDotScope: TPasDotClassScope;
  4785. Ident: TPasIdentifier;
  4786. LengthVar: TPasVariable;
  4787. begin
  4788. Result:=false;
  4789. ArgResolved:=Default(TPasResolverResult);
  4790. LengthResolved:=Default(TPasResolverResult);
  4791. PropResultResolved:=Default(TPasResolverResult);
  4792. TypeEl:=InResolved.LoTypeEl;
  4793. if (TypeEl.ClassType<>TPasClassType) or not TPasClassType(TypeEl).IsExternal then
  4794. begin
  4795. {$IFDEF VerboseIsForInExtArray}
  4796. writeln('TPas2JSResolver.IsForInExtArray TypeEl ',GetObjName(TypeEl));
  4797. {$ENDIF}
  4798. exit;
  4799. end;
  4800. // for key in JSClass do ...
  4801. aClass:=TPasClassType(TypeEl);
  4802. ClassScope:=TPas2JSClassScope(aClass.CustomData);
  4803. // check has default property
  4804. DefProp:=ClassScope.DefaultProperty;
  4805. if (DefProp=nil) or (DefProp.Args.Count<>1) then
  4806. begin
  4807. {$IFDEF VerboseIsForInExtArray}
  4808. writeln('TPas2JSResolver.IsForInExtArray DefProp ');
  4809. {$ENDIF}
  4810. exit;
  4811. end;
  4812. // check default property is array property
  4813. Arg0:=TPasArgument(DefProp.Args[0]);
  4814. if not (Arg0.Access in [argDefault,argConst]) then
  4815. begin
  4816. {$IFDEF VerboseIsForInExtArray}
  4817. writeln('TPas2JSResolver.IsForInExtArray Arg0 ');
  4818. {$ENDIF}
  4819. exit;
  4820. end;
  4821. // check default array property has an integer as parameter
  4822. ComputeElement(Arg0,ArgResolved,[]);
  4823. if not (ArgResolved.BaseType in btAllJSInteger) then
  4824. begin
  4825. {$IFDEF VerboseIsForInExtArray}
  4826. writeln('TPas2JSResolver.IsForInExtArray ArgResolved=',GetResolverResultDbg(ArgResolved));
  4827. {$ENDIF}
  4828. exit;
  4829. end;
  4830. // find aClass.Length
  4831. ClassDotScope:=PushClassDotScope(aClass);
  4832. Ident:=ClassDotScope.FindIdentifier('length');
  4833. PopScope;
  4834. // check 'length' is const/variable/property
  4835. if (Ident=nil) or not (Ident.Element is TPasVariable) then
  4836. begin
  4837. {$IFDEF VerboseIsForInExtArray}
  4838. writeln('TPas2JSResolver.IsForInExtArray Length ');
  4839. {$ENDIF}
  4840. exit;
  4841. end;
  4842. LengthVar:=TPasVariable(Ident.Element);
  4843. // check 'length' is same type as Arg0
  4844. ComputeElement(LengthVar,LengthResolved,[]);
  4845. if not IsSameType(LengthResolved.LoTypeEl,ArgResolved.LoTypeEl,prraNone) then
  4846. begin
  4847. {$IFDEF VerboseIsForInExtArray}
  4848. writeln('TPas2JSResolver.IsForInExtArray LengthResolved=',GetResolverResultDbg(LengthResolved),' ArgResolved=',GetResolverResultDbg(ArgResolved));
  4849. {$ENDIF}
  4850. exit;
  4851. end;
  4852. // InResolved has default getter and length -> use array enumerator
  4853. Result:=true;
  4854. // check getter is external bracket accessor
  4855. Getter:=GetPasPropertyGetter(DefProp);
  4856. if not IsExternalBracketAccessor(Getter) then
  4857. RaiseMsg(20180519141636,nForInJSArrDefaultGetterNotExtBracketAccessor,
  4858. sForInJSArrDefaultGetterNotExtBracketAccessor,[],Loop.StartExpr);
  4859. // check var fits the property type
  4860. ComputeElement(DefProp.VarType,PropResultResolved,[]);
  4861. Include(PropResultResolved.Flags,rrfReadable);
  4862. //writeln('IsForInExtArray VarResolved=',GetResolverResultDbg(VarResolved),' PropResultResolved=',GetResolverResultDbg(PropResultResolved));
  4863. CheckAssignResCompatibility(VarResolved,PropResultResolved,Loop.VariableName,true);
  4864. end;
  4865. { TParamContext }
  4866. constructor TParamContext.Create(PasEl: TPasElement; JSEl: TJSElement;
  4867. aParent: TConvertContext);
  4868. begin
  4869. inherited Create(PasEl, JSEl, aParent);
  4870. Access:=caAssign;
  4871. AccessContext:=Self;
  4872. end;
  4873. { TPas2JsElementData }
  4874. procedure TPas2JsElementData.SetElement(const AValue: TPasElement);
  4875. var
  4876. Data: TPasElementBase;
  4877. begin
  4878. if FElement=AValue then Exit;
  4879. if FElement<>nil then
  4880. begin
  4881. Data:=FElement;
  4882. while Data.CustomData<>Self do
  4883. if Data.CustomData is TPasElementBase then
  4884. Data:=TPasElementBase(Data.CustomData)
  4885. else
  4886. begin
  4887. {$IFDEF VerbosePas2JS}
  4888. writeln('TPas2JsElementData.SetElement REMOVE ',ClassName);
  4889. writeln(' ',GetObjName(Data.CustomData));
  4890. {$ENDIF}
  4891. raise EPas2JS.Create('');
  4892. end;
  4893. Data.CustomData:=CustomData;
  4894. TPasElement(FElement).Release{$IFDEF CheckPasTreeRefCount}('TPas2JsElementData.SetElement'){$ENDIF};
  4895. end;
  4896. FElement:=AValue;
  4897. if FElement<>nil then
  4898. begin
  4899. TPasElement(FElement).AddRef{$IFDEF CheckPasTreeRefCount}('TPas2JsElementData.SetElement'){$ENDIF};
  4900. Data:=FElement;
  4901. while Data.CustomData is TPasElementBase do
  4902. Data:=TPasElementBase(Data.CustomData);
  4903. if Data.CustomData<>nil then
  4904. begin
  4905. {$IFDEF VerbosePas2JS}
  4906. writeln('TPas2JsElementData.SetElement INSERT ',ClassName);
  4907. writeln(' ',GetObjName(Data.CustomData));
  4908. {$ENDIF}
  4909. raise EPas2JS.Create('');
  4910. end;
  4911. Data.CustomData:=Self;
  4912. end;
  4913. end;
  4914. constructor TPas2JsElementData.Create;
  4915. begin
  4916. end;
  4917. destructor TPas2JsElementData.Destroy;
  4918. begin
  4919. Element:=nil;
  4920. Next:=nil;
  4921. Owner:=nil;
  4922. inherited Destroy;
  4923. end;
  4924. { TAssignContext }
  4925. constructor TAssignContext.Create(PasEl: TPasElement; JSEl: TJSElement;
  4926. aParent: TConvertContext);
  4927. begin
  4928. inherited Create(PasEl, JSEl, aParent);
  4929. Access:=caAssign;
  4930. AccessContext:=Self;
  4931. end;
  4932. { TSectionContext }
  4933. constructor TSectionContext.Create(PasEl: TPasElement; JSEl: TJSElement;
  4934. aParent: TConvertContext);
  4935. begin
  4936. inherited;
  4937. IsGlobal:=true;
  4938. end;
  4939. { TFunctionContext }
  4940. destructor TFunctionContext.Destroy;
  4941. var
  4942. i: Integer;
  4943. begin
  4944. FreeAndNil(IntfElReleases);
  4945. for i:=0 to length(LocalVars)-1 do
  4946. FreeAndNil(LocalVars[i]);
  4947. inherited Destroy;
  4948. end;
  4949. procedure TFunctionContext.AddLocalVar(const aName: string; El: TPasElement);
  4950. var
  4951. l: Integer;
  4952. begin
  4953. l:=length(LocalVars);
  4954. SetLength(LocalVars,l+1);
  4955. LocalVars[l]:=TFCLocalIdentifier.Create(aName,El);
  4956. end;
  4957. procedure TFunctionContext.Add_InterfaceRelease(El: TPasElement);
  4958. begin
  4959. if IntfElReleases=nil then
  4960. IntfElReleases:=TFPList.Create;
  4961. if IntfElReleases.IndexOf(El)>=0 then exit;
  4962. IntfElReleases.Add(El);
  4963. end;
  4964. function TFunctionContext.ToString: string;
  4965. var
  4966. V: TFCLocalIdentifier;
  4967. begin
  4968. Result:=inherited ToString;
  4969. if ThisPas<>nil then
  4970. begin
  4971. Result:=Result+' this';
  4972. V:=FindLocalIdentifier(ThisPas);
  4973. if V<>nil then
  4974. Result:=Result+'="'+V.Name+'"';
  4975. Result:=Result+'='+GetObjName(ThisPas);
  4976. end;
  4977. end;
  4978. function TFunctionContext.GetLocalName(El: TPasElement): string;
  4979. var
  4980. V: TFCLocalIdentifier;
  4981. begin
  4982. if El=nil then exit('');
  4983. V:=FindLocalIdentifier(El);
  4984. if V<>nil then
  4985. Result:=V.Name
  4986. else if ThisPas=El then
  4987. Result:='this'
  4988. else
  4989. begin
  4990. Result:=inherited GetLocalName(El);
  4991. if Result='this' then
  4992. Result:='';
  4993. end;
  4994. end;
  4995. function TFunctionContext.IndexOfLocalVar(const aName: string): integer;
  4996. var
  4997. i: Integer;
  4998. begin
  4999. for i:=0 to length(LocalVars)-1 do
  5000. if LocalVars[i].Name=aName then exit(i);
  5001. Result:=-1;
  5002. end;
  5003. function TFunctionContext.IndexOfLocalVar(El: TPasElement): integer;
  5004. var
  5005. i: Integer;
  5006. begin
  5007. if El=nil then exit(-1);
  5008. for i:=0 to length(LocalVars)-1 do
  5009. if LocalVars[i].Element=El then exit(i);
  5010. Result:=-1;
  5011. end;
  5012. function TFunctionContext.FindLocalVar(const aName: string): TFCLocalIdentifier;
  5013. var
  5014. i: Integer;
  5015. begin
  5016. i:=IndexOfLocalVar(aName);
  5017. if i>=0 then
  5018. Result:=LocalVars[i]
  5019. else
  5020. Result:=nil;
  5021. end;
  5022. function TFunctionContext.FindLocalIdentifier(El: TPasElement): TFCLocalIdentifier;
  5023. var
  5024. i: Integer;
  5025. begin
  5026. i:=IndexOfLocalVar(El);
  5027. if i>=0 then
  5028. Result:=LocalVars[i]
  5029. else
  5030. Result:=nil;
  5031. end;
  5032. procedure TFunctionContext.DoWriteStack(Index: integer);
  5033. var
  5034. i: Integer;
  5035. begin
  5036. inherited DoWriteStack(Index);
  5037. {AllowWriteln}
  5038. for i:=0 to length(LocalVars)-1 do
  5039. writeln(' ',i,' ',LocalVars[i].Name,': ',GetObjName(LocalVars[i].Element));
  5040. {AllowWriteln-}
  5041. end;
  5042. { TConvertContext }
  5043. constructor TConvertContext.Create(PasEl: TPasElement; JSEl: TJSElement;
  5044. aParent: TConvertContext);
  5045. begin
  5046. PasElement:=PasEl;
  5047. JSElement:=JsEl;
  5048. Parent:=aParent;
  5049. if Parent<>nil then
  5050. begin
  5051. Resolver:=Parent.Resolver;
  5052. Access:=aParent.Access;
  5053. AccessContext:=aParent.AccessContext;
  5054. ScannerBoolSwitches:=aParent.ScannerBoolSwitches;
  5055. ScannerModeSwitches:=aParent.ScannerModeSwitches;
  5056. end;
  5057. end;
  5058. function TConvertContext.GetRootModule: TPasModule;
  5059. var
  5060. aContext: TConvertContext;
  5061. begin
  5062. aContext:=Self;
  5063. while aContext.Parent<>nil do
  5064. aContext:=aContext.Parent;
  5065. if aContext.PasElement is TPasModule then
  5066. Result:=TPasModule(aContext.PasElement)
  5067. else
  5068. Result:=nil;
  5069. end;
  5070. function TConvertContext.GetNonDotContext: TConvertContext;
  5071. begin
  5072. Result:=Self;
  5073. while Result is TDotContext do
  5074. Result:=Result.Parent;
  5075. end;
  5076. function TConvertContext.GetFunctionContext: TFunctionContext;
  5077. begin
  5078. Result:=TFunctionContext(GetContextOfType(TFunctionContext));
  5079. end;
  5080. function TConvertContext.GetLocalName(El: TPasElement): string;
  5081. begin
  5082. if Parent<>nil then
  5083. Result:=Parent.GetLocalName(El)
  5084. else
  5085. Result:='';
  5086. end;
  5087. function TConvertContext.GetSelfContext: TFunctionContext;
  5088. var
  5089. Ctx: TConvertContext;
  5090. begin
  5091. Ctx:=Self;
  5092. while Ctx<>nil do
  5093. begin
  5094. if (Ctx is TFunctionContext) and (TFunctionContext(Ctx).ThisPas is TPasClassType) then
  5095. exit(TFunctionContext(Ctx));
  5096. Ctx:=Ctx.Parent;
  5097. end;
  5098. Result:=nil;
  5099. end;
  5100. function TConvertContext.GetContextOfPasElement(El: TPasElement
  5101. ): TConvertContext;
  5102. var
  5103. ctx: TConvertContext;
  5104. begin
  5105. Result:=nil;
  5106. ctx:=Self;
  5107. repeat
  5108. if ctx.PasElement=El then
  5109. exit(ctx);
  5110. ctx:=ctx.Parent;
  5111. until ctx=nil;
  5112. end;
  5113. function TConvertContext.GetFuncContextOfPasElement(El: TPasElement
  5114. ): TFunctionContext;
  5115. var
  5116. ctx: TConvertContext;
  5117. Scope: TPas2JSProcedureScope;
  5118. begin
  5119. Result:=nil;
  5120. if El is TPasProcedure then
  5121. begin
  5122. Scope:=TPas2JSProcedureScope(El.CustomData);
  5123. if Scope.ImplProc<>nil then
  5124. El:=Scope.ImplProc;
  5125. end;
  5126. ctx:=Self;
  5127. repeat
  5128. if (ctx.PasElement=El) and (ctx is TFunctionContext) then
  5129. exit(TFunctionContext(ctx));
  5130. ctx:=ctx.Parent;
  5131. until ctx=nil;
  5132. end;
  5133. function TConvertContext.GetContextOfType(aType: TConvertContextClass
  5134. ): TConvertContext;
  5135. var
  5136. ctx: TConvertContext;
  5137. begin
  5138. Result:=nil;
  5139. ctx:=Self;
  5140. repeat
  5141. if ctx is aType then
  5142. exit(ctx);
  5143. ctx:=ctx.Parent;
  5144. until ctx=nil;
  5145. end;
  5146. function TConvertContext.CreateLocalIdentifier(const Prefix: string): string;
  5147. begin
  5148. inc(TmpVarCount);
  5149. Result:=Prefix+IntToStr(TmpVarCount);
  5150. end;
  5151. function TConvertContext.CurrentModeSwitches: TModeSwitches;
  5152. begin
  5153. if Resolver=nil then
  5154. Result:=OBJFPCModeSwitches
  5155. else
  5156. Result:=Resolver.CurrentParser.CurrentModeswitches;
  5157. end;
  5158. function TConvertContext.GetGlobalFunc: TFunctionContext;
  5159. var
  5160. Ctx: TConvertContext;
  5161. begin
  5162. Ctx:=Self;
  5163. while (Ctx<>nil) do
  5164. begin
  5165. if Ctx.IsGlobal and (Ctx.JSElement<>nil) and (Ctx is TFunctionContext) then
  5166. exit(TFunctionContext(Ctx));
  5167. Ctx:=Ctx.Parent;
  5168. end;
  5169. Result:=nil;
  5170. end;
  5171. procedure TConvertContext.WriteStack;
  5172. {AllowWriteln}
  5173. var
  5174. SelfCtx: TFunctionContext;
  5175. procedure W(Index: integer; AContext: TConvertContext);
  5176. begin
  5177. if AContext=SelfCtx then
  5178. writeln(' SelfContext:');
  5179. AContext.DoWriteStack(Index);
  5180. if AContext.Parent<>nil then
  5181. W(Index+1,AContext.Parent);
  5182. end;
  5183. begin
  5184. SelfCtx:=GetSelfContext;
  5185. writeln('TConvertContext.WriteStack: START');
  5186. W(1,Self);
  5187. writeln('TConvertContext.WriteStack: END');
  5188. end;
  5189. {AllowWriteln-}
  5190. procedure TConvertContext.DoWriteStack(Index: integer);
  5191. begin
  5192. {AllowWriteln}
  5193. writeln(' ',Index,' ',ToString);
  5194. {AllowWriteln-}
  5195. end;
  5196. function TConvertContext.ToString: string;
  5197. begin
  5198. Result:='['+ClassName+']'
  5199. +' pas='+GetObjName(PasElement)
  5200. +' js='+GetObjName(JSElement)
  5201. +' Global='+BoolToStr(IsGlobal,true);
  5202. end;
  5203. { TPasToJSConverter }
  5204. // inline
  5205. function TPasToJSConverter.GetUseEnumNumbers: boolean;
  5206. begin
  5207. Result:=coEnumNumbers in FOptions;
  5208. end;
  5209. // inline
  5210. function TPasToJSConverter.GetUseLowerCase: boolean;
  5211. begin
  5212. Result:=coLowerCase in FOptions;
  5213. end;
  5214. // inline
  5215. function TPasToJSConverter.GetUseSwitchStatement: boolean;
  5216. begin
  5217. Result:=coSwitchStatement in FOptions;
  5218. end;
  5219. procedure TPasToJSConverter.AddToSourceElements(Src: TJSSourceElements;
  5220. El: TJSElement);
  5221. Var
  5222. List : TJSStatementList;
  5223. AddEl : TJSElement;
  5224. begin
  5225. While El<>nil do
  5226. begin
  5227. if El is TJSStatementList then
  5228. begin
  5229. List:=El as TJSStatementList;
  5230. // List.A is first statement, List.B is next in list, chained.
  5231. // -> add A, continue with B and free List
  5232. AddEl:=List.A;
  5233. El:=List.B;
  5234. List.A:=Nil;
  5235. List.B:=Nil;
  5236. FreeAndNil(List);
  5237. end
  5238. else
  5239. begin
  5240. AddEl:=El;
  5241. El:=Nil;
  5242. end;
  5243. Src.Statements.AddNode.Node:=AddEl;
  5244. end;
  5245. end;
  5246. procedure TPasToJSConverter.RemoveFromSourceElements(Src: TJSSourceElements;
  5247. El: TJSElement);
  5248. var
  5249. Statements: TJSElementNodes;
  5250. i: Integer;
  5251. begin
  5252. Statements:=Src.Statements;
  5253. for i:=Statements.Count-1 downto 0 do
  5254. if Statements[i].Node=El then
  5255. Statements.Delete(i);
  5256. end;
  5257. function TPasToJSConverter.GetBuildInNames(bin: TPas2JSBuiltInName): string;
  5258. begin
  5259. Result:=FBuiltInNames[bin];
  5260. end;
  5261. procedure TPasToJSConverter.SetBuildInNames(bin: TPas2JSBuiltInName;
  5262. const AValue: string);
  5263. begin
  5264. FBuiltInNames[bin]:=AValue;
  5265. end;
  5266. procedure TPasToJSConverter.SetReservedWords(const AValue: TJSReservedWordList
  5267. );
  5268. var
  5269. i: Integer;
  5270. begin
  5271. if FReservedWords=AValue then Exit;
  5272. for i:=0 to length(AValue)-2 do
  5273. if CompareStr(AValue[i],AValue[i+1])>=0 then
  5274. raise Exception.Create('TPasToJSConverter.SetPreservedWords "'+AValue[i]+'" >= "'+AValue[i+1]+'"');
  5275. FReservedWords:=AValue;
  5276. end;
  5277. function TPasToJSConverter.ConvertModule(El: TPasModule;
  5278. AContext: TConvertContext): TJSElement;
  5279. (*
  5280. Program:
  5281. rtl.module('program',
  5282. [<uses1>,<uses2>, ...],
  5283. function(){
  5284. <programsection>
  5285. this.$main=function(){
  5286. <initialization>
  5287. };
  5288. });
  5289. Unit:
  5290. rtl.module('<unitname>',
  5291. [<interface uses1>,<uses2>, ...],
  5292. function(){
  5293. var $impl = {};
  5294. this.$impl = $impl;
  5295. <interface>
  5296. this.$init=function(){
  5297. <initialization>
  5298. };
  5299. },
  5300. [<implementation uses1>,<uses2>, ...],
  5301. function(){
  5302. var $impl = this.$impl;
  5303. <implementation>
  5304. });
  5305. *)
  5306. Var
  5307. OuterSrc , Src: TJSSourceElements;
  5308. RegModuleCall, Call: TJSCallExpression;
  5309. ArgArray: TJSArguments;
  5310. FunDecl, ImplFunc: TJSFunctionDeclarationStatement;
  5311. UsesSection: TPasSection;
  5312. ModuleName, ModVarName: String;
  5313. IntfContext: TSectionContext;
  5314. ImplVarSt: TJSVariableStatement;
  5315. HasImplUsesClause, ok, NeedRTLCheckVersion: Boolean;
  5316. UsesClause: TPasUsesClause;
  5317. begin
  5318. Result:=Nil;
  5319. OuterSrc:=TJSSourceElements(CreateElement(TJSSourceElements, El));
  5320. Result:=OuterSrc;
  5321. ok:=false;
  5322. try
  5323. // create 'rtl.module(...)'
  5324. RegModuleCall:=CreateCallExpression(El);
  5325. AddToSourceElements(OuterSrc,RegModuleCall);
  5326. RegModuleCall.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],'module']);
  5327. ArgArray := RegModuleCall.Args;
  5328. RegModuleCall.Args:=ArgArray;
  5329. // add unitname parameter: unitname
  5330. ModuleName:=TransformModuleName(El,false,AContext);
  5331. ArgArray.Elements.AddElement.Expr:=CreateLiteralString(El,ModuleName);
  5332. // add interface-uses-section parameter: [<interface uses1>,<uses2>, ...]
  5333. UsesSection:=nil;
  5334. if (El is TPasProgram) then
  5335. UsesSection:=TPasProgram(El).ProgramSection
  5336. else if (El is TPasLibrary) then
  5337. UsesSection:=TPasLibrary(El).LibrarySection
  5338. else
  5339. UsesSection:=El.InterfaceSection;
  5340. ArgArray.Elements.AddElement.Expr:=CreateUsesList(UsesSection,AContext);
  5341. // add interface parameter: function(){}
  5342. FunDecl:=CreateFunctionSt(El,true,true);
  5343. ArgArray.AddElement(FunDecl);
  5344. Src:=FunDecl.AFunction.Body.A as TJSSourceElements;
  5345. if coUseStrict in Options then
  5346. // "use strict" must be the first statement in a function
  5347. AddToSourceElements(Src,CreateLiteralString(El,'use strict'));
  5348. NeedRTLCheckVersion:=(coRTLVersionCheckUnit in Options)
  5349. or ((coRTLVersionCheckSystem in Options) and IsSystemUnit(El));
  5350. if NeedRTLCheckVersion then
  5351. begin
  5352. Call:=CreateCallExpression(El);
  5353. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnCheckVersion]]);
  5354. Call.AddArg(CreateLiteralNumber(El,RTLVersion));
  5355. AddToSourceElements(Src,Call);
  5356. end;
  5357. ImplVarSt:=nil;
  5358. HasImplUsesClause:=false;
  5359. IntfContext:=TSectionContext.Create(El,Src,AContext);
  5360. try
  5361. // add "var $mod = this;"
  5362. IntfContext.ThisPas:=El;
  5363. if El.CustomData is TPasModuleScope then
  5364. IntfContext.ScannerBoolSwitches:=TPasModuleScope(El.CustomData).BoolSwitches;
  5365. ModVarName:=FBuiltInNames[pbivnModule];
  5366. IntfContext.AddLocalVar(ModVarName,El);
  5367. AddToSourceElements(Src,CreateVarStatement(ModVarName,
  5368. CreatePrimitiveDotExpr('this',El),El));
  5369. if (El is TPasProgram) then
  5370. begin // program
  5371. if Assigned(TPasProgram(El).ProgramSection) then
  5372. AddToSourceElements(Src,ConvertDeclarations(TPasProgram(El).ProgramSection,IntfContext));
  5373. CreateInitSection(El,Src,IntfContext);
  5374. end
  5375. else if El is TPasLibrary then
  5376. begin // library
  5377. if Assigned(TPasLibrary(El).LibrarySection) then
  5378. AddToSourceElements(Src,ConvertDeclarations(TPasLibrary(El).LibrarySection,IntfContext));
  5379. CreateInitSection(El,Src,IntfContext);
  5380. end
  5381. else
  5382. begin // unit
  5383. if Assigned(El.ImplementationSection) then
  5384. begin
  5385. // add var $impl = $mod.$impl
  5386. ImplVarSt:=CreateVarStatement(FBuiltInNames[pbivnImplementation],
  5387. CreateMemberExpression([ModVarName,FBuiltInNames[pbivnImplementation]]),El);
  5388. AddToSourceElements(Src,ImplVarSt);
  5389. // register local var $impl
  5390. IntfContext.AddLocalVar(FBuiltInNames[pbivnImplementation],El.ImplementationSection);
  5391. end;
  5392. if Assigned(El.InterfaceSection) then
  5393. AddToSourceElements(Src,ConvertDeclarations(El.InterfaceSection,IntfContext));
  5394. CreateInitSection(El,Src,IntfContext);
  5395. // add optional implementation uses list: [<implementation uses1>,<uses2>, ...]
  5396. if Assigned(El.ImplementationSection) then
  5397. begin
  5398. UsesClause:=El.ImplementationSection.UsesClause;
  5399. if length(UsesClause)>0 then
  5400. begin
  5401. ArgArray.AddElement(CreateUsesList(El.ImplementationSection,AContext));
  5402. HasImplUsesClause:=true;
  5403. end;
  5404. end;
  5405. end;
  5406. finally
  5407. IntfContext.Free;
  5408. end;
  5409. // add implementation function
  5410. if ImplVarSt<>nil then
  5411. begin
  5412. ImplFunc:=CreateImplementationSection(El,AContext);
  5413. if ImplFunc=nil then
  5414. begin
  5415. // remove unneeded $impl from interface
  5416. RemoveFromSourceElements(Src,ImplVarSt);
  5417. end
  5418. else
  5419. begin
  5420. // add param
  5421. if not HasImplUsesClause then
  5422. ArgArray.AddElement(CreateLiteralNull(El));
  5423. ArgArray.AddElement(ImplFunc);
  5424. end;
  5425. end;
  5426. ok:=true;
  5427. finally
  5428. if not ok then
  5429. FreeAndNil(Result);
  5430. end;
  5431. end;
  5432. function TPasToJSConverter.CreateElement(C: TJSElementClass; Src: TPasElement
  5433. ): TJSElement;
  5434. var
  5435. Line, Col: Integer;
  5436. begin
  5437. if Assigned(Src) then
  5438. begin
  5439. TPasResolver.UnmangleSourceLineNumber(Src.SourceLinenumber,Line,Col);
  5440. Result:=C.Create(Line,Col,Src.SourceFilename);
  5441. end
  5442. else
  5443. Result:=C.Create(0,0);
  5444. end;
  5445. function TPasToJSConverter.CreateFreeOrNewInstanceExpr(Ref: TResolvedReference;
  5446. AContext: TConvertContext): TJSCallExpression;
  5447. // create "$create("funcname");"
  5448. var
  5449. C: TJSCallExpression;
  5450. Proc: TPasProcedure;
  5451. ProcScope: TPasProcedureScope;
  5452. ClassScope: TPasClassScope;
  5453. aClass: TPasElement;
  5454. ArgEx: TJSLiteral;
  5455. FunName: String;
  5456. begin
  5457. Result:=nil;
  5458. //writeln('TPasToJSConverter.CreateFreeOrNewInstanceExpr Ref.Declaration=',GetObjName(Ref.Declaration));
  5459. Proc:=Ref.Declaration as TPasProcedure;
  5460. if Proc.Name='' then
  5461. RaiseInconsistency(20170125191914,Proc);
  5462. //writeln('TPasToJSConverter.CreateFreeOrNewInstanceExpr Proc.Name=',Proc.Name);
  5463. ProcScope:=Proc.CustomData as TPasProcedureScope;
  5464. //writeln('TPasToJSConverter.CreateFreeOrNewInstanceExpr ProcScope.Element=',GetObjName(ProcScope.Element),' ProcScope.ClassScope=',GetObjName(ProcScope.ClassScope),' ProcScope.DeclarationProc=',GetObjName(ProcScope.DeclarationProc),' ProcScope.ImplProc=',GetObjName(ProcScope.ImplProc),' ProcScope.CustomData=',GetObjName(ProcScope.CustomData));
  5465. ClassScope:=ProcScope.ClassScope;
  5466. aClass:=ClassScope.Element;
  5467. if aClass.Name='' then
  5468. RaiseInconsistency(20170125191923,aClass);
  5469. //writeln('TPasToJSConverter.CreateFreeOrNewInstanceExpr aClass.Name=',aClass.Name);
  5470. C:=CreateCallExpression(Ref.Element);
  5471. try
  5472. // add "$create()"
  5473. if rrfNewInstance in Ref.Flags then
  5474. FunName:=FBuiltInNames[pbifnClassInstanceNew]
  5475. else
  5476. FunName:=FBuiltInNames[pbifnClassInstanceFree];
  5477. FunName:=CreateReferencePath(Proc,AContext,rpkPathWithDot,false,Ref)+FunName;
  5478. C.Expr:=CreatePrimitiveDotExpr(FunName,Ref.Element);
  5479. // parameter: "funcname"
  5480. ArgEx := CreateLiteralString(Ref.Element,TransformVariableName(Proc,AContext));
  5481. C.AddArg(ArgEx);
  5482. Result:=C;
  5483. finally
  5484. if Result=nil then
  5485. C.Free;
  5486. end;
  5487. end;
  5488. function TPasToJSConverter.CreateFunctionSt(El: TPasElement; WithBody: boolean;
  5489. WithSrc: boolean): TJSFunctionDeclarationStatement;
  5490. var
  5491. FuncSt: TJSFunctionDeclarationStatement;
  5492. begin
  5493. FuncSt:=TJSFunctionDeclarationStatement(CreateElement(TJSFunctionDeclarationStatement,El));
  5494. Result:=FuncSt;
  5495. FuncSt.AFunction:=CreateFunctionDef(El,WithBody,WithSrc);
  5496. end;
  5497. function TPasToJSConverter.CreateFunctionDef(El: TPasElement;
  5498. WithBody: boolean; WithSrc: boolean): TJSFuncDef;
  5499. begin
  5500. Result:=TJSFuncDef.Create;
  5501. if WithBody then
  5502. begin
  5503. Result.Body:=TJSFunctionBody(CreateElement(TJSFunctionBody,El));
  5504. if WithSrc then
  5505. Result.Body.A:=TJSSourceElements(CreateElement(TJSSourceElements, El));
  5506. end;
  5507. end;
  5508. function TPasToJSConverter.ConvertUnaryExpression(El: TUnaryExpr;
  5509. AContext: TConvertContext): TJSElement;
  5510. procedure NotSupported(Id: TMaxPrecInt);
  5511. var
  5512. ResolvedEl: TPasResolverResult;
  5513. begin
  5514. if AContext.Resolver<>nil then
  5515. begin
  5516. AContext.Resolver.ComputeElement(El.Operand,ResolvedEl,[],El);
  5517. DoError(Id,nIllegalQualifierInFrontOf,sIllegalQualifierInFrontOf,
  5518. [OpcodeStrings[El.OpCode],AContext.Resolver.GetResolverResultDescription(ResolvedEl)],El);
  5519. end
  5520. else
  5521. DoError(Id,nUnaryOpcodeNotSupported,sUnaryOpcodeNotSupported,
  5522. [OpcodeStrings[El.OpCode]],El);
  5523. end;
  5524. function DerefPointer(TypeEl: TPasType): boolean;
  5525. begin
  5526. if TypeEl.ClassType=TPasRecordType then
  5527. begin
  5528. // PRecordVar^ -> PRecordVar
  5529. ConvertUnaryExpression:=ConvertElement(El.Operand,AContext);
  5530. exit(true);
  5531. end;
  5532. Result:=false;
  5533. end;
  5534. Var
  5535. U : TJSUnaryExpression;
  5536. E : TJSElement;
  5537. ResolvedOp, ResolvedEl: TPasResolverResult;
  5538. BitwiseNot: Boolean;
  5539. aResolver: TPas2JSResolver;
  5540. TypeEl, SubTypeEl: TPasType;
  5541. begin
  5542. if AContext=nil then ;
  5543. aResolver:=AContext.Resolver;
  5544. Result:=Nil;
  5545. U:=nil;
  5546. Case El.OpCode of
  5547. eopAdd:
  5548. begin
  5549. E:=ConvertElement(El.Operand,AContext);
  5550. U:=CreateUnaryPlus(E,El);
  5551. U.A:=E;
  5552. end;
  5553. eopSubtract:
  5554. begin
  5555. E:=ConvertElement(El.Operand,AContext);
  5556. U:=TJSUnaryMinusExpression(CreateElement(TJSUnaryMinusExpression,El));
  5557. U.A:=E;
  5558. end;
  5559. eopNot:
  5560. begin
  5561. E:=ConvertElement(El.Operand,AContext);
  5562. BitwiseNot:=true;
  5563. if aResolver<>nil then
  5564. begin
  5565. aResolver.ComputeElement(El.Operand,ResolvedOp,[]);
  5566. BitwiseNot:=ResolvedOp.BaseType in btAllJSInteger;
  5567. end;
  5568. if BitwiseNot then
  5569. begin
  5570. U:=TJSUnaryInvExpression(CreateElement(TJSUnaryInvExpression,El));
  5571. U.A:=E;
  5572. end
  5573. else
  5574. U:=CreateUnaryNot(E,El);
  5575. end;
  5576. eopAddress:
  5577. begin
  5578. if aResolver=nil then
  5579. NotSupported(20180423162321);
  5580. aResolver.ComputeElement(El.Operand,ResolvedEl,[rcNoImplicitProc]);
  5581. {$IFDEF VerbosePas2JS}
  5582. writeln('TPasToJSConverter.ConvertUnaryExpression ',GetResolverResultDbg(ResolvedEl));
  5583. {$ENDIF}
  5584. if ResolvedEl.BaseType=btProc then
  5585. begin
  5586. if ResolvedEl.IdentEl is TPasProcedure then
  5587. begin
  5588. Result:=CreateCallback(El.Operand,ResolvedEl,AContext);
  5589. exit;
  5590. end;
  5591. end
  5592. else if (ResolvedEl.BaseType=btContext) then
  5593. begin
  5594. TypeEl:=ResolvedEl.LoTypeEl;
  5595. if TypeEl.ClassType=TPasRecordType then
  5596. begin
  5597. // @RecVar -> RecVar
  5598. Result:=ConvertElement(El.Operand,AContext);
  5599. exit;
  5600. end;
  5601. end;
  5602. end;
  5603. eopDeref:
  5604. begin
  5605. if aResolver=nil then
  5606. NotSupported(20180423162350);
  5607. aResolver.ComputeElement(El.Operand,ResolvedEl,[rcNoImplicitProc]);
  5608. if ResolvedEl.BaseType=btPointer then
  5609. begin
  5610. TypeEl:=ResolvedEl.LoTypeEl;
  5611. if DerefPointer(TypeEl) then exit;
  5612. end
  5613. else if (ResolvedEl.BaseType=btContext) then
  5614. begin
  5615. TypeEl:=ResolvedEl.LoTypeEl;
  5616. if TypeEl.ClassType=TPasPointerType then
  5617. begin
  5618. SubTypeEl:=aResolver.ResolveAliasType(TPasPointerType(TypeEl).DestType);
  5619. if DerefPointer(SubTypeEl) then exit;
  5620. end;
  5621. end;
  5622. end;
  5623. eopMemAddress:
  5624. begin
  5625. // @@ProcVar -> ProcVar
  5626. Result:=ConvertElement(El.Operand,AContext);
  5627. exit;
  5628. end;
  5629. end;
  5630. if U=nil then
  5631. NotSupported(20180423162324);
  5632. Result:=U;
  5633. end;
  5634. function TPasToJSConverter.GetExpressionValueType(El: TPasExpr;
  5635. AContext: TConvertContext): TJSType;
  5636. Function CombineValueType(A,B : TJSType) : TJSType;
  5637. begin
  5638. If (A=jstUNDEFINED) then
  5639. Result:=B
  5640. else if (B=jstUNDEFINED) then
  5641. Result:=A
  5642. else
  5643. Result:=A; // pick the first
  5644. end;
  5645. Var
  5646. A,B : TJSType;
  5647. begin
  5648. if (El is TBoolConstExpr) then
  5649. Result:=jstBoolean
  5650. else if (El is TPrimitiveExpr) then
  5651. begin
  5652. Case El.Kind of
  5653. pekIdent : Result:=GetPasIdentValueType(El.Name,AContext);
  5654. pekNumber : Result:=jstNumber;
  5655. pekString : Result:=jstString;
  5656. pekSet : Result:=jstUNDEFINED;
  5657. pekNil : Result:=jstNull;
  5658. pekBoolConst : Result:=jstBoolean;
  5659. pekRange : Result:=jstUNDEFINED;
  5660. pekFuncParams : Result:=jstUNDEFINED;
  5661. pekArrayParams : Result:=jstUNDEFINED;
  5662. pekListOfExp : Result:=jstUNDEFINED;
  5663. pekInherited : Result:=jstUNDEFINED;
  5664. pekSelf : Result:=jstObject;
  5665. end
  5666. end
  5667. else if (El is TUnaryExpr) then
  5668. Result:=GetExpressionValueType(TUnaryExpr(El).Operand,AContext)
  5669. else if (El is TBinaryExpr) then
  5670. begin
  5671. A:=GetExpressionValueType(TBinaryExpr(El).Left,AContext);
  5672. B:=GetExpressionValueType(TBinaryExpr(El).Right,AContext);
  5673. Result:=CombineValueType(A,B);
  5674. end
  5675. else
  5676. result:=jstUndefined
  5677. end;
  5678. function TPasToJSConverter.GetPasIdentValueType(AName: String;
  5679. AContext: TConvertContext): TJSType;
  5680. begin
  5681. if AContext=nil then ;
  5682. if AName='' then ;
  5683. Result:=jstUNDEFINED;
  5684. end;
  5685. function TPasToJSConverter.ComputeConstString(Expr: TPasExpr;
  5686. AContext: TConvertContext; NotEmpty: boolean): String;
  5687. var
  5688. Prim: TPrimitiveExpr;
  5689. begin
  5690. if AContext.Resolver<>nil then
  5691. Result:=AContext.Resolver.ComputeConstString(Expr,false,NotEmpty)
  5692. else
  5693. begin
  5694. // fall back:
  5695. Result:='';
  5696. if Expr is TPrimitiveExpr then
  5697. begin
  5698. Prim:=TPrimitiveExpr(Expr);
  5699. if Prim.Kind=pekString then
  5700. Result:=Prim.Value
  5701. else
  5702. RaiseNotSupported(Prim,AContext,20170215124733);
  5703. end
  5704. else
  5705. RaiseNotSupported(Expr,AContext,20170322121331);
  5706. end;
  5707. end;
  5708. function TPasToJSConverter.IsLiteralInteger(El: TJSElement; out
  5709. Number: TMaxPrecInt): boolean;
  5710. var
  5711. Value: TJSValue;
  5712. begin
  5713. Result:=false;
  5714. if not (El is TJSLiteral) then exit;
  5715. Value:=TJSLiteral(El).Value;
  5716. if (Value.ValueType=jstNumber) then
  5717. try
  5718. Number:=Round(Value.AsNumber);
  5719. if Number=Value.AsNumber then
  5720. exit(true);
  5721. except
  5722. end;
  5723. end;
  5724. function TPasToJSConverter.IsLiteralNumber(El: TJSElement; out n: TJSNumber
  5725. ): boolean;
  5726. var
  5727. Value: TJSValue;
  5728. begin
  5729. if not (El is TJSLiteral) then exit(false);
  5730. Value:=TJSLiteral(El).Value;
  5731. if Value.ValueType<>jstNumber then exit(false);
  5732. Result:=true;
  5733. n:=Value.AsNumber;
  5734. end;
  5735. function TPasToJSConverter.GetOverloadName(El: TPasElement;
  5736. AContext: TConvertContext): string;
  5737. begin
  5738. if AContext.Resolver<>nil then
  5739. Result:=AContext.Resolver.GetOverloadName(El)
  5740. else
  5741. Result:=El.Name;
  5742. end;
  5743. function TPasToJSConverter.CanClashWithGlobal(El: TPasElement): boolean;
  5744. var
  5745. C: TClass;
  5746. begin
  5747. C:=El.ClassType;
  5748. if C=TPasArgument then
  5749. Result:=true
  5750. else if El.Parent is TProcedureBody then
  5751. Result:=true
  5752. else if El.Parent is TPasImplExceptOn then
  5753. Result:=true
  5754. else
  5755. Result:=false;
  5756. end;
  5757. function TPasToJSConverter.ConvertBinaryExpression(El: TBinaryExpr;
  5758. AContext: TConvertContext): TJSElement;
  5759. Const
  5760. BinClasses : Array [TExprOpCode] of TJSBinaryClass = (
  5761. Nil, //eopEmpty,
  5762. TJSAdditiveExpressionPlus, // +
  5763. TJSAdditiveExpressionMinus, // -
  5764. TJSMultiplicativeExpressionMul, // *
  5765. TJSMultiplicativeExpressionDiv, // /
  5766. TJSMultiplicativeExpressionDiv, // div
  5767. TJSMultiplicativeExpressionMod, // mod
  5768. Nil, //eopPower
  5769. TJSURShiftExpression, // shr
  5770. TJSLShiftExpression, // shl
  5771. Nil, // Not
  5772. Nil, // And
  5773. Nil, // Or
  5774. Nil, // XOr
  5775. TJSEqualityExpressionSEQ,
  5776. TJSEqualityExpressionSNE,
  5777. TJSRelationalExpressionLT,
  5778. TJSRelationalExpressionGT,
  5779. TJSRelationalExpressionLE,
  5780. TJSRelationalExpressionGE,
  5781. Nil, // In
  5782. TJSRelationalExpressionInstanceOf, // is
  5783. Nil, // As
  5784. Nil, // Symmetrical diff
  5785. Nil, // Address,
  5786. Nil, // Deref
  5787. Nil, // MemAddress
  5788. Nil // SubIndent,
  5789. );
  5790. Var
  5791. LeftResolved, RightResolved: TPasResolverResult;
  5792. procedure NotSupportedRes(id: TMaxPrecInt);
  5793. begin
  5794. {$IFDEF VerbosePas2JS}
  5795. writeln('TPasToJSConverter.ConvertBinaryExpression.NotSupportedRes',
  5796. ' Left=',GetResolverResultDbg(LeftResolved),
  5797. ' Op=',ExprKindNames[El.Kind],
  5798. ' Right=',GetResolverResultDbg(RightResolved));
  5799. {$ENDIF}
  5800. RaiseNotSupported(El,AContext,id,
  5801. GetResolverResultDbg(LeftResolved)+ExprKindNames[El.Kind]
  5802. +GetResolverResultDbg(RightResolved));
  5803. end;
  5804. var
  5805. R : TJSBinary;
  5806. C : TJSBinaryClass;
  5807. A,B: TJSElement;
  5808. UseBitwiseOp: Boolean;
  5809. Call: TJSCallExpression;
  5810. Flags: TPasResolverComputeFlags;
  5811. ModeSwitches: TModeSwitches;
  5812. aResolver: TPas2JSResolver;
  5813. LeftTypeEl, RightTypeEl: TPasType;
  5814. begin
  5815. Result:=Nil;
  5816. aResolver:=AContext.Resolver;
  5817. case El.OpCode of
  5818. eopSubIdent:
  5819. begin
  5820. Result:=ConvertSubIdentExpression(El,AContext);
  5821. exit;
  5822. end;
  5823. eopNone:
  5824. if El.left is TInheritedExpr then
  5825. begin
  5826. Result:=ConvertInheritedExpr(TInheritedExpr(El.left),AContext);
  5827. exit;
  5828. end;
  5829. end;
  5830. if AContext.Access<>caRead then
  5831. begin
  5832. {$IFDEF VerbosePas2JS}
  5833. writeln('TPasToJSConverter.ConvertBinaryExpression OpCode=',El.OpCode,' AContext.Access=',AContext.Access);
  5834. {$ENDIF}
  5835. DoError(20170209152633,nVariableIdentifierExpected,sVariableIdentifierExpected,[],El);
  5836. end;
  5837. Call:=nil;
  5838. A:=ConvertElement(El.left,AContext);
  5839. B:=nil;
  5840. try
  5841. B:=ConvertElement(El.right,AContext);
  5842. if aResolver<>nil then
  5843. begin
  5844. ModeSwitches:=AContext.CurrentModeSwitches;
  5845. // compute left
  5846. Flags:=[];
  5847. if El.OpCode in [eopEqual,eopNotEqual] then
  5848. if not (msDelphi in ModeSwitches) then
  5849. Flags:=[rcNoImplicitProcType];
  5850. aResolver.ComputeElement(El.left,LeftResolved,Flags);
  5851. // compute right
  5852. Flags:=[];
  5853. if (El.OpCode in [eopEqual,eopNotEqual])
  5854. and not (msDelphi in ModeSwitches) then
  5855. begin
  5856. if LeftResolved.BaseType=btNil then
  5857. Flags:=[rcNoImplicitProcType]
  5858. else if aResolver.IsProcedureType(LeftResolved,true) then
  5859. Flags:=[rcNoImplicitProcType]
  5860. else
  5861. Flags:=[];
  5862. end;
  5863. aResolver.ComputeElement(El.right,RightResolved,Flags);
  5864. Result:=ConvertBinaryExpressionRes(El,AContext,LeftResolved,RightResolved,A,B);
  5865. if Result<>nil then exit;
  5866. {$IFDEF VerbosePas2JS}
  5867. writeln('TPasToJSConverter.ConvertBinaryExpression Left=',GetResolverResultDbg(LeftResolved),' Right=',GetResolverResultDbg(RightResolved));
  5868. {$ENDIF}
  5869. end;
  5870. C:=BinClasses[El.OpCode];
  5871. if C=nil then
  5872. Case El.OpCode of
  5873. eopAs :
  5874. begin
  5875. // "A as B"
  5876. Call:=CreateCallExpression(El);
  5877. LeftTypeEl:=LeftResolved.LoTypeEl;
  5878. RightTypeEl:=RightResolved.LoTypeEl;
  5879. if LeftTypeEl is TPasClassType then
  5880. begin
  5881. if RightTypeEl is TPasClassType then
  5882. case TPasClassType(LeftTypeEl).ObjKind of
  5883. okClass:
  5884. case TPasClassType(RightTypeEl).ObjKind of
  5885. okClass:
  5886. // ClassInstVar is ClassType
  5887. if TPasClassType(RightResolved.LoTypeEl).IsExternal then
  5888. // B is external class -> "rtl.asExt(A,B)"
  5889. Call.Expr:=CreatePrimitiveDotExpr(FBuiltInNames[pbivnRTL]+'.'+FBuiltInNames[pbifnAsExt],El)
  5890. else
  5891. // otherwise -> "rtl.as(A,B)"
  5892. Call.Expr:=CreatePrimitiveDotExpr(FBuiltInNames[pbivnRTL]+'.'+FBuiltInNames[pbifnAs],El);
  5893. okInterface:
  5894. begin
  5895. // ClassInstVar as IntfType
  5896. case TPasClassType(RightTypeEl).InterfaceType of
  5897. citCom:
  5898. begin
  5899. // COM: $ir.ref(rtl.queryIntfT(objVar,intftype),"id")
  5900. Call.Expr:=CreatePrimitiveDotExpr(FBuiltInNames[pbivnRTL]+'.'+FBuiltInNames[pbifnIntfQueryIntfT],El);
  5901. Call.AddArg(A);
  5902. Call.AddArg(B);
  5903. Call:=CreateIntfRef(Call,AContext,El);
  5904. Result:=Call;
  5905. exit;
  5906. end;
  5907. citCorba:
  5908. // CORBA: rtl.getIntfT(objVar,intftype)
  5909. Call.Expr:=CreatePrimitiveDotExpr(FBuiltInNames[pbivnRTL]+'.'+FBuiltInNames[pbifnIntfGetIntfT],El);
  5910. else RaiseNotSupported(El,AContext,20180401225752);
  5911. end;
  5912. end
  5913. else
  5914. NotSupportedRes(20180327214535);
  5915. end;
  5916. okInterface:
  5917. case TPasClassType(RightTypeEl).ObjKind of
  5918. okClass:
  5919. // IntfVar as ClassType -> rtl.intfAsClass(intfvar,classtype)
  5920. Call.Expr:=CreatePrimitiveDotExpr(FBuiltInNames[pbivnRTL]+'.'+FBuiltInNames[pbifnIntfAsClass],El);
  5921. okInterface:
  5922. // IntfVar as IntfType -> "rtl.as(A,B)"
  5923. Call.Expr:=CreatePrimitiveDotExpr(FBuiltInNames[pbivnRTL]+'.'+FBuiltInNames[pbifnAs],El);
  5924. else
  5925. NotSupportedRes(20180327214545);
  5926. end;
  5927. else
  5928. NotSupportedRes(20180327214559);
  5929. end
  5930. else if RightTypeEl is TPasClassOfType then
  5931. begin
  5932. // ClassInstVar is ClassOfType -> "rtl.as(A,B)"
  5933. Call.Expr:=CreatePrimitiveDotExpr(FBuiltInNames[pbivnRTL]+'.'+FBuiltInNames[pbifnAs],El);
  5934. end;
  5935. end;
  5936. Call.AddArg(A);
  5937. Call.AddArg(B);
  5938. Result:=Call;
  5939. exit;
  5940. end;
  5941. eopAnd,
  5942. eopOr,
  5943. eopXor:
  5944. begin
  5945. if aResolver<>nil then
  5946. UseBitwiseOp:=((LeftResolved.BaseType in btAllJSInteger)
  5947. or (RightResolved.BaseType in btAllJSInteger))
  5948. else
  5949. UseBitwiseOp:=(GetExpressionValueType(El.left,AContext)=jstNumber)
  5950. or (GetExpressionValueType(El.right,AContext)=jstNumber);
  5951. if UseBitwiseOp then
  5952. Case El.OpCode of
  5953. eopAnd : C:=TJSBitwiseAndExpression;
  5954. eopOr : C:=TJSBitwiseOrExpression;
  5955. eopXor : C:=TJSBitwiseXOrExpression;
  5956. end
  5957. else
  5958. Case El.OpCode of
  5959. eopAnd : C:=TJSLogicalAndExpression;
  5960. eopOr : C:=TJSLogicalOrExpression;
  5961. eopXor : C:=TJSBitwiseXOrExpression;
  5962. else
  5963. DoError(20161024191234,nBinaryOpcodeNotSupported,sBinaryOpcodeNotSupported,['logical XOR'],El);
  5964. end;
  5965. end;
  5966. eopPower:
  5967. begin
  5968. Call:=CreateCallExpression(El);
  5969. Call.Expr:=CreatePrimitiveDotExpr('Math.pow',El);
  5970. Call.AddArg(A);
  5971. Call.AddArg(B);
  5972. Result:=Call;
  5973. end
  5974. else
  5975. if C=nil then
  5976. DoError(20161024191244,nBinaryOpcodeNotSupported,sBinaryOpcodeNotSupported,[OpcodeStrings[El.OpCode]],El);
  5977. end;
  5978. if (Result=Nil) and (C<>Nil) then
  5979. begin
  5980. R:=TJSBinary(CreateElement(C,El));
  5981. R.A:=A; A:=nil;
  5982. R.B:=B; B:=nil;
  5983. Result:=R;
  5984. if El.OpCode=eopDiv then
  5985. begin
  5986. // convert "a div b" to "Math.floor(a/b)"
  5987. Result:=CreateMathFloor(El,Result);
  5988. end;
  5989. end;
  5990. finally
  5991. if Result=nil then
  5992. begin
  5993. A.Free;
  5994. B.Free;
  5995. end;
  5996. end;
  5997. end;
  5998. function TPasToJSConverter.ConvertBinaryExpressionRes(El: TBinaryExpr;
  5999. AContext: TConvertContext; const LeftResolved,
  6000. RightResolved: TPasResolverResult; var A, B: TJSElement): TJSElement;
  6001. procedure NotSupported(id: TMaxPrecInt);
  6002. begin
  6003. {$IFDEF VerbosePas2JS}
  6004. writeln('TPasToJSConverter.ConvertBinaryExpressionRes.NotSupported',
  6005. ' Left=',GetResolverResultDbg(LeftResolved),
  6006. ' Op=',ExprKindNames[El.Kind],
  6007. ' Right=',GetResolverResultDbg(RightResolved));
  6008. {$ENDIF}
  6009. RaiseNotSupported(El,AContext,id,
  6010. GetResolverResultDbg(LeftResolved)+ExprKindNames[El.Kind]
  6011. +GetResolverResultDbg(RightResolved));
  6012. end;
  6013. function CreateEqualCallback: TJSElement;
  6014. var
  6015. Call: TJSCallExpression;
  6016. begin
  6017. // convert "proctypeA = proctypeB" to "rtl.eqCallback(proctypeA,proctypeB)"
  6018. Call:=CreateCallExpression(El);
  6019. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnProcType_Equal]]);
  6020. Call.AddArg(A);
  6021. A:=nil;
  6022. Call.AddArg(B);
  6023. B:=nil;
  6024. if El.OpCode=eopNotEqual then
  6025. begin
  6026. // convert "proctypeA <> proctypeB" to "!rtl.eqCallback(proctypeA,proctypeB)"
  6027. Result:=CreateUnaryNot(Call,El);
  6028. end
  6029. else
  6030. Result:=Call;
  6031. end;
  6032. procedure ConcatArray(ArrayType: TPasArrayType);
  6033. var
  6034. Call: TJSCallExpression;
  6035. begin
  6036. Call:=CreateArrayConcat(ArrayType,El,AContext);
  6037. Result:=Call;
  6038. Call.AddArg(A); A:=nil;
  6039. Call.AddArg(B); B:=nil;
  6040. end;
  6041. var
  6042. aResolver: TPas2JSResolver;
  6043. FunName: String;
  6044. Call: TJSCallExpression;
  6045. DotExpr: TJSDotMemberExpression;
  6046. InOp: TJSRelationalExpressionIn;
  6047. TypeEl, LeftTypeEl, RightTypeEl: TPasType;
  6048. SNE: TJSEqualityExpressionSNE;
  6049. JSBinClass: TJSBinaryClass;
  6050. ResolvedEl: TPasResolverResult;
  6051. begin
  6052. {$IFDEF VerbosePas2JS}
  6053. writeln('TPasToJSConverter.ConvertBinaryExpressionRes OpCode="',OpcodeStrings[El.OpCode],'" Left=',GetResolverResultDbg(LeftResolved),' Right=',GetResolverResultDbg(RightResolved));
  6054. {$ENDIF}
  6055. Result:=nil;
  6056. aResolver:=AContext.Resolver;
  6057. LeftTypeEl:=LeftResolved.LoTypeEl;
  6058. RightTypeEl:=RightResolved.LoTypeEl;
  6059. if (LeftResolved.BaseType in [btSet,btArrayOrSet])
  6060. and (RightResolved.BaseType in [btSet,btArrayOrSet]) then
  6061. begin
  6062. // set operators -> rtl.operatorfunction(a,b)
  6063. case El.OpCode of
  6064. eopAdd: FunName:=FBuiltInNames[pbifnSet_Union];
  6065. eopSubtract: FunName:=FBuiltInNames[pbifnSet_Difference];
  6066. eopMultiply: FunName:=FBuiltInNames[pbifnSet_Intersect];
  6067. eopSymmetricaldifference: FunName:=FBuiltInNames[pbifnSet_SymDiffSet];
  6068. eopEqual: FunName:=FBuiltInNames[pbifnSet_Equal];
  6069. eopNotEqual: FunName:=FBuiltInNames[pbifnSet_NotEqual];
  6070. eopGreaterThanEqual: FunName:=FBuiltInNames[pbifnSet_GreaterEqual];
  6071. eopLessthanEqual: FunName:=FBuiltInNames[pbifnSet_LowerEqual];
  6072. else
  6073. DoError(20170209151300,nBinaryOpcodeNotSupported,sBinaryOpcodeNotSupported,[OpcodeStrings[El.OpCode]],El);
  6074. end;
  6075. Call:=CreateCallExpression(El);
  6076. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FunName]);
  6077. Call.AddArg(A); A:=nil;
  6078. Call.AddArg(B); B:=nil;
  6079. Result:=Call;
  6080. exit;
  6081. end
  6082. else if (El.OpCode=eopIn) and (RightResolved.BaseType in [btSet,btArrayOrSet]) then
  6083. begin
  6084. // a in b -> a in b
  6085. if not (A is TJSLiteral) or (TJSLiteral(A).Value.ValueType<>jstNumber) then
  6086. begin
  6087. FreeAndNil(A);
  6088. A:=CreateSetLiteralElement(El.left,AContext);
  6089. end;
  6090. InOp:=TJSRelationalExpressionIn(CreateElement(TJSRelationalExpressionIn,El));
  6091. InOp.A:=A; A:=nil;
  6092. InOp.B:=B; B:=nil;
  6093. Result:=InOp;
  6094. exit;
  6095. end
  6096. else if (El.OpCode=eopAdd)
  6097. and ((LeftResolved.BaseType=btContext) and (LeftResolved.LoTypeEl.ClassType=TPasArrayType)) then
  6098. begin
  6099. // Arr+Arr Arr+[] Arr+[...]
  6100. ConcatArray(TPasArrayType(LeftResolved.LoTypeEl));
  6101. exit;
  6102. end
  6103. else if (El.OpCode=eopAdd)
  6104. and ((RightResolved.BaseType=btContext) and (RightResolved.LoTypeEl.ClassType=TPasArrayType)) then
  6105. begin
  6106. // []+Arr [...]+Arr
  6107. ConcatArray(TPasArrayType(RightResolved.LoTypeEl));
  6108. exit;
  6109. end
  6110. else if (El.OpCode=eopAdd)
  6111. and (LeftResolved.BaseType=btArrayLit) then
  6112. begin
  6113. // [...]+[] [...]+[...]
  6114. SetResolverValueExpr(ResolvedEl,LeftResolved.SubType,LeftResolved.LoTypeEl,
  6115. LeftResolved.HiTypeEl,El.left,LeftResolved.Flags);
  6116. Call:=CreateArrayConcat(ResolvedEl,El,AContext);
  6117. Result:=Call;
  6118. Call.AddArg(A); A:=nil;
  6119. Call.AddArg(B); B:=nil;
  6120. exit;
  6121. end
  6122. else if (LeftResolved.BaseType=btCurrency) or (RightResolved.BaseType=btCurrency) then
  6123. begin
  6124. case El.OpCode of
  6125. eopAdd,eopSubtract,
  6126. eopEqual, eopNotEqual, // Logical
  6127. eopLessThan,eopGreaterThan, eopLessthanEqual,eopGreaterThanEqual: // ordering
  6128. begin
  6129. // currency + currency -> currency + currency
  6130. // currency + number -> currency + number*10000
  6131. // number + currency -> number*10000 + currency
  6132. case El.OpCode of
  6133. eopAdd: JSBinClass:=TJSAdditiveExpressionPlus;
  6134. eopSubtract: JSBinClass:=TJSAdditiveExpressionMinus;
  6135. eopEqual: JSBinClass:=TJSEqualityExpressionSEQ;
  6136. eopNotEqual: JSBinClass:=TJSEqualityExpressionSNE;
  6137. eopLessThan: JSBinClass:=TJSRelationalExpressionLT;
  6138. eopGreaterThan: JSBinClass:=TJSRelationalExpressionGT;
  6139. eopLessthanEqual: JSBinClass:=TJSRelationalExpressionLE;
  6140. eopGreaterThanEqual: JSBinClass:=TJSRelationalExpressionGE;
  6141. end;
  6142. Result:=TJSBinary(CreateElement(JSBinClass,El));
  6143. if LeftResolved.BaseType<>btCurrency then
  6144. A:=CreateMulNumber(El,A,10000);
  6145. TJSBinary(Result).A:=A; A:=nil;
  6146. if RightResolved.BaseType<>btCurrency then
  6147. B:=CreateMulNumber(El,B,10000);
  6148. TJSBinary(Result).B:=B; B:=nil;
  6149. exit;
  6150. end;
  6151. eopMultiply:
  6152. begin
  6153. // currency * currency -> (currency * currency)/10000
  6154. // currency * number -> currency * number
  6155. // number * currency -> number * currency
  6156. Result:=TJSMultiplicativeExpressionMul(CreateElement(TJSMultiplicativeExpressionMul,El));
  6157. TJSBinaryExpression(Result).A:=A; A:=nil;
  6158. TJSBinaryExpression(Result).B:=B; B:=nil;
  6159. if (LeftResolved.BaseType=btCurrency) and (RightResolved.BaseType=btCurrency) then
  6160. Result:=CreateDivideNumber(El,Result,10000);
  6161. exit;
  6162. end;
  6163. eopDivide:
  6164. begin
  6165. // currency / currency -> Math.floor((currency/currency)*10000)
  6166. // currency / number -> Math.floor(currency/number)
  6167. // number / currency -> Math.floor(number/currency)
  6168. Result:=TJSMultiplicativeExpressionDiv(CreateElement(TJSMultiplicativeExpressionDiv,El));
  6169. TJSBinaryExpression(Result).A:=A; A:=nil;
  6170. TJSBinaryExpression(Result).B:=B; B:=nil;
  6171. if (LeftResolved.BaseType=btCurrency) and (RightResolved.BaseType=btCurrency) then
  6172. Result:=CreateMulNumber(El,Result,10000);
  6173. Result:=CreateMathFloor(El,Result);
  6174. exit;
  6175. end;
  6176. eopPower:
  6177. begin
  6178. // currency^^currency -> Math.floor(Math.pow(currency/10000,currency/10000)*10000)
  6179. // currency^^number -> Math.floor(Math.pow(currency/10000,number)*10000)
  6180. // number^^currency -> Math.floor(Math.pow(number,currency/10000)*10000)
  6181. if LeftResolved.BaseType=btCurrency then
  6182. A:=CreateDivideNumber(El,A,10000);
  6183. if RightResolved.BaseType=btCurrency then
  6184. B:=CreateDivideNumber(El,B,10000);
  6185. Call:=CreateCallExpression(El);
  6186. Call.Expr:=CreatePrimitiveDotExpr('Math.pow',El);
  6187. Call.AddArg(A); A:=nil;
  6188. Call.AddArg(B); B:=nil;
  6189. Result:=CreateMulNumber(El,Call,10000);
  6190. Result:=CreateMathFloor(El,Result);
  6191. end
  6192. else
  6193. RaiseNotSupported(El,AContext,20180422104215);
  6194. end;
  6195. end
  6196. else if (LeftResolved.BaseType=btPointer)
  6197. or ((LeftResolved.BaseType=btContext) and (LeftTypeEl.ClassType=TPasPointerType)) then
  6198. case El.OpCode of
  6199. eopEqual,eopNotEqual: ;
  6200. else
  6201. DoError(20180423114054,nIllegalQualifierAfter,sIllegalQualifierAfter,
  6202. [OpcodeStrings[El.OpCode],aResolver.GetResolverResultDescription(LeftResolved,true)],El);
  6203. end
  6204. else if (RightResolved.BaseType=btPointer)
  6205. or ((RightResolved.BaseType=btContext) and (RightTypeEl.ClassType=TPasPointerType)) then
  6206. case El.OpCode of
  6207. eopEqual,eopNotEqual: ;
  6208. else
  6209. DoError(20180423114246,nIllegalQualifierInFrontOf,sIllegalQualifierInFrontOf,
  6210. [OpcodeStrings[El.OpCode],aResolver.GetResolverResultDescription(RightResolved,true)],El);
  6211. end
  6212. else if (El.OpCode=eopIs) then
  6213. begin
  6214. // "A is B"
  6215. Call:=CreateCallExpression(El);
  6216. Result:=Call;
  6217. Call.AddArg(A); A:=nil;
  6218. if (RightResolved.IdentEl is TPasType) then
  6219. TypeEl:=aResolver.ResolveAliasType(TPasType(RightResolved.IdentEl))
  6220. else
  6221. TypeEl:=nil;
  6222. if (TypeEl is TPasClassOfType) then
  6223. begin
  6224. // "A is class-of-type" -> use the class
  6225. FreeAndNil(B);
  6226. TypeEl:=aResolver.ResolveAliasType(TPasClassOfType(TypeEl).DestType);
  6227. B:=CreateReferencePathExpr(TypeEl,AContext);
  6228. end;
  6229. if (LeftResolved.BaseType=btCustom) then
  6230. begin
  6231. // aJSValue is ... -> "rtl.isExt(A,B,mode)"
  6232. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnIsExt]]);
  6233. Call.AddArg(B); B:=nil;
  6234. if RightTypeEl is TPasClassType then
  6235. Call.AddArg(CreateLiteralNumber(El.right,IsExtModePasClassInstance))
  6236. else if RightTypeEl is TPasClassOfType then
  6237. Call.AddArg(CreateLiteralNumber(El.right,IsExtModePasClass))
  6238. else
  6239. NotSupported(20180119005904);
  6240. end
  6241. else if (RightTypeEl is TPasClassType) and TPasClassType(RightTypeEl).IsExternal then
  6242. begin
  6243. // B is an external class -> "rtl.isExt(A,B)"
  6244. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnIsExt]]);
  6245. Call.AddArg(B); B:=nil;
  6246. end
  6247. else if LeftTypeEl is TPasClassOfType then
  6248. begin
  6249. // A is a TPasClassOfType -> "rtl.is(A,B)"
  6250. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnIs]]);
  6251. Call.AddArg(B); B:=nil;
  6252. end
  6253. else
  6254. begin
  6255. if LeftTypeEl is TPasClassType then
  6256. begin
  6257. if RightTypeEl is TPasClassType then
  6258. case TPasClassType(LeftTypeEl).ObjKind of
  6259. okClass:
  6260. case TPasClassType(RightTypeEl).ObjKind of
  6261. okClass: ;
  6262. okInterface:
  6263. begin
  6264. // ClassInstVar is IntfType
  6265. case TPasClassType(RightTypeEl).InterfaceType of
  6266. citCom:
  6267. begin
  6268. // COM: rtl.queryIntfIsT(A,B)
  6269. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnIntfQueryIntfIsT]]);
  6270. Call.AddArg(B); B:=nil;
  6271. end;
  6272. citCorba:
  6273. begin
  6274. // CORBA: rtl.getIntfT(A,B)!==null
  6275. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnIntfGetIntfT]]);
  6276. Call.AddArg(B); B:=nil;
  6277. SNE:=TJSEqualityExpressionSNE(CreateElement(TJSEqualityExpressionSNE,El));
  6278. Result:=SNE;
  6279. SNE.A:=Call;
  6280. SNE.B:=CreateLiteralNull(El);
  6281. end;
  6282. else
  6283. RaiseNotSupported(El,AContext,20180401225502,InterfaceTypeNames[TPasClassType(RightTypeEl).InterfaceType]);
  6284. end;
  6285. exit;
  6286. end;
  6287. else
  6288. NotSupported(20180327210501);
  6289. end;
  6290. okInterface:
  6291. case TPasClassType(RightTypeEl).ObjKind of
  6292. okClass:
  6293. begin
  6294. // IntfVar is ClassType -> rtl.intfIsClass(A,B)
  6295. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnIntfIsClass]]);
  6296. Call.AddArg(B); B:=nil;
  6297. exit;
  6298. end;
  6299. okInterface: ;
  6300. else
  6301. NotSupported(20180327210741);
  6302. end;
  6303. else
  6304. NotSupported(20180327210251);
  6305. end;
  6306. end;
  6307. // use directly "B.isPrototypeOf(A)"
  6308. DotExpr:=TJSDotMemberExpression(CreateElement(TJSDotMemberExpression,El));
  6309. DotExpr.MExpr:=B; B:=nil;
  6310. DotExpr.Name:='isPrototypeOf';
  6311. Call.Expr:=DotExpr;
  6312. end;
  6313. exit;
  6314. end
  6315. else if (El.OpCode in [eopEqual,eopNotEqual]) then
  6316. begin
  6317. if aResolver.IsProcedureType(LeftResolved,true) then
  6318. begin
  6319. if RightResolved.BaseType=btNil then
  6320. else if aResolver.IsProcedureType(RightResolved,true)
  6321. or aResolver.IsJSBaseType(RightResolved,pbtJSValue,true) then
  6322. exit(CreateEqualCallback);
  6323. end
  6324. else if aResolver.IsProcedureType(RightResolved,true) then
  6325. begin
  6326. if LeftResolved.BaseType=btNil then
  6327. else if aResolver.IsJSBaseType(LeftResolved,pbtJSValue,true) then
  6328. exit(CreateEqualCallback);
  6329. end
  6330. else if LeftResolved.BaseType=btNil then
  6331. begin
  6332. if RightResolved.BaseType=btContext then
  6333. begin
  6334. RightTypeEl:=RightResolved.LoTypeEl;
  6335. if RightTypeEl.ClassType=TPasArrayType then
  6336. begin
  6337. // convert "nil = array" to "rtl.length(array) > 0"
  6338. FreeAndNil(A);
  6339. Result:=CreateCmpArrayWithNil(El,B,El.OpCode);
  6340. B:=nil;
  6341. exit;
  6342. end;
  6343. end;
  6344. end
  6345. else if LeftResolved.BaseType in btAllStrings then
  6346. begin
  6347. if RightResolved.BaseType=btContext then
  6348. begin
  6349. RightTypeEl:=RightResolved.LoTypeEl;
  6350. if RightTypeEl.ClassType=TPasRecordType then
  6351. begin
  6352. if aResolver.IsTGUID(TPasRecordType(RightTypeEl)) then
  6353. begin
  6354. // "aString=GuidVar" -> "GuidVar.$equal(rtl.createTGUID(aString))"
  6355. Call:=CreateCallExpression(El);
  6356. Call.Expr:=CreatePrimitiveDotExpr(FBuiltInNames[pbivnRTL]+'.'+FBuiltInNames[pbifnIntfCreateTGUID],El);
  6357. Call.AddArg(A);
  6358. A:=Call;
  6359. Call:=CreateCallExpression(El);
  6360. Call.Expr:=CreateDotExpression(El,B,CreatePrimitiveDotExpr(FBuiltInNames[pbifnRecordEqual],El));
  6361. B:=nil;
  6362. Call.AddArg(A);
  6363. A:=nil;
  6364. if El.OpCode=eopNotEqual then
  6365. Result:=CreateUnaryNot(Call,El)
  6366. else
  6367. Result:=Call;
  6368. exit;
  6369. end;
  6370. end
  6371. else if RightTypeEl.ClassType=TPasClassType then
  6372. begin
  6373. if TPasClassType(RightTypeEl).ObjKind=okInterface then
  6374. begin
  6375. // "aString=IntfTypeOrVar" -> "aString===IntfTypeOrVar.$guid"
  6376. B:=CreateDotExpression(El.left,B,CreatePrimitiveDotExpr(FBuiltInNames[pbivnIntfGUID],El.left));
  6377. end;
  6378. end;
  6379. end;
  6380. end
  6381. else if LeftResolved.BaseType=btContext then
  6382. begin
  6383. LeftTypeEl:=LeftResolved.LoTypeEl;
  6384. if LeftTypeEl.ClassType=TPasRecordType then
  6385. begin
  6386. // LHS is a record
  6387. if RightResolved.BaseType=btContext then
  6388. begin
  6389. RightTypeEl:=RightResolved.LoTypeEl;
  6390. if RightTypeEl.ClassType=TPasRecordType then
  6391. begin
  6392. // convert "recordA = recordB" to "recordA.$equal(recordB)"
  6393. Call:=CreateCallExpression(El);
  6394. Call.Expr:=CreateDotExpression(El,A,CreatePrimitiveDotExpr(FBuiltInNames[pbifnRecordEqual],El));
  6395. A:=nil;
  6396. Call.AddArg(B);
  6397. B:=nil;
  6398. if El.OpCode=eopNotEqual then
  6399. begin
  6400. // convert "recordA <> recordB" to "!recordA.$equal(recordB)"
  6401. Result:=CreateUnaryNot(Call,El);
  6402. end
  6403. else
  6404. Result:=Call;
  6405. exit;
  6406. end
  6407. else if (RightTypeEl.ClassType=TPasClassType)
  6408. and (TPasClassType(RightTypeEl).ObjKind=okInterface)
  6409. and aResolver.IsTGUID(TPasRecordType(LeftTypeEl)) then
  6410. begin
  6411. // "GuidVar = intfTypeOrVar" -> "GuidVar.$equal(rtl.getIntfGUIDR(intfTypeOrVar))"
  6412. Call:=CreateCallExpression(El);
  6413. Call.Expr:=CreatePrimitiveDotExpr(FBuiltInNames[pbivnRTL]+'.'+FBuiltInNames[pbifnIntfGetGUIDR],El);
  6414. Call.AddArg(B);
  6415. B:=Call;
  6416. Call:=CreateCallExpression(El);
  6417. Call.Expr:=CreateDotExpression(El,A,CreatePrimitiveDotExpr(FBuiltInNames[pbifnRecordEqual],El));
  6418. A:=nil;
  6419. Call.AddArg(B);
  6420. B:=nil;
  6421. if El.OpCode=eopNotEqual then
  6422. Result:=CreateUnaryNot(Call,El)
  6423. else
  6424. Result:=Call;
  6425. exit;
  6426. end;
  6427. end
  6428. else if (RightResolved.BaseType in btAllStrings)
  6429. and aResolver.IsTGUID(TPasRecordType(LeftTypeEl)) then
  6430. begin
  6431. // "GuidVar = aString" -> "GuidVar.$equal(rtl.createTGUID(aString))"
  6432. Call:=CreateCallExpression(El);
  6433. Call.Expr:=CreatePrimitiveDotExpr(FBuiltInNames[pbivnRTL]+'.'+FBuiltInNames[pbifnIntfCreateTGUID],El);
  6434. Call.AddArg(B);
  6435. B:=Call;
  6436. Call:=CreateCallExpression(El);
  6437. Call.Expr:=CreateDotExpression(El,A,CreatePrimitiveDotExpr(FBuiltInNames[pbifnRecordEqual],El));
  6438. A:=nil;
  6439. Call.AddArg(B);
  6440. B:=nil;
  6441. if El.OpCode=eopNotEqual then
  6442. Result:=CreateUnaryNot(Call,El)
  6443. else
  6444. Result:=Call;
  6445. exit;
  6446. end;
  6447. end
  6448. else if LeftTypeEl.ClassType=TPasClassType then
  6449. begin
  6450. if RightResolved.BaseType in btAllStrings then
  6451. begin
  6452. if (TPasClassType(LeftTypeEl).ObjKind=okInterface) then
  6453. begin
  6454. // "IntfTypeOrVar=aString" -> "IntfTypeOrVar.$guid === aString"
  6455. A:=CreateDotExpression(El.left,A,CreatePrimitiveDotExpr(FBuiltInNames[pbivnIntfGUID],El.left));
  6456. end;
  6457. end
  6458. else if RightResolved.BaseType=btContext then
  6459. begin
  6460. RightTypeEl:=RightResolved.LoTypeEl;
  6461. if RightTypeEl.ClassType=TPasRecordType then
  6462. begin
  6463. if (TPasClassType(LeftTypeEl).ObjKind=okInterface)
  6464. and aResolver.IsTGUID(TPasRecordType(RightTypeEl)) then
  6465. begin
  6466. // "IntfTypeOrVar=GuidVar" -> "GuidVar.$equal(rtl.getIntfGUIDR(intfTypeOrVar))"
  6467. Call:=CreateCallExpression(El);
  6468. Call.Expr:=CreatePrimitiveDotExpr(FBuiltInNames[pbivnRTL]+'.'+FBuiltInNames[pbifnIntfGetGUIDR],El);
  6469. Call.AddArg(A);
  6470. A:=Call;
  6471. Call:=CreateCallExpression(El);
  6472. Call.Expr:=CreateDotExpression(El,B,CreatePrimitiveDotExpr(FBuiltInNames[pbifnRecordEqual],El));
  6473. B:=nil;
  6474. Call.AddArg(A);
  6475. A:=nil;
  6476. if El.OpCode=eopNotEqual then
  6477. Result:=CreateUnaryNot(Call,El)
  6478. else
  6479. Result:=Call;
  6480. exit;
  6481. end;
  6482. end;
  6483. end;
  6484. end
  6485. else if LeftTypeEl.ClassType=TPasArrayType then
  6486. begin
  6487. if RightResolved.BaseType=btNil then
  6488. begin
  6489. // convert "array = nil" to "rtl.length(array) === 0"
  6490. FreeAndNil(B);
  6491. Result:=CreateCmpArrayWithNil(El,A,El.OpCode);
  6492. A:=nil;
  6493. exit;
  6494. end;
  6495. end;
  6496. end;
  6497. if aResolver.IsJSBaseType(LeftResolved,pbtJSValue)
  6498. or aResolver.IsJSBaseType(RightResolved,pbtJSValue) then
  6499. begin
  6500. // convert "jsvalue = something" to "jsvalue == something" (not strict)
  6501. // Note: default "=" is converted to "===" (strict equal)
  6502. if El.OpCode=eopEqual then
  6503. Result:=TJSEqualityExpressionEQ(CreateElement(TJSEqualityExpressionEQ,El))
  6504. else
  6505. Result:=TJSEqualityExpressionNE(CreateElement(TJSEqualityExpressionNE,El));
  6506. TJSBinaryExpression(Result).A:=A; A:=nil;
  6507. TJSBinaryExpression(Result).B:=B; B:=nil;
  6508. exit;
  6509. end;
  6510. end;
  6511. end;
  6512. function TPasToJSConverter.ConvertSubIdentExpression(El: TBinaryExpr;
  6513. AContext: TConvertContext): TJSElement;
  6514. // connect El.left and El.right with a dot.
  6515. var
  6516. Left, Right: TJSElement;
  6517. DotContext: TDotContext;
  6518. OldAccess: TCtxAccess;
  6519. LeftResolved: TPasResolverResult;
  6520. RightRef: TResolvedReference;
  6521. ParamsExpr: TParamsExpr;
  6522. RightEl: TPasExpr;
  6523. RightRefDecl: TPasElement;
  6524. aResolver: TPas2JSResolver;
  6525. begin
  6526. Result:=nil;
  6527. aResolver:=AContext.Resolver;
  6528. ParamsExpr:=nil;
  6529. // a.(RightEl.(b.c))
  6530. RightEl:=El.right;
  6531. while RightEl.ClassType=TParamsExpr do
  6532. begin
  6533. ParamsExpr:=TParamsExpr(RightEl);
  6534. RightEl:=ParamsExpr.Value;
  6535. end;
  6536. RightRef:=nil;
  6537. RightRefDecl:=nil;
  6538. if (RightEl.ClassType=TPrimitiveExpr)
  6539. and (RightEl.CustomData is TResolvedReference) then
  6540. begin
  6541. RightRef:=TResolvedReference(RightEl.CustomData);
  6542. RightRefDecl:=RightRef.Declaration;
  6543. if aResolver.IsExternalClassConstructor(RightRefDecl) then
  6544. begin
  6545. if ParamsExpr<>nil then
  6546. begin
  6547. // left side is done in ConvertFuncParams
  6548. Result:=ConvertParamsExpr(El.right as TParamsExpr,AContext);
  6549. end
  6550. else
  6551. // e.g. ExtClass.new;
  6552. Result:=ConvertExternalConstructor(El.left,RightRef,nil,AContext);
  6553. exit;
  6554. end
  6555. else if aResolver.IsTObjectFreeMethod(RightEl) then
  6556. begin
  6557. Result:=ConvertTObjectFree_Bin(El,RightEl,AContext);
  6558. exit;
  6559. end
  6560. else if (RightRef.Access in rraAllWrite)
  6561. and aResolver.IsClassField(RightRefDecl) then
  6562. begin
  6563. // e.g. "Something.aClassVar:=" -> "aClass.aClassVar:="
  6564. Left:=CreateReferencePathExpr(RightRefDecl.Parent,AContext);
  6565. Result:=TJSDotMemberExpression(CreateElement(TJSDotMemberExpression,El));
  6566. TJSDotMemberExpression(Result).MExpr:=Left;
  6567. TJSDotMemberExpression(Result).Name:=TJSString(TransformVariableName(RightRefDecl,AContext));
  6568. exit;
  6569. end;
  6570. end;
  6571. if aResolver<>nil then
  6572. begin
  6573. aResolver.ComputeElement(El.left,LeftResolved,[]);
  6574. if LeftResolved.BaseType=btModule then
  6575. begin
  6576. // e.g. System.ExitCode
  6577. // unit prefix is automatically created -> omit
  6578. Result:=ConvertElement(El.right,AContext);
  6579. exit;
  6580. end
  6581. end;
  6582. // convert left side
  6583. OldAccess:=AContext.Access;
  6584. AContext.Access:=caRead;
  6585. Left:=ConvertElement(El.left,AContext);
  6586. if Left=nil then
  6587. RaiseInconsistency(20170201140821,El);
  6588. AContext.Access:=OldAccess;
  6589. // convert right side
  6590. DotContext:=TDotContext.Create(El,Left,AContext);
  6591. Right:=nil;
  6592. try
  6593. DotContext.LeftResolved:=LeftResolved;
  6594. Right:=ConvertElement(El.right,DotContext);
  6595. if DotContext.JS<>nil then
  6596. begin
  6597. Left:=nil;
  6598. Right:=nil;
  6599. exit(DotContext.JS);
  6600. end;
  6601. finally
  6602. DotContext.Free;
  6603. if Right=nil then
  6604. Left.Free;
  6605. end;
  6606. if Right is TJSLiteral then
  6607. begin
  6608. FreeAndNil(Left);
  6609. exit(Right);
  6610. end;
  6611. // connect via dot
  6612. Result:=CreateDotExpression(El,Left,Right,true);
  6613. end;
  6614. function TPasToJSConverter.CreateIdentifierExpr(El: TPasElement;
  6615. AContext: TConvertContext): TJSElement;
  6616. begin
  6617. Result:=CreatePrimitiveDotExpr(TransformVariableName(El,AContext),El);
  6618. end;
  6619. function TPasToJSConverter.CreateIdentifierExpr(AName: string;
  6620. CheckGlobal: boolean; PosEl: TPasElement; AContext: TConvertContext
  6621. ): TJSElement;
  6622. // CheckGlobal: check name clashes with global identifiers too
  6623. begin
  6624. Result:=CreatePrimitiveDotExpr(TransformVariableName(PosEl,AName,CheckGlobal,AContext),PosEl);
  6625. end;
  6626. function TPasToJSConverter.CreateSubDeclNameExpr(El: TPasElement;
  6627. const Name: string; AContext: TConvertContext; PosEl: TPasElement
  6628. ): TJSElement;
  6629. var
  6630. CurName, ParentName: String;
  6631. begin
  6632. if PosEl=nil then PosEl:=El;
  6633. CurName:=TransformVariableName(El,Name,false,AContext);
  6634. if not (El.Parent is TProcedureBody) then
  6635. begin
  6636. ParentName:=AContext.GetLocalName(El.Parent);
  6637. if ParentName='' then
  6638. ParentName:='this';
  6639. CurName:=ParentName+'.'+CurName;
  6640. end;
  6641. Result:=CreatePrimitiveDotExpr(CurName,PosEl);
  6642. end;
  6643. function TPasToJSConverter.CreateSubDeclNameExpr(El: TPasElement;
  6644. AContext: TConvertContext; PosEl: TPasElement): TJSElement;
  6645. var
  6646. Name: String;
  6647. begin
  6648. if AContext.Resolver<>nil then
  6649. Name:=AContext.Resolver.GetOverloadName(El)
  6650. else
  6651. Name:=El.Name;
  6652. Result:=CreateSubDeclNameExpr(El,Name,AContext,PosEl);
  6653. end;
  6654. function TPasToJSConverter.ConvertPrimitiveExpression(El: TPrimitiveExpr;
  6655. AContext: TConvertContext): TJSElement;
  6656. function DeleteLeadingZeroes(const s: string): string;
  6657. // Note: 01 is in JS octal, and in strict mode forbidden
  6658. // $00ff00 -> $ff00
  6659. // 00E001 -> 0E1
  6660. // 0.001 -> 0.001
  6661. // 0.00E1 -> 0.00E1
  6662. var
  6663. i: Integer;
  6664. begin
  6665. Result:=s;
  6666. i:=1;
  6667. if Result[1]='$' then
  6668. // hexadecimal -> can not be a float, 'E' is a hexdigit
  6669. while i<length(Result) do
  6670. begin
  6671. if (Result[i]='0') and (Result[i+1] in ['0'..'9','A'..'F','a'..'f'])
  6672. and ((i=1) or not (Result[i-1] in ['0'..'9','A'..'F','a'..'f'])) then
  6673. Delete(Result,i,1)
  6674. else
  6675. inc(i);
  6676. end
  6677. else
  6678. // decimal, can be a float, 'E' is a start of a new number
  6679. while i<length(Result) do
  6680. begin
  6681. if (Result[i]='0') and (Result[i+1] in ['0'..'9'])
  6682. and ((i=1) or not (Result[i-1] in ['.','0'..'9'])) then
  6683. Delete(Result,i,1)
  6684. else
  6685. inc(i);
  6686. end;
  6687. end;
  6688. Var
  6689. L : TJSLiteral;
  6690. Number : TJSNumber;
  6691. ConversionError , Code: Integer;
  6692. i: TMaxPrecInt;
  6693. S: String;
  6694. begin
  6695. {$IFDEF VerbosePas2JS}
  6696. str(El.Kind,S);
  6697. writeln('TPasToJSConverter.ConvertPrimitiveExpression El=',GetObjName(El),' Context=',GetObjName(AContext),' El.Kind=',S);
  6698. {$ENDIF}
  6699. Result:=Nil;
  6700. case El.Kind of
  6701. pekString:
  6702. begin
  6703. if AContext.Resolver<>nil then
  6704. Result:=CreateLiteralJSString(El,
  6705. AContext.Resolver.ExtractPasStringLiteral(El,El.Value))
  6706. else
  6707. begin
  6708. S:={$IFDEF pas2js}DeQuoteString{$ELSE}AnsiDequotedStr{$ENDIF}(El.Value,'''');
  6709. Result:=CreateLiteralString(El,S);
  6710. end;
  6711. //writeln('TPasToJSConverter.ConvertPrimitiveExpression Result="',TJSLiteral(Result).Value.AsString,'" ',GetObjName(AContext.Resolver));
  6712. end;
  6713. pekNumber:
  6714. begin
  6715. case El.Value[1] of
  6716. '0'..'9':
  6717. begin
  6718. Val(El.Value,Number,ConversionError);
  6719. if ConversionError<>0 then
  6720. DoError(20161024191248,nInvalidNumber,sInvalidNumber,[El.Value],El);
  6721. L:=CreateLiteralNumber(El,Number);
  6722. L.Value.CustomValue:=TJSString(DeleteLeadingZeroes(El.Value));
  6723. end;
  6724. '$','&','%':
  6725. begin
  6726. val(El.Value,i,Code);
  6727. if Code<>0 then
  6728. DoError(20161024224442,nInvalidNumber,sInvalidNumber,[El.Value],El);
  6729. Number:=i;
  6730. if Number<>i then
  6731. // number was rounded -> we lost precision
  6732. DoError(20161024230812,nInvalidNumber,sInvalidNumber,[El.Value],El);
  6733. L:=CreateLiteralNumber(El,Number);
  6734. S:=DeleteLeadingZeroes(El.Value);
  6735. S:=copy(S,2,length(S));
  6736. case El.Value[1] of
  6737. '$': S:='0x'+S;
  6738. '&': if TargetProcessor=ProcessorECMAScript5 then
  6739. S:='' // in strict mode 01 is forbidden
  6740. else
  6741. S:='0o'+S;
  6742. '%': if TargetProcessor=ProcessorECMAScript5 then
  6743. S:='' // use decimal
  6744. else
  6745. S:='0b'+S;
  6746. end;
  6747. L.Value.CustomValue:=TJSString(S);
  6748. end;
  6749. else
  6750. DoError(20161024223232,nInvalidNumber,sInvalidNumber,[El.Value],El);
  6751. end;
  6752. Result:=L;
  6753. end;
  6754. pekIdent:
  6755. Result:=ConvertIdentifierExpr(El,El.Value,AContext);
  6756. else
  6757. RaiseNotSupported(El,AContext,20161024222543);
  6758. end;
  6759. end;
  6760. function TPasToJSConverter.ConvertIdentifierExpr(El: TPasExpr;
  6761. const aName: string; AContext: TConvertContext): TJSElement;
  6762. procedure CallImplicit(Decl: TPasElement);
  6763. var
  6764. ProcType: TPasProcedureType;
  6765. ResolvedEl: TPasResolverResult;
  6766. Call: TJSCallExpression;
  6767. NeedIntfRef: Boolean;
  6768. begin
  6769. // create a call with default parameters
  6770. ProcType:=nil;
  6771. if Decl is TPasProcedure then
  6772. ProcType:=TPasProcedure(Decl).ProcType
  6773. else
  6774. begin
  6775. AContext.Resolver.ComputeElement(El,ResolvedEl,[rcNoImplicitProc]);
  6776. if ResolvedEl.LoTypeEl is TPasProcedureType then
  6777. ProcType:=TPasProcedureType(ResolvedEl.LoTypeEl)
  6778. else
  6779. RaiseNotSupported(El,AContext,20170217005025);
  6780. end;
  6781. NeedIntfRef:=false;
  6782. if (ProcType is TPasFunctionType)
  6783. and AContext.Resolver.IsInterfaceType(
  6784. TPasFunctionType(ProcType).ResultEl.ResultType,citCom)
  6785. then
  6786. NeedIntfRef:=true;
  6787. Call:=nil;
  6788. try
  6789. CreateProcedureCall(Call,nil,ProcType,AContext);
  6790. Call.Expr:=Result;
  6791. if NeedIntfRef then
  6792. // $ir.ref(id,fnname())
  6793. Call:=CreateIntfRef(Call,AContext,El);
  6794. Result:=Call;
  6795. finally
  6796. if Result<>Call then
  6797. Call.Free;
  6798. end;
  6799. end;
  6800. var
  6801. Decl: TPasElement;
  6802. Name: String;
  6803. Ref: TResolvedReference;
  6804. Call: TJSCallExpression;
  6805. BuiltInProc: TResElDataBuiltInProc;
  6806. Prop: TPasProperty;
  6807. IsImplicitCall: Boolean;
  6808. AssignContext: TAssignContext;
  6809. TargetProcType: TPasProcedureType;
  6810. ArrLit: TJSArrayLiteral;
  6811. IndexExpr: TPasExpr;
  6812. FuncScope: TPas2JSProcedureScope;
  6813. Value: TResEvalValue;
  6814. aResolver: TPas2JSResolver;
  6815. BracketExpr: TJSBracketMemberExpression;
  6816. PathExpr: TJSElement;
  6817. Proc: TPasProcedure;
  6818. begin
  6819. Result:=nil;
  6820. if not (El.CustomData is TResolvedReference) then
  6821. begin
  6822. if AContext.Resolver<>nil then
  6823. RaiseIdentifierNotFound(aName,El,20161024191306)
  6824. else
  6825. // simple mode
  6826. Result:=CreateIdentifierExpr(aName,true,El,AContext);
  6827. exit;
  6828. end;
  6829. aResolver:=AContext.Resolver;
  6830. Ref:=TResolvedReference(El.CustomData);
  6831. Decl:=Ref.Declaration;
  6832. if aResolver.IsExternalClassConstructor(Decl) then
  6833. begin
  6834. // create external object/function
  6835. Result:=ConvertExternalConstructor(nil,Ref,nil,AContext);
  6836. exit;
  6837. end;
  6838. if aResolver.IsExternalBracketAccessor(Decl) then
  6839. DoError(20180511154132,nCantCallExtBracketAccessor,sCantCallExtBracketAccessor,[],El);
  6840. if [rrfNewInstance,rrfFreeInstance]*Ref.Flags<>[] then
  6841. begin
  6842. // call constructor, destructor
  6843. Call:=CreateFreeOrNewInstanceExpr(Ref,AContext);
  6844. Result:=Call;
  6845. if Decl is TPasProcedure then
  6846. begin
  6847. TargetProcType:=TPasProcedure(Decl).ProcType;
  6848. if TargetProcType.Args.Count>0 then
  6849. begin
  6850. // add default parameters:
  6851. // insert array parameter [], e.g. this.TObject.$create("create",[])
  6852. ArrLit:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,El));
  6853. CreateProcedureCallArgs(ArrLit.Elements,nil,TargetProcType,AContext);
  6854. Call.AddArg(ArrLit);
  6855. end;
  6856. end;
  6857. exit;
  6858. end;
  6859. if (Ref.WithExprScope<>nil) and aResolver.IsTObjectFreeMethod(El) then
  6860. begin
  6861. Result:=ConvertTObjectFree_With(El,AContext);
  6862. exit;
  6863. end;
  6864. Prop:=nil;
  6865. AssignContext:=nil;
  6866. IsImplicitCall:=rrfImplicitCallWithoutParams in Ref.Flags;
  6867. if Decl.ClassType=TPasProperty then
  6868. begin
  6869. // Decl is a property -> redirect to getter/setter
  6870. Prop:=TPasProperty(Decl);
  6871. case AContext.Access of
  6872. caAssign:
  6873. begin
  6874. Decl:=aResolver.GetPasPropertySetter(Prop);
  6875. if Decl is TPasProcedure then
  6876. begin
  6877. AssignContext:=AContext.AccessContext as TAssignContext;
  6878. if AssignContext.Call<>nil then
  6879. RaiseNotSupported(El,AContext,20170206000310);
  6880. AssignContext.PropertyEl:=Prop;
  6881. AssignContext.Setter:=Decl;
  6882. // Setter
  6883. Call:=CreateCallExpression(El);
  6884. AssignContext.Call:=Call;
  6885. Call.Expr:=CreateReferencePathExpr(Decl,AContext,false,Ref);
  6886. IndexExpr:=aResolver.GetPasPropertyIndex(Prop);
  6887. if IndexExpr<>nil then
  6888. begin
  6889. Value:=aResolver.Eval(IndexExpr,[refConst]);
  6890. try
  6891. Call.AddArg(ConvertConstValue(Value,AssignContext,El));
  6892. finally
  6893. ReleaseEvalValue(Value);
  6894. end;
  6895. end;
  6896. Call.AddArg(AssignContext.RightSide);
  6897. AssignContext.RightSide:=nil;
  6898. Result:=Call;
  6899. exit;
  6900. end;
  6901. end;
  6902. caRead:
  6903. begin
  6904. Result:=CreatePropertyGet(Prop,Ref,AContext,El);
  6905. if Result is TJSCallExpression then exit;
  6906. if not IsImplicitCall then exit;
  6907. end;
  6908. else
  6909. RaiseNotSupported(El,AContext,20170213212623);
  6910. end;
  6911. end
  6912. else if Decl.ClassType=TPasArgument then
  6913. begin
  6914. Result:=CreateArgumentAccess(TPasArgument(Decl),AContext,El);
  6915. if IsImplicitCall then
  6916. CallImplicit(Decl);
  6917. exit;
  6918. end
  6919. else if (Ref.Access in rraAllWrite)
  6920. and aResolver.IsClassField(Decl) then
  6921. begin
  6922. // writing a class var -> aClass.VarName
  6923. PathExpr:=CreateReferencePathExpr(Decl.Parent,AContext);
  6924. Result:=TJSDotMemberExpression(CreateElement(TJSDotMemberExpression,El));
  6925. TJSDotMemberExpression(Result).MExpr:=PathExpr;
  6926. TJSDotMemberExpression(Result).Name:=TJSString(TransformVariableName(Decl,AContext));
  6927. exit;
  6928. end
  6929. else if Decl.ClassType=TPasConst then
  6930. begin
  6931. if TPasConst(Decl).IsConst and (TPasConst(Decl).Expr<>nil) then
  6932. begin
  6933. // const with expression
  6934. Value:=aResolver.Eval(TPasConst(Decl).Expr,[refConst]);
  6935. if Value<>nil then
  6936. try
  6937. if Value.Kind in [revkNil,revkBool,revkInt,revkUInt,revkFloat,revkEnum] then
  6938. begin
  6939. Result:=ConvertConstValue(Value,AContext,El);
  6940. exit;
  6941. end;
  6942. finally
  6943. ReleaseEvalValue(Value);
  6944. end;
  6945. if vmExternal in TPasConst(Decl).VarModifiers then
  6946. begin
  6947. // external constant with expression is always added by value, not by reference
  6948. Result:=ConvertElement(TPasConst(Decl).Expr,AContext);
  6949. exit;
  6950. end;
  6951. end;
  6952. end
  6953. else if Decl.ClassType=TPasResString then
  6954. begin
  6955. // read resourcestring -> rtl.getResStr($mod,"name")
  6956. Call:=CreateCallExpression(El);
  6957. Result:=Call;
  6958. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnGetResourcestring]]);
  6959. Call.AddArg(CreatePrimitiveDotExpr(TransformModuleName(Decl.GetModule,true,AContext),El));
  6960. Call.AddArg(CreateLiteralString(El,TransformVariableName(Decl,AContext)));
  6961. exit;
  6962. end
  6963. else if Decl.CustomData is TResElDataBuiltInProc then
  6964. begin
  6965. BuiltInProc:=TResElDataBuiltInProc(Decl.CustomData);
  6966. {$IFDEF VerbosePas2JS}
  6967. writeln('TPasToJSConverter.ConvertIdentifierExpr ',Decl.Name,' ',ResolverBuiltInProcNames[BuiltInProc.BuiltIn]);
  6968. {$ENDIF}
  6969. case BuiltInProc.BuiltIn of
  6970. bfBreak: Result:=ConvertBuiltInBreak(El,AContext);
  6971. bfContinue: Result:=ConvertBuiltInContinue(El,AContext);
  6972. bfExit: Result:=ConvertBuiltIn_Exit(El,AContext);
  6973. bfCustom:
  6974. case BuiltInProc.Element.Name of
  6975. 'Debugger': Result:=ConvertBuiltIn_Debugger(El,AContext);
  6976. else
  6977. RaiseNotSupported(El,AContext,20181126102554,'built in custom proc '+BuiltInProc.Element.Name);
  6978. end
  6979. else
  6980. RaiseNotSupported(El,AContext,20161130164955,'built in proc '+ResolverBuiltInProcNames[BuiltInProc.BuiltIn]);
  6981. end;
  6982. if Result=nil then
  6983. RaiseInconsistency(20170214120048,Decl);
  6984. exit;
  6985. end;
  6986. {$IFDEF VerbosePas2JS}
  6987. writeln('TPasToJSConverter.ConvertIdentifierExpr ',GetObjName(El),' Decl=',GetObjName(Decl),' Decl.Parent=',GetObjName(Decl.Parent));
  6988. //if CompareText(aName,'Result')=0 then
  6989. // begin
  6990. // writeln('TPasToJSConverter.ConvertIdentifierExpr AContext=',GetObjName(AContext),' SelfContext=',GetObjName(AContext.GetSelfContext),' LocalVar=',AContext.GetLocalName(Decl),' ',GetObjName(Decl));
  6991. // AContext.WriteStack;
  6992. // end;
  6993. {$ENDIF}
  6994. if Decl is TPasModule then
  6995. Name:=TransformModuleName(TPasModule(Decl),true,AContext)
  6996. else if (Decl is TPasResultElement) then
  6997. begin
  6998. Name:=ResolverResultVar;
  6999. Proc:=Decl.Parent.Parent as TPasProcedure;
  7000. FuncScope:=Proc.CustomData as TPas2JSProcedureScope;
  7001. if FuncScope.ImplProc<>nil then
  7002. FuncScope:=FuncScope.ImplProc.CustomData as TPas2JSProcedureScope;
  7003. if FuncScope.ResultVarName<>'' then
  7004. Name:=FuncScope.ResultVarName;
  7005. end
  7006. else if Decl.ClassType=TPasEnumValue then
  7007. begin
  7008. if UseEnumNumbers then
  7009. begin
  7010. Result:=CreateLiteralNumber(El,(Decl.Parent as TPasEnumType).Values.IndexOf(Decl));
  7011. exit;
  7012. end
  7013. else
  7014. begin
  7015. // enums always need the full path
  7016. Name:=CreateReferencePath(Decl,AContext,rpkPathAndName,true);
  7017. end;
  7018. end
  7019. else if (CompareText(aName,'Self')=0) and (AContext.GetSelfContext<>nil) then
  7020. Name:=AContext.GetLocalName(Decl)
  7021. else
  7022. Name:=CreateReferencePath(Decl,AContext,rpkPathAndName,false,Ref);
  7023. if Name='' then
  7024. RaiseNotSupported(El,AContext,20180509134804,GetObjName(Decl));
  7025. if Result=nil then
  7026. begin
  7027. if (Name[1]='[') and (Name[length(Name)]=']')
  7028. and (AContext is TDotContext)
  7029. and (AContext.JSElement<>nil) then
  7030. begin
  7031. // e.g. Obj.A and A is defined as: A: t external name '["name"]';
  7032. // -> Obj["name"]
  7033. if IsImplicitCall then
  7034. RaiseNotSupported(El,AContext,20180509134951,Name);
  7035. BracketExpr:=TJSBracketMemberExpression(CreateElement(TJSBracketMemberExpression,El));
  7036. TDotContext(AContext).JS:=BracketExpr;
  7037. BracketExpr.MExpr:=AContext.JSElement;
  7038. Result:=CreateLiteralCustomValue(El,TJSString(copy(Name,2,length(Name)-2)));
  7039. BracketExpr.Name:=Result;
  7040. exit;
  7041. end;
  7042. Result:=CreatePrimitiveDotExpr(Name,El);
  7043. end;
  7044. if IsImplicitCall then
  7045. CallImplicit(Decl);
  7046. end;
  7047. function TPasToJSConverter.ConvertBoolConstExpression(El: TBoolConstExpr;
  7048. AContext: TConvertContext): TJSElement;
  7049. begin
  7050. if AContext=nil then ;
  7051. Result:=CreateLiteralBoolean(El,El.Value);
  7052. end;
  7053. function TPasToJSConverter.ConvertNilExpr(El: TNilExpr;
  7054. AContext: TConvertContext): TJSElement;
  7055. begin
  7056. if AContext=nil then ;
  7057. Result:=CreateLiteralNull(El);
  7058. end;
  7059. function TPasToJSConverter.ConvertInheritedExpr(El: TInheritedExpr;
  7060. AContext: TConvertContext): TJSElement;
  7061. function CreateAncestorCall(ParentEl: TPasElement; Apply: boolean;
  7062. AncestorProc: TPasProcedure; ParamsExpr: TParamsExpr): TJSElement;
  7063. var
  7064. FunName, SelfName: String;
  7065. Call: TJSCallExpression;
  7066. SelfContext: TFunctionContext;
  7067. ClassScope, AncestorScope: TPasClassScope;
  7068. AncestorClass, aClass: TPasClassType;
  7069. begin
  7070. Result:=nil;
  7071. SelfContext:=AContext.GetSelfContext;
  7072. if SelfContext=nil then
  7073. RaiseInconsistency(20170418114702,El);
  7074. SelfName:=SelfContext.GetLocalName(SelfContext.ThisPas);
  7075. if Apply and (SelfContext<>AContext) then
  7076. DoError(20170418204325,nNestedInheritedNeedsParameters,sNestedInheritedNeedsParameters,
  7077. [],El);
  7078. if (AncestorProc.Parent is TPasClassType)
  7079. and TPasClassType(AncestorProc.Parent).IsExternal then
  7080. begin
  7081. // ancestor is in an external class
  7082. // They could be overriden, without a Pascal declaration
  7083. // -> use the direct ancestor class of the current proc
  7084. aClass:=SelfContext.ThisPas as TPasClassType;
  7085. if aClass.CustomData=nil then
  7086. RaiseInconsistency(20170323111252,aClass);
  7087. ClassScope:=TPasClassScope(aClass.CustomData);
  7088. AncestorScope:=ClassScope.AncestorScope;
  7089. if AncestorScope=nil then
  7090. RaiseInconsistency(20170323111306,aClass);
  7091. AncestorClass:=AncestorScope.Element as TPasClassType;
  7092. FunName:=CreateReferencePath(AncestorClass,AContext,rpkPathAndName,true)
  7093. +'.'+TransformVariableName(AncestorProc,AContext);
  7094. end
  7095. else
  7096. FunName:=CreateReferencePath(AncestorProc,AContext,rpkPathAndName,true);
  7097. if Apply and (SelfContext=AContext) then
  7098. // create "ancestor.funcname.apply(this,arguments)"
  7099. FunName:=FunName+'.apply'
  7100. else
  7101. // create "ancestor.funcname.call(this,param1,param2,...)"
  7102. FunName:=FunName+'.call';
  7103. Call:=nil;
  7104. try
  7105. Call:=CreateCallExpression(ParentEl);
  7106. Call.Expr:=CreatePrimitiveDotExpr(FunName,ParentEl);
  7107. Call.AddArg(CreatePrimitiveDotExpr(SelfName,ParentEl));
  7108. if Apply then
  7109. // "inherited;" -> pass the arguments
  7110. Call.AddArg(CreatePrimitiveDotExpr('arguments',ParentEl))
  7111. else
  7112. // "inherited Name(...)" -> pass the user arguments
  7113. CreateProcedureCall(Call,ParamsExpr,AncestorProc.ProcType,AContext);
  7114. if (AncestorProc is TPasFunction)
  7115. and AContext.Resolver.IsInterfaceType(
  7116. TPasFunction(AncestorProc).FuncType.ResultEl.ResultType,citCom) then
  7117. Call:=CreateIntfRef(Call,AContext,El);
  7118. Result:=Call;
  7119. finally
  7120. if Result=nil then
  7121. Call.Free;
  7122. end;
  7123. end;
  7124. var
  7125. Right: TPasExpr;
  7126. Ref: TResolvedReference;
  7127. PrimExpr: TPrimitiveExpr;
  7128. AncestorProc: TPasProcedure;
  7129. ParamsExpr: TParamsExpr;
  7130. begin
  7131. Result:=nil;
  7132. if (El.Parent is TBinaryExpr) and (TBinaryExpr(El.Parent).OpCode=eopNone)
  7133. and (TBinaryExpr(El.Parent).left=El) then
  7134. begin
  7135. // "inherited <name>"
  7136. AncestorProc:=nil;
  7137. ParamsExpr:=nil;
  7138. Right:=TBinaryExpr(El.Parent).right;
  7139. if Right.ClassType=TPrimitiveExpr then
  7140. begin
  7141. PrimExpr:=TPrimitiveExpr(Right);
  7142. Ref:=PrimExpr.CustomData as TResolvedReference;
  7143. if rrfImplicitCallWithoutParams in Ref.Flags then
  7144. begin
  7145. // inherited <function>
  7146. // -> create "AncestorProc.call(this,defaultargs)"
  7147. AncestorProc:=Ref.Declaration as TPasProcedure;
  7148. end
  7149. else
  7150. begin
  7151. // inherited <varname>
  7152. // all variables have unique names -> simply access it
  7153. Result:=ConvertPrimitiveExpression(PrimExpr,AContext);
  7154. exit;
  7155. end;
  7156. end
  7157. else if Right.ClassType=TParamsExpr then
  7158. begin
  7159. ParamsExpr:=TParamsExpr(Right);
  7160. if ParamsExpr.Kind=pekFuncParams then
  7161. begin
  7162. if ParamsExpr.Value is TPrimitiveExpr then
  7163. begin
  7164. // inherited <function>(args)
  7165. // -> create "AncestorProc.call(this,args,defaultargs)"
  7166. PrimExpr:=TPrimitiveExpr(ParamsExpr.Value);
  7167. Ref:=PrimExpr.CustomData as TResolvedReference;
  7168. AncestorProc:=Ref.Declaration as TPasProcedure;
  7169. end
  7170. else
  7171. DoError(20170418205802,nXExpectedButYFound,sXExpectedButYFound,
  7172. ['inherited name()',ParamsExpr.Value.ElementTypeName],ParamsExpr.Value);
  7173. end
  7174. else
  7175. begin
  7176. // inherited <varname>[]
  7177. // all variables have unique names -> simply access it
  7178. Result:=ConvertElement(Right,AContext);
  7179. exit;
  7180. end;
  7181. end
  7182. else
  7183. begin
  7184. {$IFDEF VerbosePas2JS}
  7185. writeln('TPasToJSConverter.ConvertInheritedExpression Parent=',GetTreeDbg(El.Parent,2));
  7186. {$ENDIF}
  7187. DoError(20170418205955,nXExpectedButYFound,sXExpectedButYFound,
  7188. ['inherited name()',Right.ElementTypeName],Right);
  7189. end;
  7190. if AncestorProc=nil then
  7191. begin
  7192. {$IFDEF VerbosePas2JS}
  7193. writeln('TPasToJSConverter.ConvertInheritedExpression Right=',GetObjName(Right));
  7194. {$ENDIF}
  7195. RaiseNotSupported(El,AContext,20170201190824);
  7196. end;
  7197. //writeln('TPasToJSConverter.ConvertInheritedExpression Func=',GetObjName(FuncContext.PasElement));
  7198. Result:=CreateAncestorCall(Right,false,AncestorProc,ParamsExpr);
  7199. end
  7200. else
  7201. begin
  7202. // "inherited;"
  7203. if El.CustomData=nil then
  7204. exit; // "inherited;" when there is no AncestorProc proc -> silently ignore
  7205. // create "AncestorProc.apply(this,arguments)"
  7206. Ref:=TResolvedReference(El.CustomData);
  7207. AncestorProc:=Ref.Declaration as TPasProcedure;
  7208. Result:=CreateAncestorCall(El,true,AncestorProc,nil);
  7209. end;
  7210. end;
  7211. function TPasToJSConverter.ConvertSelfExpression(El: TSelfExpr;
  7212. AContext: TConvertContext): TJSElement;
  7213. begin
  7214. Result:=ConvertIdentifierExpr(El,'Self',AContext);
  7215. end;
  7216. function TPasToJSConverter.ConvertParamsExpr(El: TParamsExpr;
  7217. AContext: TConvertContext): TJSElement;
  7218. begin
  7219. Result:=Nil;
  7220. {$IFDEF VerbosePas2JS}
  7221. writeln('TPasToJSConverter.ConvertParamsExpression ',GetObjName(El),' El.Kind=',ExprKindNames[El.Kind]);
  7222. {$ENDIF}
  7223. Case El.Kind of
  7224. pekFuncParams:
  7225. Result:=ConvertFuncParams(El,AContext);
  7226. pekArrayParams:
  7227. Result:=ConvertArrayParams(El,AContext);
  7228. pekSet:
  7229. Result:=ConvertArrayOrSetLiteral(El,AContext);
  7230. else
  7231. RaiseNotSupported(El,AContext,20170209103235,ExprKindNames[El.Kind]);
  7232. end;
  7233. end;
  7234. function TPasToJSConverter.ConvertArrayParams(El: TParamsExpr;
  7235. AContext: TConvertContext): TJSElement;
  7236. var
  7237. ArgContext: TConvertContext;
  7238. procedure RaiseIllegalBrackets(id: TMaxPrecInt; const ResolvedEl: TPasResolverResult);
  7239. begin
  7240. DoError(id,nIllegalQualifierAfter,sIllegalQualifierAfter,
  7241. ['[',AContext.Resolver.GetResolverResultDescription(ResolvedEl,true)],El);
  7242. end;
  7243. function GetValueReference: TResolvedReference;
  7244. var
  7245. Value: TPasExpr;
  7246. begin
  7247. Result:=nil;
  7248. Value:=El.Value;
  7249. if (Value.ClassType=TPrimitiveExpr)
  7250. and (Value.CustomData is TResolvedReference) then
  7251. exit(TResolvedReference(Value.CustomData));
  7252. end;
  7253. function ConvertIndexMinus1(Param: TPasExpr): TJSElement;
  7254. var
  7255. NeedMinus1: Boolean;
  7256. JSVal: TJSValue;
  7257. MinusJS: TJSAdditiveExpressionMinus;
  7258. begin
  7259. Result:=ConvertElement(Param,ArgContext);
  7260. NeedMinus1:=true;
  7261. if (Result is TJSLiteral) then
  7262. begin
  7263. JSVal:=TJSLiteral(Result).Value;
  7264. if (JSVal.ValueType=jstNumber) then
  7265. begin
  7266. // simply subtract 1 from constant
  7267. JSVal.AsNumber:=JSVal.AsNumber-1;
  7268. NeedMinus1:=false;
  7269. end;
  7270. end;
  7271. if NeedMinus1 then
  7272. begin
  7273. // index-1
  7274. MinusJS:=TJSAdditiveExpressionMinus(CreateElement(TJSAdditiveExpressionMinus,Param));
  7275. MinusJS.A:=Result;
  7276. MinusJS.B:=CreateLiteralNumber(Param,1);
  7277. Result:=MinusJS;
  7278. end;
  7279. end;
  7280. procedure ConvertStringBracket(const ResolvedValue: TPasResolverResult);
  7281. var
  7282. CallEx, SetStrCall: TJSCallExpression;
  7283. Param: TPasExpr;
  7284. DotExpr: TJSDotMemberExpression;
  7285. AssignContext: TAssignContext;
  7286. AssignSt: TJSSimpleAssignStatement;
  7287. OldAccess: TCtxAccess;
  7288. IndexExpr: TJSElement;
  7289. Arg: TPasArgument;
  7290. IsRangeCheck: Boolean;
  7291. begin
  7292. Result:=nil;
  7293. IsRangeCheck:=(bsRangeChecks in AContext.ScannerBoolSwitches)
  7294. and (AContext.Access in [caRead,caAssign]);
  7295. Param:=El.Params[0];
  7296. case AContext.Access of
  7297. caAssign:
  7298. begin
  7299. // s[index] := value
  7300. AssignContext:=AContext.AccessContext as TAssignContext;
  7301. if AssignContext.RightSide=nil then
  7302. RaiseInconsistency(20180123192020,El);
  7303. AssignSt:=nil;
  7304. SetStrCall:=nil;
  7305. CallEx:=nil;
  7306. try
  7307. // CallEx: rtl.setCharAt(s,index,value)
  7308. // rtl.setCharAt
  7309. CallEx:=CreateCallExpression(El);
  7310. if IsRangeCheck then
  7311. CallEx.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnRangeCheckSetCharAt]])
  7312. else
  7313. CallEx.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnSetCharAt]]);
  7314. // first param s
  7315. OldAccess:=AContext.Access;
  7316. AContext.Access:=caRead;
  7317. CallEx.AddArg(ConvertElement(El.Value,AContext));
  7318. // second param index-1
  7319. CallEx.AddArg(ConvertIndexMinus1(Param));
  7320. AContext.Access:=OldAccess;
  7321. // third param value
  7322. CallEx.AddArg(AssignContext.RightSide);
  7323. AssignContext.RightSide:=nil;
  7324. if ResolvedValue.IdentEl is TPasArgument then
  7325. begin
  7326. Arg:=TPasArgument(ResolvedValue.IdentEl);
  7327. if Arg.Access in [argVar,argOut] then
  7328. begin
  7329. // call by reference
  7330. // s[index] := value -> s.set(CallEx)
  7331. SetStrCall:=CreateCallExpression(El.Value);
  7332. SetStrCall.Expr:=CreateMemberExpression([TransformVariableName(Arg,AContext),TempRefObjSetterName]);
  7333. SetStrCall.AddArg(CallEx);
  7334. AssignContext.Call:=CallEx;
  7335. CallEx:=nil;
  7336. Result:=SetStrCall;
  7337. end;
  7338. end
  7339. else if ResolvedValue.IdentEl is TPasProperty then
  7340. RaiseNotSupported(El,AContext,20180124115924);
  7341. if Result=nil then
  7342. begin
  7343. // s[index] := value -> s = CallEx
  7344. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  7345. AssignSt.Expr:=CallEx;
  7346. AssignContext.Call:=CallEx;
  7347. CallEx:=nil;
  7348. OldAccess:=AContext.Access;
  7349. AContext.Access:=caRead;
  7350. AssignSt.LHS:=ConvertElement(El.Value,AContext);
  7351. Result:=AssignSt;
  7352. end;
  7353. finally
  7354. if Result=nil then
  7355. begin
  7356. CallEx.Free;
  7357. SetStrCall.Free;
  7358. AssignSt.Free;
  7359. end;
  7360. end;
  7361. end;
  7362. caRead:
  7363. begin
  7364. CallEx:=CreateCallExpression(El);
  7365. try
  7366. if IsRangeCheck and not TBinaryExpr.IsRightSubIdent(El) then
  7367. begin
  7368. // read s[index] -> rtl.rcCharAt(s,index-1)
  7369. CallEx.Expr:=CreatePrimitiveDotExpr(FBuiltInNames[pbivnRTL]+'.'+FBuiltInNames[pbifnRangeCheckGetCharAt],El);
  7370. CallEx.AddArg(ConvertElement(El.Value,AContext));
  7371. end
  7372. else
  7373. begin
  7374. // s[index] -> s.charAt(index-1)
  7375. // add string accessor
  7376. DotExpr:=TJSDotMemberExpression(CreateElement(TJSDotMemberExpression,El));
  7377. CallEx.Expr:=DotExpr;
  7378. DotExpr.MExpr:=ConvertElement(El.Value,AContext);
  7379. DotExpr.Name:='charAt';
  7380. end;
  7381. // add parameter "index-1"
  7382. IndexExpr:=ConvertIndexMinus1(Param);
  7383. CallEx.AddArg(IndexExpr);
  7384. Result:=CallEx;
  7385. finally
  7386. if Result=nil then
  7387. CallEx.Free;
  7388. end;
  7389. end;
  7390. else
  7391. RaiseNotSupported(El,AContext,20170213213101);
  7392. end;
  7393. end;
  7394. procedure ConvCharToInt(var Arg: TJSElement; Param: TPasElement);
  7395. begin
  7396. if (Arg is TJSLiteral) and (TJSLiteral(Arg).Value.ValueType=jstString) then
  7397. begin
  7398. // convert char literal to int
  7399. ConvertCharLiteralToInt(TJSLiteral(Arg),Param,ArgContext);
  7400. end
  7401. else
  7402. begin
  7403. // convert char to int -> Arg.charCodeAt(0)
  7404. Arg:=CreateCallCharCodeAt(Arg,0,Param);
  7405. end;
  7406. end;
  7407. procedure ConvertArray(ArrayEl: TPasArrayType);
  7408. var
  7409. BracketEx, Sub: TJSBracketMemberExpression;
  7410. i, ArgNo: Integer;
  7411. Arg, ArrJS: TJSElement;
  7412. OldAccess: TCtxAccess;
  7413. Ranges: TPasExprArray;
  7414. Int: TMaxPrecInt;
  7415. Param: TPasExpr;
  7416. JSAdd: TJSAdditiveExpression;
  7417. LowRg: TResEvalValue;
  7418. IsRangeCheck, ok, NeedRangeCheck: Boolean;
  7419. CallEx: TJSCallExpression;
  7420. AssignContext: TAssignContext;
  7421. ArgList: TFPList;
  7422. {$IFDEF FPC_HAS_CPSTRING}
  7423. w: WideChar;
  7424. {$ENDIF}
  7425. begin
  7426. Result:=nil;
  7427. Arg:=nil;
  7428. ArrJS:=nil;
  7429. ArgList:=TFPList.Create;
  7430. NeedRangeCheck:=false;
  7431. ok:=false;
  7432. try
  7433. // add read accessor
  7434. OldAccess:=AContext.Access;
  7435. AContext.Access:=caRead;
  7436. ArrJS:=ConvertElement(El.Value,AContext);
  7437. AContext.Access:=OldAccess;
  7438. ArgNo:=0;
  7439. repeat
  7440. // Note: dynamic array has length(ArrayEl.Ranges)=0
  7441. Ranges:=ArrayEl.Ranges;
  7442. for i:=1 to Max(length(Ranges),1) do
  7443. begin
  7444. // add parameter
  7445. Param:=El.Params[ArgNo];
  7446. ArgContext.Access:=caRead;
  7447. Arg:=ConvertElement(Param,ArgContext);
  7448. ArgContext.Access:=OldAccess;
  7449. if not (Arg is TJSLiteral) then
  7450. NeedRangeCheck:=true;
  7451. if i<=length(Ranges) then
  7452. begin
  7453. // static array
  7454. LowRg:=ArgContext.Resolver.EvalRangeLimit(Ranges[i-1],[refConst],true,El);
  7455. if LowRg=nil then
  7456. RaiseNotSupported(Param,ArgContext,20170910163341);
  7457. try
  7458. Int:=0;
  7459. case LowRg.Kind of
  7460. revkBool:
  7461. if TResEvalBool(LowRg).B=false then
  7462. begin
  7463. // array starts at 'false'
  7464. if (Arg is TJSLiteral) and (TJSLiteral(Arg).Value.ValueType=jstBoolean) then
  7465. begin
  7466. // convert Pascal boolean literal to JS number
  7467. if TJSLiteral(Arg).Value.AsBoolean then
  7468. TJSLiteral(Arg).Value.AsNumber:=1
  7469. else
  7470. TJSLiteral(Arg).Value.AsNumber:=0;
  7471. end
  7472. else
  7473. begin
  7474. // -> convert bool to int with unary plus: +bool
  7475. Arg:=CreateUnaryPlus(Arg,Param);
  7476. end;
  7477. end
  7478. else
  7479. begin
  7480. // array starts at 'true'
  7481. if (Arg is TJSLiteral) and (TJSLiteral(Arg).Value.ValueType=jstBoolean) then
  7482. begin
  7483. if TJSLiteral(Arg).Value.AsBoolean then
  7484. TJSLiteral(Arg).Value.AsNumber:=0
  7485. else
  7486. ArgContext.Resolver.ExprEvaluator.EmitRangeCheckConst(
  7487. 20170910203312,'false','true','true',Param,mtError);
  7488. end
  7489. else
  7490. begin
  7491. // convert bool to int with offset: 1-bool
  7492. JSAdd:=TJSAdditiveExpressionMinus(CreateElement(TJSAdditiveExpressionMinus,Param));
  7493. JSAdd.A:=CreateLiteralNumber(Param,1);
  7494. JSAdd.B:=Arg;
  7495. Arg:=JSAdd;
  7496. end;
  7497. end;
  7498. revkEnum:
  7499. Int:=TResEvalEnum(LowRg).Index;
  7500. revkInt:
  7501. Int:=TResEvalInt(LowRg).Int;
  7502. {$IFDEF FPC_HAS_CPSTRING}
  7503. revkString:
  7504. begin
  7505. if length(TResEvalString(LowRg).S)<>1 then
  7506. begin
  7507. if ArgContext.Resolver.ExprEvaluator.GetWideChar(TResEvalString(LowRg).S,w) then
  7508. Int:=ord(w)
  7509. else
  7510. ArgContext.Resolver.RaiseXExpectedButYFound(20170910213203,'char','string',Param);
  7511. end
  7512. else
  7513. Int:=ord(TResEvalString(LowRg).S[1]);
  7514. ConvCharToInt(Arg,Param);
  7515. end;
  7516. {$ENDIF}
  7517. revkUnicodeString:
  7518. begin
  7519. if length(TResEvalUTF16(LowRg).S)<>1 then
  7520. ArgContext.Resolver.RaiseXExpectedButYFound(20170910213247,'char','string',Param)
  7521. else
  7522. Int:=ord(TResEvalUTF16(LowRg).S[1]);
  7523. ConvCharToInt(Arg,Param);
  7524. end
  7525. else
  7526. RaiseNotSupported(Param,ArgContext,20170910170446);
  7527. end;
  7528. if Int<>0 then
  7529. begin
  7530. if (Arg is TJSLiteral) and (TJSLiteral(Arg).Value.ValueType=jstNumber) then
  7531. // parameter is single number -> simply subtract the offset
  7532. TJSLiteral(Arg).Value.AsNumber:=TJSLiteral(Arg).Value.AsNumber-Int
  7533. else
  7534. begin
  7535. // parameter is an expression -> add offset
  7536. if Int>0 then
  7537. begin
  7538. // Arg-Offset
  7539. JSAdd:=TJSAdditiveExpressionMinus(CreateElement(TJSAdditiveExpressionMinus,Param));
  7540. JSAdd.A:=Arg;
  7541. JSAdd.B:=CreateLiteralNumber(Param,Int);
  7542. Arg:=JSAdd;
  7543. end
  7544. else
  7545. begin
  7546. // Arg+Offset
  7547. JSAdd:=TJSAdditiveExpressionPlus(CreateElement(TJSAdditiveExpressionPlus,Param));
  7548. JSAdd.A:=Arg;
  7549. JSAdd.B:=CreateLiteralNumber(Param,-Int);
  7550. Arg:=JSAdd;
  7551. end;
  7552. end;
  7553. end;
  7554. finally
  7555. ReleaseEvalValue(LowRg);
  7556. end;
  7557. end;
  7558. ArgList.Add(Arg);
  7559. Arg:=nil;
  7560. inc(ArgNo);
  7561. if ArgNo>length(El.Params) then
  7562. RaiseInconsistency(20170206180553,El);
  7563. end;
  7564. if ArgNo=length(El.Params) then
  7565. break;
  7566. // continue in sub array
  7567. ArrayEl:=AContext.Resolver.ResolveAliasType(ArrayEl.ElType) as TPasArrayType;
  7568. until false;
  7569. IsRangeCheck:=NeedRangeCheck
  7570. and (bsRangeChecks in AContext.ScannerBoolSwitches)
  7571. and (AContext.Access in [caRead,caAssign]);
  7572. if IsRangeCheck and not TBinaryExpr.IsRightSubIdent(El) then
  7573. begin
  7574. // read a[i,j,k] -> rtl.rcArrR(a,i,j,k)
  7575. // assign a[i,j,k]=RHS -> rtl.rcArrW(a,i,j,k,RHS)
  7576. CallEx:=CreateCallExpression(El);
  7577. Result:=CallEx;
  7578. if AContext.Access=caRead then
  7579. CallEx.Expr:=CreatePrimitiveDotExpr(FBuiltInNames[pbivnRTL]+'.'+FBuiltInNames[pbifnRangeCheckArrayRead],El)
  7580. else
  7581. CallEx.Expr:=CreatePrimitiveDotExpr(FBuiltInNames[pbivnRTL]+'.'+FBuiltInNames[pbifnRangeCheckArrayWrite],El);
  7582. CallEx.AddArg(ArrJS); ArrJS:=nil;
  7583. for i:=0 to ArgList.Count-1 do
  7584. CallEx.AddArg(TJSElement(ArgList[i]));
  7585. ArgList.Clear;
  7586. if AContext.Access=caAssign then
  7587. begin
  7588. AssignContext:=AContext.AccessContext as TAssignContext;
  7589. if AssignContext.Call<>nil then
  7590. RaiseNotSupported(El,AContext,20180424192155);
  7591. CallEx.AddArg(AssignContext.RightSide);
  7592. AssignContext.RightSide:=nil;
  7593. AssignContext.Call:=CallEx;
  7594. end;
  7595. end
  7596. else
  7597. begin
  7598. BracketEx:=TJSBracketMemberExpression(CreateElement(TJSBracketMemberExpression,El));
  7599. BracketEx.MExpr:=ArrJS; ArrJS:=nil;
  7600. for i:=0 to ArgList.Count-1 do
  7601. begin
  7602. if BracketEx.Name<>nil then
  7603. begin
  7604. // nested [][]
  7605. Sub:=BracketEx;
  7606. BracketEx:=TJSBracketMemberExpression(CreateElement(TJSBracketMemberExpression,El));
  7607. BracketEx.MExpr:=Sub;
  7608. end;
  7609. BracketEx.Name:=TJSElement(ArgList[i]);
  7610. end;
  7611. Result:=BracketEx;
  7612. ArgList.Clear;
  7613. end;
  7614. ok:=true;
  7615. finally
  7616. if not ok then
  7617. begin
  7618. ArrJS.Free;
  7619. for i:=0 to ArgList.Count-1 do
  7620. TJSElement(ArgList[i]).{$IFDEF pas2js}Destroy{$ELSE}Free{$ENDIF};
  7621. Arg.Free;
  7622. Result.Free;
  7623. end;
  7624. ArgList.Free;
  7625. end;
  7626. end;
  7627. function IsJSBracketAccessorAndConvert(Prop: TPasProperty;
  7628. AccessEl: TPasElement;
  7629. AContext: TConvertContext; ChompPropName: boolean): boolean;
  7630. // If El.Value contains property name set ChompPropName = true
  7631. var
  7632. Bracket: TJSBracketMemberExpression;
  7633. OldAccess: TCtxAccess;
  7634. PathEl: TPasExpr;
  7635. Ref: TResolvedReference;
  7636. Path: String;
  7637. begin
  7638. if not AContext.Resolver.IsExternalBracketAccessor(AccessEl) then
  7639. exit(false);
  7640. Result:=true;
  7641. // bracket accessor of external class
  7642. if AContext.Resolver.GetPasPropertyArgs(Prop).Count<>1 then
  7643. RaiseInconsistency(20170403003753,Prop);
  7644. // bracket accessor of external class -> create PathEl[param]
  7645. Bracket:=TJSBracketMemberExpression(CreateElement(TJSBracketMemberExpression,El.Params[0]));
  7646. try
  7647. PathEl:=El.Value;
  7648. if ChompPropName then
  7649. begin
  7650. if (PathEl is TPrimitiveExpr)
  7651. and (TPrimitiveExpr(PathEl).Kind=pekIdent)
  7652. and (PathEl.CustomData is TResolvedReference) then
  7653. begin
  7654. // propname without path, e.g. propname[param]
  7655. Ref:=TResolvedReference(PathEl.CustomData);
  7656. Path:=CreateReferencePath(Prop,AContext,rpkPath,false,Ref);
  7657. if Path<>'' then
  7658. Bracket.MExpr:=CreatePrimitiveDotExpr(Path,PathEl);
  7659. PathEl:=nil;
  7660. end
  7661. else if (PathEl is TBinaryExpr)
  7662. and (TBinaryExpr(PathEl).OpCode=eopSubIdent)
  7663. and (TBinaryExpr(PathEl).right is TPrimitiveExpr)
  7664. and (TPrimitiveExpr(TBinaryExpr(PathEl).right).Kind=pekIdent) then
  7665. begin
  7666. // instance.propname[param] -> instance[param]
  7667. PathEl:=TBinaryExpr(PathEl).left;
  7668. end
  7669. else
  7670. RaiseNotSupported(El.Value,AContext,20170402225050);
  7671. end;
  7672. if (PathEl<>nil) and (Bracket.MExpr=nil) then
  7673. begin
  7674. OldAccess:=AContext.Access;
  7675. AContext.Access:=caRead;
  7676. Bracket.MExpr:=ConvertElement(PathEl,AContext);
  7677. AContext.Access:=OldAccess;
  7678. end;
  7679. OldAccess:=ArgContext.Access;
  7680. ArgContext.Access:=caRead;
  7681. Bracket.Name:=ConvertElement(El.Params[0],ArgContext);
  7682. ArgContext.Access:=OldAccess;
  7683. ConvertArrayParams:=Bracket;
  7684. Bracket:=nil;
  7685. finally
  7686. Bracket.Free;
  7687. end;
  7688. end;
  7689. procedure ConvertIndexedProperty(Prop: TPasProperty; AContext: TConvertContext);
  7690. var
  7691. Call: TJSCallExpression;
  7692. i: Integer;
  7693. TargetArg: TPasArgument;
  7694. Elements: TJSArrayLiteralElements;
  7695. Arg: TJSElement;
  7696. AccessEl: TPasElement;
  7697. AssignContext: TAssignContext;
  7698. OldAccess: TCtxAccess;
  7699. IndexExpr: TPasExpr;
  7700. Value: TResEvalValue;
  7701. PropArgs: TFPList;
  7702. aResolver: TPas2JSResolver;
  7703. TypeEl: TPasType;
  7704. begin
  7705. Result:=nil;
  7706. AssignContext:=nil;
  7707. aResolver:=AContext.Resolver;
  7708. Call:=CreateCallExpression(El);
  7709. try
  7710. case AContext.Access of
  7711. caAssign:
  7712. begin
  7713. AccessEl:=aResolver.GetPasPropertySetter(Prop);
  7714. if IsJSBracketAccessorAndConvert(Prop,AccessEl,AContext,true) then
  7715. begin
  7716. FreeAndNil(Call);
  7717. exit;
  7718. end;
  7719. AssignContext:=AContext.AccessContext as TAssignContext;
  7720. AssignContext.PropertyEl:=Prop;
  7721. AssignContext.Setter:=AccessEl;
  7722. AssignContext.Call:=Call;
  7723. end;
  7724. caRead:
  7725. begin
  7726. AccessEl:=aResolver.GetPasPropertyGetter(Prop);
  7727. if IsJSBracketAccessorAndConvert(Prop,AccessEl,AContext,true) then
  7728. begin
  7729. FreeAndNil(Call);
  7730. exit;
  7731. end;
  7732. end
  7733. else
  7734. RaiseNotSupported(El,AContext,20170213213317);
  7735. end;
  7736. Call.Expr:=CreateReferencePathExpr(AccessEl,AContext,false,GetValueReference);
  7737. Elements:=Call.Args.Elements;
  7738. OldAccess:=ArgContext.Access;
  7739. // add params
  7740. PropArgs:=aResolver.GetPasPropertyArgs(Prop);
  7741. i:=0;
  7742. while i<PropArgs.Count do
  7743. begin
  7744. TargetArg:=TPasArgument(PropArgs[i]);
  7745. Arg:=CreateProcCallArg(El.Params[i],TargetArg,ArgContext);
  7746. Elements.AddElement.Expr:=Arg;
  7747. inc(i);
  7748. end;
  7749. // fill up default values
  7750. while i<PropArgs.Count do
  7751. begin
  7752. TargetArg:=TPasArgument(PropArgs[i]);
  7753. if TargetArg.ValueExpr=nil then
  7754. begin
  7755. {$IFDEF VerbosePas2JS}
  7756. writeln('TPasToJSConverter.ConvertArrayParams.ConvertIndexedProperty missing default value: Prop=',Prop.Name,' i=',i);
  7757. {$ENDIF}
  7758. RaiseInconsistency(20170206185126,TargetArg);
  7759. end;
  7760. AContext.Access:=caRead;
  7761. Arg:=ConvertElement(TargetArg.ValueExpr,ArgContext);
  7762. Elements.AddElement.Expr:=Arg;
  7763. inc(i);
  7764. end;
  7765. // add index specifier
  7766. IndexExpr:=aResolver.GetPasPropertyIndex(Prop);
  7767. if IndexExpr<>nil then
  7768. begin
  7769. Value:=aResolver.Eval(IndexExpr,[refConst]);
  7770. try
  7771. Elements.AddElement.Expr:=ConvertConstValue(Value,ArgContext,El);
  7772. finally
  7773. ReleaseEvalValue(Value);
  7774. end;
  7775. end;
  7776. // finally add as last parameter the value
  7777. if AssignContext<>nil then
  7778. begin
  7779. Elements.AddElement.Expr:=AssignContext.RightSide;
  7780. AssignContext.RightSide:=nil;
  7781. end;
  7782. ArgContext.Access:=OldAccess;
  7783. // add interface reference
  7784. if AContext.Access=caRead then
  7785. begin
  7786. TypeEl:=aResolver.GetPasPropertyType(Prop);
  7787. if aResolver.IsInterfaceType(TypeEl,citCom) then
  7788. Call:=CreateIntfRef(Call,AContext,El);
  7789. end;
  7790. Result:=Call;
  7791. finally
  7792. if Result=nil then
  7793. begin
  7794. if (AssignContext<>nil) and (AssignContext.Call=Call) then
  7795. AssignContext.Call:=nil;
  7796. Call.Free;
  7797. end;
  7798. end;
  7799. end;
  7800. procedure ConvertDefaultProperty(const ResolvedEl: TPasResolverResult;
  7801. Prop: TPasProperty);
  7802. var
  7803. DotContext: TDotContext;
  7804. Left, Right: TJSElement;
  7805. OldAccess: TCtxAccess;
  7806. AccessEl, SetAccessEl: TPasElement;
  7807. begin
  7808. case AContext.Access of
  7809. caAssign:
  7810. begin
  7811. AccessEl:=AContext.Resolver.GetPasPropertySetter(Prop);
  7812. if IsJSBracketAccessorAndConvert(Prop,AccessEl,AContext,false) then
  7813. exit;
  7814. end;
  7815. caRead:
  7816. begin
  7817. AccessEl:=AContext.Resolver.GetPasPropertyGetter(Prop);
  7818. if IsJSBracketAccessorAndConvert(Prop,AccessEl,AContext,false) then
  7819. exit;
  7820. end;
  7821. caByReference:
  7822. begin
  7823. //ParamContext:=AContext.AccessContext as TParamContext;
  7824. AccessEl:=AContext.Resolver.GetPasPropertyGetter(Prop);
  7825. SetAccessEl:=AContext.Resolver.GetPasPropertySetter(Prop);
  7826. if AContext.Resolver.IsExternalBracketAccessor(AccessEl) then
  7827. begin
  7828. if AContext.Resolver.IsExternalBracketAccessor(SetAccessEl) then
  7829. begin
  7830. // read and write are brackets -> easy
  7831. if not IsJSBracketAccessorAndConvert(Prop,AccessEl,AContext,false) then
  7832. RaiseNotSupported(El,AContext,20170405090845);
  7833. exit;
  7834. end;
  7835. end;
  7836. RaiseNotSupported(El,AContext,20170403000550);
  7837. end;
  7838. else
  7839. RaiseNotSupported(El,AContext,20170402233834);
  7840. end;
  7841. DotContext:=nil;
  7842. Left:=nil;
  7843. Right:=nil;
  7844. try
  7845. OldAccess:=AContext.Access;
  7846. AContext.Access:=caRead;
  7847. Left:=ConvertElement(El.Value,AContext);
  7848. AContext.Access:=OldAccess;
  7849. DotContext:=TDotContext.Create(El.Value,Left,AContext);
  7850. DotContext.LeftResolved:=ResolvedEl;
  7851. ConvertIndexedProperty(Prop,DotContext);
  7852. if DotContext.JS<>nil then
  7853. RaiseNotSupported(El,AContext,20180509134226,GetObjName(DotContext.JS));
  7854. Right:=Result;
  7855. Result:=nil;
  7856. finally
  7857. DotContext.Free;
  7858. if Right=nil then
  7859. Left.Free;
  7860. end;
  7861. Result:=CreateDotExpression(El,Left,Right,true);
  7862. end;
  7863. Var
  7864. ResolvedEl: TPasResolverResult;
  7865. TypeEl, DestType: TPasType;
  7866. ClassScope: TPas2JSClassScope;
  7867. B: TJSBracketMemberExpression;
  7868. OldAccess: TCtxAccess;
  7869. aClass: TPasClassType;
  7870. aResolver: TPas2JSResolver;
  7871. begin
  7872. if El.Kind<>pekArrayParams then
  7873. RaiseInconsistency(20170209113713,El);
  7874. ArgContext:=AContext.GetNonDotContext;
  7875. if AContext.Resolver=nil then
  7876. begin
  7877. // without Resolver
  7878. if Length(El.Params)>1 then
  7879. RaiseNotSupported(El,AContext,20170207151325,'Cannot convert 2-dim arrays');
  7880. B:=TJSBracketMemberExpression(CreateElement(TJSBracketMemberExpression,El));
  7881. try
  7882. // add reference
  7883. OldAccess:=AContext.Access;
  7884. AContext.Access:=caRead;
  7885. B.MExpr:=ConvertElement(El.Value,AContext);
  7886. // add parameter
  7887. OldAccess:=ArgContext.Access;
  7888. ArgContext.Access:=caRead;
  7889. B.Name:=ConvertElement(El.Params[0],ArgContext);
  7890. ArgContext.Access:=OldAccess;
  7891. Result:=B;
  7892. finally
  7893. if Result=nil then
  7894. B.Free;
  7895. end;
  7896. exit;
  7897. end;
  7898. // has Resolver
  7899. aResolver:=AContext.Resolver;
  7900. aResolver.ComputeElement(El.Value,ResolvedEl,[]);
  7901. {$IFDEF VerbosePas2JS}
  7902. writeln('TPasToJSConverter.ConvertArrayParams Value=',GetResolverResultDbg(ResolvedEl));
  7903. {$ENDIF}
  7904. if ResolvedEl.BaseType in btAllJSStrings then
  7905. // astring[]
  7906. ConvertStringBracket(ResolvedEl)
  7907. else if (ResolvedEl.IdentEl is TPasProperty)
  7908. and (El.Value is TPrimitiveExpr)
  7909. and (aResolver.GetPasPropertyArgs(TPasProperty(ResolvedEl.IdentEl)).Count>0) then
  7910. // aproperty[]
  7911. ConvertIndexedProperty(TPasProperty(ResolvedEl.IdentEl),AContext)
  7912. else if ResolvedEl.BaseType=btContext then
  7913. begin
  7914. TypeEl:=ResolvedEl.LoTypeEl;
  7915. if TypeEl.ClassType=TPasClassType then
  7916. begin
  7917. aClass:=TPasClassType(TypeEl);
  7918. ClassScope:=aClass.CustomData as TPas2JSClassScope;
  7919. if ClassScope.DefaultProperty<>nil then
  7920. // anObject[]
  7921. ConvertDefaultProperty(ResolvedEl,ClassScope.DefaultProperty)
  7922. else
  7923. RaiseInconsistency(20170206180448,aClass);
  7924. end
  7925. else if TypeEl.ClassType=TPasClassOfType then
  7926. begin
  7927. // aClass[]
  7928. DestType:=aResolver.ResolveAliasType(TPasClassOfType(TypeEl).DestType);
  7929. ClassScope:=DestType.CustomData as TPas2JSClassScope;
  7930. if ClassScope.DefaultProperty=nil then
  7931. RaiseInconsistency(20170206180503,DestType);
  7932. ConvertDefaultProperty(ResolvedEl,ClassScope.DefaultProperty);
  7933. end
  7934. else if TypeEl.ClassType=TPasArrayType then
  7935. // anArray[]
  7936. ConvertArray(TPasArrayType(TypeEl))
  7937. else
  7938. RaiseIllegalBrackets(20170206181220,ResolvedEl);
  7939. end
  7940. else
  7941. RaiseIllegalBrackets(20170206180222,ResolvedEl);
  7942. end;
  7943. function TPasToJSConverter.ConvertFuncParams(El: TParamsExpr;
  7944. AContext: TConvertContext): TJSElement;
  7945. var
  7946. Ref: TResolvedReference;
  7947. Decl, Left: TPasElement;
  7948. BuiltInProc: TResElDataBuiltInProc;
  7949. TargetProcType: TPasProcedureType;
  7950. Call: TJSCallExpression;
  7951. Elements: TJSArrayLiteralElements;
  7952. JsArrLit: TJSArrayLiteral;
  7953. OldAccess: TCtxAccess;
  7954. DeclResolved, ParamResolved, ValueResolved: TPasResolverResult;
  7955. Param: TPasExpr;
  7956. JSBaseType: TPas2jsBaseType;
  7957. C: TClass;
  7958. aName: String;
  7959. aClassTypeEl: TPasClassType;
  7960. ParamTypeEl, TypeEl: TPasType;
  7961. aResolver: TPas2JSResolver;
  7962. NeedIntfRef: Boolean;
  7963. DestRange, SrcRange: TResEvalValue;
  7964. LastArg: TJSArrayLiteralElement;
  7965. CallArgs: TJSArguments;
  7966. begin
  7967. Result:=nil;
  7968. if El.Kind<>pekFuncParams then
  7969. RaiseInconsistency(20170209113515,El);
  7970. aResolver:=AContext.Resolver;
  7971. //writeln('TPasToJSConverter.ConvertFuncParams START pekFuncParams ',GetObjName(El.CustomData),' ',GetObjName(El.Value.CustomData));
  7972. Call:=nil;
  7973. Elements:=nil;
  7974. TargetProcType:=nil;
  7975. if El.Value.CustomData is TResolvedReference then
  7976. begin
  7977. Ref:=TResolvedReference(El.Value.CustomData);
  7978. Decl:=Ref.Declaration;
  7979. if Decl is TPasType then
  7980. Decl:=aResolver.ResolveAliasType(TPasType(Decl));
  7981. //writeln('TPasToJSConverter.ConvertFuncParams pekFuncParams TResolvedReference ',GetObjName(Ref.Declaration),' ',GetObjName(Ref.Declaration.CustomData));
  7982. C:=Decl.ClassType;
  7983. if C=TPasUnresolvedSymbolRef then
  7984. begin
  7985. if Decl.CustomData is TResElDataBuiltInProc then
  7986. begin
  7987. BuiltInProc:=TResElDataBuiltInProc(Decl.CustomData);
  7988. {$IFDEF VerbosePas2JS}
  7989. writeln('TPasToJSConverter.ConvertFuncParams BuiltInProc ',Decl.Name,' ',ResolverBuiltInProcNames[BuiltInProc.BuiltIn]);
  7990. {$ENDIF}
  7991. case BuiltInProc.BuiltIn of
  7992. bfLength: Result:=ConvertBuiltIn_Length(El,AContext);
  7993. bfSetLength: Result:=ConvertBuiltIn_SetLength(El,AContext);
  7994. bfInclude: Result:=ConvertBuiltIn_ExcludeInclude(El,AContext,true);
  7995. bfExclude: Result:=ConvertBuiltIn_ExcludeInclude(El,AContext,false);
  7996. bfExit: Result:=ConvertBuiltIn_Exit(El,AContext);
  7997. bfInc,
  7998. bfDec: Result:=ConvertBuiltIn_IncDec(El,AContext);
  7999. bfAssigned: Result:=ConvertBuiltIn_Assigned(El,AContext);
  8000. bfChr: Result:=ConvertBuiltIn_Chr(El,AContext);
  8001. bfOrd: Result:=ConvertBuiltIn_Ord(El,AContext);
  8002. bfLow: Result:=ConvertBuiltIn_LowHigh(El,AContext,true);
  8003. bfHigh: Result:=ConvertBuiltIn_LowHigh(El,AContext,false);
  8004. bfPred: Result:=ConvertBuiltIn_PredSucc(El,AContext,true);
  8005. bfSucc: Result:=ConvertBuiltIn_PredSucc(El,AContext,false);
  8006. bfStrProc: Result:=ConvertBuiltIn_StrProc(El,AContext);
  8007. bfStrFunc: Result:=ConvertBuiltIn_StrFunc(El,AContext);
  8008. bfWriteStr: Result:=ConvertBuiltIn_WriteStr(El,AContext);
  8009. bfConcatArray: Result:=ConvertBuiltIn_ConcatArray(El,AContext);
  8010. bfCopyArray: Result:=ConvertBuiltIn_CopyArray(El,AContext);
  8011. bfInsertArray: Result:=ConvertBuiltIn_InsertArray(El,AContext);
  8012. bfDeleteArray: Result:=ConvertBuiltIn_DeleteArray(El,AContext);
  8013. bfTypeInfo: Result:=ConvertBuiltIn_TypeInfo(El,AContext);
  8014. bfAssert:
  8015. begin
  8016. Result:=ConvertBuiltIn_Assert(El,AContext);
  8017. if Result=nil then exit;
  8018. end;
  8019. bfNew: Result:=ConvertBuiltIn_New(El,AContext);
  8020. bfDispose:
  8021. begin
  8022. Result:=ConvertBuiltIn_Dispose(El,AContext);
  8023. if Result=nil then exit;
  8024. end;
  8025. bfDefault: Result:=ConvertBuiltIn_Default(El,AContext);
  8026. bfCustom:
  8027. case BuiltInProc.Element.Name of
  8028. 'Debugger': Result:=ConvertBuiltIn_Debugger(El,AContext);
  8029. else
  8030. RaiseNotSupported(El,AContext,20181126101801,'built in custom proc '+BuiltInProc.Element.Name);
  8031. end;
  8032. else
  8033. RaiseNotSupported(El,AContext,20161130164955,'built in proc '+ResolverBuiltInProcNames[BuiltInProc.BuiltIn]);
  8034. end;
  8035. if Result=nil then
  8036. RaiseInconsistency(20170210121932,El);
  8037. exit;
  8038. end
  8039. else if Decl.CustomData is TResElDataBaseType then
  8040. begin
  8041. // typecast to base type
  8042. Result:=ConvertTypeCastToBaseType(El,AContext,TResElDataBaseType(Decl.CustomData));
  8043. exit;
  8044. end
  8045. else
  8046. RaiseNotSupported(El,AContext,20170325160624);
  8047. end
  8048. else if aResolver.IsExternalClassConstructor(Decl) then
  8049. begin
  8050. // create external object/function
  8051. // -> check if there is complex left side, e.g. TExtA.new(params)
  8052. Left:=El;
  8053. while (Left.Parent.ClassType=TParamsExpr) do
  8054. Left:=Left.Parent;
  8055. if (Left.Parent.ClassType=TBinaryExpr) and (TBinaryExpr(Left.Parent).right=Left) then
  8056. Left:=TBinaryExpr(Left.Parent).Left
  8057. else
  8058. Left:=nil;
  8059. Result:=ConvertExternalConstructor(Left,Ref,El,AContext);
  8060. exit;
  8061. end
  8062. else if C.InheritsFrom(TPasProcedure) then
  8063. begin
  8064. TargetProcType:=TPasProcedure(Decl).ProcType;
  8065. if aResolver.IsExternalBracketAccessor(Decl) then
  8066. exit(ConvertExternalBracketAccessorCall(El,AContext));
  8067. end
  8068. else if (C=TPasClassType)
  8069. or (C=TPasClassOfType)
  8070. or (C=TPasRecordType)
  8071. or (C=TPasEnumType)
  8072. or (C=TPasRangeType)
  8073. or (C=TPasArrayType)
  8074. or (C=TPasPointerType) then
  8075. begin
  8076. // typecast
  8077. // default is to simply replace "aType(value)" with "value"
  8078. Param:=El.Params[0];
  8079. aResolver.ComputeElement(Param,ParamResolved,[]);
  8080. ParamTypeEl:=ParamResolved.LoTypeEl;
  8081. Result:=ConvertElement(Param,AContext);
  8082. if C=TPasRangeType then
  8083. begin
  8084. DestRange:=aResolver.EvalTypeRange(TPasRangeType(Decl),[refConst]);
  8085. SrcRange:=nil;
  8086. try
  8087. if DestRange=nil then
  8088. RaiseNotSupported(El,AContext,20180424124708);
  8089. SrcRange:=aResolver.EvalTypeRange(ParamResolved.LoTypeEl,[]);
  8090. if SrcRange=nil then
  8091. RaiseNotSupported(El,AContext,20180424125331);
  8092. case DestRange.Kind of
  8093. revkRangeInt:
  8094. case TResEvalRangeInt(DestRange).ElKind of
  8095. revskEnum, revskInt:
  8096. // type cast to integer-range
  8097. case SrcRange.Kind of
  8098. revkRangeInt:
  8099. case TResEvalRangeInt(SrcRange).ElKind of
  8100. revskEnum, revskInt:
  8101. ; // ToDo: higher precision to lower precision -> modulo
  8102. else
  8103. RaiseNotSupported(El,AContext,20180424130705);
  8104. end;
  8105. revkRangeUInt: ;
  8106. else
  8107. RaiseNotSupported(El,AContext,20180424125608);
  8108. end;
  8109. else
  8110. RaiseNotSupported(El,AContext,20180424125419);
  8111. end;
  8112. else
  8113. RaiseNotSupported(El,AContext,20180424124814);
  8114. end;
  8115. finally
  8116. ReleaseEvalValue(SrcRange);
  8117. ReleaseEvalValue(DestRange);
  8118. end;
  8119. end
  8120. else if C=TPasClassType then
  8121. begin
  8122. if ParamTypeEl is TPasClassType then
  8123. case TPasClassType(Decl).ObjKind of
  8124. okClass:
  8125. case TPasClassType(ParamTypeEl).ObjKind of
  8126. okClass:;
  8127. okInterface:
  8128. if not TPasClassType(Decl).IsExternal then
  8129. begin
  8130. // classtype(intfvar) -> rtl.intfToClass(intfvar,classtype)
  8131. Call:=CreateCallExpression(El);
  8132. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnIntfToClass]]);
  8133. Call.AddArg(Result);
  8134. Result:=Call;
  8135. Call.AddArg(CreateReferencePathExpr(Decl,AContext));
  8136. exit; // bsObjectChecks not needed
  8137. end;
  8138. else
  8139. RaiseNotSupported(El,AContext,20180327221211,ObjKindNames[TPasClassType(ParamTypeEl).ObjKind]);
  8140. end;
  8141. okInterface:
  8142. case TPasClassType(ParamTypeEl).ObjKind of
  8143. okClass:
  8144. begin
  8145. case TPasClassType(Decl).InterfaceType of
  8146. citCom:
  8147. // IntfType(ClassInstVar) -> queryIntfT(ClassInstVar,IntfType)
  8148. begin
  8149. Call:=CreateCallExpression(El);
  8150. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnIntfQueryIntfT]]);
  8151. Call.AddArg(Result);
  8152. Result:=Call;
  8153. Call.AddArg(CreateReferencePathExpr(Decl,AContext));
  8154. Result:=CreateIntfRef(Result,AContext,El);
  8155. end;
  8156. citCorba:
  8157. // IntfType(ClassInstVar) -> getIntfT(ClassInstVar,IntfType)
  8158. begin
  8159. Call:=CreateCallExpression(El);
  8160. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnIntfGetIntfT]]);
  8161. Call.AddArg(Result);
  8162. Result:=Call;
  8163. Call.AddArg(CreateReferencePathExpr(Decl,AContext));
  8164. end;
  8165. else
  8166. RaiseNotSupported(El,AContext,20180416102614,InterfaceTypeNames[TPasClassType(Decl).InterfaceType]);
  8167. end;
  8168. exit; // bsObjectChecks not needed
  8169. end;
  8170. okInterface:;
  8171. else
  8172. RaiseNotSupported(El,AContext,20180327221233,ObjKindNames[TPasClassType(ParamTypeEl).ObjKind]);
  8173. end;
  8174. else
  8175. RaiseNotSupported(El,AContext,20180327221130,ObjKindNames[TPasClassType(Decl).ObjKind]);
  8176. end;
  8177. end;
  8178. if bsObjectChecks in AContext.ScannerBoolSwitches then
  8179. begin
  8180. if (C=TPasClassType)
  8181. or (C=TPasClassOfType) then
  8182. begin
  8183. // TObject(value) -> rtl.asExt(value,type,mode)
  8184. if C=TPasClassOfType then
  8185. aClassTypeEl:=aResolver.ResolveAliasType(TPasClassOfType(Decl).DestType) as TPasClassType
  8186. else
  8187. aClassTypeEl:=TPasClassType(Decl);
  8188. aName:=CreateReferencePath(aClassTypeEl,AContext,rpkPathAndName);
  8189. Call:=CreateCallExpression(El);
  8190. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnAsExt]]);
  8191. Call.AddArg(Result);
  8192. Call.AddArg(CreatePrimitiveDotExpr(aName,El.Value));
  8193. if aClassTypeEl.IsExternal then
  8194. else if C=TPasClassOfType then
  8195. Call.AddArg(CreateLiteralNumber(El.Value,IsExtModePasClass))
  8196. else
  8197. Call.AddArg(CreateLiteralNumber(El.Value,IsExtModePasClassInstance));
  8198. Result:=Call;
  8199. end;
  8200. end
  8201. else if (ParamResolved.BaseType=btCustom)
  8202. and (ParamTypeEl.CustomData is TResElDataPas2JSBaseType) then
  8203. begin
  8204. JSBaseType:=TResElDataPas2JSBaseType(ParamTypeEl.CustomData).JSBaseType;
  8205. if JSBaseType=pbtJSValue then
  8206. begin
  8207. if (C=TPasClassType)
  8208. or (C=TPasClassOfType)
  8209. or (C=TPasRecordType) then
  8210. begin
  8211. // TObject(jsvalue) -> rtl.getObject(jsvalue)
  8212. Call:=CreateCallExpression(El);
  8213. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnGetObject]]);
  8214. Call.AddArg(Result);
  8215. Result:=Call;
  8216. end;
  8217. end;
  8218. end;
  8219. exit;
  8220. end
  8221. else if C.InheritsFrom(TPasVariable) then
  8222. begin
  8223. aResolver.ComputeElement(Decl,DeclResolved,[rcType]);
  8224. if DeclResolved.LoTypeEl is TPasProcedureType then
  8225. // e.g. OnClick()
  8226. TargetProcType:=TPasProcedureType(DeclResolved.LoTypeEl)
  8227. else
  8228. RaiseNotSupported(El,AContext,20170217115244);
  8229. end
  8230. else if (C=TPasArgument) then
  8231. begin
  8232. aResolver.ComputeElement(Decl,DeclResolved,[rcType]);
  8233. if DeclResolved.LoTypeEl is TPasProcedureType then
  8234. TargetProcType:=TPasProcedureType(DeclResolved.LoTypeEl)
  8235. else
  8236. RaiseNotSupported(El,AContext,20170328224020);
  8237. end
  8238. else if (C=TPasProcedureType)
  8239. or (C=TPasFunctionType) then
  8240. begin
  8241. aResolver.ComputeElement(El.Value,ValueResolved,[rcNoImplicitProc]);
  8242. if (ValueResolved.IdentEl is TPasType)
  8243. and (aResolver.ResolveAliasType(TPasType(ValueResolved.IdentEl)) is TPasProcedureType) then
  8244. begin
  8245. // type cast to proc type
  8246. Param:=El.Params[0];
  8247. Result:=ConvertElement(Param,AContext);
  8248. exit;
  8249. end
  8250. else
  8251. begin
  8252. // calling proc var
  8253. TargetProcType:=TPasProcedureType(Decl);
  8254. end;
  8255. end
  8256. else
  8257. begin
  8258. {$IFDEF VerbosePas2JS}
  8259. writeln('TPasToJSConverter.ConvertFuncParams El=',GetObjName(El),' Decl=',GetObjName(Decl));
  8260. {$ENDIF}
  8261. RaiseNotSupported(El,AContext,20170215114337);
  8262. end;
  8263. if [rrfNewInstance,rrfFreeInstance]*Ref.Flags<>[] then
  8264. begin
  8265. // call constructor, destructor
  8266. Call:=CreateFreeOrNewInstanceExpr(Ref,AContext);
  8267. if rrfNewInstance in Ref.Flags then
  8268. begin
  8269. // insert array parameter [], e.g. this.TObject.$create("create",[])
  8270. JsArrLit:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,El));
  8271. Call.AddArg(JsArrLit);
  8272. Elements:=JsArrLit.Elements;
  8273. end
  8274. else
  8275. Elements:=Call.Args.Elements;
  8276. end;
  8277. end;
  8278. // BEWARE: TargetProcType can be nil, if called without resolver
  8279. NeedIntfRef:=false;
  8280. if (TargetProcType is TPasFunctionType) and (aResolver<>nil) then
  8281. begin
  8282. TypeEl:=aResolver.ResolveAliasType(TPasFunctionType(TargetProcType).ResultEl.ResultType);
  8283. if (TypeEl is TPasClassType)
  8284. and (TPasClassType(TypeEl).ObjKind=okInterface)
  8285. and (TPasClassType(TypeEl).InterfaceType=citCom) then
  8286. NeedIntfRef:=true;
  8287. end;
  8288. if Call=nil then
  8289. begin
  8290. Call:=CreateCallExpression(El);
  8291. Elements:=Call.Args.Elements;
  8292. end;
  8293. OldAccess:=AContext.Access;
  8294. try
  8295. AContext.Access:=caRead;
  8296. if Call.Expr=nil then
  8297. Call.Expr:=ConvertElement(El.Value,AContext);
  8298. //if Call.Expr is TPrimitiveExpr then
  8299. // writeln('TPasToJSConverter.ConvertFuncParams ',TPrimitiveExpr(Call.Expr).GetDeclaration(true));
  8300. if Call.Args=nil then
  8301. begin
  8302. // append ()
  8303. Call.Args:=TJSArguments(CreateElement(TJSArguments,El));
  8304. Elements:=Call.Args.Elements;
  8305. end
  8306. else if Elements=nil then
  8307. RaiseInconsistency(20180720154413,El);
  8308. CreateProcedureCallArgs(Elements,El,TargetProcType,AContext);
  8309. CallArgs:=Call.Args;
  8310. if (Elements.Count=0)
  8311. and (CallArgs.Elements.Count>0)
  8312. then
  8313. begin
  8314. LastArg:=CallArgs.Elements[CallArgs.Elements.Count-1];
  8315. if not (LastArg.Expr is TJSArrayLiteral) then
  8316. RaiseNotSupported(El,AContext,20180720161317);
  8317. JsArrLit:=TJSArrayLiteral(LastArg.Expr);
  8318. if JsArrLit.Elements<>Elements then
  8319. RaiseNotSupported(El,AContext,20180720161324);
  8320. LastArg.Free;
  8321. end;
  8322. if CallArgs.Elements.Count=0 then
  8323. begin
  8324. CallArgs.Free;
  8325. Call.Args:=nil;
  8326. end;
  8327. if NeedIntfRef then
  8328. // $ir.ref(id,path.fnname())
  8329. Call:=CreateIntfRef(Call,AContext,El);
  8330. Result:=Call;
  8331. finally
  8332. AContext.Access:=OldAccess;
  8333. if Result=nil then
  8334. Call.Free;
  8335. end;
  8336. end;
  8337. function TPasToJSConverter.ConvertExternalConstructor(Left: TPasElement;
  8338. Ref: TResolvedReference; ParamsExpr: TParamsExpr; AContext: TConvertContext
  8339. ): TJSElement;
  8340. var
  8341. Proc: TPasConstructor;
  8342. ExtName: String;
  8343. NewExpr: TJSNewMemberExpression;
  8344. Call: TJSCallExpression;
  8345. LeftResolved: TPasResolverResult;
  8346. OldAccess: TCtxAccess;
  8347. ExtNameEl: TJSElement;
  8348. WithData: TPas2JSWithExprScope;
  8349. begin
  8350. Result:=nil;
  8351. NewExpr:=nil;
  8352. Call:=nil;
  8353. ExtNameEl:=nil;
  8354. try
  8355. Proc:=Ref.Declaration as TPasConstructor;
  8356. ExtNameEl:=nil;
  8357. if Left<>nil then
  8358. begin
  8359. if AContext.Resolver<>nil then
  8360. begin
  8361. AContext.Resolver.ComputeElement(Left,LeftResolved,[]);
  8362. if LeftResolved.BaseType=btModule then
  8363. begin
  8364. // e.g. Unit.TExtA
  8365. // ExtName is global -> omit unit
  8366. Left:=nil;
  8367. end
  8368. else ;
  8369. end;
  8370. if Left<>nil then
  8371. begin
  8372. // convert left side
  8373. OldAccess:=AContext.Access;
  8374. AContext.Access:=caRead;
  8375. ExtNameEl:=ConvertElement(Left,AContext);
  8376. AContext.Access:=OldAccess;
  8377. end;
  8378. end;
  8379. if ExtNameEl=nil then
  8380. begin
  8381. if Ref.WithExprScope<>nil then
  8382. begin
  8383. // using local WITH var
  8384. WithData:=Ref.WithExprScope as TPas2JSWithExprScope;
  8385. ExtName:=WithData.WithVarName;
  8386. end
  8387. else
  8388. // use external class name
  8389. ExtName:=(Proc.Parent as TPasClassType).ExternalName;
  8390. if ExtName='' then
  8391. DoError(20180511163944,nJSNewNotSupported,sJSNewNotSupported,[],ParamsExpr);
  8392. ExtNameEl:=CreatePrimitiveDotExpr(ExtName,Ref.Element);
  8393. end;
  8394. if CompareText(Proc.Name,'new')=0 then
  8395. begin
  8396. // create 'new ExtName(params)'
  8397. NewExpr:=TJSNewMemberExpression(CreateElement(TJSNewMemberExpression,Ref.Element));
  8398. NewExpr.MExpr:=ExtNameEl;
  8399. NewExpr.Args:=TJSArguments(CreateElement(TJSArguments,Ref.Element));
  8400. ExtNameEl:=nil;
  8401. if ParamsExpr<>nil then
  8402. CreateProcedureCallArgs(NewExpr.Args.Elements,ParamsExpr,Proc.ProcType,AContext);
  8403. Result:=NewExpr;
  8404. NewExpr:=nil;
  8405. end
  8406. else
  8407. RaiseInconsistency(20170323083214,Proc);
  8408. finally
  8409. ExtNameEl.Free;
  8410. NewExpr.Free;
  8411. Call.Free;
  8412. end;
  8413. end;
  8414. function TPasToJSConverter.ConvertTObjectFree_Bin(Bin: TBinaryExpr;
  8415. NameExpr: TPasExpr; AContext: TConvertContext): TJSElement;
  8416. function CreateCallRTLFree(Obj, Prop: TJSElement): TJSElement;
  8417. // create "rtl.free(obj,prop)"
  8418. var
  8419. Call: TJSCallExpression;
  8420. begin
  8421. Call:=CreateCallExpression(Bin.right);
  8422. Call.Expr:=CreateMemberExpression([GetBuildInNames(pbivnRTL),GetBuildInNames(pbifnFreeVar)]);
  8423. Call.Args.AddElement(Obj);
  8424. Call.Args.AddElement(Prop);
  8425. Result:=Call;
  8426. end;
  8427. var
  8428. LeftJS, Obj, Prop, Getter, Setter: TJSElement;
  8429. DotExpr: TJSDotMemberExpression;
  8430. BracketJS: TJSBracketMemberExpression;
  8431. aName: TJSString;
  8432. begin
  8433. Result:=nil;
  8434. LeftJS:=ConvertElement(Bin.left,AContext);
  8435. try
  8436. {$IFDEF VerbosePas2JS}
  8437. writeln('TPasToJSConverter.ConvertTObjectFree_Bin ',GetObjName(LeftJS));
  8438. {$ENDIF}
  8439. if LeftJS is TJSPrimaryExpressionIdent then
  8440. begin
  8441. aName:=TJSPrimaryExpressionIdent(LeftJS).Name;
  8442. if Pos('.',aName)>0 then
  8443. RaiseInconsistency(20170516173832,Bin.left);
  8444. // v.free
  8445. // -> v=rtl.freeLoc(v);
  8446. Getter:=LeftJS;
  8447. Setter:=ClonePrimaryExpression(TJSPrimaryExpressionIdent(LeftJS),Bin.left);
  8448. Result:=CreateCallRTLFreeLoc(Setter,Getter,NameExpr);
  8449. end
  8450. else if LeftJS is TJSDotMemberExpression then
  8451. begin
  8452. // obj.prop.free
  8453. // -> rtl.free(obj,"prop");
  8454. DotExpr:=TJSDotMemberExpression(LeftJS);
  8455. Obj:=DotExpr.MExpr;
  8456. DotExpr.MExpr:=nil;
  8457. Prop:=CreateLiteralJSString(Bin.right,DotExpr.Name);
  8458. FreeAndNil(LeftJS);
  8459. Result:=CreateCallRTLFree(Obj,Prop);
  8460. end
  8461. else if LeftJS is TJSBracketMemberExpression then
  8462. begin
  8463. // obj[prop].free
  8464. // -> rtl.free(obj,prop);
  8465. BracketJS:=TJSBracketMemberExpression(LeftJS);
  8466. Obj:=BracketJS.MExpr;
  8467. BracketJS.MExpr:=nil;
  8468. Prop:=BracketJS.Name;
  8469. BracketJS.Name:=nil;
  8470. FreeAndNil(LeftJS);
  8471. Result:=CreateCallRTLFree(Obj,Prop);
  8472. end
  8473. else
  8474. RaiseNotSupported(Bin.left,AContext,20170516164659,'invalid scope for Free');
  8475. finally
  8476. if Result=nil then
  8477. LeftJS.Free;
  8478. end;
  8479. end;
  8480. function TPasToJSConverter.ConvertTObjectFree_With(NameExpr: TPasExpr;
  8481. AContext: TConvertContext): TJSElement;
  8482. var
  8483. WithExprScope: TPas2JSWithExprScope;
  8484. Getter, Setter: TJSElement;
  8485. begin
  8486. Result:=nil;
  8487. WithExprScope:=TResolvedReference(NameExpr.CustomData).WithExprScope as TPas2JSWithExprScope;
  8488. if WithExprScope=nil then
  8489. RaiseInconsistency(20181027133210,NameExpr);
  8490. if AContext.Resolver.GetNewInstanceExpr(WithExprScope.Expr)<>nil then
  8491. begin
  8492. // "with TSomeClass.Create do Free"
  8493. // -> "$with1=rtl.freeLoc($with1);
  8494. Getter:=CreatePrimitiveDotExpr(WithExprScope.WithVarName,WithExprScope.Expr);
  8495. Setter:=CreatePrimitiveDotExpr(WithExprScope.WithVarName,WithExprScope.Expr);
  8496. Result:=CreateCallRTLFreeLoc(Setter,Getter,NameExpr);
  8497. exit;
  8498. end;
  8499. {$IFDEF VerbosePas2JS}
  8500. writeln('TPasToJSConverter.ConvertTObjectFree_With With=',GetObjName(WithExprScope.Expr));
  8501. {$ENDIF}
  8502. RaiseInconsistency(20170517092248,NameExpr);
  8503. end;
  8504. function TPasToJSConverter.ConvertTypeCastToBaseType(El: TParamsExpr;
  8505. AContext: TConvertContext; ToBaseTypeData: TResElDataBaseType): TJSElement;
  8506. var
  8507. to_bt: TResolverBaseType;
  8508. Param: TPasExpr;
  8509. ParamResolved: TPasResolverResult;
  8510. JSBaseType: TPas2jsBaseType;
  8511. JSBaseTypeData: TResElDataPas2JSBaseType;
  8512. function IsParamPas2JSBaseType: boolean;
  8513. var
  8514. TypeEl: TPasType;
  8515. begin
  8516. if ParamResolved.BaseType<>btCustom then exit(false);
  8517. TypeEl:=ParamResolved.LoTypeEl;
  8518. if TypeEl.ClassType<>TPasUnresolvedSymbolRef then exit(false);
  8519. if not (TypeEl.CustomData is TResElDataPas2JSBaseType) then exit(false);
  8520. Result:=true;
  8521. JSBaseTypeData:=TResElDataPas2JSBaseType(TypeEl.CustomData);
  8522. JSBaseType:=JSBaseTypeData.JSBaseType;
  8523. end;
  8524. function CreateBitWiseAnd(Value: TJSElement; const Mask: TMaxPrecInt; Shift: integer): TJSElement;
  8525. // ig sign=false: Value & Mask
  8526. // if sign=true: Value & Mask << ZeroBits >> ZeroBits
  8527. var
  8528. AndEx: TJSBitwiseAndExpression;
  8529. Hex: String;
  8530. i: Integer;
  8531. ShiftEx: TJSShiftExpression;
  8532. begin
  8533. AndEx:=TJSBitwiseAndExpression(CreateElement(TJSBitwiseAndExpression,El));
  8534. Result:=AndEx;
  8535. AndEx.A:=Value;
  8536. AndEx.B:=CreateLiteralNumber(El,Mask);
  8537. if Mask>999999 then
  8538. begin
  8539. Hex:=HexStr(Mask,8);
  8540. i:=1;
  8541. while i<8 do
  8542. if Hex[i]='0' then
  8543. inc(i)
  8544. else
  8545. break;
  8546. Hex:=Copy(Hex,i,8);
  8547. TJSLiteral(AndEx.B).Value.CustomValue:=TJSString('0x'+Hex);
  8548. end;
  8549. if Shift>0 then
  8550. begin
  8551. // value << ZeroBits
  8552. ShiftEx:=TJSLShiftExpression(CreateElement(TJSLShiftExpression,El));
  8553. ShiftEx.A:=Result;
  8554. Result:=ShiftEx;
  8555. ShiftEx.B:=CreateLiteralNumber(El,Shift);
  8556. // value << ZeroBits >> ZeroBits
  8557. ShiftEx:=TJSRShiftExpression(CreateElement(TJSRShiftExpression,El));
  8558. ShiftEx.A:=Result;
  8559. Result:=ShiftEx;
  8560. ShiftEx.B:=CreateLiteralNumber(El,Shift);
  8561. end;
  8562. end;
  8563. var
  8564. NotEqual: TJSEqualityExpressionNE;
  8565. CondExpr: TJSConditionalExpression;
  8566. Call: TJSCallExpression;
  8567. NotExpr: TJSUnaryNotExpression;
  8568. AddExpr: TJSAdditiveExpressionPlus;
  8569. TypeEl: TPasType;
  8570. C: TClass;
  8571. Int, MinVal, MaxVal: TMaxPrecInt;
  8572. aResolver: TPas2JSResolver;
  8573. ShiftEx: TJSURShiftExpression;
  8574. begin
  8575. Result:=nil;
  8576. Param:=El.Params[0];
  8577. aResolver:=AContext.Resolver;
  8578. aResolver.ComputeElement(Param,ParamResolved,[]);
  8579. JSBaseTypeData:=nil;
  8580. JSBaseType:=pbtNone;
  8581. to_bt:=ToBaseTypeData.BaseType;
  8582. if to_bt in btAllJSInteger then
  8583. begin
  8584. if ParamResolved.BaseType in btAllJSInteger then
  8585. begin
  8586. // integer to integer -> value
  8587. Result:=ConvertElement(Param,AContext);
  8588. if ParamResolved.BaseType=btCurrency then
  8589. begin
  8590. if to_bt<>btCurrency then
  8591. // currency to integer -> Math.floor(value/10000)
  8592. Result:=CreateMathFloor(Param,CreateDivideNumber(Param,Result,10000));
  8593. end
  8594. else if to_bt=btCurrency then
  8595. // integer to currency -> value*10000
  8596. Result:=CreateMulNumber(Param,Result,10000);
  8597. if (to_bt<>btIntDouble) and not (Result is TJSLiteral) then
  8598. begin
  8599. if bsRangeChecks in AContext.ScannerBoolSwitches then
  8600. begin
  8601. // rtl.rc(param,MinInt,MaxInt)
  8602. if not aResolver.GetIntegerRange(to_bt,MinVal,MaxVal) then
  8603. RaiseNotSupported(Param,AContext,20180425131839);
  8604. Call:=CreateCallExpression(El);
  8605. Call.Expr:=CreatePrimitiveDotExpr(FBuiltInNames[pbivnRTL]+'.'+FBuiltInNames[pbifnRangeCheckInt],El);
  8606. Call.AddArg(Result);
  8607. Result:=Call;
  8608. Call.AddArg(CreateLiteralNumber(El,MinVal));
  8609. Call.AddArg(CreateLiteralNumber(El,MaxVal));
  8610. end
  8611. else
  8612. case to_bt of
  8613. btByte:
  8614. // value to byte -> value & 255
  8615. if ParamResolved.BaseType<>btByte then
  8616. Result:=CreateBitWiseAnd(Result,255,0);
  8617. btShortInt:
  8618. // value to shortint -> value & 255 << 24 >> 24
  8619. if ParamResolved.BaseType<>btShortInt then
  8620. Result:=CreateBitWiseAnd(Result,255,24);
  8621. btWord:
  8622. // value to word -> value & 65535
  8623. if not (ParamResolved.BaseType in [btByte,btWord]) then
  8624. Result:=CreateBitWiseAnd(Result,65535,0);
  8625. btSmallInt:
  8626. // value to smallint -> value & 65535 << 16 >> 16
  8627. if not (ParamResolved.BaseType in [btShortInt,btSmallInt]) then
  8628. Result:=CreateBitWiseAnd(Result,65535,16);
  8629. btLongWord:
  8630. // value to longword -> value >>> 0
  8631. if not (ParamResolved.BaseType in [btByte,btWord,btLongWord,btUIntSingle]) then
  8632. begin
  8633. ShiftEx:=TJSURShiftExpression(CreateElement(TJSURShiftExpression,El));
  8634. ShiftEx.A:=Result;
  8635. ShiftEx.B:=CreateLiteralNumber(El,0);
  8636. Result:=ShiftEx;
  8637. end;
  8638. btLongint:
  8639. // value to longint -> value & 0xffffffff
  8640. if not (ParamResolved.BaseType in [btShortInt,btSmallInt,btLongint,btIntSingle]) then
  8641. Result:=CreateBitWiseAnd(Result,$ffffffff,0);
  8642. end;
  8643. end;
  8644. exit;
  8645. end
  8646. else if ParamResolved.BaseType in btAllJSBooleans then
  8647. begin
  8648. // boolean to integer -> value?1:0
  8649. Result:=ConvertElement(Param,AContext);
  8650. // Note: convert Param first in case it raises an exception
  8651. CondExpr:=TJSConditionalExpression(CreateElement(TJSConditionalExpression,El));
  8652. CondExpr.A:=Result;
  8653. if to_bt=btCurrency then
  8654. CondExpr.B:=CreateLiteralNumber(El,10000)
  8655. else
  8656. CondExpr.B:=CreateLiteralNumber(El,1);
  8657. CondExpr.C:=CreateLiteralNumber(El,0);
  8658. Result:=CondExpr;
  8659. exit;
  8660. end
  8661. else if ParamResolved.BaseType=btContext then
  8662. begin
  8663. if ParamResolved.LoTypeEl.ClassType=TPasEnumType then
  8664. begin
  8665. // e.g. longint(TEnum) -> value
  8666. Result:=ConvertElement(Param,AContext);
  8667. if to_bt=btCurrency then
  8668. // value*10000
  8669. Result:=CreateMulNumber(Param,Result,10000);
  8670. exit;
  8671. end;
  8672. end
  8673. else if IsParamPas2JSBaseType then
  8674. begin
  8675. if JSBaseType=pbtJSValue then
  8676. begin
  8677. // convert jsvalue to integer -> Math.floor(value)
  8678. Result:=ConvertElement(Param,AContext);
  8679. // Note: convert Param first in case it raises an exception
  8680. if to_bt=btCurrency then
  8681. // jsvalue to currency -> Math.floor(value*10000)
  8682. Result:=CreateMulNumber(Param,Result,10000);
  8683. Result:=CreateMathFloor(El,Result);
  8684. exit;
  8685. end;
  8686. end
  8687. else if (to_bt=btCurrency) and (ParamResolved.BaseType in btAllJSFloats) then
  8688. begin
  8689. // currency(double) -> double*10000
  8690. Result:=ConvertElement(Param,AContext);
  8691. Result:=CreateMulNumber(Param,Result,10000);
  8692. exit;
  8693. end;
  8694. end
  8695. else if to_bt in btAllJSBooleans then
  8696. begin
  8697. if ParamResolved.BaseType in btAllJSBooleans then
  8698. begin
  8699. // boolean to boolean -> value
  8700. Result:=ConvertElement(Param,AContext);
  8701. exit;
  8702. end
  8703. else if ParamResolved.BaseType in btAllJSInteger then
  8704. begin
  8705. // integer to boolean -> value!=0
  8706. Result:=ConvertElement(Param,AContext);
  8707. // Note: convert Param first in case it raises an exception
  8708. NotEqual:=TJSEqualityExpressionNE(CreateElement(TJSEqualityExpressionNE,El));
  8709. NotEqual.A:=Result;
  8710. NotEqual.B:=CreateLiteralNumber(El,0);
  8711. Result:=NotEqual;
  8712. exit;
  8713. end
  8714. else if IsParamPas2JSBaseType then
  8715. begin
  8716. if JSBaseType=pbtJSValue then
  8717. begin
  8718. // convert jsvalue to boolean -> !(value==false)
  8719. Result:=ConvertElement(Param,AContext);
  8720. // Note: convert Param first in case it raises an exception
  8721. NotExpr:=TJSUnaryNotExpression(CreateElement(TJSUnaryNotExpression,El));
  8722. NotExpr.A:=TJSEqualityExpressionEQ(CreateElement(TJSEqualityExpressionEQ,El));
  8723. TJSEqualityExpressionEQ(NotExpr.A).A:=Result;
  8724. TJSEqualityExpressionEQ(NotExpr.A).B:=CreateLiteralBoolean(El,false);
  8725. Result:=NotExpr;
  8726. exit;
  8727. end;
  8728. end;
  8729. end
  8730. else if to_bt in btAllJSFloats then
  8731. begin
  8732. if ParamResolved.BaseType in (btAllJSFloats+btAllJSInteger) then
  8733. begin
  8734. // int to double -> value
  8735. Result:=ConvertElement(Param,AContext);
  8736. if ParamResolved.BaseType=btCurrency then
  8737. // currency to double -> value/10000
  8738. Result:=CreateDivideNumber(El,Result,10000);
  8739. exit;
  8740. end
  8741. else if IsParamPas2JSBaseType then
  8742. begin
  8743. if JSBaseType=pbtJSValue then
  8744. begin
  8745. // convert jsvalue to double -> rtl.getNumber(value)
  8746. Result:=ConvertElement(Param,AContext);
  8747. // Note: convert Param first in case it raises an exception
  8748. Call:=CreateCallExpression(El);
  8749. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnGetNumber]]);
  8750. Call.AddArg(Result);
  8751. Result:=Call;
  8752. exit;
  8753. end;
  8754. end;
  8755. end
  8756. else if to_bt in btAllJSStrings then
  8757. begin
  8758. if ParamResolved.BaseType in btAllJSStringAndChars then
  8759. begin
  8760. // string or char to string -> value
  8761. Result:=ConvertElement(Param,AContext);
  8762. exit;
  8763. end
  8764. else if ParamResolved.BaseType=btPointer then
  8765. begin
  8766. // string(aPointer) -> value
  8767. Result:=ConvertElement(Param,AContext);
  8768. exit;
  8769. end
  8770. else if IsParamPas2JSBaseType then
  8771. begin
  8772. if JSBaseType=pbtJSValue then
  8773. begin
  8774. // convert jsvalue to string -> ""+value
  8775. Result:=ConvertElement(Param,AContext);
  8776. // Note: convert value first in case it raises an exception
  8777. AddExpr:=TJSAdditiveExpressionPlus(CreateElement(TJSAdditiveExpressionPlus,El));
  8778. AddExpr.A:=CreateLiteralString(El,'');
  8779. AddExpr.B:=Result;
  8780. Result:=AddExpr;
  8781. exit;
  8782. end;
  8783. end;
  8784. end
  8785. else if to_bt=btChar then
  8786. begin
  8787. if ParamResolved.BaseType=btChar then
  8788. begin
  8789. // char to char
  8790. Result:=ConvertElement(Param,AContext);
  8791. exit;
  8792. end
  8793. else if (ParamResolved.BaseType in btAllJSInteger)
  8794. or ((ParamResolved.BaseType=btContext)
  8795. and (aResolver.ResolveAliasType(ParamResolved.LoTypeEl).ClassType=TPasEnumType))
  8796. then
  8797. begin
  8798. // Note: convert value first in case it raises an exception
  8799. Result:=ConvertElement(Param,AContext);
  8800. if IsLiteralInteger(Result,Int)
  8801. and (Int>=0) and (Int<=$ffff) then
  8802. begin
  8803. FreeAndNil(Result);
  8804. Result:=CreateLiteralJSString(Param,WideChar(Int));
  8805. end
  8806. else
  8807. begin
  8808. // char(integer) -> String.fromCharCode(integer)
  8809. Result:=CreateCallFromCharCode(Result,El);
  8810. end;
  8811. exit;
  8812. end
  8813. else if (ParamResolved.BaseType in (btArrayRangeTypes+[btRange]))
  8814. or (IsParamPas2JSBaseType and (JSBaseType=pbtJSValue)) then
  8815. begin
  8816. // convert value to char -> rtl.getChar(value)
  8817. // Note: convert value first in case it raises an exception
  8818. Result:=ConvertElement(Param,AContext);
  8819. if IsLiteralInteger(Result,Int) then
  8820. begin
  8821. if (Int>=0) and (Int<=$ffff) then
  8822. begin
  8823. FreeAndNil(Result);
  8824. Result:=CreateLiteralJSString(Param,WideChar(Int));
  8825. end
  8826. else
  8827. begin
  8828. // char(integer) -> String.fromCharCode(integer)
  8829. Result:=CreateCallFromCharCode(Result,El);
  8830. end;
  8831. end
  8832. else
  8833. begin
  8834. // convert value to char -> rtl.getChar(value)
  8835. Call:=CreateCallExpression(El);
  8836. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnGetChar]]);
  8837. Call.AddArg(Result);
  8838. Result:=Call;
  8839. end;
  8840. exit;
  8841. end;
  8842. end
  8843. else if to_bt=btPointer then
  8844. begin
  8845. if IsParamPas2JSBaseType then
  8846. begin
  8847. if JSBaseType=pbtJSValue then
  8848. begin
  8849. // convert jsvalue to pointer -> value
  8850. Result:=ConvertElement(Param,AContext);
  8851. exit;
  8852. end;
  8853. end
  8854. else if ParamResolved.BaseType in btAllJSStrings then
  8855. begin
  8856. // pointer(aString) -> value
  8857. Result:=ConvertElement(Param,AContext);
  8858. exit;
  8859. end
  8860. else if ParamResolved.BaseType=btContext then
  8861. begin
  8862. // convert user type/value to pointer -> value
  8863. Result:=ConvertElement(Param,AContext);
  8864. exit;
  8865. end;
  8866. end
  8867. else if (to_bt=btCustom) and (ToBaseTypeData is TResElDataPas2JSBaseType) then
  8868. begin
  8869. JSBaseType:=TResElDataPas2JSBaseType(ToBaseTypeData).JSBaseType;
  8870. if JSBaseType=pbtJSValue then
  8871. begin
  8872. // type cast to jsvalue
  8873. Result:=ConvertElement(Param,AContext);
  8874. // Note: convert value first in case it raises an exception
  8875. if ParamResolved.BaseType=btContext then
  8876. begin
  8877. TypeEl:=ParamResolved.LoTypeEl;
  8878. C:=TypeEl.ClassType;
  8879. if C=TPasClassType then
  8880. begin
  8881. // TObject(vsvalue) -> rtl.getObject(vsvalue)
  8882. Call:=CreateCallExpression(El);
  8883. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnGetObject]]);
  8884. Call.AddArg(Result);
  8885. Result:=Call;
  8886. end;
  8887. end;
  8888. exit;
  8889. end;
  8890. end;
  8891. {$IFDEF VerbosePas2JS}
  8892. writeln('TPasToJSConverter.ConvertTypeCastToBaseType BaseTypeData=',aResolver.BaseTypeNames[to_bt],' ParamResolved=',GetResolverResultDbg(ParamResolved));
  8893. {$ENDIF}
  8894. RaiseNotSupported(El,AContext,20170325161150);
  8895. end;
  8896. function TPasToJSConverter.ConvertArrayOrSetLiteral(El: TParamsExpr;
  8897. AContext: TConvertContext): TJSElement;
  8898. var
  8899. Call: TJSCallExpression;
  8900. ArgContext: TConvertContext;
  8901. procedure AddArg(Expr: TPasExpr);
  8902. begin
  8903. Call.AddArg(CreateSetLiteralElement(Expr,ArgContext));
  8904. end;
  8905. var
  8906. i: Integer;
  8907. ArgEl: TPasExpr;
  8908. aResolver: TPas2JSResolver;
  8909. ArrayType: TPasArrayType;
  8910. begin
  8911. if El.Kind<>pekSet then
  8912. RaiseInconsistency(20170209112737,El);
  8913. if AContext.Access<>caRead then
  8914. DoError(20170209112926,nCantWriteSetLiteral,sCantWriteSetLiteral,[],El);
  8915. aResolver:=AContext.Resolver;
  8916. if aResolver<>nil then
  8917. begin
  8918. ArrayType:=aResolver.IsArrayExpr(El);
  8919. if ArrayType<>nil then
  8920. begin
  8921. // array literal
  8922. Result:=CreateArrayInit(ArrayType,El,El,AContext);
  8923. exit;
  8924. end;
  8925. end;
  8926. if length(El.Params)=0 then
  8927. Result:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,El))
  8928. else
  8929. begin
  8930. Result:=nil;
  8931. ArgContext:=AContext.GetNonDotContext;
  8932. Call:=CreateCallExpression(El);
  8933. try
  8934. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnSet_Create]]);
  8935. for i:=0 to length(El.Params)-1 do
  8936. begin
  8937. ArgEl:=El.Params[i];
  8938. {$IFDEF VerbosePas2JS}
  8939. writeln('TPasToJSConverter.ConvertSetLiteral ',i,' El.Params[i]=',GetObjName(ArgEl));
  8940. {$ENDIF}
  8941. if (ArgEl.ClassType=TBinaryExpr) and (TBinaryExpr(ArgEl).Kind=pekRange) then
  8942. begin
  8943. // range -> add three parameters: null,left,right
  8944. Call.AddArg(CreateLiteralNull(ArgEl));
  8945. AddArg(TBinaryExpr(ArgEl).left);
  8946. AddArg(TBinaryExpr(ArgEl).right);
  8947. end
  8948. else
  8949. AddArg(ArgEl);
  8950. end;
  8951. Result:=Call;
  8952. finally
  8953. if Result=nil then
  8954. Call.Free;
  8955. end;
  8956. end;
  8957. end;
  8958. function TPasToJSConverter.ConvertBuiltIn_Length(El: TParamsExpr;
  8959. AContext: TConvertContext): TJSElement;
  8960. var
  8961. Arg: TJSElement;
  8962. Param, RangeEl: TPasExpr;
  8963. ParamResolved: TPasResolverResult;
  8964. Ranges: TPasExprArray;
  8965. Call: TJSCallExpression;
  8966. RgLen: TMaxPrecInt;
  8967. begin
  8968. Result:=nil;
  8969. Param:=El.Params[0];
  8970. AContext.Resolver.ComputeElement(Param,ParamResolved,[]);
  8971. if ParamResolved.BaseType=btContext then
  8972. begin
  8973. if ParamResolved.LoTypeEl is TPasArrayType then
  8974. begin
  8975. Ranges:=TPasArrayType(ParamResolved.LoTypeEl).Ranges;
  8976. if length(Ranges)>0 then
  8977. begin
  8978. // static array -> number literal
  8979. if length(Ranges)>1 then
  8980. RaiseNotSupported(El,AContext,20170223131042);
  8981. RangeEl:=Ranges[0];
  8982. RgLen:=AContext.Resolver.GetRangeLength(RangeEl);
  8983. Result:=CreateLiteralNumber(El,RgLen);
  8984. exit;
  8985. end
  8986. else
  8987. begin
  8988. // dynamic array -> rtl.length(array)
  8989. Result:=ConvertElement(El.Params[0],AContext);
  8990. // Note: convert param first, it may raise an exception
  8991. Call:=CreateCallExpression(El);
  8992. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnArray_Length]]);
  8993. Call.AddArg(Result);
  8994. Result:=Call;
  8995. exit;
  8996. end;
  8997. end;
  8998. end;
  8999. // default: Param.length
  9000. Arg:=ConvertElement(Param,AContext);
  9001. Result:=CreateDotExpression(El,Arg,CreatePrimitiveDotExpr('length',El));
  9002. end;
  9003. function TPasToJSConverter.ConvertBuiltIn_SetLength(El: TParamsExpr;
  9004. AContext: TConvertContext): TJSElement;
  9005. // convert "SetLength(a,Len)" to "a = rtl.arraySetLength(a,Len)"
  9006. var
  9007. Param0: TPasExpr;
  9008. ResolvedParam0: TPasResolverResult;
  9009. ArrayType: TPasArrayType;
  9010. Call: TJSCallExpression;
  9011. ValInit: TJSElement;
  9012. AssignContext: TAssignContext;
  9013. ElType, TypeEl: TPasType;
  9014. i: Integer;
  9015. begin
  9016. Result:=nil;
  9017. Param0:=El.Params[0];
  9018. if AContext.Access<>caRead then
  9019. RaiseInconsistency(20170213213621,El);
  9020. AContext.Resolver.ComputeElement(Param0,ResolvedParam0,[rcNoImplicitProc]);
  9021. {$IFDEF VerbosePasResolver}
  9022. writeln('TPasToJSConverter.ConvertBuiltInSetLength ',GetResolverResultDbg(ResolvedParam0));
  9023. {$ENDIF}
  9024. TypeEl:=ResolvedParam0.LoTypeEl;
  9025. if TypeEl is TPasArrayType then
  9026. begin
  9027. // SetLength(AnArray,dim1,dim2,...)
  9028. ArrayType:=TPasArrayType(TypeEl);
  9029. {$IFDEF VerbosePasResolver}
  9030. writeln('TPasToJSConverter.ConvertBuiltInSetLength array');
  9031. {$ENDIF}
  9032. // -> AnArray = rtl.setArrayLength(AnArray,defaultvalue,dim1,dim2,...)
  9033. AssignContext:=TAssignContext.Create(El,nil,AContext);
  9034. try
  9035. AContext.Resolver.ComputeElement(Param0,AssignContext.LeftResolved,[rcNoImplicitProc]);
  9036. AssignContext.RightResolved:=ResolvedParam0;
  9037. // create right side
  9038. // rtl.setArrayLength()
  9039. Call:=CreateCallExpression(El);
  9040. AssignContext.RightSide:=Call;
  9041. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnArray_SetLength]]);
  9042. // 1st param: AnArray
  9043. Call.AddArg(ConvertElement(Param0,AContext));
  9044. // 2nd param: default value
  9045. for i:=3 to length(El.Params) do
  9046. begin
  9047. ElType:=AContext.Resolver.ResolveAliasType(ArrayType.ElType);
  9048. ArrayType:=ElType as TPasArrayType;
  9049. end;
  9050. ElType:=AContext.Resolver.ResolveAliasType(ArrayType.ElType);
  9051. if ElType.ClassType=TPasRecordType then
  9052. ValInit:=CreateReferencePathExpr(ElType,AContext)
  9053. else
  9054. ValInit:=CreateValInit(ElType,nil,Param0,AContext);
  9055. Call.AddArg(ValInit);
  9056. // add params: dim1, dim2, ...
  9057. for i:=1 to length(El.Params)-1 do
  9058. Call.AddArg(ConvertElement(El.Params[i],AContext));
  9059. // create left side: array =
  9060. Result:=CreateAssignStatement(Param0,AssignContext);
  9061. finally
  9062. AssignContext.RightSide.Free;
  9063. AssignContext.Free;
  9064. end;
  9065. end
  9066. else if ResolvedParam0.BaseType=btString then
  9067. begin
  9068. // convert "SetLength(astring,NewLen);" to "astring = rtl.strSetLength(astring,NewLen);"
  9069. {$IFDEF VerbosePasResolver}
  9070. writeln('TPasToJSConverter.ConvertBuiltInSetLength string');
  9071. {$ENDIF}
  9072. AssignContext:=TAssignContext.Create(El,nil,AContext);
  9073. try
  9074. AContext.Resolver.ComputeElement(Param0,AssignContext.LeftResolved,[rcNoImplicitProc]);
  9075. AssignContext.RightResolved:=AssignContext.LeftResolved;
  9076. // create right side rtl.strSetLength(aString,NewLen)
  9077. Call:=CreateCallExpression(El);
  9078. AssignContext.RightSide:=Call;
  9079. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnStringSetLength]]);
  9080. Call.AddArg(ConvertElement(Param0,AContext));
  9081. Call.AddArg(ConvertElement(El.Params[1],AContext));
  9082. Result:=CreateAssignStatement(Param0,AssignContext);
  9083. finally
  9084. AssignContext.RightSide.Free;
  9085. AssignContext.Free;
  9086. end;
  9087. end
  9088. else
  9089. RaiseNotSupported(El.Value,AContext,20170130141026,'setlength '+GetResolverResultDbg(ResolvedParam0));
  9090. end;
  9091. function TPasToJSConverter.ConvertBuiltIn_ExcludeInclude(El: TParamsExpr;
  9092. AContext: TConvertContext; IsInclude: boolean): TJSElement;
  9093. // convert "Include(aSet,Enum)" to "aSet=rtl.includeSet(aSet,Enum)"
  9094. var
  9095. Call: TJSCallExpression;
  9096. Param0: TPasExpr;
  9097. AssignContext: TAssignContext;
  9098. FunName: String;
  9099. begin
  9100. Result:=nil;
  9101. Param0:=El.Params[0];
  9102. AssignContext:=TAssignContext.Create(El,nil,AContext);
  9103. try
  9104. AContext.Resolver.ComputeElement(Param0,AssignContext.LeftResolved,[rcNoImplicitProc]);
  9105. AssignContext.RightResolved:=AssignContext.LeftResolved;
  9106. // create right side rtl.includeSet(aSet,Enum)
  9107. Call:=CreateCallExpression(El);
  9108. AssignContext.RightSide:=Call;
  9109. if IsInclude then
  9110. FunName:=FBuiltInNames[pbifnSet_Include]
  9111. else
  9112. FunName:=FBuiltInNames[pbifnSet_Exclude];
  9113. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FunName]);
  9114. Call.AddArg(ConvertElement(Param0,AContext));
  9115. Call.AddArg(ConvertElement(El.Params[1],AContext));
  9116. Result:=CreateAssignStatement(Param0,AssignContext);
  9117. finally
  9118. AssignContext.RightSide.Free;
  9119. AssignContext.Free;
  9120. end;
  9121. end;
  9122. function TPasToJSConverter.ConvertBuiltInContinue(El: TPasExpr;
  9123. AContext: TConvertContext): TJSElement;
  9124. begin
  9125. if AContext=nil then;
  9126. Result:=TJSContinueStatement(CreateElement(TJSContinueStatement,El));
  9127. end;
  9128. function TPasToJSConverter.ConvertBuiltInBreak(El: TPasExpr;
  9129. AContext: TConvertContext): TJSElement;
  9130. begin
  9131. if AContext=nil then;
  9132. Result:=TJSBreakStatement(CreateElement(TJSBreakStatement,El));
  9133. end;
  9134. function TPasToJSConverter.ConvertBuiltIn_Exit(El: TPasExpr;
  9135. AContext: TConvertContext): TJSElement;
  9136. // convert "exit;" -> in a function: "return result;" in a procedure: "return;"
  9137. // convert "exit(param);" -> "return param;"
  9138. var
  9139. ProcEl: TPasElement;
  9140. Scope: TPas2JSProcedureScope;
  9141. VarName: String;
  9142. FuncContext: TFunctionContext;
  9143. AssignSt: TJSSimpleAssignStatement;
  9144. St: TJSStatementList;
  9145. Proc: TPasProcedure;
  9146. begin
  9147. {$IFDEF VerbosePas2JS}
  9148. writeln('TPasToJSConverter.ConvertBuiltIn_Exit ',GetObjName(El));
  9149. {$ENDIF}
  9150. ProcEl:=El.Parent;
  9151. while (ProcEl<>nil) and not (ProcEl is TPasProcedure) do
  9152. ProcEl:=ProcEl.Parent;
  9153. // ProcEl can be nil, when exit is in program begin block
  9154. Proc:=TPasProcedure(ProcEl);
  9155. Result:=TJSReturnStatement(CreateElement(TJSReturnStatement,El));
  9156. if (El is TParamsExpr) and (length(TParamsExpr(El).Params)>0) then
  9157. begin
  9158. // with parameter. convert "exit(param);" -> "return param;"
  9159. TJSReturnStatement(Result).Expr:=ConvertExpression(TParamsExpr(El).Params[0],AContext);
  9160. end
  9161. else
  9162. begin
  9163. // without parameter
  9164. if (Proc<>nil) and (Proc.ProcType is TPasFunctionType) then
  9165. begin
  9166. // in a function, "return result;"
  9167. Scope:=Proc.CustomData as TPas2JSProcedureScope;
  9168. VarName:=Scope.ResultVarName;
  9169. if VarName='' then
  9170. VarName:=ResolverResultVar;
  9171. TJSReturnStatement(Result).Expr:=CreatePrimitiveDotExpr(VarName,El);
  9172. end
  9173. else
  9174. ; // in a procedure, "return;" which means "return undefined;"
  9175. end;
  9176. FuncContext:=AContext.GetFunctionContext;
  9177. if (FuncContext<>nil) and FuncContext.ResultNeedsIntfRelease then
  9178. begin
  9179. // add "$ok = true;"
  9180. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  9181. AssignSt.LHS:=CreatePrimitiveDotExpr(FBuiltInNames[pbivnProcOk],El);
  9182. AssignSt.Expr:=CreateLiteralBoolean(El,true);
  9183. St:=TJSStatementList(CreateElement(TJSStatementList,El));
  9184. St.A:=AssignSt;
  9185. St.B:=Result;
  9186. Result:=St;
  9187. end;
  9188. end;
  9189. function TPasToJSConverter.ConvertBuiltIn_IncDec(El: TParamsExpr;
  9190. AContext: TConvertContext): TJSElement;
  9191. { inc(a) or inc(a,b)
  9192. if a is a variable:
  9193. convert inc(a,b) to a+=b
  9194. if a is a var/out arg:
  9195. convert inc(a,b) to a.set(a.get+b)
  9196. if a is a property
  9197. Getter: field, procedure
  9198. if a is an indexed-property
  9199. Getter: field, procedure
  9200. if a is a property with index-specifier
  9201. Getter: field, procedure
  9202. }
  9203. var
  9204. AssignSt: TJSAssignStatement;
  9205. Expr, SrcEl: TPasExpr;
  9206. ExprResolved: TPasResolverResult;
  9207. ExprArg: TPasArgument;
  9208. LHS, ValueJS: TJSElement;
  9209. Call: TJSCallExpression;
  9210. IsInc: Boolean;
  9211. AddJS: TJSAdditiveExpression;
  9212. AssignContext: TAssignContext;
  9213. begin
  9214. Result:=nil;
  9215. IsInc:=CompareText((El.Value as TPrimitiveExpr).Value,'inc')=0;
  9216. Expr:=El.Params[0];
  9217. AContext.Resolver.ComputeElement(Expr,ExprResolved,[]);
  9218. // convert value
  9219. if length(El.Params)=1 then
  9220. ValueJS:=CreateLiteralNumber(El,1)
  9221. else
  9222. ValueJS:=ConvertExpression(El.Params[1],AContext);
  9223. SrcEl:=El.Value;
  9224. // check target variable
  9225. AssignSt:=nil;
  9226. Call:=nil;
  9227. AssignContext:=nil;
  9228. LHS:=nil;
  9229. try
  9230. if ExprResolved.IdentEl is TPasArgument then
  9231. begin
  9232. ExprArg:=TPasArgument(ExprResolved.IdentEl);
  9233. if ExprArg.Access in [argVar,argOut] then
  9234. begin
  9235. // target variable is a reference
  9236. // -> convert inc(ref,b) to ref.set(ref.get()+b)
  9237. Call:=CreateCallExpression(SrcEl);
  9238. // create "ref.set"
  9239. Call.Expr:=CreateDotExpression(SrcEl,
  9240. CreateIdentifierExpr(ExprResolved.IdentEl,AContext),
  9241. CreatePrimitiveDotExpr(TempRefObjSetterName,SrcEl));
  9242. // create "+"
  9243. if IsInc then
  9244. AddJS:=TJSAdditiveExpressionPlus(CreateElement(TJSAdditiveExpressionPlus,SrcEl))
  9245. else
  9246. AddJS:=TJSAdditiveExpressionMinus(CreateElement(TJSAdditiveExpressionMinus,SrcEl));
  9247. Call.AddArg(AddJS);
  9248. // create "ref.get()"
  9249. AddJS.A:=TJSCallExpression(CreateElement(TJSCallExpression,SrcEl));
  9250. TJSCallExpression(AddJS.A).Expr:=CreateDotExpression(SrcEl,
  9251. CreateIdentifierExpr(ExprResolved.IdentEl,AContext),
  9252. CreatePrimitiveDotExpr(TempRefObjGetterName,SrcEl));
  9253. // add "b"
  9254. AddJS.B:=ValueJS;
  9255. ValueJS:=nil;
  9256. Result:=Call;
  9257. exit;
  9258. end;
  9259. end
  9260. else if ExprResolved.IdentEl is TPasProperty then
  9261. begin
  9262. RaiseNotSupported(Expr,AContext,20170501151316);
  9263. end;
  9264. AssignContext:=TAssignContext.Create(Expr,nil,AContext);
  9265. AContext.Resolver.ComputeElement(Expr,AssignContext.LeftResolved,[rcNoImplicitProc]);
  9266. SetResolverValueExpr(AssignContext.RightResolved,
  9267. AssignContext.LeftResolved.BaseType,AssignContext.LeftResolved.LoTypeEl,
  9268. AssignContext.LeftResolved.HiTypeEl,Expr,[rrfReadable]);
  9269. AssignContext.RightSide:=ValueJS;
  9270. ValueJS:=nil;
  9271. LHS:=ConvertElement(Expr,AssignContext);
  9272. if AssignContext.Call<>nil then
  9273. begin
  9274. // left side is a Setter -> RightSide was already inserted as parameter
  9275. RaiseNotSupported(El,AContext,20181101154351);
  9276. end
  9277. else
  9278. begin
  9279. // left side is a variable
  9280. if AssignContext.RightSide=nil then
  9281. RaiseInconsistency(20180622211919,El);
  9282. end;
  9283. // convert inc(avar,b) to a+=b
  9284. if IsInc then
  9285. AssignSt:=TJSAddEqAssignStatement(CreateElement(TJSAddEqAssignStatement,SrcEl))
  9286. else
  9287. AssignSt:=TJSSubEqAssignStatement(CreateElement(TJSSubEqAssignStatement,SrcEl));
  9288. AssignSt.LHS:=LHS;
  9289. LHS:=nil;
  9290. AssignSt.Expr:=AssignContext.RightSide;
  9291. AssignContext.RightSide:=nil;
  9292. Result:=AssignSt;
  9293. finally
  9294. ValueJS.Free;
  9295. if Result=nil then
  9296. begin
  9297. AssignSt.Free;
  9298. Call.Free;
  9299. LHS.Free;
  9300. end;
  9301. if AssignContext<>nil then
  9302. begin
  9303. AssignContext.RightSide.Free;
  9304. AssignContext.Free;
  9305. end;
  9306. end;
  9307. end;
  9308. function TPasToJSConverter.ConvertBuiltIn_Assigned(El: TParamsExpr;
  9309. AContext: TConvertContext): TJSElement;
  9310. var
  9311. NE: TJSEqualityExpressionNE;
  9312. Param: TPasExpr;
  9313. ParamResolved: TPasResolverResult;
  9314. C: TClass;
  9315. GT: TJSRelationalExpressionGT;
  9316. Call: TJSCallExpression;
  9317. begin
  9318. Result:=nil;
  9319. if AContext.Resolver=nil then
  9320. RaiseInconsistency(20170210105235,El);
  9321. Param:=El.Params[0];
  9322. AContext.Resolver.ComputeElement(Param,ParamResolved,[rcNoImplicitProcType]);
  9323. {$IFDEF VerbosePas2JS}
  9324. writeln('TPasToJSConverter.ConvertBuiltInAssigned ParamResolved=',GetResolverResultDbg(ParamResolved));
  9325. {$ENDIF}
  9326. if ParamResolved.BaseType=btPointer then
  9327. begin
  9328. // convert Assigned(value) -> value!=null
  9329. Result:=ConvertElement(Param,AContext);
  9330. // Note: convert Param first, it may raise an exception
  9331. NE:=TJSEqualityExpressionNE(CreateElement(TJSEqualityExpressionNE,El));
  9332. NE.A:=Result;
  9333. NE.B:=CreateLiteralNull(El);
  9334. Result:=NE;
  9335. end
  9336. else if ParamResolved.BaseType=btContext then
  9337. begin
  9338. C:=ParamResolved.LoTypeEl.ClassType;
  9339. if (C=TPasClassType)
  9340. or (C=TPasClassOfType)
  9341. or C.InheritsFrom(TPasProcedureType) then
  9342. begin
  9343. // convert Assigned(value) -> value!=null
  9344. Result:=ConvertElement(Param,AContext);
  9345. // Note: convert Param first, it may raise an exception
  9346. NE:=TJSEqualityExpressionNE(CreateElement(TJSEqualityExpressionNE,El));
  9347. NE.A:=Result;
  9348. NE.B:=CreateLiteralNull(El);
  9349. Result:=NE;
  9350. end
  9351. else if C=TPasArrayType then
  9352. begin
  9353. // convert Assigned(value) -> rtl.length(value)>0
  9354. Result:=ConvertElement(Param,AContext);
  9355. // Note: convert Param first, it may raise an exception
  9356. GT:=TJSRelationalExpressionGT(CreateElement(TJSRelationalExpressionGT,El));
  9357. Call:=CreateCallExpression(El);
  9358. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnArray_Length]]);
  9359. Call.AddArg(Result);
  9360. GT.A:=Call;
  9361. GT.B:=CreateLiteralNumber(El,0);
  9362. Result:=GT;
  9363. end
  9364. else
  9365. RaiseNotSupported(El,AContext,20170328124606);
  9366. end;
  9367. end;
  9368. function TPasToJSConverter.ConvertBuiltIn_Chr(El: TParamsExpr;
  9369. AContext: TConvertContext): TJSElement;
  9370. var
  9371. ParamResolved: TPasResolverResult;
  9372. Param: TPasExpr;
  9373. begin
  9374. Result:=nil;
  9375. if AContext.Resolver=nil then
  9376. RaiseInconsistency(20170325185847,El);
  9377. Param:=El.Params[0];
  9378. AContext.Resolver.ComputeElement(Param,ParamResolved,[]);
  9379. if ParamResolved.BaseType in btAllJSInteger then
  9380. begin
  9381. // chr(integer) -> String.fromCharCode(integer)
  9382. Result:=ConvertElement(Param,AContext);
  9383. // Note: convert Param first, as it might raise an exception
  9384. Result:=CreateCallFromCharCode(Result,El);
  9385. exit;
  9386. end;
  9387. DoError(20170325185906,nXExpectedButYFound,sXExpectedButYFound,['integer',
  9388. AContext.Resolver.GetResolverResultDescription(ParamResolved)],Param);
  9389. end;
  9390. function TPasToJSConverter.ConvertBuiltIn_Ord(El: TParamsExpr;
  9391. AContext: TConvertContext): TJSElement;
  9392. var
  9393. ParamResolved, SubParamResolved: TPasResolverResult;
  9394. Param, SubParam: TPasExpr;
  9395. Call: TJSCallExpression;
  9396. SubParams: TParamsExpr;
  9397. SubParamJS: TJSElement;
  9398. Minus: TJSAdditiveExpressionMinus;
  9399. Add: TJSAdditiveExpressionPlus;
  9400. begin
  9401. Result:=nil;
  9402. if AContext.Resolver=nil then
  9403. RaiseInconsistency(20170210105235,El);
  9404. Param:=El.Params[0];
  9405. AContext.Resolver.ComputeElement(Param,ParamResolved,[]);
  9406. if ParamResolved.BaseType=btChar then
  9407. begin
  9408. if Param is TParamsExpr then
  9409. begin
  9410. SubParams:=TParamsExpr(Param);
  9411. if SubParams.Kind=pekArrayParams then
  9412. begin
  9413. // e.g. ord(something[index])
  9414. SubParam:=SubParams.Value;
  9415. AContext.Resolver.ComputeElement(SubParam,SubParamResolved,[]);
  9416. if SubParamResolved.BaseType in btAllJSStrings then
  9417. begin
  9418. // e.g. ord(aString[index]) -> aString.charCodeAt(index-1)
  9419. SubParamJS:=ConvertElement(SubParam,AContext);
  9420. // Note: convert SubParam first, as it might raise an exception
  9421. Call:=nil;
  9422. try
  9423. Call:=CreateCallExpression(El);
  9424. Call.Expr:=CreateDotExpression(El,SubParamJS,
  9425. CreatePrimitiveDotExpr('charCodeAt',El));
  9426. Minus:=TJSAdditiveExpressionMinus(CreateElement(TJSAdditiveExpressionMinus,Param));
  9427. Call.AddArg(Minus);
  9428. if length(SubParams.Params)<>1 then
  9429. RaiseInconsistency(20170405231706,El);
  9430. Minus.A:=ConvertElement(SubParams.Params[0],AContext);
  9431. Minus.B:=CreateLiteralNumber(Param,1);
  9432. Result:=Call;
  9433. finally
  9434. if Result=nil then
  9435. Call.Free;
  9436. end;
  9437. exit;
  9438. end;
  9439. end;
  9440. end;
  9441. // ord(aChar) -> aChar.charCodeAt()
  9442. Result:=ConvertElement(Param,AContext);
  9443. // Note: convert Param first, as it might raise an exception
  9444. Result:=CreateCallCharCodeAt(Result,0,El);
  9445. exit;
  9446. end
  9447. else if ParamResolved.BaseType in btAllJSBooleans then
  9448. begin
  9449. // ord(bool) -> bool+0
  9450. Result:=ConvertElement(Param,AContext);
  9451. // Note: convert Param first, as it might raise an exception
  9452. Add:=TJSAdditiveExpressionPlus(CreateElement(TJSAdditiveExpressionPlus,El));
  9453. Add.A:=Result;
  9454. Add.B:=CreateLiteralNumber(El,0);
  9455. Result:=Add;
  9456. exit;
  9457. end
  9458. else if ParamResolved.BaseType=btContext then
  9459. begin
  9460. if ParamResolved.LoTypeEl.ClassType=TPasEnumType then
  9461. begin
  9462. // ord(enum) -> enum
  9463. Result:=ConvertElement(Param,AContext);
  9464. exit;
  9465. end;
  9466. end;
  9467. DoError(20170210105339,nXExpectedButYFound,sXExpectedButYFound,['enum',
  9468. AContext.Resolver.GetResolverResultDescription(ParamResolved)],Param);
  9469. end;
  9470. function TPasToJSConverter.ConvertBuiltIn_LowHigh(El: TParamsExpr;
  9471. AContext: TConvertContext; IsLow: boolean): TJSElement;
  9472. // low(enumtype) -> first enumvalue
  9473. // high(enumtype) -> last enumvalue
  9474. // low(set var) -> first enumvalue
  9475. // high(set var) -> last enumvalue
  9476. // low(settype) -> first enumvalue
  9477. // high(settype) -> last enumvalue
  9478. // low(array var) -> first index
  9479. // high(dynamic array) -> array.length-1
  9480. // high(static array) -> last index
  9481. procedure CreateEnumValue(TypeEl: TPasEnumType);
  9482. var
  9483. EnumValue: TPasEnumValue;
  9484. begin
  9485. if IsLow then
  9486. EnumValue:=TPasEnumValue(TypeEl.Values[0])
  9487. else
  9488. EnumValue:=TPasEnumValue(TypeEl.Values[TypeEl.Values.Count-1]);
  9489. Result:=CreateReferencePathExpr(EnumValue,AContext);
  9490. end;
  9491. var
  9492. ResolvedEl: TPasResolverResult;
  9493. Param: TPasExpr;
  9494. TypeEl: TPasType;
  9495. Ranges: TPasExprArray;
  9496. Value: TResEvalValue;
  9497. Call: TJSCallExpression;
  9498. MinusExpr: TJSAdditiveExpressionMinus;
  9499. MinVal, MaxVal: TMaxPrecInt;
  9500. begin
  9501. Result:=nil;
  9502. if AContext.Resolver=nil then
  9503. RaiseInconsistency(20170210120659,El);
  9504. Param:=El.Params[0];
  9505. AContext.Resolver.ComputeElement(Param,ResolvedEl,[]);
  9506. case ResolvedEl.BaseType of
  9507. btContext:
  9508. begin
  9509. TypeEl:=ResolvedEl.LoTypeEl;
  9510. if TypeEl.ClassType=TPasEnumType then
  9511. begin
  9512. CreateEnumValue(TPasEnumType(TypeEl));
  9513. exit;
  9514. end
  9515. else if (TypeEl.ClassType=TPasSetType) then
  9516. begin
  9517. if TPasSetType(TypeEl).EnumType<>nil then
  9518. begin
  9519. TypeEl:=TPasSetType(TypeEl).EnumType;
  9520. CreateEnumValue(TPasEnumType(TypeEl));
  9521. exit;
  9522. end;
  9523. end
  9524. else if TypeEl.ClassType=TPasArrayType then
  9525. begin
  9526. Ranges:=TPasArrayType(TypeEl).Ranges;
  9527. if IsLow then
  9528. begin
  9529. // low(arr)
  9530. if length(Ranges)=0 then
  9531. begin
  9532. // dynamic array starts at 0
  9533. Result:=CreateLiteralNumber(El,0);
  9534. exit;
  9535. end
  9536. else
  9537. begin
  9538. // static array
  9539. Value:=AContext.Resolver.EvalRangeLimit(Ranges[0],[refConst],true,El);
  9540. if Value=nil then
  9541. RaiseNotSupported(El,AContext,20170910160817);
  9542. try
  9543. Result:=ConvertConstValue(Value,AContext,Param);
  9544. finally
  9545. ReleaseEvalValue(Value);
  9546. end;
  9547. exit;
  9548. end;
  9549. end
  9550. else
  9551. begin
  9552. // high(arr)
  9553. if length(Ranges)=0 then
  9554. begin
  9555. // dynamic array -> rtl.length(Param)-1
  9556. Result:=ConvertElement(Param,AContext);
  9557. // Note: convert Param first, it may raise an exception
  9558. Call:=CreateCallExpression(El);
  9559. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnArray_Length]]);
  9560. Call.AddArg(Result);
  9561. MinusExpr:=TJSAdditiveExpressionMinus(CreateElement(TJSAdditiveExpressionMinus,El));
  9562. MinusExpr.A:=Call;
  9563. MinusExpr.B:=CreateLiteralNumber(El,1);
  9564. Result:=MinusExpr;
  9565. exit;
  9566. end
  9567. else
  9568. begin
  9569. // static array
  9570. Value:=AContext.Resolver.EvalRangeLimit(Ranges[0],[refConst],false,El);
  9571. if Value=nil then
  9572. RaiseNotSupported(El,AContext,20170910161555);
  9573. try
  9574. Result:=ConvertConstValue(Value,AContext,Param);
  9575. finally
  9576. ReleaseEvalValue(Value);
  9577. end;
  9578. exit;
  9579. end;
  9580. end;
  9581. end;
  9582. end;
  9583. btBoolean,btByteBool,btWordBool,btLongBool:
  9584. begin
  9585. if IsLow then
  9586. Result:=CreateLiteralBoolean(El,LowJSBoolean)
  9587. else
  9588. Result:=CreateLiteralBoolean(El,HighJSBoolean);
  9589. exit;
  9590. end;
  9591. btChar,
  9592. btWideChar:
  9593. begin
  9594. if IsLow then
  9595. Result:=CreateLiteralJSString(El,#0)
  9596. else
  9597. Result:=CreateLiteralJSString(El,#$ffff);
  9598. exit;
  9599. end;
  9600. btByte..btIntMax:
  9601. begin
  9602. TypeEl:=ResolvedEl.LoTypeEl;
  9603. if TypeEl.ClassType=TPasUnresolvedSymbolRef then
  9604. begin
  9605. if TypeEl.CustomData is TResElDataBaseType then
  9606. begin
  9607. AContext.Resolver.GetIntegerRange(ResolvedEl.BaseType,MinVal,MaxVal);
  9608. if IsLow then
  9609. Result:=CreateLiteralNumber(El,MinVal)
  9610. else
  9611. Result:=CreateLiteralNumber(El,MaxVal);
  9612. exit;
  9613. end;
  9614. end
  9615. else if TypeEl.ClassType=TPasRangeType then
  9616. begin
  9617. Value:=AContext.Resolver.EvalRangeLimit(TPasRangeType(TypeEl).RangeExpr,
  9618. [refConst],IsLow,El);
  9619. try
  9620. case Value.Kind of
  9621. revkInt:
  9622. Result:=CreateLiteralNumber(El,TResEvalInt(Value).Int);
  9623. revkUInt:
  9624. Result:=CreateLiteralNumber(El,TResEvalUInt(Value).UInt);
  9625. else
  9626. RaiseNotSupported(El,AContext,20170925214317);
  9627. end;
  9628. exit;
  9629. finally
  9630. ReleaseEvalValue(Value);
  9631. end;
  9632. end;
  9633. {$IFDEF VerbosePas2JS}
  9634. writeln('TPasToJSConverter.ConvertBuiltIn_LowHigh ',GetResolverResultDbg(ResolvedEl));
  9635. {$ENDIF}
  9636. RaiseNotSupported(El,AContext,20170925214351);
  9637. end;
  9638. btSet,btArrayOrSet:
  9639. begin
  9640. TypeEl:=ResolvedEl.LoTypeEl;
  9641. if TypeEl.ClassType=TPasEnumType then
  9642. begin
  9643. CreateEnumValue(TPasEnumType(TypeEl));
  9644. exit;
  9645. end;
  9646. end;
  9647. end;
  9648. DoError(20170210110717,nXExpectedButYFound,sXExpectedButYFound,['enum or array',
  9649. AContext.Resolver.GetResolverResultDescription(ResolvedEl)],Param);
  9650. end;
  9651. function TPasToJSConverter.ConvertBuiltIn_PredSucc(El: TParamsExpr;
  9652. AContext: TConvertContext; IsPred: boolean): TJSElement;
  9653. // pred(enumvalue) -> enumvalue-1
  9654. // succ(enumvalue) -> enumvalue+1
  9655. var
  9656. ResolvedEl: TPasResolverResult;
  9657. TypeEl: TPasType;
  9658. procedure EnumExpected(Id: TMaxPrecInt);
  9659. begin
  9660. {$IFDEF VerbosePas2JS}
  9661. writeln('TPasToJSConverter.ConvertBuiltIn_PredSucc ',ResolvedEl.BaseType,' ',ResolvedEl.SubType,' ',GetObjName(TypeEl));
  9662. {$ENDIF}
  9663. DoError(Id,nXExpectedButYFound,sXExpectedButYFound,['enum',
  9664. AContext.Resolver.GetResolverResultDescription(ResolvedEl)],El.Params[0]);
  9665. end;
  9666. procedure CreateAdd(Param: TPasExpr);
  9667. var
  9668. V: TJSElement;
  9669. Expr: TJSAdditiveExpression;
  9670. begin
  9671. V:=ConvertElement(Param,AContext);
  9672. if IsPred then
  9673. // pred(int) -> Param-1
  9674. Expr:=TJSAdditiveExpressionMinus(CreateElement(TJSAdditiveExpressionMinus,El))
  9675. else
  9676. // succ(int) -> Param+1
  9677. Expr:=TJSAdditiveExpressionPlus(CreateElement(TJSAdditiveExpressionPlus,El));
  9678. Expr.A:=V;
  9679. Expr.B:=CreateLiteralNumber(El,1);
  9680. ConvertBuiltIn_PredSucc:=Expr;
  9681. end;
  9682. procedure CreateSwitchBool;
  9683. begin
  9684. if IsPred then
  9685. // pred(bool) -> false
  9686. ConvertBuiltIn_PredSucc:=CreateLiteralBoolean(El,false)
  9687. else
  9688. // succ(bool) -> true
  9689. ConvertBuiltIn_PredSucc:=CreateLiteralBoolean(El,true);
  9690. end;
  9691. procedure CreateCharPredSucc(Param: TPasExpr);
  9692. var
  9693. V: TJSElement;
  9694. Call: TJSCallExpression;
  9695. Expr: TJSAdditiveExpression;
  9696. begin
  9697. V:=ConvertElement(Param,AContext);
  9698. // V.charCodeAt()
  9699. Call:=CreateCallCharCodeAt(V,0,El);
  9700. if IsPred then
  9701. // pred(V) -> V.charCodeAt-1
  9702. Expr:=TJSAdditiveExpressionMinus(CreateElement(TJSAdditiveExpressionMinus,El))
  9703. else
  9704. // succ(V) -> V.charCodeAt+1
  9705. Expr:=TJSAdditiveExpressionPlus(CreateElement(TJSAdditiveExpressionPlus,El));
  9706. Expr.A:=Call;
  9707. Expr.B:=CreateLiteralNumber(El,1);
  9708. // String.fromCharCode(V.charCodeAt+1)
  9709. Call:=CreateCallFromCharCode(Expr,El);
  9710. ConvertBuiltIn_PredSucc:=Call;
  9711. end;
  9712. var
  9713. Param: TPasExpr;
  9714. Value: TResEvalValue;
  9715. begin
  9716. Result:=nil;
  9717. if AContext.Resolver=nil then
  9718. RaiseInconsistency(20170210120648,El);
  9719. Param:=El.Params[0];
  9720. AContext.Resolver.ComputeElement(Param,ResolvedEl,[]);
  9721. TypeEl:=ResolvedEl.LoTypeEl;
  9722. if ResolvedEl.BaseType in btAllJSInteger then
  9723. begin
  9724. CreateAdd(Param);
  9725. exit;
  9726. end
  9727. else if ResolvedEl.BaseType in btAllJSBooleans then
  9728. begin
  9729. CreateSwitchBool;
  9730. exit;
  9731. end
  9732. else if ResolvedEl.BaseType in btAllJSChars then
  9733. begin
  9734. CreateCharPredSucc(Param);
  9735. exit;
  9736. end
  9737. else if ResolvedEl.BaseType=btContext then
  9738. begin
  9739. if TypeEl.ClassType=TPasEnumType then
  9740. begin
  9741. CreateAdd(Param);
  9742. exit;
  9743. end
  9744. else
  9745. EnumExpected(20180424115902);
  9746. end
  9747. else if ResolvedEl.BaseType=btRange then
  9748. begin
  9749. if ResolvedEl.SubType in btAllJSInteger then
  9750. begin
  9751. CreateAdd(Param);
  9752. exit;
  9753. end
  9754. else if ResolvedEl.SubType in btAllJSBooleans then
  9755. begin
  9756. CreateAdd(Param);
  9757. exit;
  9758. end
  9759. else if ResolvedEl.SubType=btContext then
  9760. begin
  9761. if TypeEl.ClassType=TPasRangeType then
  9762. begin
  9763. Value:=AContext.Resolver.EvalTypeRange(TypeEl,[refConst]);
  9764. if Value<>nil then
  9765. try
  9766. case Value.Kind of
  9767. revkRangeInt:
  9768. case TResEvalRangeInt(Value).ElKind of
  9769. revskEnum, revskInt:
  9770. begin
  9771. CreateAdd(Param);
  9772. exit;
  9773. end;
  9774. revskChar:
  9775. EnumExpected(20180424115736);
  9776. revskBool:
  9777. begin
  9778. CreateSwitchBool;
  9779. exit;
  9780. end;
  9781. else
  9782. EnumExpected(20180424115959);
  9783. end;
  9784. revkRangeUInt:
  9785. begin
  9786. CreateAdd(Param);
  9787. exit;
  9788. end;
  9789. else
  9790. EnumExpected(20180424115757);
  9791. end;
  9792. finally
  9793. ReleaseEvalValue(Value);
  9794. end;
  9795. end
  9796. else
  9797. EnumExpected(20180424115934);
  9798. end;
  9799. end;
  9800. EnumExpected(20170210120039);
  9801. end;
  9802. function TPasToJSConverter.ConvertBuiltIn_StrProc(El: TParamsExpr;
  9803. AContext: TConvertContext): TJSElement;
  9804. // convert 'str(value,aString)' to 'aString = <string>'
  9805. // for the conversion see ConvertBuiltInStrParam
  9806. var
  9807. AssignContext: TAssignContext;
  9808. StrVar: TPasExpr;
  9809. TypeEl: TPasType;
  9810. begin
  9811. Result:=nil;
  9812. AssignContext:=TAssignContext.Create(El,nil,AContext);
  9813. try
  9814. StrVar:=El.Params[1];
  9815. AContext.Resolver.ComputeElement(StrVar,AssignContext.LeftResolved,[rcNoImplicitProc]);
  9816. // create right side
  9817. AssignContext.RightSide:=ConvertBuiltInStrParam(El.Params[0],AContext,false,true);
  9818. TypeEl:=AContext.Resolver.BaseTypes[btString];
  9819. SetResolverValueExpr(AssignContext.RightResolved,btString,
  9820. TypeEl,TypeEl,El,[rrfReadable]);
  9821. // create 'StrVar = rightside'
  9822. Result:=CreateAssignStatement(StrVar,AssignContext);
  9823. finally
  9824. AssignContext.RightSide.Free;
  9825. AssignContext.Free;
  9826. end;
  9827. end;
  9828. function TPasToJSConverter.ConvertBuiltIn_StrFunc(El: TParamsExpr;
  9829. AContext: TConvertContext): TJSElement;
  9830. // convert 'str(boolean)' to '""+boolean'
  9831. // convert 'str(integer)' to '""+integer'
  9832. // convert 'str(float)' to '""+float'
  9833. // convert 'str(float:width)' to rtl.spaceLeft('""+float,width)'
  9834. // convert 'str(float:width:precision)' to 'rtl.spaceLeft(float.toFixed(precision),width)'
  9835. var
  9836. i: Integer;
  9837. Param: TPasExpr;
  9838. Sum, Add: TJSElement;
  9839. AddEl: TJSAdditiveExpressionPlus;
  9840. begin
  9841. {$IFDEF VerbosePas2JS}
  9842. writeln('TPasToJSConverter.ConvertBuiltInStrFunc Count=',length(El.Params));
  9843. {$ENDIF}
  9844. Result:=nil;
  9845. Sum:=nil;
  9846. Add:=nil;
  9847. try
  9848. for i:=0 to length(El.Params)-1 do
  9849. begin
  9850. Param:=El.Params[i];
  9851. Add:=ConvertBuiltInStrParam(Param,AContext,true,i=0);
  9852. if Sum=nil then
  9853. Sum:=Add
  9854. else
  9855. begin
  9856. AddEl:=TJSAdditiveExpressionPlus(CreateElement(TJSAdditiveExpressionPlus,Param));
  9857. AddEl.A:=Sum;
  9858. AddEl.B:=Add;
  9859. Sum:=AddEl;
  9860. end;
  9861. Add:=nil;
  9862. end;
  9863. Result:=Sum;
  9864. finally
  9865. Add.Free;
  9866. if Result=nil then
  9867. Sum.Free;
  9868. end;
  9869. end;
  9870. function TPasToJSConverter.ConvertBuiltInStrParam(El: TPasExpr;
  9871. AContext: TConvertContext; IsStrFunc, IsFirst: boolean): TJSElement;
  9872. var
  9873. Add: TJSElement;
  9874. procedure PrependStrLit;
  9875. var
  9876. PlusEl: TJSAdditiveExpressionPlus;
  9877. begin
  9878. PlusEl:=TJSAdditiveExpressionPlus(CreateElement(TJSAdditiveExpressionPlus,El));
  9879. PlusEl.A:=CreateLiteralString(El,'');
  9880. PlusEl.B:=Add;
  9881. Add:=PlusEl;
  9882. end;
  9883. var
  9884. ResolvedEl: TPasResolverResult;
  9885. NeedStrLit: Boolean;
  9886. Call: TJSCallExpression;
  9887. Bracket: TJSBracketMemberExpression;
  9888. Arg: TJSElement;
  9889. begin
  9890. Result:=nil;
  9891. AContext.Resolver.ComputeElement(El,ResolvedEl,[]);
  9892. Add:=nil;
  9893. Call:=nil;
  9894. Bracket:=nil;
  9895. try
  9896. NeedStrLit:=false;
  9897. if ResolvedEl.BaseType in (btAllJSBooleans+btAllJSInteger-[btCurrency]) then
  9898. begin
  9899. NeedStrLit:=true;
  9900. Add:=ConvertElement(El,AContext);
  9901. end
  9902. else if ResolvedEl.BaseType in (btAllJSFloats+[btCurrency]) then
  9903. begin
  9904. // convert to rtl.floatToStr(El,width,precision)
  9905. Call:=CreateCallExpression(El);
  9906. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnFloatToStr]]);
  9907. Arg:=ConvertElement(El,AContext);
  9908. if ResolvedEl.BaseType=btCurrency then
  9909. Arg:=CreateDivideNumber(El,Arg,10000);
  9910. Call.AddArg(Arg);
  9911. if El.format1<>nil then
  9912. Call.AddArg(ConvertElement(El.format1,AContext));
  9913. if El.format2<>nil then
  9914. Call.AddArg(ConvertElement(El.format2,AContext));
  9915. Result:=Call;
  9916. Call:=nil;
  9917. exit;
  9918. end
  9919. else if IsStrFunc and (ResolvedEl.BaseType in btAllJSStringAndChars) then
  9920. Add:=ConvertElement(El,AContext)
  9921. else if ResolvedEl.BaseType=btContext then
  9922. begin
  9923. if ResolvedEl.LoTypeEl.ClassType=TPasEnumType then
  9924. begin
  9925. // create enumtype[enumvalue]
  9926. Bracket:=TJSBracketMemberExpression(CreateElement(TJSBracketMemberExpression,El));
  9927. Bracket.MExpr:=CreateReferencePathExpr(TPasEnumType(ResolvedEl.LoTypeEl),AContext);
  9928. Bracket.Name:=ConvertElement(El,AContext);
  9929. Add:=Bracket;
  9930. Bracket:=nil;
  9931. end
  9932. else
  9933. RaiseNotSupported(El,AContext,20170320123827);
  9934. end
  9935. else
  9936. RaiseNotSupported(El,AContext,20170320093001);
  9937. if El.format1<>nil then
  9938. begin
  9939. // width -> leading spaces
  9940. if NeedStrLit then
  9941. PrependStrLit;
  9942. // create 'rtl.spaceLeft(add,width)'
  9943. Call:=CreateCallExpression(El);
  9944. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnSpaceLeft]]);
  9945. Call.AddArg(Add);
  9946. Add:=nil;
  9947. Call.AddArg(ConvertElement(El.format1,AContext));
  9948. Add:=Call;
  9949. Call:=nil;
  9950. end
  9951. else if IsFirst and NeedStrLit then
  9952. PrependStrLit;
  9953. Result:=Add;
  9954. finally
  9955. Call.Free;
  9956. Bracket.Free;
  9957. if Result=nil then
  9958. Add.Free;
  9959. end;
  9960. end;
  9961. function TPasToJSConverter.ConvertBuiltIn_WriteStr(El: TParamsExpr;
  9962. AContext: TConvertContext): TJSElement;
  9963. // convert 'writestr(aString,v:width,p)' to 'aString = <string of v> + (<string of p>+"")'
  9964. // for the conversion see ConvertBuiltInStrParam
  9965. var
  9966. AssignContext: TAssignContext;
  9967. StrVar: TPasExpr;
  9968. TypeEl: TPasType;
  9969. JS: TJSElement;
  9970. AddJS: TJSAdditiveExpressionPlus;
  9971. i: Integer;
  9972. begin
  9973. Result:=nil;
  9974. AssignContext:=TAssignContext.Create(El,nil,AContext);
  9975. try
  9976. StrVar:=El.Params[0];
  9977. AContext.Resolver.ComputeElement(StrVar,AssignContext.LeftResolved,[rcNoImplicitProc]);
  9978. // create right side
  9979. for i:=1 to length(El.Params)-1 do
  9980. begin
  9981. JS:=ConvertBuiltInStrParam(El.Params[i],AContext,false,true);
  9982. if AssignContext.RightSide=nil then
  9983. AssignContext.RightSide:=JS
  9984. else
  9985. begin
  9986. AddJS:=TJSAdditiveExpressionPlus(CreateElement(TJSAdditiveExpressionPlus,El));
  9987. AddJS.A:=AssignContext.RightSide;
  9988. AssignContext.RightSide:=AddJS;
  9989. AddJS.B:=JS;
  9990. end;
  9991. end;
  9992. TypeEl:=AContext.Resolver.BaseTypes[btString];
  9993. SetResolverValueExpr(AssignContext.RightResolved,btString,
  9994. TypeEl,TypeEl,El,[rrfReadable]);
  9995. // create 'StrVar = rightside'
  9996. Result:=CreateAssignStatement(StrVar,AssignContext);
  9997. finally
  9998. AssignContext.RightSide.Free;
  9999. AssignContext.Free;
  10000. end;
  10001. end;
  10002. function TPasToJSConverter.ConvertBuiltIn_ConcatArray(El: TParamsExpr;
  10003. AContext: TConvertContext): TJSElement;
  10004. // concat(array1, array2)
  10005. var
  10006. Params: TPasExprArray;
  10007. ParamResolved: TPasResolverResult;
  10008. Param0, Param: TPasExpr;
  10009. ArrayType: TPasArrayType;
  10010. i: Integer;
  10011. Call: TJSCallExpression;
  10012. JS: TJSElement;
  10013. begin
  10014. Result:=nil;
  10015. Params:=El.Params;
  10016. if length(Params)<1 then
  10017. RaiseInconsistency(20170331000332,El);
  10018. Param0:=El.Params[0];
  10019. if length(Params)=1 then
  10020. begin
  10021. // concat(array1) -> array1
  10022. {$IFDEF VerbosePas2JS}
  10023. writeln('TPasToJSConverter.ConvertBuiltInConcatArray Count=',length(El.Params));
  10024. {$ENDIF}
  10025. Result:=ConvertElement(Param0,AContext);
  10026. end
  10027. else
  10028. begin
  10029. // concat(array1,array2,...)
  10030. Call:=nil;
  10031. AContext.Resolver.ComputeElement(Param0,ParamResolved,[]);
  10032. if ParamResolved.LoTypeEl is TPasArrayType then
  10033. begin
  10034. ArrayType:=TPasArrayType(ParamResolved.LoTypeEl);
  10035. Call:=CreateArrayConcat(ArrayType,El,AContext);
  10036. end
  10037. else if ParamResolved.BaseType=btArrayLit then
  10038. begin
  10039. ParamResolved.BaseType:=ParamResolved.SubType;
  10040. ParamResolved.SubType:=btNone;
  10041. Call:=CreateArrayConcat(ParamResolved,El,AContext);
  10042. end;
  10043. if Call=nil then
  10044. begin
  10045. {$IFDEF VerbosePas2JS}
  10046. writeln('TPasToJSConverter.ConvertBuiltIn_ConcatArray Param0Resolved=',GetResolverResultDbg(ParamResolved));
  10047. {$ENDIF}
  10048. RaiseNotSupported(Param0,AContext,20170331000846);
  10049. end;
  10050. try
  10051. for i:=0 to length(Params)-1 do
  10052. begin
  10053. Param:=Params[i];
  10054. JS:=ConvertElement(Param,AContext);
  10055. JS:=CreateArrayEl(Param,JS,AContext);
  10056. Call.AddArg(JS);
  10057. end;
  10058. Result:=Call;
  10059. finally
  10060. if Result=nil then
  10061. Call.Free;
  10062. end;
  10063. end;
  10064. end;
  10065. function TPasToJSConverter.ConvertBuiltIn_CopyArray(El: TParamsExpr;
  10066. AContext: TConvertContext): TJSElement;
  10067. var
  10068. Param: TPasExpr;
  10069. ParamResolved, ElTypeResolved: TPasResolverResult;
  10070. C: TClass;
  10071. TypeParam: TJSElement;
  10072. Call: TJSCallExpression;
  10073. ArrayType: TPasArrayType;
  10074. begin
  10075. Result:=nil;
  10076. Call:=nil;
  10077. try
  10078. Param:=El.Params[0];
  10079. AContext.Resolver.ComputeElement(El,ParamResolved,[]);
  10080. if (ParamResolved.BaseType=btContext)
  10081. and (ParamResolved.LoTypeEl.ClassType=TPasArrayType) then
  10082. begin
  10083. ArrayType:=TPasArrayType(ParamResolved.LoTypeEl);
  10084. AContext.Resolver.ComputeElement(ArrayType.ElType,ElTypeResolved,[rcType]);
  10085. end
  10086. else if ParamResolved.BaseType=btArrayLit then
  10087. begin
  10088. ElTypeResolved:=ParamResolved;
  10089. ElTypeResolved.BaseType:=ElTypeResolved.SubType;
  10090. ElTypeResolved.SubType:=btNone;
  10091. end;
  10092. // rtl.arrayCopy(type,src,start,count)
  10093. TypeParam:=nil;
  10094. if ElTypeResolved.BaseType=btContext then
  10095. begin
  10096. C:=ElTypeResolved.LoTypeEl.ClassType;
  10097. if C=TPasRecordType then
  10098. // copy array of record
  10099. TypeParam:=CreateReferencePathExpr(TPasRecordType(ElTypeResolved.LoTypeEl),AContext);
  10100. end
  10101. else if ElTypeResolved.BaseType=btSet then
  10102. // copy array of set
  10103. TypeParam:=CreateLiteralString(El,FBuiltInNames[pbifnSet_Reference]);
  10104. if TypeParam=nil then
  10105. TypeParam:=CreateLiteralNumber(El,0);
  10106. Call:=CreateCallExpression(El);
  10107. // rtl.arrayCopy
  10108. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnArray_Copy]]);
  10109. // param: type
  10110. Call.AddArg(TypeParam);
  10111. // param: src
  10112. Call.AddArg(ConvertElement(Param,AContext));
  10113. // param: start
  10114. if length(El.Params)=1 then
  10115. Call.AddArg(CreateLiteralNumber(El,0))
  10116. else
  10117. Call.AddArg(ConvertElement(El.Params[1],AContext));
  10118. // param: count
  10119. if length(El.Params)>=3 then
  10120. Call.AddArg(ConvertElement(El.Params[2],AContext));
  10121. Result:=Call;
  10122. finally
  10123. if Result=nil then
  10124. Call.Free;
  10125. end;
  10126. if El=nil then ;
  10127. if AContext=nil then;
  10128. end;
  10129. function TPasToJSConverter.ConvertBuiltIn_InsertArray(El: TParamsExpr;
  10130. AContext: TConvertContext): TJSElement;
  10131. // procedure insert(item,var array,const position)
  10132. // -> array.splice(position,0,item);
  10133. var
  10134. ArrEl: TJSElement;
  10135. Call: TJSCallExpression;
  10136. begin
  10137. Result:=nil;
  10138. Call:=nil;
  10139. try
  10140. Call:=CreateCallExpression(El);
  10141. ArrEl:=ConvertElement(El.Params[1],AContext);
  10142. Call.Expr:=CreateDotExpression(El,ArrEl,CreatePrimitiveDotExpr('splice',El));
  10143. Call.AddArg(ConvertElement(El.Params[2],AContext));
  10144. Call.AddArg(CreateLiteralNumber(El,0));
  10145. Call.AddArg(ConvertElement(El.Params[0],AContext));
  10146. Result:=Call;
  10147. finally
  10148. if Result=nil then
  10149. Call.Free;
  10150. end;
  10151. end;
  10152. function TPasToJSConverter.ConvertBuiltIn_DeleteArray(El: TParamsExpr;
  10153. AContext: TConvertContext): TJSElement;
  10154. // proc delete(var array,const start,count)
  10155. // -> array.splice(start,count)
  10156. var
  10157. ArrEl: TJSElement;
  10158. Call: TJSCallExpression;
  10159. begin
  10160. Result:=nil;
  10161. Call:=nil;
  10162. try
  10163. Call:=CreateCallExpression(El);
  10164. ArrEl:=ConvertElement(El.Params[0],AContext);
  10165. Call.Expr:=CreateDotExpression(El,ArrEl,CreatePrimitiveDotExpr('splice',El));
  10166. Call.AddArg(ConvertElement(El.Params[1],AContext));
  10167. Call.AddArg(ConvertElement(El.Params[2],AContext));
  10168. Result:=Call;
  10169. finally
  10170. if Result=nil then
  10171. Call.Free;
  10172. end;
  10173. end;
  10174. function TPasToJSConverter.ConvertBuiltIn_TypeInfo(El: TParamsExpr;
  10175. AContext: TConvertContext): TJSElement;
  10176. var
  10177. ParamResolved: TPasResolverResult;
  10178. Param: TPasExpr;
  10179. ResultEl: TPasResultElement;
  10180. TypeEl: TPasType;
  10181. begin
  10182. Result:=nil;
  10183. Param:=El.Params[0];
  10184. AContext.Resolver.ComputeElement(Param,ParamResolved,[rcNoImplicitProc]);
  10185. {$IFDEF VerbosePas2JS}
  10186. writeln('TPasToJSConverter.ConvertBuiltIn_TypeInfo ',GetResolverResultDbg(ParamResolved));
  10187. {$ENDIF}
  10188. if (ParamResolved.BaseType=btProc) and (ParamResolved.IdentEl is TPasFunction) then
  10189. begin
  10190. // typeinfo(function) -> typeinfo(resulttype)
  10191. ResultEl:=TPasFunction(ParamResolved.IdentEl).FuncType.ResultEl;
  10192. AContext.Resolver.ComputeElement(ResultEl.ResultType,ParamResolved,[rcNoImplicitProc]);
  10193. {$IFDEF VerbosePas2JS}
  10194. writeln('TPasToJSConverter.ConvertBuiltIn_TypeInfo FuncResult=',GetResolverResultDbg(ParamResolved));
  10195. {$ENDIF}
  10196. Include(ParamResolved.Flags,rrfReadable);
  10197. ParamResolved.IdentEl:=ResultEl;
  10198. end;
  10199. TypeEl:=ResolveSimpleAliasType(ParamResolved.HiTypeEl);
  10200. if TypeEl=nil then
  10201. RaiseNotSupported(El,AContext,20170413001544)
  10202. else if ParamResolved.IdentEl is TPasType then
  10203. Result:=CreateTypeInfoRef(TPasType(ParamResolved.IdentEl),AContext,Param)
  10204. else if (rrfReadable in ParamResolved.Flags)
  10205. and ((TypeEl.ClassType=TPasClassType)
  10206. or (TypeEl.ClassType=TPasClassOfType))
  10207. and ((ParamResolved.IdentEl is TPasVariable)
  10208. or (ParamResolved.IdentEl.ClassType=TPasArgument)
  10209. or (ParamResolved.IdentEl.ClassType=TPasResultElement)) then
  10210. begin
  10211. // typeinfo(classinstance) -> classinstance.$rtti
  10212. // typeinfo(classof) -> classof.$rtti
  10213. Result:=ConvertElement(Param,AContext);
  10214. Result:=CreateDotExpression(El,Result,
  10215. CreatePrimitiveDotExpr(FBuiltInNames[pbivnRTTI],Param));
  10216. end
  10217. else
  10218. Result:=CreateTypeInfoRef(TypeEl,AContext,Param);
  10219. end;
  10220. function TPasToJSConverter.ConvertBuiltIn_Assert(El: TParamsExpr;
  10221. AContext: TConvertContext): TJSElement;
  10222. // throw pas.SysUtils.EAssertionFailed.$create("Create");
  10223. // throw pas.SysUtils.EAssertionFailed.$create("Create$1",["text"]);
  10224. // throw "text"
  10225. var
  10226. IfSt: TJSIfStatement;
  10227. ThrowSt: TJSThrowStatement;
  10228. ModScope: TPasModuleScope;
  10229. aConstructor: TPasConstructor;
  10230. Ref: TResolvedReference;
  10231. ArrLit: TJSArrayLiteral;
  10232. Call: TJSCallExpression;
  10233. FunName: String;
  10234. PosEl: TPasExpr;
  10235. begin
  10236. Result:=nil;
  10237. // check if assertions are enabled
  10238. if not (bsAssertions in AContext.ScannerBoolSwitches) then
  10239. exit;
  10240. Ref:=nil;
  10241. IfSt:=TJSIfStatement(CreateElement(TJSIfStatement,El));
  10242. try
  10243. PosEl:=El.Params[0];
  10244. IfSt.Cond:=CreateUnaryNot(ConvertExpression(PosEl,AContext),PosEl);
  10245. ThrowSt:=TJSThrowStatement(CreateElement(TJSThrowStatement,PosEl));
  10246. IfSt.BTrue:=ThrowSt;
  10247. // using sysutils.EAssertionFailed if available
  10248. aConstructor:=nil;
  10249. if El.CustomData is TResolvedReference then
  10250. begin
  10251. Ref:=TResolvedReference(El.CustomData);
  10252. if Ref.Declaration is TPasConstructor then
  10253. aConstructor:=TPasConstructor(Ref.Declaration);
  10254. Ref:=nil;
  10255. end;
  10256. //writeln('TPasToJSConverter.ConvertBuiltIn_Assert ',GetObjName(aConstructor));
  10257. if aConstructor<>nil then
  10258. begin
  10259. Ref:=TResolvedReference.Create;
  10260. ModScope:=El.GetModule.CustomData as TPasModuleScope;
  10261. Ref.Declaration:=ModScope.AssertClass;
  10262. // pas.sysutils.EAssertionFailed
  10263. FunName:=CreateReferencePath(ModScope.AssertClass,AContext,rpkPathAndName,true,Ref);
  10264. // append .$create('Create')
  10265. FunName:=FunName+'.'+FBuiltInNames[pbifnClassInstanceNew];
  10266. Call:=CreateCallExpression(PosEl);
  10267. Call.Expr:=CreatePrimitiveDotExpr(FunName,PosEl);
  10268. // parameter: "Create"
  10269. Call.AddArg(CreateLiteralString(PosEl,TransformVariableName(aConstructor,AContext)));
  10270. ThrowSt.A:=Call;
  10271. if length(El.Params)>1 then
  10272. begin
  10273. // add [msg]
  10274. ArrLit:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,El.Params[1]));
  10275. Call.AddArg(ArrLit);
  10276. ArrLit.AddElement(ConvertExpression(El.Params[1],AContext));
  10277. end;
  10278. end;
  10279. if ThrowSt.A=nil then
  10280. begin
  10281. // fallback: throw msg
  10282. if length(El.Params)>1 then
  10283. ThrowSt.A:=ConvertExpression(El.Params[1],AContext)
  10284. else
  10285. ThrowSt.A:=CreateLiteralJSString(El.Params[0],'assert failed');
  10286. end;
  10287. Result:=IfSt;
  10288. finally
  10289. Ref.Free;
  10290. if Result=nil then
  10291. IfSt.Free;
  10292. end;
  10293. end;
  10294. function TPasToJSConverter.ConvertBuiltIn_New(El: TParamsExpr;
  10295. AContext: TConvertContext): TJSElement;
  10296. // new(p) -> p=new TRecord();
  10297. var
  10298. Param0: TPasExpr;
  10299. ParamResolved: TPasResolverResult;
  10300. AssignContext: TAssignContext;
  10301. TypeEl, SubTypeEl: TPasType;
  10302. aResolveR: TPas2JSResolver;
  10303. RecType: TPasRecordType;
  10304. begin
  10305. Result:=nil;
  10306. Param0:=El.Params[0];
  10307. aResolveR:=AContext.Resolver;
  10308. aResolveR.ComputeElement(Param0,ParamResolved,[]);
  10309. RecType:=nil;
  10310. if ParamResolved.BaseType=btContext then
  10311. begin
  10312. TypeEl:=ParamResolved.LoTypeEl;
  10313. if TypeEl.ClassType=TPasPointerType then
  10314. begin
  10315. SubTypeEl:=aResolveR.ResolveAliasType(TPasPointerType(TypeEl).DestType);
  10316. if SubTypeEl.ClassType=TPasRecordType then
  10317. RecType:=TPasRecordType(SubTypeEl);
  10318. end;
  10319. end;
  10320. if RecType=nil then
  10321. DoError(20180425011901,nIncompatibleTypesGotExpected,sIncompatibleTypesGotExpected,
  10322. [aResolveR.GetResolverResultDescription(ParamResolved,true),'pointer of record'],Param0);
  10323. AssignContext:=TAssignContext.Create(El,nil,AContext);
  10324. try
  10325. aResolveR.ComputeElement(Param0,AssignContext.LeftResolved,[rcNoImplicitProc]);
  10326. AssignContext.RightResolved:=AssignContext.LeftResolved;
  10327. // create right side new TRecord()
  10328. AssignContext.RightSide:=CreateNewRecord(El,RecType,AContext);
  10329. Result:=CreateAssignStatement(Param0,AssignContext);
  10330. finally
  10331. AssignContext.RightSide.Free;
  10332. AssignContext.Free;
  10333. end;
  10334. end;
  10335. function TPasToJSConverter.ConvertBuiltIn_Dispose(El: TParamsExpr;
  10336. AContext: TConvertContext): TJSElement;
  10337. // dispose(p)
  10338. // if p is writable set to null
  10339. var
  10340. Param0: TPasExpr;
  10341. aResolveR: TPas2JSResolver;
  10342. ParamResolved: TPasResolverResult;
  10343. TypeEl, SubTypeEl: TPasType;
  10344. RecType: TPasRecordType;
  10345. AssignContext: TAssignContext;
  10346. begin
  10347. Result:=nil;
  10348. Param0:=El.Params[0];
  10349. aResolveR:=AContext.Resolver;
  10350. aResolveR.ComputeElement(Param0,ParamResolved,[]);
  10351. RecType:=nil;
  10352. if ParamResolved.BaseType=btContext then
  10353. begin
  10354. TypeEl:=ParamResolved.LoTypeEl;
  10355. if TypeEl.ClassType=TPasPointerType then
  10356. begin
  10357. SubTypeEl:=aResolveR.ResolveAliasType(TPasPointerType(TypeEl).DestType);
  10358. if SubTypeEl.ClassType=TPasRecordType then
  10359. RecType:=TPasRecordType(SubTypeEl);
  10360. end;
  10361. end;
  10362. if RecType=nil then
  10363. DoError(20180425012910,nIncompatibleTypesGotExpected,sIncompatibleTypesGotExpected,
  10364. [aResolveR.GetResolverResultDescription(ParamResolved,true),'pointer of record'],Param0);
  10365. if not (rrfWritable in ParamResolved.Flags) then
  10366. // Param0 is no writable
  10367. exit(nil);
  10368. // Param0 is writable -> set to null
  10369. AssignContext:=TAssignContext.Create(El,nil,AContext);
  10370. try
  10371. aResolveR.ComputeElement(Param0,AssignContext.LeftResolved,[rcNoImplicitProc]);
  10372. AssignContext.RightResolved:=AssignContext.LeftResolved;
  10373. // create right side: null
  10374. AssignContext.RightSide:=CreateLiteralNull(El);
  10375. Result:=CreateAssignStatement(Param0,AssignContext);
  10376. finally
  10377. AssignContext.RightSide.Free;
  10378. AssignContext.Free;
  10379. end;
  10380. end;
  10381. function TPasToJSConverter.ConvertBuiltIn_Default(El: TParamsExpr;
  10382. AContext: TConvertContext): TJSElement;
  10383. procedure CreateEnumValue(TypeEl: TPasEnumType);
  10384. var
  10385. EnumValue: TPasEnumValue;
  10386. begin
  10387. EnumValue:=TPasEnumValue(TypeEl.Values[0]);
  10388. Result:=CreateReferencePathExpr(EnumValue,AContext);
  10389. end;
  10390. var
  10391. ResolvedEl: TPasResolverResult;
  10392. Param: TPasExpr;
  10393. TypeEl: TPasType;
  10394. Value: TResEvalValue;
  10395. MinVal, MaxVal: TMaxPrecInt;
  10396. C: TClass;
  10397. begin
  10398. Result:=nil;
  10399. if AContext.Resolver=nil then
  10400. RaiseInconsistency(20180501011029,El);
  10401. Param:=El.Params[0];
  10402. AContext.Resolver.ComputeElement(Param,ResolvedEl,[]);
  10403. case ResolvedEl.BaseType of
  10404. btBoolean,btByteBool,btWordBool,btLongBool:
  10405. begin
  10406. Result:=CreateLiteralBoolean(El,LowJSBoolean);
  10407. exit;
  10408. end;
  10409. btChar,
  10410. btWideChar:
  10411. begin
  10412. Result:=CreateLiteralJSString(El,#0);
  10413. exit;
  10414. end;
  10415. btString,btUnicodeString:
  10416. begin
  10417. Result:=CreateLiteralJSString(El,'');
  10418. exit;
  10419. end;
  10420. btByte..btIntMax:
  10421. begin
  10422. TypeEl:=ResolvedEl.LoTypeEl;
  10423. if TypeEl.ClassType=TPasUnresolvedSymbolRef then
  10424. begin
  10425. if TypeEl.CustomData is TResElDataBaseType then
  10426. begin
  10427. AContext.Resolver.GetIntegerRange(ResolvedEl.BaseType,MinVal,MaxVal);
  10428. Result:=CreateLiteralNumber(El,MinVal);
  10429. exit;
  10430. end;
  10431. end
  10432. else if TypeEl.ClassType=TPasRangeType then
  10433. begin
  10434. Value:=AContext.Resolver.EvalRangeLimit(TPasRangeType(TypeEl).RangeExpr,
  10435. [refConst],true,El);
  10436. try
  10437. case Value.Kind of
  10438. revkInt:
  10439. Result:=CreateLiteralNumber(El,TResEvalInt(Value).Int);
  10440. revkUInt:
  10441. Result:=CreateLiteralNumber(El,TResEvalUInt(Value).UInt);
  10442. else
  10443. RaiseNotSupported(El,AContext,20180501011646);
  10444. end;
  10445. exit;
  10446. finally
  10447. ReleaseEvalValue(Value);
  10448. end;
  10449. end;
  10450. {$IFDEF VerbosePas2JS}
  10451. writeln('TPasToJSConverter.ConvertBuiltIn_Default ',GetResolverResultDbg(ResolvedEl));
  10452. {$ENDIF}
  10453. RaiseNotSupported(El,AContext,20180501011649);
  10454. end;
  10455. btSingle,btDouble:
  10456. begin
  10457. Result:=CreateLiteralNumber(El,0);
  10458. TJSLiteral(Result).Value.CustomValue:='0.0';
  10459. exit;
  10460. end;
  10461. btCurrency:
  10462. begin
  10463. Result:=CreateLiteralNumber(El,0);
  10464. exit;
  10465. end;
  10466. btContext:
  10467. begin
  10468. TypeEl:=ResolvedEl.LoTypeEl;
  10469. C:=TypeEl.ClassType;
  10470. if C=TPasEnumType then
  10471. begin
  10472. CreateEnumValue(TPasEnumType(TypeEl));
  10473. exit;
  10474. end
  10475. else if C=TPasSetType then
  10476. begin
  10477. Result:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,El));
  10478. exit;
  10479. end
  10480. else if C=TPasArrayType then
  10481. begin
  10482. Result:=CreateArrayInit(TPasArrayType(TypeEl),nil,El,AContext);
  10483. exit;
  10484. end
  10485. else if C=TPasRecordType then
  10486. begin
  10487. Result:=CreateRecordInit(TPasRecordType(TypeEl),nil,El,AContext);
  10488. exit;
  10489. end
  10490. else if C=TPasRangeType then
  10491. // a custom range without initial value -> use first value
  10492. begin
  10493. Value:=AContext.Resolver.Eval(TPasRangeType(TypeEl).RangeExpr.left,[refConst]);
  10494. try
  10495. Result:=ConvertConstValue(Value,AContext,El);
  10496. finally
  10497. ReleaseEvalValue(Value);
  10498. end;
  10499. end
  10500. else if (C=TPasClassType) or (C=TPasPointerType) then
  10501. begin
  10502. Result:=CreateLiteralNull(El);
  10503. exit;
  10504. end;
  10505. end;
  10506. btRange:
  10507. begin
  10508. if ResolvedEl.LoTypeEl is TPasRangeType then
  10509. begin
  10510. Value:=AContext.Resolver.Eval(TPasRangeType(ResolvedEl.LoTypeEl).RangeExpr.left,[refConst]);
  10511. try
  10512. Result:=ConvertConstValue(Value,AContext,El);
  10513. finally
  10514. ReleaseEvalValue(Value);
  10515. end;
  10516. exit;
  10517. end;
  10518. end;
  10519. btSet:
  10520. begin
  10521. Result:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,El));
  10522. exit;
  10523. end;
  10524. end;
  10525. {$IFDEF VerbosePas2JS}
  10526. writeln('TPasToJSConverter.ConvertBuiltIn_Default ',GetResolverResultDbg(ResolvedEl));
  10527. {$ENDIF}
  10528. DoError(20180501011723,nXExpectedButYFound,sXExpectedButYFound,['record',
  10529. AContext.Resolver.GetResolverResultDescription(ResolvedEl)],Param);
  10530. end;
  10531. function TPasToJSConverter.ConvertBuiltIn_Debugger(El: TPasExpr;
  10532. AContext: TConvertContext): TJSElement;
  10533. begin
  10534. Result:=CreateLiteralCustomValue(El,'debugger');
  10535. if AContext=nil then ;
  10536. end;
  10537. function TPasToJSConverter.ConvertRecordValues(El: TRecordValues;
  10538. AContext: TConvertContext): TJSElement;
  10539. var
  10540. ObjLit: TJSObjectLiteral;
  10541. i: Integer;
  10542. RecFields: TRecordValuesItemArray;
  10543. Field: PRecordValuesItem;
  10544. Ref: TResolvedReference;
  10545. Member: TPasVariable;
  10546. NewMemE: TJSNewMemberExpression;
  10547. aResolver: TPas2JSResolver;
  10548. ResolvedEl: TPasResolverResult;
  10549. RecType: TPasRecordType;
  10550. ok: Boolean;
  10551. ObjLitEl: TJSObjectLiteralElement;
  10552. begin
  10553. Result:=nil;
  10554. aResolver:=AContext.Resolver;
  10555. ok:=false;
  10556. try
  10557. if aResolver<>nil then
  10558. begin
  10559. // with resolver: new TRecord({...})
  10560. aResolver.ComputeElement(El,ResolvedEl,[]);
  10561. if (ResolvedEl.BaseType<>btContext)
  10562. or (ResolvedEl.LoTypeEl.ClassType<>TPasRecordType) then
  10563. RaiseNotSupported(El,AContext,20180429210932);
  10564. RecType:=TPasRecordType(ResolvedEl.LoTypeEl);
  10565. NewMemE:=CreateNewRecord(El,RecType,AContext);
  10566. Result:=NewMemE;
  10567. ObjLit:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,El));
  10568. NewMemE.AddArg(ObjLit);
  10569. end
  10570. else
  10571. begin
  10572. // without resolver: {...}
  10573. ObjLit:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,El));
  10574. Result:=ObjLit;;
  10575. end;
  10576. RecFields:=El.Fields;
  10577. for i:=0 to length(RecFields)-1 do
  10578. begin
  10579. Field:=@RecFields[i];
  10580. Ref:=Field^.NameExp.CustomData as TResolvedReference;
  10581. Member:=Ref.Declaration as TPasVariable;
  10582. ObjLitEl:=ObjLit.Elements.AddElement;
  10583. ObjLitEl.Name:=TJSString(TransformVariableName(Member,AContext));
  10584. ObjLitEl.Expr:=CreateValInit(Member.VarType,Field^.ValueExp,Field^.NameExp,AContext);
  10585. end;
  10586. ok:=true;
  10587. finally
  10588. if not ok then
  10589. Result.Free;
  10590. end;
  10591. end;
  10592. function TPasToJSConverter.ConvertArrayValues(El: TArrayValues;
  10593. AContext: TConvertContext): TJSElement;
  10594. Var
  10595. ArrLit : TJSArrayLiteral;
  10596. I : Integer;
  10597. begin
  10598. ArrLit:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,El));
  10599. For I:=0 to Length(El.Values)-1 do
  10600. begin
  10601. ArrLit.AddElement(ConvertElement(El.Values[i],AContext));
  10602. end;
  10603. Result:=ArrLit;
  10604. end;
  10605. function TPasToJSConverter.ConvertExpression(El: TPasExpr;
  10606. AContext: TConvertContext): TJSElement;
  10607. begin
  10608. {$IFDEF VerbosePas2JS}
  10609. writeln('TPasToJSConverter.ConvertExpression El=',GetObjName(El),' Context=',GetObjName(AContext));
  10610. {$ENDIF}
  10611. Result:=Nil;
  10612. if (El.ClassType=TUnaryExpr) then
  10613. Result:=ConvertUnaryExpression(TUnaryExpr(El),AContext)
  10614. else if (El.ClassType=TBinaryExpr) then
  10615. Result:=ConvertBinaryExpression(TBinaryExpr(El),AContext)
  10616. else if (El.ClassType=TPrimitiveExpr) then
  10617. Result:=ConvertPrimitiveExpression(TPrimitiveExpr(El),AContext)
  10618. else if (El.ClassType=TBoolConstExpr) then
  10619. Result:=ConvertBoolConstExpression(TBoolConstExpr(El),AContext)
  10620. else if (El.ClassType=TNilExpr) then
  10621. Result:=ConvertNilExpr(TNilExpr(El),AContext)
  10622. else if (El.ClassType=TInheritedExpr) then
  10623. Result:=ConvertInheritedExpr(TInheritedExpr(El),AContext)
  10624. else if (El.ClassType=TSelfExpr) then
  10625. Result:=ConvertSelfExpression(TSelfExpr(El),AContext)
  10626. else if (El.ClassType=TParamsExpr) then
  10627. Result:=ConvertParamsExpr(TParamsExpr(El),AContext)
  10628. else if (El.ClassType=TProcedureExpr) then
  10629. Result:=ConvertProcedure(TProcedureExpr(El).Proc,AContext)
  10630. else if (El.ClassType=TRecordValues) then
  10631. Result:=ConvertRecordValues(TRecordValues(El),AContext)
  10632. else if (El.ClassType=TArrayValues) then
  10633. Result:=ConvertArrayValues(TArrayValues(El),AContext)
  10634. else
  10635. RaiseNotSupported(El,AContext,20161024191314);
  10636. end;
  10637. function TPasToJSConverter.CreatePrimitiveDotExpr(AName: string;
  10638. Src: TPasElement): TJSElement;
  10639. var
  10640. p: Integer;
  10641. DotExpr: TJSDotMemberExpression;
  10642. Ident: TJSPrimaryExpressionIdent;
  10643. begin
  10644. if AName='' then
  10645. RaiseInconsistency(20170402230134,Src);
  10646. p:=PosLast('.',AName);
  10647. if p>0 then
  10648. begin
  10649. if Src<>nil then
  10650. DotExpr:=TJSDotMemberExpression(CreateElement(TJSDotMemberExpression,Src))
  10651. else
  10652. DotExpr:=TJSDotMemberExpression.Create(0,0);
  10653. DotExpr.Name:=TJSString(copy(AName,p+1,length(AName))); // do not lowercase
  10654. DotExpr.MExpr:=CreatePrimitiveDotExpr(LeftStr(AName,p-1),Src);
  10655. Result:=DotExpr;
  10656. end
  10657. else
  10658. begin
  10659. if Src<>nil then
  10660. Ident:=TJSPrimaryExpressionIdent(CreateElement(TJSPrimaryExpressionIdent,Src))
  10661. else
  10662. Ident:=TJSPrimaryExpressionIdent.Create(0,0);
  10663. Ident.Name:=TJSString(AName); // do not lowercase
  10664. Result:=Ident;
  10665. end;
  10666. end;
  10667. function TPasToJSConverter.CreateTypeDecl(El: TPasType;
  10668. AContext: TConvertContext): TJSElement;
  10669. var
  10670. C: TClass;
  10671. begin
  10672. Result:=Nil;
  10673. C:=El.ClassType;
  10674. if C=TPasClassType then
  10675. Result := ConvertClassType(TPasClassType(El), AContext)
  10676. else if (C=TPasClassOfType) then
  10677. Result := ConvertClassOfType(TPasClassOfType(El), AContext)
  10678. else if C=TPasRecordType then
  10679. Result := ConvertRecordType(TPasRecordType(El), AContext)
  10680. else if C=TPasEnumType then
  10681. Result := ConvertEnumType(TPasEnumType(El), AContext)
  10682. else if (C=TPasSetType) then
  10683. Result := ConvertSetType(TPasSetType(El), AContext)
  10684. else if (C=TPasRangeType) then
  10685. Result:=ConvertRangeType(TPasRangeType(El),AContext)
  10686. else if (C=TPasAliasType) then
  10687. else if (C=TPasTypeAliasType) then
  10688. Result:=ConvertTypeAliasType(TPasTypeAliasType(El),AContext)
  10689. else if (C=TPasPointerType) then
  10690. Result:=ConvertPointerType(TPasPointerType(El),AContext)
  10691. else if (C=TPasProcedureType)
  10692. or (C=TPasFunctionType) then
  10693. Result:=ConvertProcedureType(TPasProcedureType(El),AContext)
  10694. else if (C=TPasArrayType) then
  10695. Result:=ConvertArrayType(TPasArrayType(El),AContext)
  10696. else
  10697. begin
  10698. {$IFDEF VerbosePas2JS}
  10699. writeln('TPasToJSConverter.CreateTypeDecl El=',GetObjName(El));
  10700. {$ENDIF}
  10701. RaiseNotSupported(El,AContext,20170208144053);
  10702. end;
  10703. end;
  10704. function TPasToJSConverter.CreateVarDecl(El: TPasVariable;
  10705. AContext: TConvertContext): TJSElement;
  10706. Var
  10707. C : TJSElement;
  10708. V : TJSVariableStatement;
  10709. AssignSt: TJSSimpleAssignStatement;
  10710. Obj: TJSObjectLiteral;
  10711. ObjLit: TJSObjectLiteralElement;
  10712. begin
  10713. Result:=nil;
  10714. if El.AbsoluteExpr<>nil then
  10715. exit; // absolute: do not add a declaration
  10716. if vmExternal in El.VarModifiers then
  10717. exit; // external: do not add a declaration
  10718. if AContext is TObjectContext then
  10719. begin
  10720. // create 'A: initvalue'
  10721. Obj:=TObjectContext(AContext).JSElement as TJSObjectLiteral;
  10722. ObjLit:=Obj.Elements.AddElement;
  10723. ObjLit.Name:=TJSString(TransformVariableName(El,AContext));
  10724. ObjLit.Expr:=CreateVarInit(El,AContext);
  10725. end
  10726. else if AContext.IsGlobal then
  10727. begin
  10728. // create 'this.A=initvalue'
  10729. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  10730. Result:=AssignSt;
  10731. AssignSt.LHS:=CreateSubDeclNameExpr(El,AContext);
  10732. AssignSt.Expr:=CreateVarInit(El,AContext);
  10733. end
  10734. else
  10735. begin
  10736. // create 'var A=initvalue'
  10737. C:=ConvertVariable(El,AContext);
  10738. if C=nil then
  10739. RaiseInconsistency(20180501114300,El);
  10740. V:=TJSVariableStatement(CreateElement(TJSVariableStatement,El));
  10741. V.A:=C;
  10742. Result:=V;
  10743. end;
  10744. end;
  10745. function TPasToJSConverter.CreateSwitchStatement(El: TPasImplCaseOf;
  10746. AContext: TConvertContext): TJSElement;
  10747. var
  10748. SwitchEl: TJSSwitchStatement;
  10749. JSCaseEl: TJSCaseElement;
  10750. SubEl: TPasImplElement;
  10751. St: TPasImplCaseStatement;
  10752. ok: Boolean;
  10753. i, j: Integer;
  10754. BreakSt: TJSBreakStatement;
  10755. BodySt: TJSElement;
  10756. StList: TJSStatementList;
  10757. Expr: TPasExpr;
  10758. begin
  10759. Result:=nil;
  10760. SwitchEl:=TJSSwitchStatement(CreateElement(TJSSwitchStatement,El));
  10761. ok:=false;
  10762. try
  10763. SwitchEl.Cond:=ConvertExpression(El.CaseExpr,AContext);
  10764. for i:=0 to El.Elements.Count-1 do
  10765. begin
  10766. SubEl:=TPasImplElement(El.Elements[i]);
  10767. if not (SubEl is TPasImplCaseStatement) then
  10768. continue;
  10769. St:=TPasImplCaseStatement(SubEl);
  10770. JSCaseEl:=nil;
  10771. for j:=0 to St.Expressions.Count-1 do
  10772. begin
  10773. Expr:=TPasExpr(St.Expressions[j]);
  10774. JSCaseEl:=SwitchEl.Cases.AddCase;
  10775. JSCaseEl.Expr:=ConvertExpression(Expr,AContext);
  10776. end;
  10777. BodySt:=nil;
  10778. if St.Body<>nil then
  10779. BodySt:=ConvertElement(St.Body,AContext);
  10780. // add break
  10781. BreakSt:=TJSBreakStatement(CreateElement(TJSBreakStatement,St));
  10782. if BodySt=nil then
  10783. // no Pascal statement -> add only one 'break;'
  10784. BodySt:=BreakSt
  10785. else
  10786. begin
  10787. if (BodySt is TJSStatementList) then
  10788. begin
  10789. // list of statements -> append 'break;' to end
  10790. StList:=TJSStatementList(BodySt);
  10791. AddToStatementList(TJSStatementList(BodySt),StList,BreakSt,St);
  10792. end
  10793. else
  10794. begin
  10795. // single statement -> create list of old and 'break;'
  10796. StList:=TJSStatementList(CreateElement(TJSStatementList,St));
  10797. StList.A:=BodySt;
  10798. StList.B:=BreakSt;
  10799. BodySt:=StList;
  10800. end;
  10801. end;
  10802. JSCaseEl.Body:=BodySt;
  10803. end;
  10804. if El.ElseBranch<>nil then
  10805. begin
  10806. JSCaseEl:=SwitchEl.Cases.AddCase;
  10807. JSCaseEl.Body:=ConvertImplBlockElements(El.ElseBranch,AContext,false);
  10808. SwitchEl.TheDefault:=JSCaseEl;
  10809. end;
  10810. ok:=true;
  10811. finally
  10812. if not ok then
  10813. SwitchEl.Free;
  10814. end;
  10815. Result:=SwitchEl;
  10816. end;
  10817. function TPasToJSConverter.ConvertDeclarations(El: TPasDeclarations;
  10818. AContext: TConvertContext): TJSElement;
  10819. Var
  10820. SLFirst, SLLast: TJSStatementList;
  10821. IsProcBody, IsFunction, IsAssembler, HasResult: boolean;
  10822. PasProc: TPasProcedure;
  10823. ProcScope: TPasProcedureScope;
  10824. ProcBody: TPasImplBlock;
  10825. ResultEl: TPasResultElement;
  10826. ResultVarName: String;
  10827. ResStrVarEl: TJSVarDeclaration;
  10828. ResStrVarElAdd: boolean;
  10829. Procedure Add(NewEl: TJSElement; PosEl: TPasElement);
  10830. begin
  10831. if AContext is TObjectContext then
  10832. begin
  10833. // NewEl is already added
  10834. end
  10835. else if AContext.IsGlobal and (AContext.JSElement is TJSSourceElements) then
  10836. AddToSourceElements(TJSSourceElements(AContext.JSElement),NewEl)
  10837. else
  10838. begin
  10839. AddToStatementList(SLFirst,SLLast,NewEl,PosEl);
  10840. ConvertDeclarations:=SLFirst;
  10841. end;
  10842. end;
  10843. Procedure AddFunctionResultInit;
  10844. var
  10845. Proc: TPasProcedure;
  10846. FunType: TPasFunctionType;
  10847. VarSt: TJSVariableStatement;
  10848. SrcEl: TPasElement;
  10849. Scope: TPas2JSProcedureScope;
  10850. begin
  10851. Proc:=El.Parent as TPasProcedure;
  10852. FunType:=Proc.ProcType as TPasFunctionType;
  10853. ResultEl:=FunType.ResultEl;
  10854. Scope:=Proc.CustomData as TPas2JSProcedureScope;
  10855. if Scope.ResultVarName<>'' then
  10856. ResultVarName:=Scope.ResultVarName
  10857. else
  10858. ResultVarName:=ResolverResultVar;
  10859. // add 'var result=initvalue'
  10860. SrcEl:=ResultEl;
  10861. VarSt:=CreateVarStatement(ResultVarName,
  10862. CreateValInit(ResultEl.ResultType,nil,SrcEl,aContext),ResultEl);
  10863. Add(VarSt,ResultEl);
  10864. Result:=SLFirst;
  10865. end;
  10866. Procedure AddFunctionResultReturn;
  10867. var
  10868. RetSt: TJSReturnStatement;
  10869. begin
  10870. RetSt:=TJSReturnStatement(CreateElement(TJSReturnStatement,ResultEl));
  10871. RetSt.Expr:=CreatePrimitiveDotExpr(ResultVarName,ResultEl);
  10872. Add(RetSt,ResultEl);
  10873. end;
  10874. procedure AddResourceString(ResStr: TPasResString);
  10875. // $mod.$resourcestrings = {
  10876. // name1 : { org: "value" },
  10877. // name2 : { org: "value" },
  10878. // ...
  10879. // }
  10880. var
  10881. Value: TResEvalValue;
  10882. ObjLit: TJSObjectLiteral;
  10883. Lit: TJSObjectLiteralElement;
  10884. RootContext: TRootContext;
  10885. begin
  10886. // first convert expression, it might fail
  10887. Value:=AContext.Resolver.Eval(ResStr.Expr,[refConst]);
  10888. //writeln('AddResourceString ',GetObjName(ResStr),' Value=',Value.AsDebugString);
  10889. // create table
  10890. if (ResStrVarEl=nil) and (El.ClassType=TImplementationSection) then
  10891. begin
  10892. RootContext:=TRootContext(AContext.GetContextOfType(TRootContext));
  10893. ResStrVarEl:=RootContext.ResourceStrings;
  10894. end;
  10895. if ResStrVarEl=nil then
  10896. begin
  10897. ResStrVarEl:=TJSVarDeclaration(CreateElement(TJSVarDeclaration,El));
  10898. ResStrVarEl.Name:=FBuiltInNames[pbivnModule]+'.'+FBuiltInNames[pbivnResourceStrings];
  10899. ResStrVarElAdd:=true;
  10900. ObjLit:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,El));
  10901. ResStrVarEl.Init:=ObjLit;
  10902. RootContext:=TRootContext(AContext.GetContextOfType(TRootContext));
  10903. RootContext.ResourceStrings:=ResStrVarEl;
  10904. end;
  10905. // add element: name : { ... }
  10906. Lit:=TJSObjectLiteral(ResStrVarEl.Init).Elements.AddElement;
  10907. Lit.Name:=TJSString(TransformVariableName(ResStr,AContext));
  10908. ObjLit:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,ResStr));
  10909. Lit.Expr:=ObjLit;
  10910. // add sub element: org: value
  10911. Lit:=ObjLit.Elements.AddElement;
  10912. Lit.Name:=TJSString(FBuiltInNames[pbivnResourceStringOrg]);
  10913. Lit.Expr:=ConvertConstValue(Value,AContext,ResStr);
  10914. ReleaseEvalValue(Value);
  10915. end;
  10916. procedure AddResultInterfacRelease(FuncContext: TFunctionContext);
  10917. var
  10918. AssignSt: TJSSimpleAssignStatement;
  10919. IfSt: TJSIfStatement;
  10920. VarSt: TJSVariableStatement;
  10921. Call: TJSCallExpression;
  10922. begin
  10923. AddInterfaceReleases(FuncContext,ProcBody);
  10924. if FuncContext.ResultNeedsIntfRelease then
  10925. begin
  10926. // add in front of try "var $ok=false;"
  10927. VarSt:=CreateVarStatement(FBuiltInNames[pbivnProcOk],CreateLiteralBoolean(ProcBody,false),ProcBody);
  10928. AddInFrontOfFunctionTry(VarSt,ProcBody,FuncContext);
  10929. // add in front of finally "$ok=true;"
  10930. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,ProcBody));
  10931. AddToStatementList(FuncContext.TrySt.Block as TJSStatementList,AssignSt,ProcBody);
  10932. AssignSt.LHS:=CreatePrimitiveDotExpr(FBuiltInNames[pbivnProcOk],ProcBody);
  10933. AssignSt.Expr:=CreateLiteralBoolean(ProcBody,true);
  10934. // add finally: "if(!$ok) rtl._Release(Result);"
  10935. IfSt:=TJSIfStatement(CreateElement(TJSIfStatement,ProcBody));
  10936. AddFunctionFinallySt(IfSt,ProcBody,FuncContext);
  10937. // !$ok
  10938. IfSt.Cond:=CreateUnaryNot(
  10939. CreatePrimitiveDotExpr(FBuiltInNames[pbivnProcOk],ProcBody),ProcBody);
  10940. // rtl._Release(Result)
  10941. Call:=CreateCallExpression(ProcBody);
  10942. IfSt.BTrue:=Call;
  10943. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnIntf_Release]]);
  10944. Call.AddArg(CreatePrimitiveDotExpr(ResultVarName,ProcBody));
  10945. end;
  10946. end;
  10947. var
  10948. E, BodySt: TJSElement;
  10949. I : Integer;
  10950. P: TPasElement;
  10951. C: TClass;
  10952. SectionScope: TPas2JSSectionScope;
  10953. begin
  10954. Result:=nil;
  10955. {
  10956. TPasDeclarations = class(TPasElement)
  10957. TPasSection = class(TPasDeclarations)
  10958. TInterfaceSection = class(TPasSection)
  10959. TImplementationSection = class(TPasSection)
  10960. TProgramSection = class(TImplementationSection)
  10961. TLibrarySection = class(TImplementationSection)
  10962. TProcedureBody = class(TPasDeclarations)
  10963. }
  10964. IsProcBody:=(El is TProcedureBody) and (TProcedureBody(El).Body<>nil);
  10965. IsFunction:=IsProcBody and (El.Parent is TPasProcedure)
  10966. and (TPasProcedure(El.Parent).ProcType is TPasFunctionType);
  10967. IsAssembler:=IsProcBody and (TProcedureBody(El).Body is TPasImplAsmStatement);
  10968. HasResult:=IsFunction and not IsAssembler;
  10969. if (AContext.Resolver<>nil) and (El is TPasSection) then
  10970. begin
  10971. SectionScope:=El.CustomData as TPas2JSSectionScope;
  10972. AContext.ScannerBoolSwitches:=SectionScope.BoolSwitches;
  10973. AContext.ScannerModeSwitches:=SectionScope.ModeSwitches;
  10974. end;
  10975. SLFirst:=nil;
  10976. SLLast:=nil;
  10977. ResultEl:=nil;
  10978. ResultVarName:='';
  10979. ResStrVarEl:=nil;
  10980. ResStrVarElAdd:=false;
  10981. try
  10982. if HasResult then
  10983. AddFunctionResultInit;
  10984. For I:=0 to El.Declarations.Count-1 do
  10985. begin
  10986. P:=TPasElement(El.Declarations[i]);
  10987. {$IFDEF VerbosePas2JS}
  10988. //writeln('TPasToJSConverter.ConvertDeclarations El[',i,']=',GetObjName(P));
  10989. {$ENDIF}
  10990. if not IsElementUsed(P) then continue;
  10991. E:=Nil;
  10992. C:=P.ClassType;
  10993. if C=TPasConst then
  10994. E:=ConvertConst(TPasConst(P),aContext) // can be nil
  10995. else if C=TPasVariable then
  10996. E:=CreateVarDecl(TPasVariable(P),aContext) // can be nil
  10997. else if C.InheritsFrom(TPasType) then
  10998. E:=CreateTypeDecl(TPasType(P),aContext) // can be nil
  10999. else if C.InheritsFrom(TPasProcedure) then
  11000. begin
  11001. PasProc:=TPasProcedure(P);
  11002. if PasProc.IsForward then continue; // JavaScript does not need the forward
  11003. ProcScope:=TPasProcedureScope(PasProc.CustomData);
  11004. if (ProcScope.DeclarationProc<>nil)
  11005. and (not ProcScope.DeclarationProc.IsForward) then
  11006. continue; // this proc was already converted in interface or class
  11007. if ProcScope.DeclarationProc<>nil then
  11008. PasProc:=ProcScope.DeclarationProc;
  11009. E:=ConvertProcedure(PasProc,aContext);
  11010. end
  11011. else if C=TPasResString then
  11012. begin
  11013. if not (El is TPasSection) then
  11014. RaiseNotSupported(P,AContext,20171004185348);
  11015. AddResourceString(TPasResString(P));
  11016. continue;
  11017. end
  11018. else
  11019. RaiseNotSupported(P as TPasElement,AContext,20161024191434);
  11020. Add(E,P);
  11021. end;
  11022. if IsProcBody then
  11023. begin
  11024. ProcBody:=TProcedureBody(El).Body;
  11025. if (ProcBody.Elements.Count>0) or IsAssembler then
  11026. begin
  11027. // convert body (creates a TJSStatementList)
  11028. BodySt:=ConvertElement(ProcBody,aContext);
  11029. if AContext is TFunctionContext then
  11030. begin
  11031. TFunctionContext(AContext).BodySt:=BodySt;
  11032. // if needed add try..finally for COM interfaces
  11033. AddResultInterfacRelease(TFunctionContext(AContext));
  11034. BodySt:=TFunctionContext(AContext).BodySt;
  11035. end;
  11036. Add(BodySt,ProcBody);
  11037. end;
  11038. end;
  11039. if HasResult then
  11040. AddFunctionResultReturn;
  11041. if ResStrVarEl<>nil then
  11042. begin
  11043. if ResStrVarElAdd then
  11044. Add(ResStrVarEl,El);
  11045. ResStrVarEl:=nil;
  11046. end;
  11047. finally
  11048. ResStrVarEl.Free;
  11049. end;
  11050. end;
  11051. function TPasToJSConverter.ConvertClassType(El: TPasClassType;
  11052. AContext: TConvertContext): TJSElement;
  11053. (*
  11054. type
  11055. TMyClass = class(Ancestor)
  11056. i: longint;
  11057. end;
  11058. rtl.createClass(this,"TMyClass",Ancestor,function(){
  11059. this.i = 0;
  11060. });
  11061. *)
  11062. type
  11063. TMemberFunc = (mfInit, mfFinalize);
  11064. const
  11065. MemberFuncName: array[TMemberFunc] of string = (
  11066. '$init',
  11067. '$final'
  11068. );
  11069. var
  11070. IsTObject, AncestorIsExternal: boolean;
  11071. function IsMemberNeeded(aMember: TPasElement): boolean;
  11072. begin
  11073. if IsElementUsed(aMember) then exit(true);
  11074. if IsTObject then
  11075. begin
  11076. if aMember is TPasProcedure then
  11077. begin
  11078. if (CompareText(aMember.Name,'AfterConstruction')=0)
  11079. or (CompareText(aMember.Name,'BeforeDestruction')=0) then
  11080. exit(true);
  11081. end;
  11082. end;
  11083. Result:=false;
  11084. end;
  11085. procedure AddCallAncestorMemberFunction(ClassContext: TConvertContext;
  11086. Ancestor: TPasType; Src: TJSSourceElements; Kind: TMemberFunc);
  11087. var
  11088. Call: TJSCallExpression;
  11089. AncestorPath: String;
  11090. begin
  11091. if (Ancestor=nil) or AncestorIsExternal then
  11092. exit;
  11093. Call:=CreateCallExpression(El);
  11094. AncestorPath:=CreateReferencePath(Ancestor,ClassContext,rpkPathAndName);
  11095. Call.Expr:=CreatePrimitiveDotExpr(AncestorPath+'.'+MemberFuncName[Kind]+'.call',El);
  11096. Call.AddArg(CreatePrimitiveDotExpr('this',El));
  11097. AddToSourceElements(Src,Call);
  11098. end;
  11099. procedure AddInstanceMemberFunction(Src: TJSSourceElements;
  11100. ClassContext: TConvertContext; Ancestor: TPasType; Kind: TMemberFunc);
  11101. // add instance initialization function:
  11102. // this.$init = function(){
  11103. // ancestor.$init();
  11104. // ... init variables ...
  11105. // }
  11106. // or add instance finalization function:
  11107. // this.$final = function(){
  11108. // ... clear references ...
  11109. // ancestor.$final();
  11110. // }
  11111. var
  11112. FuncVD: TJSVarDeclaration;
  11113. New_Src: TJSSourceElements;
  11114. New_FuncContext: TFunctionContext;
  11115. I: Integer;
  11116. P: TPasElement;
  11117. NewEl: TJSElement;
  11118. Func: TJSFunctionDeclarationStatement;
  11119. VarType: TPasType;
  11120. AssignSt: TJSSimpleAssignStatement;
  11121. begin
  11122. // add instance members
  11123. New_Src:=TJSSourceElements(CreateElement(TJSSourceElements, El));
  11124. New_FuncContext:=TFunctionContext.Create(El,New_Src,ClassContext);
  11125. try
  11126. New_FuncContext.ThisPas:=El;
  11127. New_FuncContext.IsGlobal:=true;
  11128. // add class members
  11129. For I:=0 to El.Members.Count-1 do
  11130. begin
  11131. P:=TPasElement(El.Members[i]);
  11132. if not IsMemberNeeded(P) then continue;
  11133. NewEl:=nil;
  11134. if (P.ClassType=TPasVariable)
  11135. and (ClassVarModifiersType*TPasVariable(P).VarModifiers=[]) then
  11136. begin
  11137. if Kind=mfInit then
  11138. // mfInit: init var
  11139. NewEl:=CreateVarDecl(TPasVariable(P),New_FuncContext) // can be nil
  11140. else
  11141. begin
  11142. // mfFinalize: clear reference
  11143. if vmExternal in TPasVariable(P).VarModifiers then continue;
  11144. VarType:=ClassContext.Resolver.ResolveAliasType(TPasVariable(P).VarType);
  11145. if (VarType.ClassType=TPasRecordType)
  11146. or (VarType.ClassType=TPasClassType)
  11147. or (VarType.ClassType=TPasClassOfType)
  11148. or (VarType.ClassType=TPasSetType)
  11149. or (VarType.ClassType=TPasProcedureType)
  11150. or (VarType.ClassType=TPasFunctionType)
  11151. or (VarType.ClassType=TPasArrayType) then
  11152. begin
  11153. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  11154. NewEl:=AssignSt;
  11155. AssignSt.LHS:=CreateSubDeclNameExpr(P,New_FuncContext);
  11156. AssignSt.Expr:=CreateLiteralUndefined(El);
  11157. end;
  11158. end;
  11159. end;
  11160. if NewEl=nil then continue;
  11161. if (Kind=mfInit) and (New_Src.Statements.Count=0) then
  11162. // add call ancestor.$init.call(this)
  11163. AddCallAncestorMemberFunction(ClassContext,Ancestor,New_Src,Kind);
  11164. AddToSourceElements(New_Src,NewEl);
  11165. end;
  11166. if (Kind=mfFinalize) and (New_Src.Statements.Count>0) then
  11167. // call ancestor.$final.call(this)
  11168. AddCallAncestorMemberFunction(ClassContext,Ancestor,New_Src,Kind);
  11169. if (Ancestor<>nil) and (not AncestorIsExternal)
  11170. and (New_Src.Statements.Count=0) then
  11171. exit; // descendent does not need $init/$final
  11172. FuncVD:=TJSVarDeclaration(CreateElement(TJSVarDeclaration,El));
  11173. AddToSourceElements(Src,FuncVD);
  11174. FuncVD.Name:='this.'+MemberFuncName[Kind];
  11175. Func:=CreateFunctionSt(El);
  11176. FuncVD.Init:=Func;
  11177. Func.AFunction.Body.A:=New_Src;
  11178. New_Src:=nil;
  11179. finally
  11180. New_Src.Free;
  11181. New_FuncContext.Free;
  11182. end;
  11183. end;
  11184. procedure AddInterfaceProcNames(Call: TJSCallExpression);
  11185. var
  11186. Arr: TJSArrayLiteral;
  11187. i: Integer;
  11188. Member: TPasElement;
  11189. begin
  11190. Arr:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,El));
  11191. Call.AddArg(Arr);
  11192. for i:=0 to El.Members.Count-1 do
  11193. begin
  11194. Member:=TPasElement(El.Members[i]);
  11195. if not (Member is TPasProcedure) then continue;
  11196. if not IsMemberNeeded(Member) then continue;
  11197. Arr.AddElement(CreateLiteralString(Member,TransformVariableName(Member,AContext)));
  11198. end;
  11199. end;
  11200. procedure AddMapProcs(Map: TPasClassIntfMap; Call: TJSCallExpression;
  11201. var ObjLit: TJSObjectLiteral; FuncContext: TConvertContext);
  11202. var
  11203. i: Integer;
  11204. MapItem: TObject;
  11205. Proc, IntfProc: TPasProcedure;
  11206. ProcName, IntfProcName: String;
  11207. Intf: TPasClassType;
  11208. Lit: TJSObjectLiteralElement;
  11209. begin
  11210. Intf:=Map.Intf;
  11211. if Map.Procs<>nil then
  11212. for i:=0 to Map.Procs.Count-1 do
  11213. begin
  11214. MapItem:=TObject(Map.Procs[i]);
  11215. if not (MapItem is TPasProcedure) then continue;
  11216. Proc:=TPasProcedure(MapItem);
  11217. ProcName:=TransformVariableName(Proc,FuncContext);
  11218. IntfProc:=TObject(Intf.Members[i]) as TPasProcedure;
  11219. IntfProcName:=TransformVariableName(IntfProc,FuncContext);
  11220. if IntfProcName=ProcName then continue;
  11221. if ObjLit=nil then
  11222. begin
  11223. ObjLit:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,El));
  11224. Call.AddArg(ObjLit);
  11225. end;
  11226. Lit:=ObjLit.Elements.AddElement;
  11227. Lit.Name:=TJSString(IntfProcName);
  11228. Lit.Expr:=CreateLiteralString(El,ProcName);
  11229. end;
  11230. if Map.AncestorMap<>nil then
  11231. AddMapProcs(Map.AncestorMap,Call,ObjLit,FuncContext);
  11232. end;
  11233. procedure AddInterfaces(Src: TJSSourceElements; FuncContext: TFunctionContext);
  11234. var
  11235. Call: TJSCallExpression;
  11236. ObjLit: TJSObjectLiteral;
  11237. i: Integer;
  11238. Scope, CurScope: TPas2JSClassScope;
  11239. o: TObject;
  11240. IntfMaps: TJSSimpleAssignStatement;
  11241. MapsObj: TJSObjectLiteral;
  11242. Map: TPasClassIntfMap;
  11243. FinishedGUIDs: TStringList;
  11244. Intf: TPasType;
  11245. CurEl: TPasClassType;
  11246. NeedIntfMap, HasInterfaces: Boolean;
  11247. begin
  11248. HasInterfaces:=false;
  11249. NeedIntfMap:=false;
  11250. Scope:=TPas2JSClassScope(El.CustomData);
  11251. repeat
  11252. if Scope.Interfaces<>nil then
  11253. begin
  11254. for i:=0 to Scope.Interfaces.Count-1 do
  11255. begin
  11256. CurEl:=TPasClassType(Scope.Element);
  11257. if not IsMemberNeeded(TPasElement(CurEl.Interfaces[i])) then continue;
  11258. HasInterfaces:=true;
  11259. o:=TObject(Scope.Interfaces[i]);
  11260. if o is TPasProperty then
  11261. // interface delegation -> needs $intfmaps={}
  11262. NeedIntfMap:=true;
  11263. end;
  11264. end;
  11265. Scope:=TPas2JSClassScope(Scope.AncestorScope);
  11266. until Scope=nil;
  11267. if not HasInterfaces then exit;
  11268. IntfMaps:=nil;
  11269. FinishedGUIDs:=TStringList.Create;
  11270. try
  11271. ObjLit:=nil;
  11272. Scope:=TPas2JSClassScope(El.CustomData);
  11273. repeat
  11274. if Scope.Interfaces<>nil then
  11275. begin
  11276. for i:=0 to Scope.Interfaces.Count-1 do
  11277. begin
  11278. CurEl:=TPasClassType(Scope.Element);
  11279. if not IsMemberNeeded(TPasElement(CurEl.Interfaces[i])) then continue;
  11280. if NeedIntfMap then
  11281. begin
  11282. // add "this.$intfmaps = {};"
  11283. IntfMaps:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  11284. AddToSourceElements(Src,IntfMaps);
  11285. IntfMaps.LHS:=CreatePrimitiveDotExpr('this.'+FBuiltInNames[pbivnIntfMaps],El);
  11286. MapsObj:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,El));
  11287. IntfMaps.Expr:=MapsObj;
  11288. NeedIntfMap:=false;
  11289. end;
  11290. o:=TObject(Scope.Interfaces[i]);
  11291. if o is TPasClassIntfMap then
  11292. begin
  11293. // add rtl.addIntf(this,intftype,{ intfprocname: "procname", ...});
  11294. Map:=TPasClassIntfMap(o);
  11295. Intf:=Map.Intf;
  11296. CurScope:=TPas2JSClassScope(Intf.CustomData);
  11297. if FinishedGUIDs.IndexOf(CurScope.GUID)>=0 then continue;
  11298. FinishedGUIDs.Add(CurScope.GUID);
  11299. Call:=CreateCallExpression(El);
  11300. AddToSourceElements(Src,Call);
  11301. Call.Expr:=CreatePrimitiveDotExpr(FBuiltInNames[pbivnRTL]+'.'+FBuiltInNames[pbifnIntfAddMap],El);
  11302. Call.AddArg(CreatePrimitiveDotExpr('this',El));
  11303. Call.AddArg(CreateReferencePathExpr(Map.Intf,FuncContext));
  11304. AddMapProcs(Map,Call,ObjLit,FuncContext);
  11305. end
  11306. else if o is TPasProperty then
  11307. AddIntfDelegations(El,TPasProperty(o),FinishedGUIDs,MapsObj,FuncContext)
  11308. else
  11309. RaiseNotSupported(El,FuncContext,20180326234026,GetObjName(o));
  11310. end;
  11311. end;
  11312. Scope:=TPas2JSClassScope(Scope.AncestorScope);
  11313. until Scope=nil;
  11314. finally
  11315. FinishedGUIDs.Free;
  11316. end;
  11317. end;
  11318. procedure AddRTTI(Src: TJSSourceElements; FuncContext: TFunctionContext);
  11319. var
  11320. HasRTTIMembers: Boolean;
  11321. i: Integer;
  11322. P: TPasElement;
  11323. NewEl: TJSElement;
  11324. VarSt: TJSVariableStatement;
  11325. C: TClass;
  11326. begin
  11327. // add $r to local vars, to avoid name clashes and for nicer debugging
  11328. FuncContext.AddLocalVar(FBuiltInNames[pbivnRTTILocal],nil);
  11329. HasRTTIMembers:=false;
  11330. For i:=0 to El.Members.Count-1 do
  11331. begin
  11332. P:=TPasElement(El.Members[i]);
  11333. //writeln('TPasToJSConverter.ConvertClassType RTTI El[',i,']=',GetObjName(P));
  11334. if (El.ObjKind=okClass) and (P.Visibility<>visPublished) then
  11335. continue;
  11336. if not IsMemberNeeded(P) then continue;
  11337. NewEl:=nil;
  11338. C:=P.ClassType;
  11339. if C=TPasVariable then
  11340. NewEl:=CreateRTTIClassField(TPasVariable(P),FuncContext)
  11341. else if C.InheritsFrom(TPasProcedure) then
  11342. NewEl:=CreateRTTIClassMethod(TPasProcedure(P),FuncContext)
  11343. else if C=TPasProperty then
  11344. NewEl:=CreateRTTIClassProperty(TPasProperty(P),FuncContext)
  11345. else if C.InheritsFrom(TPasType) then
  11346. continue
  11347. else if C=TPasMethodResolution then
  11348. continue
  11349. else
  11350. DoError(20170409202315,nSymbolCannotBePublished,sSymbolCannotBePublished,[],P);
  11351. if NewEl=nil then
  11352. continue; // e.g. abstract or external proc
  11353. // add RTTI element
  11354. if not HasRTTIMembers then
  11355. begin
  11356. // add "var $r = this.$rtti"
  11357. VarSt:=CreateVarStatement(FBuiltInNames[pbivnRTTILocal],
  11358. CreateMemberExpression(['this',FBuiltInNames[pbivnRTTI]]),El);
  11359. AddToSourceElements(Src,VarSt);
  11360. HasRTTIMembers:=true;
  11361. end;
  11362. AddToSourceElements(Src,NewEl);
  11363. end;
  11364. end;
  11365. var
  11366. Call: TJSCallExpression;
  11367. FunDecl: TJSFunctionDeclarationStatement;
  11368. Src: TJSSourceElements;
  11369. ArgEx: TJSLiteral;
  11370. FuncContext: TFunctionContext;
  11371. i: Integer;
  11372. NewEl: TJSElement;
  11373. P: TPasElement;
  11374. Scope: TPas2JSClassScope;
  11375. Ancestor: TPasType;
  11376. AncestorPath, OwnerName, DestructorName, FnName, IntfKind: String;
  11377. C: TClass;
  11378. AssignSt: TJSSimpleAssignStatement;
  11379. NeedInitFunction: Boolean;
  11380. begin
  11381. Result:=nil;
  11382. {$IFDEF VerbosePas2JS}
  11383. writeln('TPasToJSConverter.ConvertClassType START ',GetObjName(El));
  11384. {$ENDIF}
  11385. if not (El.ObjKind in [okClass,okInterface]) then
  11386. RaiseNotSupported(El,AContext,20170927183645);
  11387. if El.IsForward then
  11388. begin
  11389. Result:=ConvertClassForwardType(El,AContext);
  11390. exit;
  11391. end;
  11392. if El.IsExternal then exit;
  11393. if El.CustomData is TPas2JSClassScope then
  11394. begin
  11395. Scope:=TPas2JSClassScope(El.CustomData);
  11396. if Scope.AncestorScope<>nil then
  11397. Ancestor:=Scope.AncestorScope.Element as TPasType
  11398. else
  11399. begin
  11400. Ancestor:=nil;
  11401. IsTObject:=(El.ObjKind=okClass) and SameText(El.Name,'TObject');
  11402. end;
  11403. end
  11404. else
  11405. begin
  11406. Scope:=nil;
  11407. IsTObject:=(El.AncestorType=nil) and (El.ObjKind=okClass) and SameText(El.Name,'TObject');
  11408. Ancestor:=El.AncestorType;
  11409. end;
  11410. // create call 'rtl.createClass(' or 'rtl.createInterface('
  11411. FuncContext:=nil;
  11412. Call:=CreateCallExpression(El);
  11413. try
  11414. AncestorIsExternal:=(Ancestor is TPasClassType) and TPasClassType(Ancestor).IsExternal;
  11415. if El.ObjKind=okInterface then
  11416. FnName:=FBuiltInNames[pbifnIntfCreate]
  11417. else if AncestorIsExternal then
  11418. FnName:=FBuiltInNames[pbifnCreateClassExt]
  11419. else
  11420. FnName:=FBuiltInNames[pbifnCreateClass];
  11421. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FnName]);
  11422. // add parameter: owner. For top level class, the module is the owner.
  11423. if (El.Parent=nil)
  11424. or ((El.Parent is TPasSection)
  11425. and (El.Parent.ClassType<>TImplementationSection)) then
  11426. OwnerName:=AContext.GetLocalName(El.GetModule)
  11427. else
  11428. OwnerName:=AContext.GetLocalName(El.Parent);
  11429. if OwnerName='' then
  11430. OwnerName:='this';
  11431. Call.AddArg(CreatePrimitiveDotExpr(OwnerName,El));
  11432. // add parameter: string constant '"classname"'
  11433. ArgEx := CreateLiteralString(El,TransformVariableName(El,AContext));
  11434. Call.AddArg(ArgEx);
  11435. if El.ObjKind=okInterface then
  11436. begin
  11437. // add parameter: string constant guid
  11438. Call.AddArg(CreateLiteralString(El,uppercase(Scope.GUID)));
  11439. // add parameter: array of function names
  11440. AddInterfaceProcNames(Call);
  11441. end;
  11442. // add parameter: ancestor
  11443. if Ancestor=nil then
  11444. AncestorPath:='null'
  11445. else if AncestorIsExternal then
  11446. AncestorPath:=TPasClassType(Ancestor).ExternalName
  11447. else
  11448. AncestorPath:=CreateReferencePath(Ancestor,AContext,rpkPathAndName);
  11449. Call.AddArg(CreatePrimitiveDotExpr(AncestorPath,El));
  11450. if AncestorIsExternal and (El.ObjKind=okClass) then
  11451. begin
  11452. // add the name of the NewInstance function
  11453. if Scope.NewInstanceFunction<>nil then
  11454. Call.AddArg(CreateLiteralString(
  11455. Scope.NewInstanceFunction,Scope.NewInstanceFunction.Name))
  11456. else
  11457. Call.AddArg(CreateLiteralString(El,''));
  11458. end;
  11459. NeedInitFunction:=true;
  11460. IntfKind:='';
  11461. if El.ObjKind=okInterface then
  11462. begin
  11463. if (Scope.AncestorScope=nil) and (not (coNoTypeInfo in Options)) then
  11464. case El.InterfaceType of
  11465. citCom: IntfKind:='com';
  11466. citCorba: ; // default
  11467. else
  11468. RaiseNotSupported(El,AContext,20180405093512);
  11469. end;
  11470. NeedInitFunction:=(pcsfPublished in Scope.Flags) or HasTypeInfo(El,AContext)
  11471. or (IntfKind<>'');
  11472. end;
  11473. if NeedInitFunction then
  11474. begin
  11475. // add parameter: class initialize function 'function(){...}'
  11476. FunDecl:=CreateFunctionSt(El,true,true);
  11477. Call.AddArg(FunDecl);
  11478. Src:=TJSSourceElements(FunDecl.AFunction.Body.A);
  11479. // create context
  11480. FuncContext:=TFunctionContext.Create(El,Src,AContext);
  11481. FuncContext.IsGlobal:=true;
  11482. FuncContext.ThisPas:=El;
  11483. if IntfKind<>'' then
  11484. begin
  11485. // add this.$kind="com";
  11486. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  11487. AssignSt.LHS:=CreatePrimitiveDotExpr('this.'+FBuiltInNames[pbivnIntfKind],El);
  11488. AssignSt.Expr:=CreateLiteralString(El,IntfKind);
  11489. AddToSourceElements(Src,AssignSt);
  11490. end;
  11491. // add class members: types and class vars
  11492. if El.ObjKind in [okClass] then
  11493. begin
  11494. For i:=0 to El.Members.Count-1 do
  11495. begin
  11496. P:=TPasElement(El.Members[i]);
  11497. //writeln('TPasToJSConverter.ConvertClassType class vars El[',i,']=',GetObjName(P));
  11498. if not IsMemberNeeded(P) then continue;
  11499. C:=P.ClassType;
  11500. NewEl:=nil;
  11501. if C=TPasVariable then
  11502. begin
  11503. if ClassVarModifiersType*TPasVariable(P).VarModifiers<>[] then
  11504. begin
  11505. NewEl:=CreateVarDecl(TPasVariable(P),FuncContext); // can be nil
  11506. if NewEl=nil then continue;
  11507. end
  11508. else
  11509. continue;
  11510. end
  11511. else if C=TPasConst then
  11512. NewEl:=ConvertConst(TPasConst(P),aContext)
  11513. else if C=TPasProperty then
  11514. NewEl:=ConvertProperty(TPasProperty(P),AContext)
  11515. else if C.InheritsFrom(TPasType) then
  11516. NewEl:=CreateTypeDecl(TPasType(P),aContext)
  11517. else if C.InheritsFrom(TPasProcedure) then
  11518. continue
  11519. else if C=TPasMethodResolution then
  11520. continue
  11521. else
  11522. RaiseNotSupported(P,FuncContext,20161221233338);
  11523. if NewEl<>nil then
  11524. AddToSourceElements(Src,NewEl);
  11525. end;
  11526. end;
  11527. if El.ObjKind in [okClass] then
  11528. begin
  11529. // instance initialization function
  11530. AddInstanceMemberFunction(Src,FuncContext,Ancestor,mfInit);
  11531. // instance finalization function
  11532. AddInstanceMemberFunction(Src,FuncContext,Ancestor,mfFinalize);
  11533. end;
  11534. if El.ObjKind in [okClass] then
  11535. begin
  11536. // add method implementations
  11537. For i:=0 to El.Members.Count-1 do
  11538. begin
  11539. P:=TPasElement(El.Members[i]);
  11540. //writeln('TPasToJSConverter.ConvertClassType methods El[',i,']=',GetObjName(P));
  11541. if not IsMemberNeeded(P) then continue;
  11542. if P is TPasProcedure then
  11543. begin
  11544. if IsTObject and (P.ClassType=TPasDestructor) then
  11545. begin
  11546. DestructorName:=TransformVariableName(P,AContext);
  11547. if DestructorName<>'Destroy' then
  11548. begin
  11549. // add 'rtl.tObjectDestroy="destroy";'
  11550. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,P));
  11551. AssignSt.LHS:=CreateMemberExpression([GetBuildInNames(pbivnRTL),GetBuildInNames(pbivnTObjectDestroy)]);
  11552. AssignSt.Expr:=CreateLiteralString(P,DestructorName);
  11553. AddToSourceElements(Src,AssignSt);
  11554. end;
  11555. end;
  11556. NewEl:=ConvertProcedure(TPasProcedure(P),FuncContext);
  11557. end
  11558. else
  11559. continue;
  11560. if NewEl=nil then
  11561. continue; // e.g. abstract or external proc
  11562. AddToSourceElements(Src,NewEl);
  11563. end;
  11564. end;
  11565. // add interfaces
  11566. if (El.ObjKind=okClass) and (AContext.Resolver<>nil) then
  11567. AddInterfaces(Src,FuncContext);
  11568. // add RTTI init function
  11569. if AContext.Resolver<>nil then
  11570. AddRTTI(Src,FuncContext);
  11571. end;// end of init function
  11572. Result:=Call;
  11573. finally
  11574. FuncContext.Free;
  11575. if Result<>Call then
  11576. Call.Free;
  11577. end;
  11578. end;
  11579. function TPasToJSConverter.ConvertClassForwardType(El: TPasClassType;
  11580. AContext: TConvertContext): TJSElement;
  11581. // module.$rtti.$Class("classname");
  11582. var
  11583. Ref: TResolvedReference;
  11584. aClass: TPasClassType;
  11585. ObjLit: TJSObjectLiteral;
  11586. Creator: String;
  11587. begin
  11588. Result:=nil;
  11589. if (AContext.Resolver=nil) or not (El.CustomData is TResolvedReference) then exit;
  11590. Ref:=TResolvedReference(El.CustomData);
  11591. aClass:=Ref.Declaration as TPasClassType;
  11592. if not HasTypeInfo(aClass,AContext) then exit;
  11593. if IsClassRTTICreatedBefore(aClass,El,AContext) then exit;
  11594. // module.$rtti.$Class("classname");
  11595. case aClass.ObjKind of
  11596. okClass: Creator:=FBuiltInNames[pbifnRTTINewClass];
  11597. okInterface: Creator:=FBuiltInNames[pbifnRTTINewInterface];
  11598. end;
  11599. Result:=CreateRTTINewType(aClass,Creator,true,AContext,ObjLit);
  11600. if ObjLit<>nil then
  11601. RaiseInconsistency(20170412093427,El);
  11602. end;
  11603. function TPasToJSConverter.ConvertClassExternalType(El: TPasClassType;
  11604. AContext: TConvertContext): TJSElement;
  11605. function IsMemberNeeded(aMember: TPasElement): boolean;
  11606. begin
  11607. Result:=IsElementUsed(aMember);
  11608. end;
  11609. var
  11610. i: Integer;
  11611. P: TPasElement;
  11612. C: TClass;
  11613. Proc: TPasProcedure;
  11614. begin
  11615. Result:=nil;
  11616. if El.IsForward then exit;
  11617. // add class members: types and class vars
  11618. For i:=0 to El.Members.Count-1 do
  11619. begin
  11620. P:=TPasElement(El.Members[i]);
  11621. //writeln('TPasToJSConverter.ConvertClassExternalType class El[',i,']=',GetObjName(P));
  11622. if not IsMemberNeeded(P) then continue;
  11623. C:=P.ClassType;
  11624. if (C=TPasVariable) or (C=TPasConst) then
  11625. begin
  11626. if not (vmExternal in TPasVariable(P).VarModifiers) then
  11627. DoError(20170321150737,nMissingExternalName,sMissingExternalName,[],P);
  11628. end
  11629. else if C=TPasProperty then
  11630. // is replaced with Getter/Setter -> nothing to do here
  11631. else if C.InheritsFrom(TPasProcedure) then
  11632. begin
  11633. Proc:=TPasProcedure(P);
  11634. if Proc.IsExternal then
  11635. // external, nothing to do here
  11636. else
  11637. DoError(20170321152209,nMissingExternalName,sMissingExternalName,[],P);
  11638. end
  11639. else
  11640. RaiseNotSupported(P,AContext,20170321151727);
  11641. end;
  11642. end;
  11643. function TPasToJSConverter.ConvertClassOfType(El: TPasClassOfType;
  11644. AContext: TConvertContext): TJSElement;
  11645. // create
  11646. // module.$rtti.$ClassRef("typename",{
  11647. // instancetype: module.$rtti["classname"])
  11648. // }
  11649. // if class is defined later add a forward define for the class
  11650. var
  11651. ObjLit: TJSObjectLiteral;
  11652. Prop: TJSObjectLiteralElement;
  11653. Call: TJSCallExpression;
  11654. ok: Boolean;
  11655. List: TJSStatementList;
  11656. DestType: TPasType;
  11657. begin
  11658. Result:=nil;
  11659. if not HasTypeInfo(El,AContext) then exit;
  11660. ok:=false;
  11661. Call:=CreateRTTINewType(El,FBuiltInNames[pbifnRTTINewClassRef],false,AContext,ObjLit);
  11662. Result:=Call;
  11663. try
  11664. Prop:=ObjLit.Elements.AddElement;
  11665. Prop.Name:=TJSString(FBuiltInNames[pbivnRTTIClassRef_InstanceType]);
  11666. DestType:=AContext.Resolver.ResolveAliasType(El.DestType);
  11667. Prop.Expr:=CreateTypeInfoRef(DestType,AContext,El);
  11668. if not IsClassRTTICreatedBefore(DestType as TPasClassType,El,AContext) then
  11669. begin
  11670. // class rtti must be forward registered
  11671. if not (AContext is TFunctionContext) then
  11672. RaiseNotSupported(El,AContext,20170412102916);
  11673. // prepend module.$rtti.$Class("classname");
  11674. Call:=CreateRTTINewType(DestType,FBuiltInNames[pbifnRTTINewClass],true,AContext,ObjLit);
  11675. if ObjLit<>nil then
  11676. RaiseInconsistency(20170412102654,El);
  11677. List:=TJSStatementList(CreateElement(TJSStatementList,El));
  11678. List.A:=Call;
  11679. List.B:=Result;
  11680. Result:=List;
  11681. end;
  11682. ok:=true;
  11683. finally
  11684. if not ok then
  11685. FreeAndNil(Result);
  11686. end;
  11687. end;
  11688. function TPasToJSConverter.ConvertEnumType(El: TPasEnumType;
  11689. AContext: TConvertContext): TJSElement;
  11690. // TMyEnum = (red, green)
  11691. // convert to
  11692. // this.TMyEnum = {
  11693. // "0":"red",
  11694. // "red":0,
  11695. // "0":"green",
  11696. // "green":0,
  11697. // };
  11698. // module.$rtti.$TIEnum("TMyEnum",{
  11699. // enumtype: this.TMyEnum,
  11700. // minvalue: 0,
  11701. // maxvalue: 1
  11702. // });
  11703. var
  11704. ObjectContect: TObjectContext;
  11705. i: Integer;
  11706. EnumValue: TPasEnumValue;
  11707. ParentObj, Obj, TIObj: TJSObjectLiteral;
  11708. ObjLit, TIProp: TJSObjectLiteralElement;
  11709. AssignSt: TJSSimpleAssignStatement;
  11710. JSName: TJSString;
  11711. Call: TJSCallExpression;
  11712. List: TJSStatementList;
  11713. ok: Boolean;
  11714. OrdType: TOrdType;
  11715. begin
  11716. Result:=nil;
  11717. for i:=0 to El.Values.Count-1 do
  11718. begin
  11719. EnumValue:=TPasEnumValue(El.Values[i]);
  11720. if EnumValue.Value<>nil then
  11721. RaiseNotSupported(EnumValue.Value,AContext,20170208145221,'enum constant');
  11722. end;
  11723. ok:=false;
  11724. ObjectContect:=nil;
  11725. try
  11726. Obj:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,El));
  11727. if AContext is TObjectContext then
  11728. begin
  11729. // add 'TypeName: {}'
  11730. ParentObj:=TObjectContext(AContext).JSElement as TJSObjectLiteral;
  11731. ObjLit:=ParentObj.Elements.AddElement;
  11732. ObjLit.Name:=TJSString(TransformVariableName(El,AContext));
  11733. ObjLit.Expr:=Obj;
  11734. Result:=Obj;
  11735. end
  11736. else if El.Parent is TProcedureBody then
  11737. begin
  11738. // add 'var TypeName = {}'
  11739. Result:=CreateVarStatement(TransformVariableName(El,AContext),Obj,El);
  11740. end
  11741. else
  11742. begin
  11743. // add 'this.TypeName = {}'
  11744. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  11745. AssignSt.LHS:=CreateSubDeclNameExpr(El,AContext);
  11746. AssignSt.Expr:=Obj;
  11747. Result:=AssignSt;
  11748. end;
  11749. ObjectContect:=TObjectContext.Create(El,Obj,AContext);
  11750. for i:=0 to El.Values.Count-1 do
  11751. begin
  11752. EnumValue:=TPasEnumValue(El.Values[i]);
  11753. JSName:=TJSString(TransformVariableName(EnumValue,AContext));
  11754. // add "0":"value"
  11755. ObjLit:=Obj.Elements.AddElement;
  11756. ObjLit.Name:=TJSString(IntToStr(i));
  11757. ObjLit.Expr:=CreateLiteralJSString(El,JSName);
  11758. // add value:0
  11759. ObjLit:=Obj.Elements.AddElement;
  11760. ObjLit.Name:=JSName;
  11761. ObjLit.Expr:=CreateLiteralNumber(El,i);
  11762. end;
  11763. if HasTypeInfo(El,AContext) then
  11764. begin
  11765. // create typeinfo
  11766. if not (AContext is TFunctionContext) then
  11767. RaiseNotSupported(El,AContext,20170411210045,'typeinfo');
  11768. // create statement list
  11769. List:=TJSStatementList(CreateElement(TJSStatementList,El));
  11770. List.A:=Result;
  11771. Result:=List;
  11772. OrdType:=GetOrdType(0,El.Values.Count-1,El);
  11773. // module.$rtti.$TIEnum("TMyEnum",{...});
  11774. Call:=CreateRTTINewType(El,FBuiltInNames[pbifnRTTINewEnum],false,AContext,TIObj);
  11775. List.B:=Call;
  11776. // add minvalue: number
  11777. TIProp:=TIObj.Elements.AddElement;
  11778. TIProp.Name:=TJSString(FBuiltInNames[pbivnRTTIInt_MinValue]);
  11779. TIProp.Expr:=CreateLiteralNumber(El,0);
  11780. // add maxvalue: number
  11781. TIProp:=TIObj.Elements.AddElement;
  11782. TIProp.Name:=TJSString(FBuiltInNames[pbivnRTTIInt_MaxValue]);
  11783. TIProp.Expr:=CreateLiteralNumber(El,El.Values.Count-1);
  11784. // add ordtype: number
  11785. TIProp:=TIObj.Elements.AddElement;
  11786. TIProp.Name:=TJSString(FBuiltInNames[pbivnRTTIInt_OrdType]);
  11787. TIProp.Expr:=CreateLiteralNumber(El,ord(OrdType));
  11788. // add enumtype: this.TypeName
  11789. TIProp:=TIObj.Elements.AddElement;
  11790. TIProp.Name:=TJSString(FBuiltInNames[pbivnRTTIEnum_EnumType]);
  11791. TIProp.Expr:=CreateSubDeclNameExpr(El,AContext);
  11792. end;
  11793. ok:=true;
  11794. finally
  11795. ObjectContect.Free;
  11796. if not ok then
  11797. FreeAndNil(Result);
  11798. end;
  11799. end;
  11800. function TPasToJSConverter.ConvertSetType(El: TPasSetType;
  11801. AContext: TConvertContext): TJSElement;
  11802. // create
  11803. // module.$rtti.$Set("name",{
  11804. // comptype: module.$rtti["enumtype"]
  11805. // })
  11806. var
  11807. Obj: TJSObjectLiteral;
  11808. Call: TJSCallExpression;
  11809. Prop: TJSObjectLiteralElement;
  11810. begin
  11811. Result:=nil;
  11812. if El.IsPacked then
  11813. DoError(20170222231613,nPasElementNotSupported,sPasElementNotSupported,
  11814. ['packed'],El);
  11815. if not HasTypeInfo(El,AContext) then exit;
  11816. // module.$rtti.$Set("name",{...})
  11817. Call:=CreateRTTINewType(El,FBuiltInNames[pbifnRTTINewSet],false,AContext,Obj);
  11818. try
  11819. // "comptype: ref"
  11820. Prop:=Obj.Elements.AddElement;
  11821. Prop.Name:=TJSString(FBuiltInNames[pbivnRTTISet_CompType]);
  11822. Prop.Expr:=CreateTypeInfoRef(El.EnumType,AContext,El);
  11823. Result:=Call;
  11824. finally
  11825. if Result=nil then
  11826. Call.Free;
  11827. end;
  11828. end;
  11829. function TPasToJSConverter.ConvertRangeType(El: TPasRangeType;
  11830. AContext: TConvertContext): TJSElement;
  11831. // create
  11832. // module.$rtti.$Int("name",{
  11833. // minvalue: <number>,
  11834. // maxvalue: <number>,
  11835. // ordtype: <number>
  11836. // })
  11837. var
  11838. TIObj: TJSObjectLiteral;
  11839. Call: TJSCallExpression;
  11840. MinVal, MaxVal: TResEvalValue;
  11841. MinInt, MaxInt: TMaxPrecInt;
  11842. OrdType: TOrdType;
  11843. TIProp: TJSObjectLiteralElement;
  11844. fn: TPas2JSBuiltInName;
  11845. begin
  11846. Result:=nil;
  11847. if not HasTypeInfo(El,AContext) then exit;
  11848. // module.$rtti.$Int("name",{...})
  11849. MinVal:=nil;
  11850. MaxVal:=nil;
  11851. Call:=nil;
  11852. try
  11853. MinVal:=AContext.Resolver.EvalRangeLimit(El.RangeExpr,[refConst],true,El);
  11854. MaxVal:=AContext.Resolver.EvalRangeLimit(El.RangeExpr,[refConst],false,El);
  11855. if MinVal.Kind=revkInt then
  11856. begin
  11857. fn:=pbifnRTTINewInt;
  11858. MinInt:=TResEvalInt(MinVal).Int;
  11859. MaxInt:=TResEvalInt(MaxVal).Int;
  11860. end
  11861. else if MinVal.Kind=revkEnum then
  11862. begin
  11863. fn:=pbifnRTTINewEnum;
  11864. MinInt:=TResEvalEnum(MinVal).Index;
  11865. MaxInt:=TResEvalEnum(MaxVal).Index;
  11866. end
  11867. else
  11868. begin
  11869. {$IFDEF VerbosePas2JS}
  11870. writeln('TPasToJSConverter.ConvertRangeType type: ',MinVal.AsDebugString,'..',MaxVal.AsDebugString);
  11871. {$ENDIF}
  11872. RaiseNotSupported(El,AContext,20170925201628);
  11873. end;
  11874. OrdType:=GetOrdType(MinInt,MaxInt,El);
  11875. Call:=CreateRTTINewType(El,FBuiltInNames[fn],false,AContext,TIObj);
  11876. // add minvalue: number
  11877. TIProp:=TIObj.Elements.AddElement;
  11878. TIProp.Name:=TJSString(FBuiltInNames[pbivnRTTIInt_MinValue]);
  11879. TIProp.Expr:=CreateLiteralNumber(El,MinInt);
  11880. // add maxvalue: number
  11881. TIProp:=TIObj.Elements.AddElement;
  11882. TIProp.Name:=TJSString(FBuiltInNames[pbivnRTTIInt_MaxValue]);
  11883. TIProp.Expr:=CreateLiteralNumber(El,MaxInt);
  11884. // add ordtype: number
  11885. TIProp:=TIObj.Elements.AddElement;
  11886. TIProp.Name:=TJSString(FBuiltInNames[pbivnRTTIInt_OrdType]);
  11887. TIProp.Expr:=CreateLiteralNumber(El,ord(OrdType));
  11888. if MinVal.Kind=revkEnum then
  11889. begin
  11890. // add enumtype: this.TypeName
  11891. TIProp:=TIObj.Elements.AddElement;
  11892. TIProp.Name:=TJSString(FBuiltInNames[pbivnRTTIEnum_EnumType]);
  11893. TIProp.Expr:=CreateSubDeclNameExpr(El,TResEvalEnum(MinVal).ElType.Name,AContext);
  11894. end;
  11895. Result:=Call;
  11896. finally
  11897. ReleaseEvalValue(MinVal);
  11898. ReleaseEvalValue(MaxVal);
  11899. if Result=nil then
  11900. Call.Free;
  11901. end;
  11902. end;
  11903. function TPasToJSConverter.ConvertTypeAliasType(El: TPasTypeAliasType;
  11904. AContext: TConvertContext): TJSElement;
  11905. // create
  11906. // module.$rtti.$inherited(name,desttype,{});
  11907. var
  11908. Obj: TJSObjectLiteral;
  11909. begin
  11910. Result:=nil;
  11911. if not HasTypeInfo(El,AContext) then exit;
  11912. Result:=CreateRTTINewType(El,FBuiltInNames[pbifnRTTIInherited],false,AContext,Obj);
  11913. end;
  11914. function TPasToJSConverter.ConvertPointerType(El: TPasPointerType;
  11915. AContext: TConvertContext): TJSElement;
  11916. // create
  11917. // module.$rtti.$Pointer("name",{
  11918. // reftype: module.$rtti["reftype"]
  11919. // })
  11920. var
  11921. Obj: TJSObjectLiteral;
  11922. Call: TJSCallExpression;
  11923. Prop: TJSObjectLiteralElement;
  11924. begin
  11925. Result:=nil;
  11926. if not HasTypeInfo(El,AContext) then exit;
  11927. // module.$rtti.$Pointer("name",{...})
  11928. Call:=CreateRTTINewType(El,FBuiltInNames[pbifnRTTIInherited],false,AContext,Obj);
  11929. try
  11930. // "comptype: ref"
  11931. Prop:=Obj.Elements.AddElement;
  11932. Prop.Name:=TJSString(FBuiltInNames[pbivnRTTISet_CompType]);
  11933. Prop.Expr:=CreateTypeInfoRef(El.DestType,AContext,El);
  11934. Result:=Call;
  11935. finally
  11936. if Result=nil then
  11937. Call.Free;
  11938. end;
  11939. end;
  11940. function TPasToJSConverter.ConvertProcedureType(El: TPasProcedureType;
  11941. AContext: TConvertContext): TJSElement;
  11942. // create
  11943. // module.$rtti.$ProcVar("name",{
  11944. // procsig: rtl.newTIProcSignature([[arg1name,arg1type,arg1flags],[arg2name...],...],resulttype,flags)
  11945. // })
  11946. // module.$rtti.$MethodVar("name",{
  11947. // procsig: rtl.newTIProcSignature([[arg1name,arg1type,arg1flags],[arg2name...],...],resulttype,flags),
  11948. // methodkind: 1
  11949. // })
  11950. var
  11951. Call, InnerCall: TJSCallExpression;
  11952. FunName: String;
  11953. ResultEl: TPasResultElement;
  11954. ResultTypeInfo: TJSElement;
  11955. Flags: Integer;
  11956. MethodKind: TMethodKind;
  11957. Obj: TJSObjectLiteral;
  11958. Prop: TJSObjectLiteralElement;
  11959. begin
  11960. Result:=nil;
  11961. if El.IsNested then
  11962. DoError(20170222231636,nPasElementNotSupported,sPasElementNotSupported,
  11963. ['is nested'],El);
  11964. if El.CallingConvention<>ccDefault then
  11965. DoError(20170222231532,nPasElementNotSupported,sPasElementNotSupported,
  11966. ['calling convention '+cCallingConventions[El.CallingConvention]],El);
  11967. if not HasTypeInfo(El,AContext) then exit;
  11968. // module.$rtti.$ProcVar("name",function(){})
  11969. if El.IsReferenceTo then
  11970. FunName:=FBuiltInNames[pbifnRTTINewRefToProcVar]
  11971. else if El.IsOfObject then
  11972. FunName:=FBuiltInNames[pbifnRTTINewMethodVar]
  11973. else
  11974. FunName:=FBuiltInNames[pbifnRTTINewProcVar];
  11975. Call:=CreateRTTINewType(El,FunName,false,AContext,Obj);
  11976. try
  11977. // add "procsig: rtl.newTIProcSignature()"
  11978. Prop:=Obj.Elements.AddElement;
  11979. Prop.Name:=TJSString(FBuiltInNames[pbivnRTTIProcVar_ProcSig]);
  11980. InnerCall:=CreateCallExpression(El);
  11981. Prop.Expr:=InnerCall;
  11982. InnerCall.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnRTTINewProcSig]]);
  11983. // add array of arguments
  11984. InnerCall.AddArg(CreateRTTIArgList(El,El.Args,AContext));
  11985. // add resulttype as typeinfo reference
  11986. if El is TPasFunctionType then
  11987. begin
  11988. ResultEl:=TPasFunctionType(El).ResultEl;
  11989. ResultTypeInfo:=CreateTypeInfoRef(ResultEl.ResultType,AContext,ResultEl);
  11990. if ResultTypeInfo<>nil then
  11991. InnerCall.AddArg(ResultTypeInfo);
  11992. end;
  11993. // add param flags
  11994. Flags:=0;
  11995. if ptmVarargs in El.Modifiers then
  11996. inc(Flags,pfVarargs);
  11997. if Flags>0 then
  11998. InnerCall.AddArg(CreateLiteralNumber(El,Flags));
  11999. if El.IsOfObject then
  12000. begin
  12001. // add "methodkind: number;"
  12002. Prop:=Obj.Elements.AddElement;
  12003. Prop.Name:=TJSString(FBuiltInNames[pbivnRTTIMethodKind]);
  12004. if El.ClassType=TPasProcedureType then
  12005. MethodKind:=mkProcedure
  12006. else if El.ClassType=TPasFunctionType then
  12007. MethodKind:=mkFunction
  12008. else
  12009. RaiseNotSupported(El,AContext,20170411180848);
  12010. Prop.Expr:=CreateLiteralNumber(El,ord(MethodKind));
  12011. end;
  12012. Result:=Call;
  12013. finally
  12014. if Result=nil then
  12015. Call.Free;
  12016. end;
  12017. end;
  12018. function TPasToJSConverter.ConvertArrayType(El: TPasArrayType;
  12019. AContext: TConvertContext): TJSElement;
  12020. // Static array of static array need clone function:
  12021. // this.TStaticArray$clone = function(a){
  12022. // var r = [];
  12023. // for (var i=0; i<*High(a)*; i++) r.push(a[i].slice(0));
  12024. // return r;
  12025. // };
  12026. //
  12027. // Published array types need:
  12028. // module.$rtti.$StaticArray("name",{
  12029. // dims: [dimsize1,dimsize2,...],
  12030. // eltype: module.$rtti["ElTypeName"]
  12031. // };
  12032. // module.$rtti.$DynArray("name",{
  12033. // eltype: module.$rtti["ElTypeName"]
  12034. // };
  12035. //
  12036. const
  12037. CloneArrName = 'a';
  12038. CloneResultName = 'r';
  12039. CloneRunName = 'i';
  12040. var
  12041. AssignSt: TJSSimpleAssignStatement;
  12042. CallName: String;
  12043. Obj: TJSObjectLiteral;
  12044. Prop: TJSObjectLiteralElement;
  12045. ArrLit: TJSArrayLiteral;
  12046. Arr: TPasArrayType;
  12047. Index: Integer;
  12048. ElType: TPasType;
  12049. RangeEl: TPasExpr;
  12050. Call: TJSCallExpression;
  12051. RgLen, RangeEnd: TMaxPrecInt;
  12052. List: TJSStatementList;
  12053. Func: TJSFunctionDeclarationStatement;
  12054. Src: TJSSourceElements;
  12055. VarSt: TJSVariableStatement;
  12056. ForLoop: TJSForStatement;
  12057. ExprLT: TJSRelationalExpressionLT;
  12058. PlusPlus: TJSUnaryPostPlusPlusExpression;
  12059. BracketEx: TJSBracketMemberExpression;
  12060. CloneEl: TJSElement;
  12061. ReturnSt: TJSReturnStatement;
  12062. begin
  12063. Result:=nil;
  12064. if El.PackMode<>pmNone then
  12065. DoError(20170222231648,nPasElementNotSupported,sPasElementNotSupported,
  12066. ['packed'],El);
  12067. {$IFDEF VerbosePas2JS}
  12068. writeln('TPasToJSConverter.ConvertArrayType ',GetObjName(El));
  12069. {$ENDIF}
  12070. if AContext.Resolver.HasStaticArrayCloneFunc(El) then
  12071. begin
  12072. // For example: type TArr = array[1..2] of array[1..2] of longint;
  12073. // this.TStaticArray$clone = function(a){
  12074. // var r = [];
  12075. // for (var i=0; i<*High(a)*; i++) r.push(a[i].slice(0));
  12076. // return r;
  12077. // };
  12078. BracketEx:=nil;
  12079. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  12080. try
  12081. // add 'this.TypeName = function(){}'
  12082. AssignSt.LHS:=CreateSubDeclNameExpr(El,
  12083. El.Name+FBuiltInNames[pbifnArray_Static_Clone],AContext);
  12084. Index:=0;
  12085. RangeEl:=El.Ranges[Index];
  12086. // function(a){...
  12087. Func:=CreateFunctionSt(El,true,true);
  12088. AssignSt.Expr:=Func;
  12089. Func.AFunction.Params.Add(CloneArrName);
  12090. Src:=Func.AFunction.Body.A as TJSSourceElements;
  12091. // var r = [];
  12092. VarSt:=CreateVarStatement(CloneResultName,TJSArrayLiteral(CreateElement(TJSArrayLiteral,El)),El);
  12093. AddToSourceElements(Src,VarSt);
  12094. // for (
  12095. ForLoop:=TJSForStatement(CreateElement(TJSForStatement,El));
  12096. AddToSourceElements(Src,ForLoop);
  12097. // var i=0;
  12098. ForLoop.Init:=CreateVarStatement(CloneRunName,CreateLiteralNumber(El,0),El);
  12099. // i<high(a)
  12100. ExprLT:=TJSRelationalExpressionLT(CreateElement(TJSRelationalExpressionLT,El));
  12101. ForLoop.Cond:=ExprLT;
  12102. ExprLT.A:=CreatePrimitiveDotExpr(CloneRunName,El);
  12103. RangeEnd:=AContext.Resolver.GetRangeLength(RangeEl);
  12104. ExprLT.B:=CreateLiteralNumber(RangeEl,RangeEnd);
  12105. // i++
  12106. PlusPlus:=TJSUnaryPostPlusPlusExpression(CreateElement(TJSUnaryPostPlusPlusExpression,El));
  12107. ForLoop.Incr:=PlusPlus;
  12108. PlusPlus.A:=CreatePrimitiveDotExpr(CloneRunName,El);
  12109. // r.push(...
  12110. Call:=CreateCallExpression(El);
  12111. ForLoop.Body:=Call;
  12112. Call.Expr:=CreatePrimitiveDotExpr(CloneResultName+'.push',El);
  12113. // a[i]
  12114. BracketEx:=TJSBracketMemberExpression(CreateElement(TJSBracketMemberExpression,El));
  12115. BracketEx.MExpr:=CreatePrimitiveDotExpr(CloneArrName,El);
  12116. BracketEx.Name:=CreatePrimitiveDotExpr(CloneRunName,El);
  12117. // clone a[i]
  12118. ElType:=AContext.Resolver.ResolveAliasType(El.ElType);
  12119. CloneEl:=nil;
  12120. if ElType is TPasArrayType then
  12121. begin
  12122. if length(TPasArrayType(ElType).Ranges)=0 then
  12123. RaiseNotSupported(El,AContext,20180218223414,GetObjName(ElType));
  12124. CloneEl:=CreateCloneStaticArray(El,TPasArrayType(ElType),BracketEx,AContext);
  12125. end
  12126. else if ElType is TPasRecordType then
  12127. CloneEl:=CreateCloneRecord(El,TPasRecordType(ElType),BracketEx,AContext)
  12128. else if ElType is TPasSetType then
  12129. CloneEl:=CreateReferencedSet(El,BracketEx)
  12130. else
  12131. RaiseNotSupported(El,AContext,20180218223618,GetObjName(ElType));
  12132. Call.AddArg(CloneEl);
  12133. BracketEx:=nil;
  12134. // return r;
  12135. ReturnSt:=TJSReturnStatement(CreateElement(TJSReturnStatement,El));
  12136. AddToSourceElements(Src,ReturnSt);
  12137. ReturnSt.Expr:=CreatePrimitiveDotExpr(CloneResultName,El);
  12138. Result:=AssignSt;
  12139. AssignSt:=nil;
  12140. finally
  12141. BracketEx.Free;
  12142. AssignSt.Free;
  12143. end;
  12144. end;
  12145. if HasTypeInfo(El,AContext) then
  12146. begin
  12147. // module.$rtti.$DynArray("name",{...})
  12148. if length(El.Ranges)>0 then
  12149. CallName:=FBuiltInNames[pbifnRTTINewStaticArray]
  12150. else
  12151. CallName:=FBuiltInNames[pbifnRTTINewDynArray];
  12152. Call:=CreateRTTINewType(El,CallName,false,AContext,Obj);
  12153. try
  12154. ElType:=AContext.Resolver.ResolveAliasType(El.ElType);
  12155. if length(El.Ranges)>0 then
  12156. begin
  12157. // static array
  12158. // dims: [dimsize1,dimsize2,...]
  12159. Prop:=Obj.Elements.AddElement;
  12160. Prop.Name:=TJSString(FBuiltInNames[pbivnRTTIArray_Dims]);
  12161. ArrLit:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,El));
  12162. Prop.Expr:=ArrLit;
  12163. Arr:=El;
  12164. Index:=0;
  12165. repeat
  12166. RangeEl:=Arr.Ranges[Index];
  12167. RgLen:=AContext.Resolver.GetRangeLength(RangeEl);
  12168. ArrLit.AddElement(CreateLiteralNumber(RangeEl,RgLen));
  12169. inc(Index);
  12170. if Index=length(Arr.Ranges) then
  12171. begin
  12172. if ElType.ClassType<>TPasArrayType then
  12173. break;
  12174. Arr:=TPasArrayType(ElType);
  12175. if length(Arr.Ranges)=0 then
  12176. RaiseNotSupported(Arr,AContext,20170411222315,'static array of anonymous array');
  12177. ElType:=AContext.Resolver.ResolveAliasType(Arr.ElType);
  12178. Index:=0;
  12179. end;
  12180. until false;
  12181. end;
  12182. // eltype: ref
  12183. Prop:=Obj.Elements.AddElement;
  12184. Prop.Name:=TJSString(FBuiltInNames[pbivnRTTIArray_ElType]);
  12185. Prop.Expr:=CreateTypeInfoRef(ElType,AContext,El);
  12186. if Result=nil then
  12187. Result:=Call
  12188. else
  12189. begin
  12190. List:=TJSStatementList(CreateElement(TJSStatementList,El));
  12191. List.A:=Result;
  12192. List.B:=Call;
  12193. Result:=List;
  12194. end;
  12195. Call:=nil;
  12196. finally
  12197. Call.Free;
  12198. end;
  12199. end;
  12200. end;
  12201. function TPasToJSConverter.GetOrdType(MinValue, MaxValue: TMaxPrecInt;
  12202. ErrorEl: TPasElement): TOrdType;
  12203. var
  12204. V: TMaxPrecInt;
  12205. begin
  12206. if MinValue<0 then
  12207. begin
  12208. if MaxValue<-(MinValue+1) then
  12209. V:=-(MinValue+1)
  12210. else
  12211. V:=MaxValue;
  12212. if V<$8f then
  12213. Result:=otSByte
  12214. else if V<$8fff then
  12215. Result:=otSWord
  12216. else if V<$8fffffff then
  12217. Result:=otSLong
  12218. else if V<=MaxSafeIntDouble then
  12219. Result:=otSIntDouble
  12220. else
  12221. DoError(20170925200802,nRangeCheckError,sRangeCheckError,[],ErrorEl);
  12222. end
  12223. else
  12224. begin
  12225. if MaxValue<$ff then
  12226. Result:=otUByte
  12227. else if MaxValue<$ffff then
  12228. Result:=otUWord
  12229. else if MaxValue<$ffffffff then
  12230. Result:=otULong
  12231. else if MaxValue<=MaxSafeIntDouble then
  12232. Result:=otUIntDouble
  12233. else
  12234. DoError(20170925201002,nRangeCheckError,sRangeCheckError,[],ErrorEl);
  12235. end;
  12236. end;
  12237. {$IFDEF EnableForLoopRunnerCheck}
  12238. procedure TPasToJSConverter.ForLoop_OnProcBodyElement(El: TPasElement;
  12239. arg: pointer);
  12240. // Called by ConvertForStatement on each element of the current proc body
  12241. // Check each element that lies behind the loop if it is reads the LoopVar
  12242. var
  12243. Data: PForLoopFindData absolute arg;
  12244. begin
  12245. if El.HasParent(Data^.ForLoop) then
  12246. Data^.FoundLoop:=true
  12247. else if Data^.FoundLoop and (not Data^.LoopVarWrite) and (not Data^.LoopVarRead) then
  12248. begin
  12249. // El comes after loop and LoopVar was not yet accessed
  12250. if (El.CustomData is TResolvedReference)
  12251. and (TResolvedReference(El.CustomData).Declaration=Data^.LoopVar) then
  12252. begin
  12253. // El refers the LoopVar
  12254. // ToDo: check write only access
  12255. Data^.LoopVarRead:=true;
  12256. end;
  12257. end;
  12258. end;
  12259. {$ENDIF}
  12260. procedure TPasToJSConverter.SetUseEnumNumbers(const AValue: boolean);
  12261. begin
  12262. if AValue then
  12263. Include(FOptions,coEnumNumbers)
  12264. else
  12265. Exclude(FOptions,coEnumNumbers);
  12266. end;
  12267. procedure TPasToJSConverter.SetUseLowerCase(const AValue: boolean);
  12268. begin
  12269. if AValue then
  12270. Include(FOptions,coLowerCase)
  12271. else
  12272. Exclude(FOptions,coLowerCase);
  12273. end;
  12274. procedure TPasToJSConverter.SetUseSwitchStatement(const AValue: boolean);
  12275. begin
  12276. if AValue then
  12277. Include(FOptions,coSwitchStatement)
  12278. else
  12279. Exclude(FOptions,coSwitchStatement);
  12280. end;
  12281. constructor TPasToJSConverter.Create;
  12282. var
  12283. n: TPas2JSBuiltInName;
  12284. begin
  12285. FOptions:=DefaultPasToJSOptions;
  12286. for n in TPas2JSBuiltInName do
  12287. FBuiltInNames[n]:=Pas2JSBuiltInNames[n];
  12288. end;
  12289. destructor TPasToJSConverter.Destroy;
  12290. begin
  12291. inherited Destroy;
  12292. end;
  12293. function TPasToJSConverter.ConvertProcedure(El: TPasProcedure;
  12294. AContext: TConvertContext): TJSElement;
  12295. var
  12296. BodyJS: TJSFunctionBody;
  12297. FirstSt, LastSt: TJSStatementList;
  12298. procedure AddBodyStatement(Add: TJSElement; Src: TPasElement);
  12299. begin
  12300. AddToStatementList(FirstSt,LastSt,Add,Src);
  12301. BodyJS.A:=FirstSt;
  12302. end;
  12303. procedure AddRangeCheck(Arg: TPasArgument; MinVal, MaxVal: TMaxPrecInt;
  12304. RTLFunc: TPas2JSBuiltInName);
  12305. var
  12306. Call: TJSCallExpression;
  12307. begin
  12308. // use Arg as PosEl, so that user knows which Arg is out of range
  12309. Call:=CreateCallExpression(Arg);
  12310. Call.Expr:=CreatePrimitiveDotExpr(FBuiltInNames[pbivnRTL]+'.'+FBuiltInNames[RTLFunc],El);
  12311. AddBodyStatement(Call,Arg);
  12312. Call.AddArg(CreateArgumentAccess(Arg,AContext,Arg));
  12313. Call.AddArg(CreateLiteralNumber(Arg,MinVal));
  12314. Call.AddArg(CreateLiteralNumber(Arg,MaxVal));
  12315. end;
  12316. procedure AddRangeCheckType(Arg: TPasArgument; aType: TPasType);
  12317. var
  12318. Value: TResEvalValue;
  12319. begin
  12320. Value:=AContext.Resolver.EvalTypeRange(aType,[refConst]);
  12321. if Value=nil then
  12322. RaiseNotSupported(Arg,AContext,20180424111936,'range checking '+GetObjName(aType));
  12323. try
  12324. case Value.Kind of
  12325. revkRangeInt:
  12326. case TResEvalRangeInt(Value).ElKind of
  12327. revskEnum, revskInt:
  12328. AddRangeCheck(Arg,TResEvalRangeInt(Value).RangeStart,
  12329. TResEvalRangeInt(Value).RangeEnd,pbifnRangeCheckInt);
  12330. revskChar:
  12331. AddRangeCheck(Arg,TResEvalRangeInt(Value).RangeStart,
  12332. TResEvalRangeInt(Value).RangeEnd,pbifnRangeCheckChar);
  12333. end;
  12334. revkRangeUInt:
  12335. AddRangeCheck(Arg,TResEvalRangeUInt(Value).RangeStart,
  12336. TResEvalRangeUInt(Value).RangeEnd,pbifnRangeCheckInt);
  12337. else
  12338. RaiseNotSupported(Arg,AContext,20180424112010,'range checking '+Value.AsDebugString);
  12339. end;
  12340. finally
  12341. ReleaseEvalValue(Value);
  12342. end;
  12343. end;
  12344. Var
  12345. FS : TJSFunctionDeclarationStatement;
  12346. FD : TJSFuncDef;
  12347. n, i, Line, Col:Integer;
  12348. AssignSt: TJSSimpleAssignStatement;
  12349. FuncContext, ConstContext: TFunctionContext;
  12350. ProcScope, ImplProcScope: TPas2JSProcedureScope;
  12351. Arg: TPasArgument;
  12352. SelfSt: TJSVariableStatement;
  12353. ImplProc: TPasProcedure;
  12354. BodyPas: TProcedureBody;
  12355. PosEl: TPasElement;
  12356. Call: TJSCallExpression;
  12357. ClassPath: String;
  12358. ArgResolved: TPasResolverResult;
  12359. MinVal, MaxVal: TMaxPrecInt;
  12360. Lit: TJSLiteral;
  12361. ConstSrcElems: TJSSourceElements;
  12362. ArgTypeEl: TPasType;
  12363. aResolver: TPas2JSResolver;
  12364. begin
  12365. Result:=nil;
  12366. if El.IsAbstract then exit;
  12367. if El.IsExternal then exit;
  12368. ProcScope:=TPas2JSProcedureScope(El.CustomData);
  12369. if ProcScope.DeclarationProc<>nil then
  12370. exit;
  12371. {$IFDEF VerbosePas2JS}
  12372. writeln('TPasToJSConverter.ConvertProcedure "',El.Name,'" Overload="',ProcScope.OverloadName,'" ',El.Parent.ClassName);
  12373. {$ENDIF}
  12374. aResolver:=AContext.Resolver;
  12375. ImplProc:=El;
  12376. if ProcScope.ImplProc<>nil then
  12377. ImplProc:=ProcScope.ImplProc;
  12378. ImplProcScope:=TPas2JSProcedureScope(ImplProc.CustomData);
  12379. if ImplProcScope.BodyJS<>'' then
  12380. begin
  12381. // using precompiled code
  12382. TPasResolver.UnmangleSourceLineNumber(El.SourceLinenumber,Line,Col);
  12383. if ImplProcScope.GlobalJS<>nil then
  12384. begin
  12385. ConstContext:=AContext.GetGlobalFunc;
  12386. if not (ConstContext.JSElement is TJSSourceElements) then
  12387. begin
  12388. {$IFDEF VerbosePas2JS}
  12389. writeln('TPasToJSConverter.ConvertProcedure ConstContext=',GetObjName(ConstContext),' JSElement=',GetObjName(ConstContext.JSElement));
  12390. {$ENDIF}
  12391. RaiseNotSupported(El,AContext,20180228231008);
  12392. end;
  12393. ConstSrcElems:=TJSSourceElements(ConstContext.JSElement);
  12394. for i:=0 to ImplProcScope.GlobalJS.Count-1 do
  12395. begin
  12396. // precompiled global var or type
  12397. Lit:=TJSLiteral.Create(Line,Col,El.SourceFilename);
  12398. Lit.Value.CustomValue:=StrToJSString(ImplProcScope.GlobalJS[i]);
  12399. AddToSourceElements(ConstSrcElems,Lit);
  12400. end;
  12401. end;
  12402. // precompiled body
  12403. Lit:=TJSLiteral.Create(Line,Col,El.SourceFilename);
  12404. Lit.Value.CustomValue:=StrToJSString(ImplProcScope.BodyJS);
  12405. Result:=Lit;
  12406. exit;
  12407. end;
  12408. AssignSt:=nil;
  12409. if AContext.IsGlobal then
  12410. begin
  12411. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,ImplProc));
  12412. Result:=AssignSt;
  12413. AssignSt.LHS:=CreateSubDeclNameExpr(El,AContext,ImplProc);
  12414. end;
  12415. FS:=CreateFunctionSt(ImplProc,ImplProc.Body<>nil);
  12416. FD:=FS.AFunction;
  12417. if AssignSt<>nil then
  12418. AssignSt.Expr:=FS
  12419. else
  12420. begin
  12421. // local/nested or anonymous function
  12422. Result:=FS;
  12423. if El.Name<>'' then
  12424. FD.Name:=TJSString(TransformVariableName(El,AContext));
  12425. end;
  12426. for n := 0 to El.ProcType.Args.Count - 1 do
  12427. begin
  12428. Arg:=TPasArgument(El.ProcType.Args[n]);
  12429. FD.Params.Add(TransformVariableName(Arg,AContext));
  12430. end;
  12431. BodyPas:=ImplProc.Body;
  12432. if BodyPas<>nil then
  12433. begin
  12434. PosEl:=BodyPas;
  12435. if PosEl=nil then
  12436. PosEl:=ImplProc;
  12437. BodyJS:=FD.Body;
  12438. FuncContext:=TFunctionContext.Create(ImplProc,FD.Body,AContext);
  12439. try
  12440. FuncContext.ScannerBoolSwitches:=ImplProcScope.BoolSwitches;
  12441. FirstSt:=nil;
  12442. LastSt:=nil;
  12443. if (bsRangeChecks in ImplProcScope.BoolSwitches) and (aResolver<>nil) then
  12444. for i:=0 to El.ProcType.Args.Count-1 do
  12445. begin
  12446. Arg:=TPasArgument(El.ProcType.Args[i]);
  12447. if Arg.ArgType=nil then continue;
  12448. aResolver.ComputeElement(Arg,ArgResolved,[rcType]);
  12449. ArgTypeEl:=ArgResolved.LoTypeEl;
  12450. if ArgTypeEl=nil then continue;
  12451. if ArgResolved.BaseType in btAllJSInteger then
  12452. begin
  12453. if ArgTypeEl is TPasUnresolvedSymbolRef then
  12454. begin
  12455. if not aResolver.GetIntegerRange(ArgResolved.BaseType,MinVal,MaxVal) then
  12456. RaiseNotSupported(Arg,AContext,20180119192608);
  12457. AddRangeCheck(Arg,MinVal,MaxVal,pbifnRangeCheckInt);
  12458. end
  12459. else if ArgTypeEl.ClassType=TPasRangeType then
  12460. AddRangeCheckType(Arg,ArgTypeEl);
  12461. end
  12462. else if ArgResolved.BaseType in btAllJSChars then
  12463. AddRangeCheckType(Arg,ArgTypeEl)
  12464. else if ArgResolved.BaseType=btContext then
  12465. begin
  12466. if ArgTypeEl.ClassType=TPasEnumType then
  12467. AddRangeCheckType(Arg,ArgTypeEl);
  12468. end
  12469. else if ArgResolved.BaseType=btRange then
  12470. begin
  12471. if ArgResolved.SubType in btAllJSChars then
  12472. AddRangeCheckType(Arg,ArgTypeEl)
  12473. else if ArgResolved.SubType=btContext then
  12474. AddRangeCheckType(Arg,ArgTypeEl)
  12475. else
  12476. begin
  12477. {$IFDEF VerbosePas2JS}
  12478. writeln('TPasToJSConverter.ConvertProcedure ',GetResolverResultDbg(ArgResolved));
  12479. RaiseNotSupported(Arg,AContext,20180424120701);
  12480. {$ENDIF}
  12481. end;
  12482. end;
  12483. end;
  12484. if ProcScope.ClassScope<>nil then
  12485. begin
  12486. // method or class method
  12487. if not AContext.IsGlobal then
  12488. begin
  12489. // nested sub procedure -> no 'this'
  12490. FuncContext.ThisPas:=nil;
  12491. end
  12492. else
  12493. begin
  12494. FuncContext.ThisPas:=ProcScope.ClassScope.Element;
  12495. if bsObjectChecks in FuncContext.ScannerBoolSwitches then
  12496. begin
  12497. // rtl.checkMethodCall(this,<class>)
  12498. Call:=CreateCallExpression(PosEl);
  12499. AddBodyStatement(Call,PosEl);
  12500. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],
  12501. FBuiltInNames[pbifnCheckMethodCall]]);
  12502. Call.AddArg(CreatePrimitiveDotExpr('this',PosEl));
  12503. ClassPath:=CreateReferencePath(ProcScope.ClassScope.Element,AContext,rpkPathAndName);
  12504. Call.AddArg(CreatePrimitiveDotExpr(ClassPath,PosEl));
  12505. end;
  12506. if ImplProc.Body.Functions.Count>0 then
  12507. begin
  12508. // has nested procs -> add "var self = this;"
  12509. FuncContext.AddLocalVar(FBuiltInNames[pbivnSelf],FuncContext.ThisPas);
  12510. SelfSt:=CreateVarStatement(FBuiltInNames[pbivnSelf],
  12511. CreatePrimitiveDotExpr('this',ImplProc),ImplProc);
  12512. AddBodyStatement(SelfSt,PosEl);
  12513. if ImplProcScope.SelfArg<>nil then
  12514. begin
  12515. // redirect Pascal-Self to JS-Self
  12516. FuncContext.AddLocalVar(FBuiltInNames[pbivnSelf],ImplProcScope.SelfArg);
  12517. end;
  12518. end
  12519. else if ImplProcScope.SelfArg<>nil then
  12520. begin
  12521. // no nested procs -> redirect Pascal-Self to JS-this
  12522. FuncContext.AddLocalVar('this',ImplProcScope.SelfArg);
  12523. end;
  12524. end;
  12525. end;
  12526. {$IFDEF VerbosePas2JS}
  12527. //FuncContext.WriteStack;
  12528. {$ENDIF}
  12529. if BodyPas<>nil then
  12530. AddBodyStatement(ConvertDeclarations(BodyPas,FuncContext),BodyPas);
  12531. finally
  12532. FuncContext.Free;
  12533. end;
  12534. end;
  12535. if (coStoreImplJS in Options) and (aResolver<>nil) then
  12536. begin
  12537. if aResolver.GetTopLvlProc(El)=El then
  12538. begin
  12539. ImplProcScope.BodyJS:=CreatePrecompiledJS(Result);
  12540. ImplProcScope.EmptyJS:=BodyPas.Body=nil;
  12541. end;
  12542. end;
  12543. end;
  12544. function TPasToJSConverter.ConvertBeginEndStatement(El: TPasImplBeginBlock;
  12545. AContext: TConvertContext; NilIfEmpty: boolean): TJSElement;
  12546. begin
  12547. Result:=ConvertImplBlockElements(El,AContext,NilIfEmpty);
  12548. end;
  12549. function TPasToJSConverter.ConvertImplBlockElements(El: TPasImplBlock;
  12550. AContext: TConvertContext; NilIfEmpty: boolean): TJSElement;
  12551. var
  12552. First, Last: TJSStatementList;
  12553. I : Integer;
  12554. PasImpl: TPasImplElement;
  12555. JSImpl : TJSElement;
  12556. begin
  12557. if Not (Assigned(El.Elements) and (El.Elements.Count>0)) then
  12558. begin
  12559. if NilIfEmpty then
  12560. Result:=nil
  12561. else
  12562. Result:=TJSEmptyBlockStatement(CreateElement(TJSEmptyBlockStatement,El));
  12563. end
  12564. else
  12565. begin
  12566. First:=nil;
  12567. Result:=First;
  12568. Last:=First;
  12569. //writeln('TPasToJSConverter.ConvertImplBlockElements START El.Elements.Count=',El.Elements.Count);
  12570. For I:=0 to El.Elements.Count-1 do
  12571. begin
  12572. PasImpl:=TPasImplElement(El.Elements[i]);
  12573. JSImpl:=ConvertElement(PasImpl,AContext);
  12574. if JSImpl=nil then
  12575. continue; // e.g. "inherited;" when there is no ancestor proc
  12576. //writeln('TPasToJSConverter.ConvertImplBlockElements ',i,' ',JSImpl.ClassName);
  12577. AddToStatementList(First,Last,JSImpl,PasImpl);
  12578. Result:=First;
  12579. end;
  12580. end;
  12581. end;
  12582. function TPasToJSConverter.ConvertInitializationSection(
  12583. El: TInitializationSection; AContext: TConvertContext): TJSElement;
  12584. var
  12585. FDS: TJSFunctionDeclarationStatement;
  12586. FunName: String;
  12587. IsMain, NeedRTLCheckVersion: Boolean;
  12588. AssignSt: TJSSimpleAssignStatement;
  12589. FuncContext: TFunctionContext;
  12590. Body: TJSFunctionBody;
  12591. Scope: TPas2JSInitialFinalizationScope;
  12592. Line, Col: integer;
  12593. Lit: TJSLiteral;
  12594. begin
  12595. // create: '$mod.$init=function(){}'
  12596. Result:=nil;
  12597. Scope:=TPas2JSInitialFinalizationScope(El.CustomData);
  12598. if Scope.JS<>'' then
  12599. begin
  12600. // precompiled JS
  12601. TPasResolver.UnmangleSourceLineNumber(El.Parent.SourceLinenumber,Line,Col);
  12602. Lit:=TJSLiteral.Create(Line,Col,El.Parent.SourceFilename);
  12603. Lit.Value.CustomValue:=StrToJSString(Scope.JS);
  12604. Result:=Lit;
  12605. exit;
  12606. end;
  12607. IsMain:=(El.Parent<>nil) and (El.Parent is TPasProgram);
  12608. if IsMain then
  12609. FunName:=FBuiltInNames[pbifnProgramMain]
  12610. else
  12611. FunName:=FBuiltInNames[pbifnUnitInit];
  12612. NeedRTLCheckVersion:=IsMain and (coRTLVersionCheckMain in Options);
  12613. FuncContext:=nil;
  12614. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  12615. try
  12616. // $mod.$init =
  12617. AssignSt.LHS:=CreateMemberExpression([FBuiltInNames[pbivnModule],FunName]);
  12618. // = function(){...}
  12619. FDS:=CreateFunctionSt(El,(El.Elements.Count>0) or NeedRTLCheckVersion);
  12620. AssignSt.Expr:=FDS;
  12621. if El.Elements.Count>0 then
  12622. begin
  12623. Body:=FDS.AFunction.Body;
  12624. FuncContext:=TFunctionContext.Create(El,Body,AContext);
  12625. // Note: although the rtl sets 'this' as the module, the function can
  12626. // simply refer to $mod, so no need to set ThisPas here
  12627. Body.A:=ConvertImplBlockElements(El,FuncContext,false);
  12628. FuncContext.BodySt:=Body.A;
  12629. AddInterfaceReleases(FuncContext,El);
  12630. Body.A:=FuncContext.BodySt;
  12631. end;
  12632. if NeedRTLCheckVersion then
  12633. begin
  12634. // prepend rtl.versionCheck
  12635. Body:=FDS.AFunction.Body;
  12636. if FuncContext=nil then
  12637. FuncContext:=TFunctionContext.Create(El,Body,AContext);
  12638. AddRTLVersionCheck(FuncContext,El);
  12639. Body.A:=FuncContext.BodySt;
  12640. end;
  12641. Result:=AssignSt;
  12642. finally
  12643. FuncContext.Free;
  12644. if Result=nil then
  12645. AssignSt.Free;
  12646. end;
  12647. if (coStoreImplJS in Options) and (AContext.Resolver<>nil) then
  12648. Scope.JS:=CreatePrecompiledJS(Result);
  12649. end;
  12650. function TPasToJSConverter.ConvertFinalizationSection(El: TFinalizationSection;
  12651. AContext: TConvertContext): TJSElement;
  12652. begin
  12653. Result:=nil;
  12654. RaiseNotSupported(El,AContext,20161024192519);
  12655. end;
  12656. function TPasToJSConverter.ConvertTryStatement(El: TPasImplTry;
  12657. AContext: TConvertContext): TJSElement;
  12658. Var
  12659. T : TJSTryStatement;
  12660. ExceptBlock: TPasImplTryHandler;
  12661. i: Integer;
  12662. ExceptOn: TPasImplExceptOn;
  12663. IfSt, Last: TJSIfStatement;
  12664. begin
  12665. Result:=nil;
  12666. T:=nil;
  12667. try
  12668. if El.FinallyExcept is TPasImplTryFinally then
  12669. begin
  12670. T:=TJSTryFinallyStatement(CreateElement(TJSTryFinallyStatement,El));
  12671. T.Block:=ConvertImplBlockElements(El,AContext,true);
  12672. T.BFinally:=ConvertImplBlockElements(El.FinallyExcept,AContext,true);
  12673. end
  12674. else
  12675. begin
  12676. T:=TJSTryCatchStatement(CreateElement(TJSTryCatchStatement,El));
  12677. T.Block:=ConvertImplBlockElements(El,AContext,true);
  12678. // always set the catch except object, needed by nodejs
  12679. T.Ident:=TJSString(FBuiltInNames[pbivnExceptObject]);
  12680. ExceptBlock:=El.FinallyExcept;
  12681. if (ExceptBlock.Elements.Count>0)
  12682. and (TPasImplElement(ExceptBlock.Elements[0]) is TPasImplExceptOn) then
  12683. begin
  12684. Last:=nil;
  12685. for i:=0 to ExceptBlock.Elements.Count-1 do
  12686. begin
  12687. ExceptOn:=TObject(ExceptBlock.Elements[i]) as TPasImplExceptOn;
  12688. IfSt:=ConvertExceptOn(ExceptOn,AContext) as TJSIfStatement;
  12689. if Last=nil then
  12690. T.BCatch:=IfSt
  12691. else
  12692. Last.BFalse:=IfSt;
  12693. Last:=IfSt;
  12694. end;
  12695. if El.ElseBranch<>nil then
  12696. Last.BFalse:=ConvertImplBlockElements(El.ElseBranch,AContext,true)
  12697. else
  12698. begin
  12699. // default else: throw exceptobject
  12700. Last.BFalse:=TJSThrowStatement(CreateElement(TJSThrowStatement,El));
  12701. TJSThrowStatement(Last.BFalse).A:=
  12702. CreatePrimitiveDotExpr(FBuiltInNames[pbivnExceptObject],El);
  12703. end;
  12704. end
  12705. else
  12706. begin
  12707. if El.ElseBranch<>nil then
  12708. RaiseNotSupported(El.ElseBranch,AContext,20170205003014);
  12709. T.BCatch:=ConvertImplBlockElements(ExceptBlock,AContext,true);
  12710. end;
  12711. end;
  12712. Result:=T;
  12713. finally
  12714. if Result=nil then
  12715. T.Free;
  12716. end;
  12717. end;
  12718. function TPasToJSConverter.ConvertCaseOfStatement(El: TPasImplCaseOf;
  12719. AContext: TConvertContext): TJSElement;
  12720. var
  12721. SubEl: TPasImplElement;
  12722. St: TPasImplCaseStatement;
  12723. ok, IsCaseOfString: Boolean;
  12724. i, j: Integer;
  12725. JSExpr: TJSElement;
  12726. StList: TJSStatementList;
  12727. Expr: TPasExpr;
  12728. IfSt, LastIfSt: TJSIfStatement;
  12729. TmpVarName: String;
  12730. VarDecl: TJSVarDeclaration;
  12731. VarSt: TJSVariableStatement;
  12732. JSOrExpr: TJSLogicalOrExpression;
  12733. JSAndExpr: TJSLogicalAndExpression;
  12734. JSLEExpr: TJSRelationalExpressionLE;
  12735. JSGEExpr: TJSRelationalExpressionGE;
  12736. JSEQExpr: TJSEqualityExpressionSEQ;
  12737. aResolver: TPas2JSResolver;
  12738. CaseResolved: TPasResolverResult;
  12739. begin
  12740. Result:=nil;
  12741. aResolver:=AContext.Resolver;
  12742. IsCaseOfString:=false;
  12743. if aResolver<>nil then
  12744. begin
  12745. aResolver.ComputeElement(El.CaseExpr,CaseResolved,[]);
  12746. if CaseResolved.BaseType in btAllStrings then
  12747. IsCaseOfString:=true;
  12748. end;
  12749. if UseSwitchStatement then
  12750. begin
  12751. // convert to switch statement
  12752. // switch does not support ranges -> check
  12753. ok:=true;
  12754. for i:=0 to El.Elements.Count-1 do
  12755. begin
  12756. SubEl:=TPasImplElement(El.Elements[i]);
  12757. if not (SubEl is TPasImplCaseStatement) then
  12758. continue;
  12759. St:=TPasImplCaseStatement(SubEl);
  12760. for j:=0 to St.Expressions.Count-1 do
  12761. begin
  12762. Expr:=TPasExpr(St.Expressions[j]);
  12763. if (Expr is TBinaryExpr) and (TBinaryExpr(Expr).Kind=pekRange) then
  12764. begin
  12765. ok:=false;
  12766. break;
  12767. end;
  12768. end;
  12769. if not ok then break;
  12770. end;
  12771. if ok then
  12772. begin
  12773. Result:=CreateSwitchStatement(El,AContext);
  12774. exit;
  12775. end;
  12776. end;
  12777. // convert to if statements
  12778. StList:=TJSStatementList(CreateElement(TJSStatementList,El));
  12779. ok:=false;
  12780. try
  12781. // create var $tmp=CaseExpr;
  12782. TmpVarName:=AContext.CreateLocalIdentifier('$tmp');
  12783. VarSt:=TJSVariableStatement(CreateElement(TJSVariableStatement,El.CaseExpr));
  12784. StList.A:=VarSt;
  12785. VarDecl:=TJSVarDeclaration(CreateElement(TJSVarDeclaration,El.CaseExpr));
  12786. VarSt.A:=VarDecl;
  12787. VarDecl.Name:=TmpVarName;
  12788. VarDecl.Init:=ConvertExpression(El.CaseExpr,AContext);
  12789. LastIfSt:=nil;
  12790. for i:=0 to El.Elements.Count-1 do
  12791. begin
  12792. SubEl:=TPasImplElement(El.Elements[i]);
  12793. if SubEl is TPasImplCaseStatement then
  12794. begin
  12795. St:=TPasImplCaseStatement(SubEl);
  12796. // create for example "if (tmp==expr) || ((tmp>=expr) && (tmp<=expr)){}"
  12797. IfSt:=TJSIfStatement(CreateElement(TJSIfStatement,SubEl));
  12798. if LastIfSt=nil then
  12799. StList.B:=IfSt
  12800. else
  12801. LastIfSt.BFalse:=IfSt;
  12802. LastIfSt:=IfSt;
  12803. for j:=0 to St.Expressions.Count-1 do
  12804. begin
  12805. Expr:=TPasExpr(St.Expressions[j]);
  12806. if (Expr is TBinaryExpr) and (TBinaryExpr(Expr).Kind=pekRange) then
  12807. begin
  12808. // range -> create "(tmp>=left) && (tmp<=right)"
  12809. // create "() && ()"
  12810. JSAndExpr:=TJSLogicalAndExpression(CreateElement(TJSLogicalAndExpression,Expr));
  12811. JSExpr:=JSAndExpr;
  12812. // create "tmp>=left"
  12813. JSGEExpr:=TJSRelationalExpressionGE(CreateElement(TJSRelationalExpressionGE,Expr));
  12814. JSAndExpr.A:=JSGEExpr;
  12815. JSGEExpr.A:=CreatePrimitiveDotExpr(TmpVarName,El.CaseExpr);
  12816. JSGEExpr.B:=ConvertExpression(TBinaryExpr(Expr).left,AContext);
  12817. // create "tmp<=right"
  12818. JSLEExpr:=TJSRelationalExpressionLE(CreateElement(TJSRelationalExpressionLE,Expr));
  12819. JSAndExpr.B:=JSLEExpr;
  12820. JSLEExpr.A:=CreatePrimitiveDotExpr(TmpVarName,El.CaseExpr);
  12821. JSLEExpr.B:=ConvertExpression(TBinaryExpr(Expr).right,AContext);
  12822. if IsCaseOfString then
  12823. begin
  12824. // case of string, range -> "(tmp.length===1) &&"
  12825. JSEQExpr:=TJSEqualityExpressionSEQ(CreateElement(TJSEqualityExpressionSEQ,Expr));
  12826. JSEQExpr.A:=CreateDotExpression(Expr,
  12827. CreatePrimitiveDotExpr(TmpVarName,El.CaseExpr),
  12828. CreatePrimitiveDotExpr('length',Expr));
  12829. JSEQExpr.B:=CreateLiteralNumber(Expr,1);
  12830. JSAndExpr:=TJSLogicalAndExpression(CreateElement(TJSLogicalAndExpression,Expr));
  12831. JSAndExpr.A:=JSEQExpr;
  12832. JSAndExpr.B:=JSExpr;
  12833. JSExpr:=JSAndExpr;
  12834. end;
  12835. end
  12836. else
  12837. begin
  12838. // value -> create (tmp===Expr)
  12839. JSEQExpr:=TJSEqualityExpressionSEQ(CreateElement(TJSEqualityExpressionSEQ,Expr));
  12840. JSExpr:=JSEQExpr;
  12841. JSEQExpr.A:=CreatePrimitiveDotExpr(TmpVarName,El.CaseExpr);
  12842. JSEQExpr.B:=ConvertExpression(Expr,AContext);
  12843. end;
  12844. if IfSt.Cond=nil then
  12845. // first expression
  12846. IfSt.Cond:=JSExpr
  12847. else
  12848. begin
  12849. // multi expression -> append with OR
  12850. JSOrExpr:=TJSLogicalOrExpression(CreateElement(TJSLogicalOrExpression,St));
  12851. JSOrExpr.A:=IfSt.Cond;
  12852. JSOrExpr.B:=JSExpr;
  12853. IfSt.Cond:=JSOrExpr;
  12854. end;
  12855. end;
  12856. // convert statement
  12857. if St.Body<>nil then
  12858. IfSt.BTrue:=ConvertElement(St.Body,AContext)
  12859. else
  12860. IfSt.BTrue:=TJSEmptyStatement(CreateElement(TJSEmptyStatement,St));
  12861. end
  12862. else if SubEl is TPasImplCaseElse then
  12863. begin
  12864. // Pascal 'else' or 'otherwise' -> create JS "else{}"
  12865. if LastIfSt=nil then
  12866. RaiseNotSupported(SubEl,AContext,20161128120802,'case-of needs at least one case');
  12867. LastIfSt.BFalse:=ConvertImplBlockElements(El.ElseBranch,AContext,true);
  12868. end
  12869. else
  12870. RaiseNotSupported(SubEl,AContext,20161128113055);
  12871. end;
  12872. ok:=true;
  12873. finally
  12874. if not ok then
  12875. StList.Free;
  12876. end;
  12877. Result:=StList;
  12878. end;
  12879. function TPasToJSConverter.ConvertAsmStatement(El: TPasImplAsmStatement;
  12880. AContext: TConvertContext): TJSElement;
  12881. var
  12882. s: String;
  12883. L: TJSLiteral;
  12884. AsmLines: TStrings;
  12885. Line, Col, StartLine: integer;
  12886. begin
  12887. if AContext=nil then ;
  12888. AsmLines:=El.Tokens;
  12889. s:=Trim(AsmLines.Text);
  12890. if (s<>'') and (s[length(s)]=';') then
  12891. Delete(s,length(s),1);
  12892. if s='' then
  12893. Result:=TJSEmptyStatement(CreateElement(TJSEmptyStatement,El))
  12894. else begin
  12895. StartLine:=0;
  12896. while (StartLine<AsmLines.Count) and (Trim(AsmLines[StartLine])='') do
  12897. inc(StartLine);
  12898. TPasResolver.UnmangleSourceLineNumber(El.SourceLinenumber,Line,Col);
  12899. if StartLine>0 then
  12900. Col:=1;
  12901. L:=TJSLiteral.Create(Line+StartLine,Col,El.SourceFilename);
  12902. L.Value.CustomValue:=TJSString(s);
  12903. Result:=L;
  12904. end;
  12905. end;
  12906. function TPasToJSConverter.ConvertConstValue(Value: TResEvalValue;
  12907. AContext: TConvertContext; El: TPasElement): TJSElement;
  12908. var
  12909. Ranges: TResEvalSet.TItems;
  12910. Range: TResEvalSet.TItem;
  12911. Call: TJSCallExpression;
  12912. i: Integer;
  12913. begin
  12914. Result:=nil;
  12915. if Value=nil then
  12916. RaiseNotSupported(El,AContext,20170910211948);
  12917. case Value.Kind of
  12918. revkNil:
  12919. Result:=CreateLiteralNull(El);
  12920. revkBool:
  12921. Result:=CreateLiteralBoolean(El,TResEvalBool(Value).B);
  12922. revkInt:
  12923. Result:=CreateLiteralNumber(El,TResEvalInt(Value).Int);
  12924. revkUInt:
  12925. Result:=CreateLiteralNumber(El,TResEvalUInt(Value).UInt);
  12926. revkFloat:
  12927. Result:=CreateLiteralNumber(El,TResEvalFloat(Value).FloatValue);
  12928. {$IFDEF FPC_HAS_CPSTRING}
  12929. revkString:
  12930. Result:=CreateLiteralString(El,TResEvalString(Value).S);
  12931. {$ENDIF}
  12932. revkUnicodeString:
  12933. Result:=CreateLiteralJSString(El,TResEvalUTF16(Value).S);
  12934. revkEnum:
  12935. Result:=CreateReferencePathExpr(TResEvalEnum(Value).GetEnumValue,AContext);
  12936. revkSetOfInt:
  12937. if Value.IdentEl is TPasExpr then
  12938. Result:=ConvertElement(Value.IdentEl,AContext)
  12939. else
  12940. begin
  12941. {$IFDEF VerbosePas2JS}
  12942. writeln('TPasToJSConverter.ConvertConstValue Value=',Value.AsDebugString,' IdentEl=',GetObjName(Value.IdentEl));
  12943. {$ENDIF}
  12944. // rtl.createSet()
  12945. Call:=CreateCallExpression(El);
  12946. try
  12947. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnSet_Create]]);
  12948. Ranges:=TResEvalSet(Value).Ranges;
  12949. for i:=0 to length(Ranges)-1 do
  12950. begin
  12951. Range:=Ranges[i];
  12952. {$IFDEF VerbosePas2JS}
  12953. writeln('TPasToJSConverter.ConvertConstValue SetLiteral ',i,' ',Range.RangeStart,'..',Range.RangeEnd);
  12954. {$ENDIF}
  12955. if Range.RangeStart=Range.RangeEnd then
  12956. begin
  12957. // add one integer
  12958. Call.AddArg(CreateLiteralNumber(El,Range.RangeStart));
  12959. end
  12960. else
  12961. begin
  12962. // range -> add three parameters: null,left,right
  12963. Call.AddArg(CreateLiteralNull(El));
  12964. Call.AddArg(CreateLiteralNumber(El,Range.RangeStart));
  12965. Call.AddArg(CreateLiteralNumber(El,Range.RangeEnd));
  12966. end;
  12967. end;
  12968. Result:=Call;
  12969. finally
  12970. if Result=nil then
  12971. Call.Free;
  12972. end;
  12973. end
  12974. else
  12975. {$IFDEF VerbosePas2JS}
  12976. writeln('TPasToJSConverter.ConvertConstValue Value=',Value.AsDebugString);
  12977. {$ENDIF}
  12978. RaiseNotSupported(El,AContext,20170910211951);
  12979. end;
  12980. end;
  12981. function TPasToJSConverter.CreateImplementationSection(El: TPasModule;
  12982. AContext: TConvertContext
  12983. ): TJSFunctionDeclarationStatement;
  12984. var
  12985. Src: TJSSourceElements;
  12986. ImplContext: TSectionContext;
  12987. ImplDecl: TJSElement;
  12988. ImplVarSt: TJSVariableStatement;
  12989. FunDecl: TJSFunctionDeclarationStatement;
  12990. ModVarName, ImplVarName: String;
  12991. begin
  12992. Result:=nil;
  12993. // create function(){}
  12994. FunDecl:=CreateFunctionSt(El,true,true);
  12995. Src:=TJSSourceElements(FunDecl.AFunction.Body.A);
  12996. // create section context (a function)
  12997. ImplContext:=TSectionContext.Create(El,Src,AContext);
  12998. try
  12999. if coUseStrict in Options then
  13000. AddToSourceElements(Src,CreateLiteralString(El,'use strict'));
  13001. // add "var $mod = this;"
  13002. ImplContext.ThisPas:=El;
  13003. ModVarName:=FBuiltInNames[pbivnModule];
  13004. AddToSourceElements(Src,CreateVarStatement(ModVarName,
  13005. CreatePrimitiveDotExpr('this',El),El));
  13006. ImplContext.AddLocalVar(ModVarName,El);
  13007. // add var $impl = $mod.$impl
  13008. ImplVarName:=FBuiltInNames[pbivnImplementation];
  13009. ImplVarSt:=CreateVarStatement(ImplVarName,
  13010. CreateMemberExpression([ModVarName,ImplVarName]),El.ImplementationSection);
  13011. AddToSourceElements(Src,ImplVarSt);
  13012. ImplContext.AddLocalVar(ImplVarName,El.ImplementationSection);
  13013. // create implementation declarations
  13014. ImplDecl:=ConvertDeclarations(El.ImplementationSection,ImplContext);
  13015. if ImplDecl<>nil then
  13016. RaiseInconsistency(20170910175032,El); // elements should have been added directly
  13017. if Src.Statements[Src.Statements.Count-1].Node=ImplVarSt then
  13018. exit; // no implementation
  13019. // add impl declarations
  13020. AddToSourceElements(Src,ImplDecl);
  13021. Result:=FunDecl;
  13022. finally
  13023. ImplContext.Free;
  13024. if Result=nil then
  13025. FunDecl.Free;
  13026. end;
  13027. end;
  13028. procedure TPasToJSConverter.CreateInitSection(El: TPasModule;
  13029. Src: TJSSourceElements; AContext: TConvertContext);
  13030. begin
  13031. // add initialization section
  13032. if Assigned(El.InitializationSection) then
  13033. AddToSourceElements(Src,ConvertInitializationSection(El.InitializationSection,AContext));
  13034. // finalization: not supported
  13035. if Assigned(El.FinalizationSection) then
  13036. raise Exception.Create('TPasToJSConverter.ConvertInitializationSection: finalization section is not supported');
  13037. end;
  13038. function TPasToJSConverter.CreateReferencedSet(El: TPasElement; SetExpr: TJSElement
  13039. ): TJSElement;
  13040. var
  13041. Call: TJSCallExpression;
  13042. begin
  13043. Call:=CreateCallExpression(El);
  13044. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnSet_Reference]]);
  13045. Call.AddArg(SetExpr);
  13046. Result:=Call;
  13047. end;
  13048. function TPasToJSConverter.CreateRecordInit(aRecord: TPasRecordType;
  13049. Expr: TPasExpr; El: TPasElement; AContext: TConvertContext): TJSElement;
  13050. // new recordtype()
  13051. var
  13052. NewMemE: TJSNewMemberExpression;
  13053. aResolver: TPas2JSResolver;
  13054. ObjLit: TJSObjectLiteral;
  13055. GUID: TGuid;
  13056. begin
  13057. Result:=nil;
  13058. if Expr<>nil then
  13059. begin
  13060. aResolver:=AContext.Resolver;
  13061. if aResolver<>nil then
  13062. begin
  13063. if aResolver.GetAssignGUIDString(aRecord,Expr,GUID) then
  13064. begin
  13065. // new TGuid({ D1:...})
  13066. ObjLit:=CreateGUIDObjLit(aRecord,GUID,El,AContext);
  13067. NewMemE:=CreateNewRecord(El,aRecord,AContext);
  13068. Result:=NewMemE;
  13069. NewMemE.AddArg(ObjLit);
  13070. exit;
  13071. end;
  13072. end;
  13073. if Expr is TRecordValues then
  13074. // new TRecord({...})
  13075. Result:=ConvertRecordValues(TRecordValues(Expr),AContext);
  13076. if Result=nil then
  13077. RaiseNotSupported(Expr,AContext,20161024192747);
  13078. end
  13079. else
  13080. begin
  13081. // new TRecord()
  13082. Result:=CreateNewRecord(El,aRecord,AContext);
  13083. end;
  13084. end;
  13085. function TPasToJSConverter.CreateNewRecord(El: TPasElement;
  13086. RecTypeEl: TPasRecordType; AContext: TConvertContext): TJSNewMemberExpression;
  13087. var
  13088. Expr: TJSElement;
  13089. begin
  13090. Expr:=CreateReferencePathExpr(RecTypeEl,AContext);
  13091. Result:=TJSNewMemberExpression(CreateElement(TJSNewMemberExpression,El));
  13092. Result.MExpr:=Expr;
  13093. end;
  13094. function TPasToJSConverter.CreateCloneRecord(El: TPasElement;
  13095. RecTypeEl: TPasRecordType; RecordExpr: TJSElement; AContext: TConvertContext
  13096. ): TJSElement;
  13097. // create "new RecordType(RecordExpr)
  13098. var
  13099. NewExpr: TJSNewMemberExpression;
  13100. Expr: TJSElement;
  13101. begin
  13102. Expr:=CreateReferencePathExpr(RecTypeEl,AContext);
  13103. if RecordExpr is TJSNewMemberExpression then
  13104. begin
  13105. if JSEquals(Expr,TJSNewMemberExpression(RecordExpr).MExpr) then
  13106. begin
  13107. // RecordExpr is already a new RecordType(...) -> skip clone
  13108. Expr.Free;
  13109. exit(RecordExpr);
  13110. end;
  13111. end;
  13112. NewExpr:=TJSNewMemberExpression(CreateElement(TJSNewMemberExpression,El));
  13113. NewExpr.MExpr:=Expr;
  13114. NewExpr.AddArg(RecordExpr);
  13115. Result:=NewExpr;
  13116. end;
  13117. function TPasToJSConverter.CreateArrayConcat(
  13118. ElTypeResolved: TPasResolverResult; PosEl: TPasElement;
  13119. AContext: TConvertContext): TJSCallExpression;
  13120. var
  13121. Call: TJSCallExpression;
  13122. begin
  13123. Result:=nil;
  13124. Call:=CreateCallExpression(PosEl);
  13125. try
  13126. {$IFDEF VerbosePas2JS}
  13127. writeln('TPasToJSConverter.CreateArrayConcat ElType=',GetResolverResultDbg(ElTypeResolved));
  13128. {$ENDIF}
  13129. if ElTypeResolved.BaseType=btContext then
  13130. begin
  13131. if ElTypeResolved.LoTypeEl.ClassType=TPasRecordType then
  13132. begin
  13133. // record: rtl.arrayConcat(RecordType,array1,array2,...)
  13134. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnArray_Concat]]);
  13135. Call.AddArg(CreateReferencePathExpr(ElTypeResolved.LoTypeEl,AContext));
  13136. end;
  13137. end
  13138. else if ElTypeResolved.BaseType=btSet then
  13139. begin
  13140. // set: rtl.arrayConcat("refSet",array1,array2,...)
  13141. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnArray_Concat]]);
  13142. Call.AddArg(CreateLiteralString(PosEl,FBuiltInNames[pbifnSet_Reference]));
  13143. end;
  13144. if Call.Expr=nil then
  13145. begin
  13146. // default: rtl.arrayConcatN(array1,array2,...)
  13147. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnArray_ConcatN]]);
  13148. end;
  13149. Result:=Call;
  13150. finally
  13151. if Result=nil then
  13152. Call.Free;
  13153. end;
  13154. end;
  13155. function TPasToJSConverter.CreateArrayConcat(ArrayType: TPasArrayType;
  13156. PosEl: TPasElement; AContext: TConvertContext): TJSCallExpression;
  13157. var
  13158. ElTypeResolved: TPasResolverResult;
  13159. begin
  13160. if length(ArrayType.Ranges)>1 then
  13161. RaiseNotSupported(PosEl,AContext,20170331001021);
  13162. AContext.Resolver.ComputeElement(ArrayType.ElType,ElTypeResolved,[rcType]);
  13163. Result:=CreateArrayConcat(ElTypeResolved,PosEl,AContext);
  13164. end;
  13165. function TPasToJSConverter.CreateCallback(El: TPasElement;
  13166. ResolvedEl: TPasResolverResult; AContext: TConvertContext): TJSElement;
  13167. // El is a reference to a proc
  13168. // for a proc or nested proc simply use the function
  13169. // for a method create "rtl.createCallback(Target,func)"
  13170. var
  13171. Call: TJSCallExpression;
  13172. Target: TJSElement;
  13173. DotExpr: TJSDotMemberExpression;
  13174. Prim: TJSPrimaryExpressionIdent;
  13175. aName: String;
  13176. DotPos: SizeInt;
  13177. FunName: String;
  13178. ProcScope: TPasProcedureScope;
  13179. begin
  13180. Result:=nil;
  13181. if not (ResolvedEl.IdentEl is TPasProcedure) then
  13182. RaiseInconsistency(20170215140756,El);
  13183. Target:=ConvertElement(El,AContext);
  13184. ProcScope:=TPasProcedureScope(ResolvedEl.IdentEl.CustomData);
  13185. if ProcScope.ClassScope=nil then
  13186. begin
  13187. // not a method -> simply use the function
  13188. Result:=Target;
  13189. exit;
  13190. end;
  13191. // a method -> create "rtl.createCallback(Target,func)"
  13192. Call:=nil;
  13193. try
  13194. Call:=CreateCallExpression(El);
  13195. // "rtl.createCallback"
  13196. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnProcType_Create]]);
  13197. // add parameters
  13198. {$IFDEF VerbosePas2JS}
  13199. writeln('TPasToJSConverter.CreateCallback ',GetObjName(Target));
  13200. {$ENDIF}
  13201. FunName:='';
  13202. // the last element of Target is the proc, chomp that off
  13203. if Target.ClassType=TJSDotMemberExpression then
  13204. begin
  13205. // chomp dot member -> rtl.createCallback(scope,"FunName")
  13206. DotExpr:=TJSDotMemberExpression(Target);
  13207. FunName:=String(DotExpr.Name);
  13208. DotPos:=PosLast('.',FunName);
  13209. if DotPos>0 then
  13210. begin
  13211. // e.g. path dot $class.funname
  13212. // keep DotExpr, chomp funname
  13213. DotExpr.Name:=TJSString(LeftStr(FunName,DotPos-1));
  13214. FunName:=copy(FunName,DotPos+1);
  13215. if not IsValidJSIdentifier(DotExpr.Name) then
  13216. begin
  13217. {$IFDEF VerbosePas2JS}
  13218. writeln('TPasToJSConverter.CreateCallback ',GetObjName(Target),' DotExpr.Name="',DotExpr.Name,'"');
  13219. {$ENDIF}
  13220. DoError(20170215161802,nInvalidFunctionReference,sInvalidFunctionReference,[],El);
  13221. end;
  13222. end
  13223. else
  13224. begin
  13225. // e.g. path dot funname
  13226. // delete DotExpr
  13227. Target:=DotExpr.MExpr;
  13228. DotExpr.MExpr:=nil;
  13229. FreeAndNil(DotExpr);
  13230. end;
  13231. if not IsValidJSIdentifier(TJSString(FunName)) then
  13232. begin
  13233. {$IFDEF VerbosePas2JS}
  13234. writeln('TPasToJSConverter.CreateCallback ',GetObjName(Target),' FunName="',FunName,'"');
  13235. {$ENDIF}
  13236. DoError(20170215161802,nInvalidFunctionReference,sInvalidFunctionReference,[],El);
  13237. end;
  13238. Call.AddArg(Target);
  13239. // add function name as parameter
  13240. Call.AddArg(CreateLiteralString(El,FunName));
  13241. end
  13242. else if Target.ClassType=TJSPrimaryExpressionIdent then
  13243. begin
  13244. Prim:=TJSPrimaryExpressionIdent(Target);
  13245. aName:=String(Prim.Name);
  13246. DotPos:=PosLast('.',aName);
  13247. if DotPos<1 then
  13248. DoError(20170418135806,nInvalidFunctionReference,sInvalidFunctionReference,[],El);
  13249. // chomp dotted identifier -> rtl.createCallback(scope,"FunName")
  13250. FunName:=copy(aName,DotPos+1);
  13251. Prim.Name:=TJSString(LeftStr(aName,DotPos-1));
  13252. Call.AddArg(Prim);
  13253. // add function name as parameter
  13254. Call.AddArg(CreateLiteralString(El,FunName));
  13255. end
  13256. else
  13257. begin
  13258. {$IFDEF VerbosePas2JS}
  13259. writeln('TPasToJSConverter.CreateCallback invalid Scope=',GetObjName(Target));
  13260. {$ENDIF}
  13261. DoError(20170418135820,nInvalidFunctionReference,sInvalidFunctionReference,[],El);
  13262. end;
  13263. Result:=Call;
  13264. finally
  13265. if Result=nil then
  13266. begin
  13267. Target.Free;
  13268. Call.Free;
  13269. end;
  13270. end;
  13271. end;
  13272. function TPasToJSConverter.ConvertExternalBracketAccessorCall(El: TParamsExpr;
  13273. AContext: TConvertContext): TJSElement;
  13274. var
  13275. Ref: TResolvedReference;
  13276. ArgContext: TConvertContext;
  13277. ok: Boolean;
  13278. AssignSt: TJSSimpleAssignStatement;
  13279. IndexJS: TJSElement;
  13280. WithData: TPas2JSWithExprScope;
  13281. Path: String;
  13282. BracketJS: TJSBracketMemberExpression;
  13283. begin
  13284. Result:=nil;
  13285. if length(El.Params)<1 then
  13286. RaiseInconsistency(20180511151259,El);
  13287. if not (El.Value.CustomData is TResolvedReference) then
  13288. RaiseInconsistency(20180511144445,El);
  13289. Ref:=TResolvedReference(El.Value.CustomData);
  13290. ArgContext:=AContext.GetNonDotContext;
  13291. ok:=false;
  13292. try
  13293. // First convert index, because it may raise an exception
  13294. IndexJS:=ConvertElement(El.Params[0],ArgContext);
  13295. if Ref.WithExprScope<>nil then
  13296. begin
  13297. // with path do GetItems(astring) -> withtmp1[astring]
  13298. WithData:=Ref.WithExprScope as TPas2JSWithExprScope;
  13299. Path:=WithData.WithVarName;
  13300. end
  13301. else
  13302. begin
  13303. // GetItems(astring) -> this[astring]
  13304. Path:='this';
  13305. end;
  13306. BracketJS:=TJSBracketMemberExpression(CreateElement(TJSBracketMemberExpression,El));
  13307. Result:=BracketJS;
  13308. BracketJS.Name:=IndexJS;
  13309. BracketJS.MExpr:=CreatePrimitiveDotExpr(Path,El);
  13310. if length(El.Params)>1 then
  13311. begin
  13312. // SetItems(astring,value) -> this[astring]:=value
  13313. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  13314. AssignSt.LHS:=Result;
  13315. Result:=AssignSt;
  13316. AssignSt.Expr:=ConvertElement(El.Params[1],ArgContext); // may raise an exception
  13317. end;
  13318. if length(El.Params)>2 then
  13319. DoError(20180511144047,nCantCallExtBracketAccessor,sCantCallExtBracketAccessor,[],El);
  13320. ok:=true;
  13321. finally
  13322. if not ok then Result.Free;
  13323. end;
  13324. end;
  13325. function TPasToJSConverter.CreateAssignStatement(LeftEl: TPasElement;
  13326. AssignContext: TAssignContext): TJSElement;
  13327. var
  13328. LHS: TJSElement;
  13329. AssignSt: TJSSimpleAssignStatement;
  13330. begin
  13331. Result:=nil;
  13332. LHS:=ConvertElement(LeftEl,AssignContext);
  13333. if AssignContext.Call<>nil then
  13334. begin
  13335. // has a setter -> right side was already added as parameter
  13336. if AssignContext.RightSide<>nil then
  13337. begin
  13338. LHS.Free;
  13339. RaiseInconsistency(20170207215447,LeftEl);
  13340. end;
  13341. Result:=LHS;
  13342. end
  13343. else
  13344. begin
  13345. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,AssignContext.PasElement));
  13346. AssignSt.LHS:=LHS;
  13347. AssignSt.Expr:=AssignContext.RightSide;
  13348. AssignContext.RightSide:=nil;
  13349. Result:=AssignSt;
  13350. end;
  13351. end;
  13352. function TPasToJSConverter.CreateGetEnumeratorLoop(El: TPasImplForLoop;
  13353. AContext: TConvertContext): TJSElement;
  13354. // for Item in List do
  13355. // convert to
  13356. // var $in=List.GetEnumerator();
  13357. // try{
  13358. // while ($in.MoveNext()){
  13359. // Item=$in.getCurrent;
  13360. // // code
  13361. // }
  13362. // } finally {
  13363. // $in=rtl.freeLoc($in);
  13364. // };
  13365. var
  13366. PosEl: TPasElement;
  13367. CurInVarName: String;
  13368. function CreateInName: TJSElement;
  13369. var
  13370. Ident: TJSPrimaryExpressionIdent;
  13371. begin
  13372. Ident:=TJSPrimaryExpressionIdent(CreateElement(TJSPrimaryExpressionIdent,PosEl));
  13373. Ident.Name:=TJSString(CurInVarName); // do not lowercase
  13374. Result:=Ident;
  13375. end;
  13376. var
  13377. ForScope: TPasForLoopScope;
  13378. Statements: TJSStatementList;
  13379. VarSt: TJSVariableStatement;
  13380. FuncContext: TConvertContext;
  13381. List, GetCurrent, J: TJSElement;
  13382. Call: TJSCallExpression;
  13383. TrySt: TJSTryFinallyStatement;
  13384. WhileSt: TJSWhileStatement;
  13385. AssignSt: TJSSimpleAssignStatement;
  13386. GetEnumeratorFunc, MoveNextFunc: TPasFunction;
  13387. CurrentProp: TPasProperty;
  13388. DotContext: TDotContext;
  13389. ResolvedEl: TPasResolverResult;
  13390. EnumeratorTypeEl: TPasType;
  13391. NeedTryFinally, NeedIntfRef: Boolean;
  13392. begin
  13393. ForScope:=TPasForLoopScope(El.CustomData);
  13394. NeedTryFinally:=true;
  13395. NeedIntfRef:=false;
  13396. // find function GetEnumerator
  13397. GetEnumeratorFunc:=ForScope.GetEnumerator;
  13398. if (GetEnumeratorFunc=nil) then
  13399. RaiseNotSupported(El,AContext,20171225104212);
  13400. if GetEnumeratorFunc.ClassType<>TPasFunction then
  13401. RaiseNotSupported(El,AContext,20171225104237);
  13402. AContext.Resolver.ComputeElement(GetEnumeratorFunc.FuncType.ResultEl,ResolvedEl,[rcType]);
  13403. EnumeratorTypeEl:=ResolvedEl.LoTypeEl;
  13404. if EnumeratorTypeEl is TPasClassType then
  13405. begin
  13406. case TPasClassType(EnumeratorTypeEl).ObjKind of
  13407. okClass: ;
  13408. okInterface:
  13409. case TPasClassType(EnumeratorTypeEl).InterfaceType of
  13410. citCom: NeedIntfRef:=true;
  13411. citCorba: NeedTryFinally:=false;
  13412. else
  13413. RaiseNotSupported(El.VariableName,AContext,20180328192842);
  13414. end;
  13415. else
  13416. RaiseNotSupported(El.VariableName,AContext,20180328192452);
  13417. end;
  13418. end;
  13419. // find function MoveNext
  13420. MoveNextFunc:=ForScope.MoveNext;
  13421. if (MoveNextFunc=nil) then
  13422. RaiseNotSupported(El,AContext,20171225104249);
  13423. if MoveNextFunc.ClassType<>TPasFunction then
  13424. RaiseNotSupported(El,AContext,20171225104256);
  13425. // find property Current
  13426. CurrentProp:=ForScope.Current;
  13427. if (CurrentProp=nil) then
  13428. RaiseNotSupported(El,AContext,20171225104306);
  13429. if CurrentProp.ClassType<>TPasProperty then
  13430. RaiseNotSupported(El,AContext,20171225104316);
  13431. // get function context
  13432. FuncContext:=AContext;
  13433. while (FuncContext.Parent<>nil) and (not (FuncContext is TFunctionContext)) do
  13434. FuncContext:=FuncContext.Parent;
  13435. PosEl:=El;
  13436. Statements:=TJSStatementList(CreateElement(TJSStatementList,PosEl));
  13437. DotContext:=nil;
  13438. try
  13439. // var...
  13440. VarSt:=TJSVariableStatement(CreateElement(TJSVariableStatement,PosEl));
  13441. Statements.A:=VarSt;
  13442. // List
  13443. List:=ConvertElement(El.StartExpr,AContext); // beware: might fail
  13444. PosEl:=El.StartExpr;
  13445. // List.GetEnumerator()
  13446. Call:=TJSCallExpression(CreateElement(TJSCallExpression,PosEl));
  13447. Call.Expr:=CreateDotExpression(PosEl,List,
  13448. CreateIdentifierExpr(GetEnumeratorFunc,AContext),true);
  13449. // var $in=
  13450. CurInVarName:=FuncContext.CreateLocalIdentifier(FBuiltInNames[pbivnLoopIn]);
  13451. VarSt.A:=CreateVarDecl(CurInVarName,Call,PosEl);
  13452. PosEl:=El.VariableName;
  13453. TrySt:=nil;
  13454. if NeedTryFinally then
  13455. begin
  13456. // try()
  13457. TrySt:=TJSTryFinallyStatement(CreateElement(TJSTryFinallyStatement,PosEl));
  13458. Statements.B:=TrySt;
  13459. end;
  13460. // while ()
  13461. WhileSt:=TJSWhileStatement(CreateElement(TJSWhileStatement,PosEl));
  13462. if TrySt<>nil then
  13463. TrySt.Block:=WhileSt
  13464. else
  13465. Statements.B:=WhileSt;
  13466. // $in.MoveNext()
  13467. Call:=TJSCallExpression(CreateElement(TJSCallExpression,PosEl));
  13468. WhileSt.Cond:=Call;
  13469. Call.Expr:=CreateDotExpression(PosEl,CreateInName,
  13470. CreateIdentifierExpr(MoveNextFunc,AContext));
  13471. // Item=$in.GetCurrent();
  13472. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,PosEl));
  13473. WhileSt.Body:=AssignSt;
  13474. AssignSt.LHS:=ConvertElement(El.VariableName,AContext); // beware: might fail
  13475. DotContext:=TDotContext.Create(El.StartExpr,nil,AContext);
  13476. try
  13477. GetCurrent:=CreatePropertyGet(CurrentProp,nil,DotContext,PosEl); // beware: might fail
  13478. if DotContext.JS<>nil then
  13479. RaiseNotSupported(El,AContext,20180509134302,GetObjName(DotContext.JS));
  13480. finally
  13481. FreeAndNil(DotContext);
  13482. end;
  13483. AssignSt.Expr:=CreateDotExpression(PosEl,CreateInName,GetCurrent,true);
  13484. // add body
  13485. if El.Body<>nil then
  13486. begin
  13487. J:=ConvertElement(El.Body,AContext); // beware: might fail
  13488. if J<>nil then
  13489. begin
  13490. List:=TJSStatementList(CreateElement(TJSStatementList,PosEl));
  13491. TJSStatementList(List).A:=WhileSt.Body;
  13492. TJSStatementList(List).B:=J;
  13493. WhileSt.Body:=List;
  13494. end;
  13495. end;
  13496. PosEl:=El.StartExpr;
  13497. if TrySt<>nil then
  13498. begin
  13499. // finally{ $in=rtl.freeLoc($in) }
  13500. if NeedIntfRef then
  13501. begin
  13502. Call:=CreateCallExpression(PosEl);
  13503. TrySt.BFinally:=Call;
  13504. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnIntf_Release]]);
  13505. Call.AddArg(CreateInName);
  13506. end
  13507. else
  13508. TrySt.BFinally:=CreateCallRTLFreeLoc(CreateInName,CreateInName,PosEl);
  13509. end;
  13510. Result:=Statements;
  13511. finally
  13512. DotContext.Free;
  13513. if Result=nil then
  13514. Statements.Free;
  13515. end;
  13516. end;
  13517. function TPasToJSConverter.CreateCallRTLFreeLoc(Setter, Getter: TJSElement;
  13518. Src: TPasElement): TJSElement;
  13519. // create "Setter=rtl.freeLoc(Getter)"
  13520. var
  13521. Call: TJSCallExpression;
  13522. AssignSt: TJSSimpleAssignStatement;
  13523. begin
  13524. Call:=CreateCallExpression(Src);
  13525. Call.Expr:=CreateMemberExpression([GetBuildInNames(pbivnRTL),GetBuildInNames(pbifnFreeLocalVar)]);
  13526. Call.Args.AddElement(Getter);
  13527. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,Src));
  13528. AssignSt.LHS:=Setter;
  13529. AssignSt.Expr:=Call;
  13530. Result:=AssignSt;
  13531. end;
  13532. function TPasToJSConverter.CreatePropertyGet(Prop: TPasProperty;
  13533. Ref: TResolvedReference; AContext: TConvertContext; PosEl: TPasElement
  13534. ): TJSElement;
  13535. var
  13536. aResolver: TPas2JSResolver;
  13537. Decl: TPasElement;
  13538. IndexExpr: TPasExpr;
  13539. Call: TJSCallExpression;
  13540. Value: TResEvalValue;
  13541. Name: String;
  13542. TypeEl: TPasType;
  13543. begin
  13544. aResolver:=AContext.Resolver;
  13545. Decl:=aResolver.GetPasPropertyGetter(Prop);
  13546. if Decl is TPasFunction then
  13547. begin
  13548. // call function
  13549. Value:=nil;
  13550. Call:=CreateCallExpression(PosEl);
  13551. try
  13552. Call.Expr:=CreateReferencePathExpr(Decl,AContext,false,Ref);
  13553. IndexExpr:=aResolver.GetPasPropertyIndex(Prop);
  13554. if IndexExpr<>nil then
  13555. begin
  13556. Value:=aResolver.Eval(IndexExpr,[refConst]);
  13557. Call.AddArg(ConvertConstValue(Value,AContext.GetFunctionContext,PosEl));
  13558. end;
  13559. TypeEl:=aResolver.GetPasPropertyType(Prop);
  13560. if aResolver.IsInterfaceType(TypeEl,citCom) then
  13561. Call:=CreateIntfRef(Call,AContext,PosEl);
  13562. Result:=Call;
  13563. finally
  13564. ReleaseEvalValue(Value);
  13565. if Result=nil then
  13566. Call.Free;
  13567. end;
  13568. end
  13569. else
  13570. begin
  13571. // read field
  13572. Name:=CreateReferencePath(Decl,AContext,rpkPathAndName,false,Ref);
  13573. Result:=CreatePrimitiveDotExpr(Name,PosEl);
  13574. end;
  13575. end;
  13576. function TPasToJSConverter.CreatePrecompiledJS(El: TJSElement): string;
  13577. var
  13578. aWriter: TBufferWriter;
  13579. aJSWriter: TJSWriter;
  13580. begin
  13581. aJSWriter:=nil;
  13582. aWriter:=TBufferWriter.Create(1000);
  13583. try
  13584. aJSWriter:=TJSWriter.Create(aWriter);
  13585. aJSWriter.Options:=DefaultJSWriterOptions;
  13586. aJSWriter.IndentSize:=2;
  13587. aJSWriter.WriteJS(El);
  13588. Result:=aWriter.AsString;
  13589. finally
  13590. aJSWriter.Free;
  13591. aWriter.Free;
  13592. end;
  13593. end;
  13594. function TPasToJSConverter.CreateArrayInit(ArrayType: TPasArrayType;
  13595. Expr: TPasExpr; El: TPasElement; AContext: TConvertContext): TJSElement;
  13596. function ConvertArrayExpr(CurArrType: TPasArrayType; RgIndex: integer;
  13597. CurExpr: TPasExpr): TJSElement;
  13598. var
  13599. NextArrType: TPasArrayType;
  13600. NextRgIndex: integer;
  13601. IsLastRange: boolean;
  13602. function ConvertSubExpr(SubExpr: TPasExpr): TJSElement;
  13603. begin
  13604. if IsLastRange then
  13605. Result:=ConvertElement(SubExpr,AContext)
  13606. else
  13607. Result:=ConvertArrayExpr(NextArrType,NextRgIndex,SubExpr);
  13608. end;
  13609. function ConvertSubValues(ExprArray: TPasExprArray): TJSArrayLiteral;
  13610. var
  13611. i: Integer;
  13612. JS: TJSElement;
  13613. Param: TPasExpr;
  13614. begin
  13615. Result:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,El));
  13616. for i:=0 to length(ExprArray)-1 do
  13617. begin
  13618. Param:=ExprArray[i];
  13619. JS:=ConvertSubExpr(Param);
  13620. JS:=CreateArrayEl(Param,JS,AContext);
  13621. Result.Elements.AddElement.Expr:=JS;
  13622. end;
  13623. end;
  13624. function IsAdd(AnExpr: TPasExpr): Boolean;
  13625. begin
  13626. Result:=(AnExpr.ClassType=TBinaryExpr) and (AnExpr.OpCode=eopAdd);
  13627. end;
  13628. procedure TraverseAdd(Bin: TBinaryExpr; ConcatCall: TJSCallExpression);
  13629. // A+B -> A,B
  13630. // (A+B)+C -> A,B,C
  13631. begin
  13632. if IsAdd(Bin.left) then
  13633. TraverseAdd(TBinaryExpr(Bin.left),ConcatCall)
  13634. else
  13635. ConcatCall.AddArg(ConvertArrayExpr(NextArrType,NextRgIndex,Bin.left));
  13636. if IsAdd(Bin.right) then
  13637. TraverseAdd(TBinaryExpr(Bin.right),ConcatCall)
  13638. else
  13639. ConcatCall.AddArg(ConvertArrayExpr(NextArrType,NextRgIndex,Bin.right));
  13640. end;
  13641. var
  13642. ElTypeResolved: TPasResolverResult;
  13643. Call: TJSCallExpression;
  13644. begin
  13645. Result:=nil;
  13646. IsLastRange:=false;
  13647. NextArrType:=CurArrType;
  13648. NextRgIndex:=RgIndex+1;
  13649. if RgIndex>=length(CurArrType.Ranges)-1 then
  13650. begin
  13651. AContext.Resolver.ComputeElement(CurArrType.ElType,ElTypeResolved,[rcType]);
  13652. if (ElTypeResolved.BaseType=btContext)
  13653. and (ElTypeResolved.LoTypeEl.ClassType=TPasArrayType) then
  13654. begin
  13655. NextArrType:=TPasArrayType(ElTypeResolved.LoTypeEl);
  13656. NextRgIndex:=0;
  13657. end
  13658. else
  13659. IsLastRange:=true;
  13660. end;
  13661. if CurExpr.ClassType=TArrayValues then
  13662. begin
  13663. // (...,...)
  13664. Result:=ConvertSubValues(TArrayValues(CurExpr).Values);
  13665. exit;
  13666. end
  13667. else if (CurExpr.ClassType=TParamsExpr) and (TParamsExpr(CurExpr).Kind=pekSet) then
  13668. begin
  13669. // [...,...]
  13670. Result:=ConvertSubValues(TParamsExpr(CurExpr).Params);
  13671. exit;
  13672. end
  13673. else if IsAdd(CurExpr) then
  13674. begin
  13675. // A+B -> rtl.arrayConcat(null,A,B)
  13676. Call:=CreateArrayConcat(ArrayType,CurExpr,AContext);
  13677. try
  13678. TraverseAdd(TBinaryExpr(CurExpr),Call);
  13679. Result:=Call;
  13680. finally
  13681. if Result=nil then
  13682. Call.Free;
  13683. end;
  13684. exit;
  13685. end;
  13686. // use default, e.g. a.b or c[...] or copy(...)
  13687. Result:=ConvertElement(CurExpr,AContext);
  13688. end;
  13689. var
  13690. Call: TJSCallExpression;
  13691. ArrLit: TJSArrayLiteral;
  13692. i, DimSize: Integer;
  13693. RangeResolved, ElTypeResolved, ExprResolved: TPasResolverResult;
  13694. Range: TPasExpr;
  13695. Lit: TJSLiteral;
  13696. CurArrayType: TPasArrayType;
  13697. DefaultValue: TJSElement;
  13698. US: TJSString;
  13699. DimLits: TObjectList;
  13700. aResolver: TPas2JSResolver;
  13701. CompFlags: TPasResolverComputeFlags;
  13702. begin
  13703. {$IFDEF VerbosePas2JS}
  13704. writeln('TPasToJSConverter.CreateArrayInit ',GetObjName(ArrayType),' ',ArrayType.ParentPath,' Expr=',GetObjName(Expr));
  13705. {$ENDIF}
  13706. aResolver:=AContext.Resolver;
  13707. if Assigned(Expr) then
  13708. begin
  13709. // init array with constant(s)
  13710. if aResolver=nil then
  13711. DoError(20161024192739,nInitializedArraysNotSupported,sInitializedArraysNotSupported,[],ArrayType);
  13712. if aResolver.ExprEvaluator.IsConst(Expr) then
  13713. CompFlags:=[rcConstant]
  13714. else
  13715. CompFlags:=[];
  13716. aResolver.ComputeElement(Expr,ExprResolved,CompFlags);
  13717. if (ExprResolved.BaseType in [btArrayOrSet,btArrayLit])
  13718. or ((ExprResolved.BaseType=btContext)
  13719. and (ExprResolved.LoTypeEl.ClassType=TPasArrayType)) then
  13720. Result:=ConvertArrayExpr(ArrayType,0,Expr)
  13721. else if ExprResolved.BaseType in btAllStringAndChars then
  13722. begin
  13723. US:=StrToJSString(aResolver.ComputeConstString(Expr,false,true));
  13724. ArrLit:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,El));
  13725. Result:=ArrLit;
  13726. for i:=1 to length(US) do
  13727. ArrLit.Elements.AddElement.Expr:=CreateLiteralJSString(Expr,US[i]);
  13728. end
  13729. else
  13730. RaiseNotSupported(Expr,AContext,20170223133034);
  13731. end
  13732. else if length(ArrayType.Ranges)=0 then
  13733. begin
  13734. // empty dynamic array: []
  13735. Result:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,El));
  13736. end
  13737. else
  13738. begin
  13739. // static array
  13740. // create "rtl.arraySetLength(null,defaultvalue,dim1,dim2,...)"
  13741. if aResolver=nil then
  13742. RaiseNotSupported(El,AContext,20170223113050,'');
  13743. Result:=nil;
  13744. DimLits:=TObjectList.Create(true);
  13745. try
  13746. Call:=CreateCallExpression(El);
  13747. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnArray_SetLength]]);
  13748. // add parameter null
  13749. Call.AddArg(CreateLiteralNull(El));
  13750. // create parameters dim1,dim2,...
  13751. CurArrayType:=ArrayType;
  13752. while true do
  13753. begin
  13754. for i:=0 to length(CurArrayType.Ranges)-1 do
  13755. begin
  13756. Range:=CurArrayType.Ranges[i];
  13757. // compute size of this dimension
  13758. DimSize:=aResolver.GetRangeLength(Range);
  13759. if DimSize=0 then
  13760. begin
  13761. aResolver.ComputeElement(Range,RangeResolved,[rcConstant]);
  13762. RaiseNotSupported(Range,AContext,20170223113318,GetResolverResultDbg(RangeResolved));
  13763. end;
  13764. Lit:=CreateLiteralNumber(El,DimSize);
  13765. DimLits.Add(Lit);
  13766. end;
  13767. aResolver.ComputeElement(CurArrayType.ElType,ElTypeResolved,[rcType]);
  13768. if (ElTypeResolved.LoTypeEl is TPasArrayType) then
  13769. begin
  13770. CurArrayType:=TPasArrayType(ElTypeResolved.LoTypeEl);
  13771. if length(CurArrayType.Ranges)>0 then
  13772. begin
  13773. // nested static array
  13774. continue;
  13775. end;
  13776. end;
  13777. break;
  13778. end;
  13779. // add parameter defaultvalue
  13780. if ElTypeResolved.LoTypeEl is TPasRecordType then
  13781. begin
  13782. // array of record -> push the type reference
  13783. DefaultValue:=CreateReferencePathExpr(ElTypeResolved.LoTypeEl,AContext);
  13784. end
  13785. else
  13786. DefaultValue:=CreateValInit(ElTypeResolved.LoTypeEl,nil,El,AContext);
  13787. Call.AddArg(DefaultValue);
  13788. // add parameters dim1,dim2,...
  13789. for i:=0 to DimLits.Count-1 do
  13790. Call.AddArg(TJSElement(DimLits[i]));
  13791. DimLits.OwnsObjects:=false;
  13792. DimLits.Clear;
  13793. Result:=Call;
  13794. finally
  13795. DimLits.Free;
  13796. if Result=nil then
  13797. Call.Free;
  13798. end;
  13799. end;
  13800. if Result=nil then
  13801. RaiseInconsistency(20180617233317,Expr);
  13802. end;
  13803. function TPasToJSConverter.CreateCmpArrayWithNil(El: TPasElement;
  13804. JSArray: TJSElement; OpCode: TExprOpCode): TJSElement;
  13805. // convert "array = nil" to "rtl.length(array) > 0"
  13806. // convert "array <> nil" to "rtl.length(array) === 0"
  13807. var
  13808. Call: TJSCallExpression;
  13809. BinExpr: TJSBinaryExpression;
  13810. begin
  13811. if not (OpCode in [eopEqual,eopNotEqual]) then
  13812. RaiseInconsistency(20170401184819,El);
  13813. Call:=CreateCallExpression(El);
  13814. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnArray_Length]]);
  13815. Call.AddArg(JSArray);
  13816. if OpCode=eopEqual then
  13817. BinExpr:=TJSEqualityExpressionSEQ(CreateElement(TJSEqualityExpressionSEQ,El))
  13818. else
  13819. BinExpr:=TJSRelationalExpressionGT(CreateElement(TJSRelationalExpressionGT,El));
  13820. BinExpr.A:=Call;
  13821. BinExpr.B:=CreateLiteralNumber(El,0);
  13822. Result:=BinExpr;
  13823. end;
  13824. function TPasToJSConverter.CreateCloneStaticArray(El: TPasElement;
  13825. ArrTypeEl: TPasArrayType; ArrayExpr: TJSElement; AContext: TConvertContext
  13826. ): TJSElement;
  13827. var
  13828. Call: TJSCallExpression;
  13829. Path: String;
  13830. FuncContext: TFunctionContext;
  13831. DotExpr: TJSDotMemberExpression;
  13832. i: TMaxPrecInt;
  13833. JSExpr: TJSElement;
  13834. begin
  13835. if ArrayExpr is TJSArrayLiteral then
  13836. exit(ArrayExpr);
  13837. if AContext.Resolver.HasStaticArrayCloneFunc(ArrTypeEl) then
  13838. begin
  13839. // TArrayType$clone(ArrayExpr);
  13840. if ArrTypeEl.Name='' then
  13841. RaiseNotSupported(El,AContext,20180218230407,'copy anonymous multi dim static array');
  13842. if length(ArrTypeEl.Ranges)>1 then
  13843. RaiseNotSupported(El,AContext,20180218231700,'copy multi dim static array');
  13844. FuncContext:=AContext.GetFunctionContext;
  13845. Path:=CreateReferencePath(ArrTypeEl,FuncContext,rpkPathAndName)
  13846. +FBuiltInNames[pbifnArray_Static_Clone];
  13847. Call:=CreateCallExpression(El);
  13848. Call.Expr:=CreatePrimitiveDotExpr(Path,El);
  13849. Call.AddArg(ArrayExpr);
  13850. Result:=Call;
  13851. end
  13852. else
  13853. begin
  13854. // ArrayExpr.slice(0)
  13855. if ArrayExpr is TJSCallExpression then
  13856. begin
  13857. Call:=TJSCallExpression(ArrayExpr);
  13858. if Call.Expr is TJSDotMemberExpression then
  13859. begin
  13860. DotExpr:=TJSDotMemberExpression(Call.Expr);
  13861. if (DotExpr.Name='slice') and (Call.Args<>nil)
  13862. and (Call.Args.Elements.Count=1) then
  13863. begin
  13864. JSExpr:=Call.Args.Elements[0].Expr;
  13865. if IsLiteralInteger(JSExpr,i) and (i=0) then
  13866. exit(Call); // is already ".slice(0)"
  13867. end;
  13868. end;
  13869. end;
  13870. Call:=CreateCallExpression(El);
  13871. Call.Expr:=CreateDotExpression(El,ArrayExpr,CreatePrimitiveDotExpr('slice',El));
  13872. Call.AddArg(CreateLiteralNumber(El,0));
  13873. Result:=Call;
  13874. end;
  13875. end;
  13876. function TPasToJSConverter.CreateTypeInfoRef(El: TPasType;
  13877. AContext: TConvertContext; ErrorEl: TPasElement): TJSElement;
  13878. var
  13879. aName, aModName: String;
  13880. CurEl: TPasElement;
  13881. aModule: TPasModule;
  13882. Bracket: TJSBracketMemberExpression;
  13883. begin
  13884. El:=ResolveSimpleAliasType(El);
  13885. aName:=GetTypeInfoName(El,AContext,ErrorEl);
  13886. if aName=FBuiltInNames[pbivnRTTILocal] then
  13887. Result:=CreatePrimitiveDotExpr(aName,El)
  13888. else if LeftStr(aName,length(FBuiltInNames[pbivnRTL])+1)=FBuiltInNames[pbivnRTL]+'.' then
  13889. Result:=CreatePrimitiveDotExpr(aName,El)
  13890. else
  13891. begin
  13892. CurEl:=El;
  13893. while CurEl<>nil do
  13894. begin
  13895. if CurEl is TPasSection then
  13896. begin
  13897. aModule:=CurEl.Parent as TPasModule;
  13898. aModName:=AContext.GetLocalName(aModule);
  13899. if aModName='' then
  13900. aModName:=TransformModuleName(aModule,true,AContext);
  13901. Bracket:=TJSBracketMemberExpression(CreateElement(TJSBracketMemberExpression,El));
  13902. Bracket.MExpr:=CreateMemberExpression([aModName,FBuiltInNames[pbivnRTTI]]);
  13903. Bracket.Name:=CreateLiteralString(El,aName);
  13904. Result:=Bracket;
  13905. exit;
  13906. end;
  13907. CurEl:=CurEl.Parent;
  13908. end;
  13909. // not supported
  13910. aName:=El.Name;
  13911. if aName='' then aName:=El.ClassName;
  13912. DoError(20170905152041,nTypeXCannotBePublished,sTypeXCannotBePublished,
  13913. [aName],ErrorEl);
  13914. end;
  13915. end;
  13916. function TPasToJSConverter.CreateRTTIArgList(Parent: TPasElement;
  13917. Args: TFPList; AContext: TConvertContext): TJSElement;
  13918. var
  13919. Params: TJSArrayLiteral;
  13920. i: Integer;
  13921. begin
  13922. Result:=nil;
  13923. if Args.Count=0 then
  13924. Result:=CreateLiteralNull(Parent)
  13925. else
  13926. begin
  13927. try
  13928. Params:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,Parent));
  13929. for i:=0 to Args.Count-1 do
  13930. AddRTTIArgument(TPasArgument(Args[i]),Params,AContext);
  13931. Result:=Params;
  13932. finally
  13933. if Result=nil then
  13934. Params.Free;
  13935. end;
  13936. end;
  13937. end;
  13938. procedure TPasToJSConverter.AddRTTIArgument(Arg: TPasArgument;
  13939. TargetParams: TJSArrayLiteral; AContext: TConvertContext);
  13940. var
  13941. Param: TJSArrayLiteral;
  13942. ArgName: String;
  13943. Flags: Integer;
  13944. ArrType: TPasArrayType;
  13945. begin
  13946. // for each param add "["argname",argtype,flags]" Note: flags only if >0
  13947. Param:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,Arg));
  13948. TargetParams.Elements.AddElement.Expr:=Param;
  13949. // add "argname"
  13950. ArgName:=TransformVariableName(Arg,Arg.Name,true,AContext);
  13951. Param.Elements.AddElement.Expr:=CreateLiteralString(Arg,ArgName);
  13952. Flags:=0;
  13953. // add "argtype"
  13954. if Arg.ArgType=nil then
  13955. // untyped
  13956. Param.Elements.AddElement.Expr:=CreateLiteralNull(Arg)
  13957. else if (Arg.ArgType.Name='') and (Arg.ArgType.ClassType=TPasArrayType) then
  13958. begin
  13959. // open array param
  13960. inc(Flags,pfArray);
  13961. ArrType:=TPasArrayType(Arg.ArgType);
  13962. Param.Elements.AddElement.Expr:=CreateTypeInfoRef(ArrType.ElType,AContext,Arg);
  13963. end
  13964. else
  13965. Param.Elements.AddElement.Expr:=CreateTypeInfoRef(Arg.ArgType,AContext,Arg);
  13966. // add flags
  13967. case Arg.Access of
  13968. argDefault: ;
  13969. argConst: inc(Flags,pfConst);
  13970. argVar: inc(Flags,pfVar);
  13971. argOut: inc(Flags,pfOut);
  13972. else
  13973. RaiseNotSupported(Arg,AContext,20170409192127,AccessNames[Arg.Access]);
  13974. end;
  13975. if Flags>0 then
  13976. Param.Elements.AddElement.Expr:=CreateLiteralNumber(Arg,Flags);
  13977. end;
  13978. function TPasToJSConverter.CreateRTTINewType(El: TPasType;
  13979. const CallFuncName: string; IsForward: boolean; AContext: TConvertContext;
  13980. out ObjLit: TJSObjectLiteral): TJSCallExpression;
  13981. // module.$rtti.$Something("name",{})
  13982. var
  13983. RttiPath, TypeName: String;
  13984. Call: TJSCallExpression;
  13985. aModule: TPasModule;
  13986. begin
  13987. Result:=nil;
  13988. ObjLit:=nil;
  13989. // get module path
  13990. aModule:=El.GetModule;
  13991. if aModule=nil then
  13992. RaiseInconsistency(20170418115552,El);
  13993. RttiPath:=AContext.GetLocalName(aModule);
  13994. if RttiPath='' then
  13995. RttiPath:=TransformModuleName(aContext.GetRootModule,true,AContext);
  13996. Call:=CreateCallExpression(El);
  13997. try
  13998. // module.$rtti.$Something
  13999. Call.Expr:=CreateMemberExpression([RttiPath,FBuiltInNames[pbivnRTTI],CallFuncName]);
  14000. // add param "typename"
  14001. TypeName:=GetTypeInfoName(El,AContext,El);
  14002. Call.AddArg(CreateLiteralString(El,TypeName));
  14003. if El is TPasTypeAliasType then
  14004. begin
  14005. // add desttype
  14006. Call.AddArg(CreateTypeInfoRef(TPasTypeAliasType(El).DestType,AContext,El));
  14007. end;
  14008. if not IsForward then
  14009. begin
  14010. // add {}
  14011. ObjLit:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,El));
  14012. Call.AddArg(ObjLit);
  14013. end;
  14014. Result:=Call;
  14015. finally
  14016. if Result=nil then
  14017. Call.Free;
  14018. end;
  14019. end;
  14020. function TPasToJSConverter.CreateRTTIClassField(V: TPasVariable;
  14021. AContext: TConvertContext): TJSElement;
  14022. // create $r.addField("varname",typeinfo);
  14023. var
  14024. Call: TJSCallExpression;
  14025. var
  14026. JSTypeInfo: TJSElement;
  14027. aName: String;
  14028. begin
  14029. Result:=nil;
  14030. JSTypeInfo:=CreateTypeInfoRef(V.VarType,AContext,V);
  14031. // Note: create JSTypeInfo first, it may raise an exception
  14032. Call:=CreateCallExpression(V);
  14033. // $r.addField
  14034. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTTILocal],FBuiltInNames[pbifnRTTIAddField]]);
  14035. // param "varname"
  14036. aName:=TransformVariableName(V,AContext);
  14037. Call.AddArg(CreateLiteralString(V,aName));
  14038. // param typeinfo
  14039. Call.AddArg(JSTypeInfo);
  14040. Result:=Call;
  14041. end;
  14042. function TPasToJSConverter.CreateRTTIClassMethod(Proc: TPasProcedure;
  14043. AContext: TConvertContext): TJSElement;
  14044. // create $r.addMethod("funcname",methodkind,params,resulttype,options)
  14045. var
  14046. OptionsEl: TJSObjectLiteral;
  14047. ResultTypeInfo: TJSElement;
  14048. Call: TJSCallExpression;
  14049. procedure AddOption(const aName: String; JS: TJSElement);
  14050. var
  14051. ObjLit: TJSObjectLiteralElement;
  14052. begin
  14053. if OptionsEl=nil then
  14054. begin
  14055. OptionsEl:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,Proc));
  14056. if ResultTypeInfo=nil then
  14057. Call.AddArg(CreateLiteralNull(Proc));
  14058. Call.AddArg(OptionsEl);
  14059. end;
  14060. ObjLit:=OptionsEl.Elements.AddElement;
  14061. ObjLit.Name:=TJSString(aName);
  14062. ObjLit.Expr:=JS;
  14063. end;
  14064. var
  14065. FunName: String;
  14066. C: TClass;
  14067. MethodKind, Flags: Integer;
  14068. ResultEl: TPasResultElement;
  14069. ProcScope, OverriddenProcScope: TPasProcedureScope;
  14070. OverriddenClass: TPasClassType;
  14071. begin
  14072. Result:=nil;
  14073. if Proc.IsOverride then
  14074. begin
  14075. ProcScope:=Proc.CustomData as TPasProcedureScope;
  14076. if ProcScope.OverriddenProc.Visibility=visPublished then
  14077. begin
  14078. // overridden proc is published as well
  14079. OverriddenProcScope:=ProcScope.OverriddenProc.CustomData as TPasProcedureScope;
  14080. OverriddenClass:=OverriddenProcScope.ClassScope.Element as TPasClassType;
  14081. if HasTypeInfo(OverriddenClass,AContext) then
  14082. exit; // overridden proc was already published in ancestor
  14083. end;
  14084. end;
  14085. OptionsEl:=nil;
  14086. ResultTypeInfo:=nil;
  14087. try
  14088. // $r.addMethod
  14089. Call:=CreateCallExpression(Proc);
  14090. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTTILocal],FBuiltInNames[pbifnRTTIAddMethod]]);
  14091. // param "funname"
  14092. FunName:=TransformVariableName(Proc,AContext);
  14093. Call.AddArg(CreateLiteralString(Proc,FunName));
  14094. // param methodkind as number
  14095. C:=Proc.ClassType;
  14096. if C=TPasProcedure then
  14097. MethodKind:=ord(mkProcedure)
  14098. else if C=TPasFunction then
  14099. MethodKind:=ord(mkFunction)
  14100. else if C=TPasConstructor then
  14101. MethodKind:=ord(mkConstructor)
  14102. else if C=TPasDestructor then
  14103. MethodKind:=ord(mkDestructor)
  14104. else if C=TPasClassProcedure then
  14105. MethodKind:=ord(mkClassProcedure)
  14106. else if C=TPasClassFunction then
  14107. MethodKind:=ord(mkClassFunction)
  14108. else
  14109. RaiseNotSupported(Proc,AContext,20170409190242);
  14110. Call.AddArg(CreateLiteralNumber(Proc,MethodKind));
  14111. // param params as []
  14112. Call.AddArg(CreateRTTIArgList(Proc,Proc.ProcType.Args,AContext));
  14113. // param resulttype as typeinfo reference
  14114. if C.InheritsFrom(TPasFunction) then
  14115. begin
  14116. ResultEl:=TPasFunction(Proc).FuncType.ResultEl;
  14117. ResultTypeInfo:=CreateTypeInfoRef(ResultEl.ResultType,AContext,ResultEl);
  14118. if ResultTypeInfo<>nil then
  14119. Call.AddArg(ResultTypeInfo);
  14120. end;
  14121. // param options if needed as {}
  14122. Flags:=0;
  14123. if Proc.IsStatic then
  14124. inc(Flags,pfStatic);
  14125. if ptmVarargs in Proc.ProcType.Modifiers then
  14126. inc(Flags,pfVarargs);
  14127. if Proc.IsExternal then
  14128. inc(Flags,pfExternal);
  14129. if Flags>0 then
  14130. AddOption(FBuiltInNames[pbivnRTTIProcFlags],CreateLiteralNumber(Proc,Flags));
  14131. Result:=Call;
  14132. finally
  14133. if Result=nil then
  14134. Call.Free;
  14135. end;
  14136. end;
  14137. function TPasToJSConverter.CreateRTTIClassProperty(Prop: TPasProperty;
  14138. AContext: TConvertContext): TJSElement;
  14139. // create $r.addProperty("propname",flags,result,"getter","setter",{options})
  14140. var
  14141. Call: TJSCallExpression;
  14142. OptionsEl: TJSObjectLiteral;
  14143. function GetAccessorName(Decl: TPasElement): String;
  14144. begin
  14145. Result:=TransformVariableName(Decl,AContext);
  14146. end;
  14147. procedure AddOption(const aName: String; JS: TJSElement);
  14148. var
  14149. ObjLit: TJSObjectLiteralElement;
  14150. begin
  14151. if OptionsEl=nil then
  14152. begin
  14153. OptionsEl:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,Prop));
  14154. Call.AddArg(OptionsEl);
  14155. end;
  14156. ObjLit:=OptionsEl.Elements.AddElement;
  14157. ObjLit.Name:=TJSString(aName);
  14158. ObjLit.Expr:=JS;
  14159. end;
  14160. var
  14161. PropName: String;
  14162. Flags: Integer;
  14163. GetterPas, SetterPas, DeclEl: TPasElement;
  14164. ResultTypeInfo, DefValue: TJSElement;
  14165. VarType: TPasType;
  14166. StoredExpr, IndexExpr, DefaultExpr: TPasExpr;
  14167. StoredResolved, VarTypeResolved: TPasResolverResult;
  14168. StoredValue, PasValue, IndexValue: TResEvalValue;
  14169. aResolver: TPas2JSResolver;
  14170. begin
  14171. Result:=nil;
  14172. aResolver:=AContext.Resolver;
  14173. OptionsEl:=nil;
  14174. try
  14175. // $r.addProperty
  14176. Call:=CreateCallExpression(Prop);
  14177. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTTILocal],FBuiltInNames[pbifnRTTIAddProperty]]);
  14178. // param "propname"
  14179. PropName:=TransformVariableName(Prop,Prop.Name,false,AContext);
  14180. Call.AddArg(CreateLiteralString(Prop,PropName));
  14181. // add flags
  14182. Flags:=0;
  14183. GetterPas:=aResolver.GetPasPropertyGetter(Prop);
  14184. if GetterPas is TPasProcedure then
  14185. inc(Flags,pfGetFunction);
  14186. SetterPas:=aResolver.GetPasPropertySetter(Prop);
  14187. if SetterPas is TPasProcedure then
  14188. inc(Flags,pfSetProcedure);
  14189. StoredExpr:=aResolver.GetPasPropertyStoredExpr(Prop);
  14190. IndexExpr:=aResolver.GetPasPropertyIndex(Prop);
  14191. if IndexExpr<>nil then
  14192. inc(Flags,pfHasIndex);
  14193. DefaultExpr:=aResolver.GetPasPropertyDefaultExpr(Prop);
  14194. if StoredExpr<>nil then
  14195. begin
  14196. aResolver.ComputeElement(StoredExpr,StoredResolved,[rcNoImplicitProc]);
  14197. if StoredResolved.IdentEl is TPasProcedure then
  14198. // stored <function>
  14199. inc(Flags,pfStoredFunction)
  14200. else
  14201. begin
  14202. if (StoredResolved.BaseType=btBoolean) and (StoredResolved.ExprEl<>nil) then
  14203. begin
  14204. // could be a const boolean
  14205. // -> try evaluating const boolean
  14206. StoredValue:=aResolver.Eval(StoredExpr,[]);
  14207. if StoredValue<>nil then
  14208. try
  14209. // stored <const bool>
  14210. if StoredValue.Kind<>revkBool then
  14211. RaiseInconsistency(20170924082845,Prop);
  14212. StoredExpr:=nil;
  14213. if TResEvalBool(StoredValue).B then
  14214. inc(Flags,pfStoredTrue)
  14215. else
  14216. inc(Flags,pfStoredFalse);
  14217. finally
  14218. ReleaseEvalValue(StoredValue);
  14219. end;
  14220. end;
  14221. if StoredExpr<>nil then
  14222. // stored <field>
  14223. inc(Flags,pfStoredField);
  14224. end;
  14225. end;
  14226. Call.AddArg(CreateLiteralNumber(Prop,Flags));
  14227. // add type
  14228. VarType:=aResolver.GetPasPropertyType(Prop);
  14229. aResolver.ComputeElement(VarType,VarTypeResolved,[rcType]);
  14230. ResultTypeInfo:=CreateTypeInfoRef(VarType,AContext,Prop);
  14231. if ResultTypeInfo<>nil then
  14232. Call.AddArg(ResultTypeInfo)
  14233. else
  14234. Call.AddArg(CreateLiteralNull(Prop));
  14235. // add "getter"
  14236. if GetterPas=nil then
  14237. Call.AddArg(CreateLiteralString(Prop,''))
  14238. else
  14239. Call.AddArg(CreateLiteralString(Prop,GetAccessorName(GetterPas)));
  14240. // add "setter"
  14241. if SetterPas=nil then
  14242. Call.AddArg(CreateLiteralString(Prop,''))
  14243. else
  14244. Call.AddArg(CreateLiteralString(Prop,GetAccessorName(SetterPas)));
  14245. // add option "index"
  14246. IndexExpr:=aResolver.GetPasPropertyIndex(Prop);
  14247. if IndexExpr<>nil then
  14248. begin
  14249. IndexValue:=aResolver.Eval(IndexExpr,[refConst]);
  14250. try
  14251. AddOption(FBuiltInNames[pbivnRTTIPropIndex],
  14252. ConvertConstValue(IndexValue,AContext,Prop));
  14253. finally
  14254. ReleaseEvalValue(IndexValue);
  14255. end;
  14256. end;
  14257. // add option "stored"
  14258. if StoredExpr<>nil then
  14259. begin
  14260. DeclEl:=(StoredExpr.CustomData as TResolvedReference).Declaration;
  14261. AddOption(FBuiltInNames[pbivnRTTIPropStored],
  14262. CreateLiteralString(Prop,GetAccessorName(DeclEl)));
  14263. end;
  14264. // add option "defaultvalue"
  14265. if DefaultExpr<>nil then
  14266. begin
  14267. PasValue:=aResolver.Eval(DefaultExpr,[refConst],false);
  14268. try
  14269. DefValue:=nil;
  14270. if VarTypeResolved.BaseType in [btSet,btArrayOrSet] then
  14271. DefValue:=CreateValInit(VarType,DefaultExpr,DefaultExpr,AContext);
  14272. if DefValue=nil then
  14273. DefValue:=ConvertConstValue(PasValue,AContext,Prop);
  14274. AddOption(FBuiltInNames[pbivnRTTIPropDefault],DefValue);
  14275. finally
  14276. ReleaseEvalValue(PasValue);
  14277. end;
  14278. end;
  14279. Result:=Call;
  14280. finally
  14281. if Result=nil then
  14282. Call.Free;
  14283. end;
  14284. end;
  14285. procedure TPasToJSConverter.CreateRTTIAnonymous(El: TPasType;
  14286. AContext: TConvertContext; var First, Last: TJSStatementList);
  14287. // if El has any anonymous types, create the RTTI
  14288. var
  14289. C: TClass;
  14290. JS: TJSElement;
  14291. begin
  14292. if El.Name<>'' then
  14293. RaiseNotSupported(El,AContext,20170905162324,'inconsistency');
  14294. C:=El.ClassType;
  14295. if C=TPasArrayType then
  14296. begin
  14297. JS:=ConvertArrayType(TPasArrayType(El),AContext);
  14298. AddToStatementList(First,Last,JS,El);
  14299. end;
  14300. end;
  14301. procedure TPasToJSConverter.AddIntfDelegations(ClassEl: TPasElement;
  14302. Prop: TPasProperty; FinishedGUIDs: TStringList; ObjLit: TJSObjectLiteral;
  14303. aContext: TFunctionContext);
  14304. var
  14305. i: Integer;
  14306. Expr: TPasExpr;
  14307. ResolvedEl: TPasResolverResult;
  14308. OrigIntfType, OrigPropType, PropType: TPasType;
  14309. IntfType: TPasClassType;
  14310. LitEl: TJSObjectLiteralElement;
  14311. Scope: TPas2JSClassScope;
  14312. FunSt: TJSFunctionDeclarationStatement;
  14313. aResolver: TPas2JSResolver;
  14314. GetterJS: TJSElement;
  14315. RetSt: TJSReturnStatement;
  14316. Call: TJSCallExpression;
  14317. FunName: String;
  14318. begin
  14319. aResolver:=aContext.Resolver;
  14320. GetterJS:=nil;
  14321. try
  14322. for i:=0 to length(Prop.Implements)-1 do
  14323. begin
  14324. Expr:=Prop.Implements[i];
  14325. aResolver.ComputeElement(Expr,ResolvedEl,[rcNoImplicitProc]);
  14326. if not (ResolvedEl.IdentEl is TPasType) then
  14327. RaiseInconsistency(20180327183019,Expr);
  14328. // mark interface as finished
  14329. OrigIntfType:=TPasType(ResolvedEl.IdentEl);
  14330. IntfType:=aResolver.ResolveAliasType(OrigIntfType) as TPasClassType;
  14331. Scope:=IntfType.CustomData as TPas2JSClassScope;
  14332. if Scope.GUID='' then
  14333. RaiseInconsistency(20180327184912,Expr);
  14334. if FinishedGUIDs.IndexOf(Scope.GUID)>=0 then
  14335. continue;
  14336. FinishedGUIDs.Add(Scope.GUID);
  14337. // "guid" : function(){ return ...}
  14338. LitEl:=ObjLit.Elements.AddElement;
  14339. LitEl.Name:=TJSString(Scope.GUID);
  14340. FunSt:=CreateFunctionSt(ClassEl,true,false);
  14341. LitEl.Expr:=FunSt;
  14342. RetSt:=TJSReturnStatement(CreateElement(TJSReturnStatement,Prop));
  14343. FunSt.AFunction.Body.A:=RetSt;
  14344. // check property type
  14345. OrigPropType:=aResolver.GetPasPropertyType(Prop);
  14346. aResolver.ComputeElement(OrigPropType,ResolvedEl,[rcType]);
  14347. if not (ResolvedEl.IdentEl is TPasType) then
  14348. RaiseInconsistency(20180327190201,Prop);
  14349. PropType:=aResolver.ResolveAliasType(TPasType(ResolvedEl.IdentEl));
  14350. if not (PropType is TPasClassType) then
  14351. RaiseInconsistency(20180327190442,Prop);
  14352. // check property getter
  14353. if aResolver.GetPasPropertyArgs(Prop).Count>0 then
  14354. RaiseNotSupported(Prop,aContext,20180327191159);
  14355. GetterJS:=CreatePropertyGet(Prop,nil,aContext,Prop);
  14356. case TPasClassType(PropType).ObjKind of
  14357. okClass:
  14358. begin
  14359. // delegate to class instance
  14360. case TPasClassType(IntfType).InterfaceType of
  14361. citCom:
  14362. // 'guid': function(){ return rtl.queryIntfT(this.FField,IntfType); }
  14363. // 'guid': function(){ return rtl.queryIntfT(this.GetObj(),IntfType); }
  14364. FunName:=FBuiltInNames[pbifnIntfQueryIntfT];
  14365. citCorba:
  14366. // 'guid': function(){ return rtl.getIntfT(this.FField,IntfType); }
  14367. // 'guid': function(){ return rtl.getIntfT(this.GetObj(),IntfType); }
  14368. FunName:=FBuiltInNames[pbifnIntfGetIntfT];
  14369. else
  14370. RaiseNotSupported(Prop,aContext,20180406085319,InterfaceTypeNames[TPasClassType(IntfType).InterfaceType]);
  14371. end;
  14372. Call:=CreateCallExpression(Prop);
  14373. RetSt.Expr:=Call;
  14374. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FunName]);
  14375. Call.AddArg(GetterJS);
  14376. GetterJS:=nil;
  14377. Call.AddArg(CreateReferencePathExpr(IntfType,aContext));
  14378. end;
  14379. okInterface:
  14380. begin
  14381. // delegate to interface
  14382. case TPasClassType(IntfType).InterfaceType of
  14383. citCom:
  14384. begin
  14385. if IsInterfaceRef(GetterJS) then
  14386. // 'guid': function(){ return this.GetIntf(); },
  14387. GetterJS:=RemoveIntfRef(TJSCallExpression(GetterJS),aContext)
  14388. else
  14389. begin
  14390. // 'guid': function(){ return rtl._AddRef(this.FField); },
  14391. Call:=CreateCallExpression(Prop);
  14392. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnIntf_AddRef]]);
  14393. Call.AddArg(GetterJS);
  14394. GetterJS:=Call;
  14395. end;
  14396. end;
  14397. citCorba:
  14398. begin
  14399. // 'guid': function(){ return this.FField; },
  14400. // 'guid': function(){ return this.GetIntf(); },
  14401. end;
  14402. else
  14403. RaiseNotSupported(Prop,aContext,20180406085053,InterfaceTypeNames[TPasClassType(IntfType).InterfaceType]);
  14404. end;
  14405. RetSt.Expr:=GetterJS;
  14406. GetterJS:=nil;
  14407. end;
  14408. else
  14409. RaiseNotSupported(Prop,aContext,20180327190538,ObjKindNames[TPasClassType(PropType).ObjKind]);
  14410. end;
  14411. end;
  14412. finally
  14413. GetterJS.Free;
  14414. end;
  14415. end;
  14416. function TPasToJSConverter.CreateGUIDObjLit(aTGUIDRecord: TPasRecordType;
  14417. const GUID: TGUID; PosEl: TPasElement; AContext: TConvertContext
  14418. ): TJSObjectLiteral;
  14419. var
  14420. Members: TFPList;
  14421. PropEl: TJSObjectLiteralElement;
  14422. MemberEl: TPasElement;
  14423. ArrLit: TJSArrayLiteral;
  14424. i: Integer;
  14425. begin
  14426. Members:=aTGUIDRecord.Members;
  14427. Result:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,PosEl));
  14428. // D1: 0x12345678
  14429. PropEl:=Result.Elements.AddElement;
  14430. MemberEl:=TPasElement(Members[0]);
  14431. if not SameText(MemberEl.Name,'D1') then
  14432. RaiseInconsistency(20180415094721,PosEl);
  14433. PropEl.Name:=TJSString(TransformVariableName(MemberEl,AContext));
  14434. PropEl.Expr:=CreateLiteralHexNumber(PosEl,GUID.D1,8);
  14435. // D2: 0x1234
  14436. PropEl:=Result.Elements.AddElement;
  14437. MemberEl:=TPasElement(Members[1]);
  14438. PropEl.Name:=TJSString(TransformVariableName(MemberEl,AContext));
  14439. PropEl.Expr:=CreateLiteralHexNumber(PosEl,GUID.D2,4);
  14440. // D3: 0x1234
  14441. PropEl:=Result.Elements.AddElement;
  14442. MemberEl:=TPasElement(Members[2]);
  14443. PropEl.Name:=TJSString(TransformVariableName(MemberEl,AContext));
  14444. PropEl.Expr:=CreateLiteralHexNumber(PosEl,GUID.D3,4);
  14445. // D4: [0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12]
  14446. PropEl:=Result.Elements.AddElement;
  14447. MemberEl:=TPasElement(Members[3]);
  14448. PropEl.Name:=TJSString(TransformVariableName(MemberEl,AContext));
  14449. ArrLit:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,PosEl));
  14450. PropEl.Expr:=ArrLit;
  14451. for i:=0 to 7 do
  14452. ArrLit.AddElement(CreateLiteralHexNumber(PosEl,GUID.D4[i],2));
  14453. end;
  14454. function TPasToJSConverter.CreateAssignComIntfVar(
  14455. const LeftResolved: TPasResolverResult; var LHS, RHS: TJSElement;
  14456. AContext: TConvertContext; PosEl: TPasElement): TJSElement;
  14457. procedure AddProcRelease(Proc: TPasProcedure; SubEl: TPasElement);
  14458. var
  14459. FuncContext: TFunctionContext;
  14460. begin
  14461. FuncContext:=AContext.GetFuncContextOfPasElement(Proc);
  14462. if FuncContext<>nil then
  14463. begin
  14464. if SubEl is TPasResultElement then
  14465. FuncContext.ResultNeedsIntfRelease:=true
  14466. else
  14467. FuncContext.Add_InterfaceRelease(SubEl);
  14468. end
  14469. else
  14470. begin
  14471. {$IFDEF VerbosePas2JS}
  14472. AContext.WriteStack;
  14473. {$ENDIF}
  14474. RaiseInconsistency(20180401164150,PosEl);
  14475. end;
  14476. end;
  14477. var
  14478. Call: TJSCallExpression;
  14479. AssignSt: TJSSimpleAssignStatement;
  14480. Prim: TJSPrimaryExpressionIdent;
  14481. IdentEl: TPasElement;
  14482. Proc: TPasProcedure;
  14483. ok, SkipAddRef: Boolean;
  14484. begin
  14485. Result:=nil;
  14486. ok:=false;
  14487. try
  14488. SkipAddRef:=false;
  14489. if IsInterfaceRef(RHS) then
  14490. begin
  14491. // simplify: $ir.ref(id,expr) -> expr
  14492. RHS:=RemoveIntfRef(TJSCallExpression(RHS),AContext);
  14493. SkipAddRef:=true;
  14494. end;
  14495. Call:=CreateCallExpression(PosEl);
  14496. Result:=Call;
  14497. if LHS is TJSDotMemberExpression then
  14498. begin
  14499. // path.name = RHS -> rtl.setIntfP(path,"IntfVar",RHS})
  14500. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnIntfSetIntfP]]);
  14501. Call.AddArg(TJSDotMemberExpression(LHS).MExpr);
  14502. TJSDotMemberExpression(LHS).MExpr:=nil;
  14503. Call.AddArg(CreateLiteralJSString(PosEl,TJSDotMemberExpression(LHS).Name));
  14504. FreeAndNil(LHS);
  14505. Call.AddArg(RHS);
  14506. RHS:=nil;
  14507. if SkipAddRef then
  14508. Call.AddArg(CreateLiteralBoolean(PosEl,true));
  14509. end
  14510. else if LHS is TJSBracketMemberExpression then
  14511. begin
  14512. // path[index] = RHS -> rtl.setIntfP(path,index,RHS})
  14513. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnIntfSetIntfP]]);
  14514. Call.AddArg(TJSBracketMemberExpression(LHS).MExpr);
  14515. TJSBracketMemberExpression(LHS).MExpr:=nil;
  14516. Call.AddArg(TJSBracketMemberExpression(LHS).Name);
  14517. FreeAndNil(LHS);
  14518. Call.AddArg(RHS);
  14519. RHS:=nil;
  14520. if SkipAddRef then
  14521. Call.AddArg(CreateLiteralBoolean(PosEl,true));
  14522. end
  14523. else if LHS is TJSPrimaryExpressionIdent then
  14524. begin
  14525. // name = RHS -> name = rtl.setIntfL(name,RHS)
  14526. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnIntfSetIntfL]]);
  14527. // add parameter name
  14528. Prim:=TJSPrimaryExpressionIdent(CreateElement(TJSPrimaryExpressionIdent,PosEl));
  14529. Prim.Name:=TJSPrimaryExpressionIdent(LHS).Name;
  14530. Call.AddArg(Prim);
  14531. // add parameter RHS
  14532. Call.AddArg(RHS);
  14533. RHS:=nil;
  14534. if SkipAddRef then
  14535. Call.AddArg(CreateLiteralBoolean(PosEl,true));
  14536. // name = ...
  14537. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,PosEl));
  14538. AssignSt.LHS:=LHS;
  14539. LHS:=nil;
  14540. AssignSt.Expr:=Call;
  14541. Result:=AssignSt;
  14542. end
  14543. else
  14544. RaiseNotSupported(PosEl,AContext,20180401105030,GetObjName(LHS));
  14545. IdentEl:=LeftResolved.IdentEl;
  14546. if (IdentEl<>nil) then
  14547. begin
  14548. if (IdentEl.ClassType=TPasVariable) and (IdentEl.Parent is TProcedureBody) then
  14549. begin
  14550. // local variable
  14551. Proc:=TPasProcedure(IdentEl.Parent.Parent);
  14552. AddProcRelease(Proc,IdentEl);
  14553. end
  14554. else if (IdentEl.ClassType=TPasArgument)
  14555. and (IdentEl.Parent is TPasProcedureType)
  14556. and (IdentEl.Parent.Parent is TPasProcedure) then
  14557. begin
  14558. // argument
  14559. Proc:=TPasProcedure(IdentEl.Parent.Parent);
  14560. AddProcRelease(Proc,IdentEl);
  14561. end
  14562. else if IdentEl.ClassType=TPasResultElement then
  14563. begin
  14564. // Result variable
  14565. Proc:=TPasFunction(TPasFunctionType(IdentEl.Parent).Parent);
  14566. AddProcRelease(Proc,IdentEl);
  14567. end;
  14568. end;
  14569. ok:=true;
  14570. finally
  14571. if not ok then Result.Free;
  14572. end;
  14573. end;
  14574. function TPasToJSConverter.IsInterfaceRef(Expr: TJSElement): boolean;
  14575. var
  14576. Call: TJSCallExpression;
  14577. DotExpr: TJSDotMemberExpression;
  14578. begin
  14579. Result:=false;
  14580. if Expr=nil then exit;
  14581. if Expr.ClassType<>TJSCallExpression then exit;
  14582. Call:=TJSCallExpression(Expr);
  14583. if Call.Expr.ClassType<>TJSDotMemberExpression then exit;
  14584. DotExpr:=TJSDotMemberExpression(Call.Expr);
  14585. Result:=(DotExpr.Name=TJSString(FBuiltInNames[pbifnIntfExprRefsAdd]))
  14586. and (DotExpr.MExpr is TJSPrimaryExpressionIdent)
  14587. and (TJSPrimaryExpressionIdent(DotExpr.MExpr).Name=TJSString(FBuiltInNames[pbivnIntfExprRefs]));
  14588. end;
  14589. function TPasToJSConverter.CreateIntfRef(Expr: TJSElement;
  14590. aContext: TConvertContext; PosEl: TPasElement): TJSCallExpression;
  14591. // enclose Expr
  14592. // -> $ir.ref(id,Expr)
  14593. var
  14594. FuncContext: TFunctionContext;
  14595. Call: TJSCallExpression;
  14596. begin
  14597. FuncContext:=aContext.GetFunctionContext;
  14598. if FuncContext=nil then
  14599. RaiseNotSupported(PosEl,aContext,20180402183859);
  14600. if IsInterfaceRef(Expr) then
  14601. exit(TJSCallExpression(Expr));
  14602. inc(FuncContext.IntfExprReleaseCount);
  14603. Call:=CreateCallExpression(PosEl);
  14604. Call.Expr:=CreatePrimitiveDotExpr(FBuiltInNames[pbivnIntfExprRefs]+'.'+FBuiltInNames[pbifnIntfExprRefsAdd],PosEl);
  14605. Call.AddArg(CreateLiteralNumber(PosEl,FuncContext.IntfExprReleaseCount));
  14606. Call.AddArg(Expr);
  14607. Result:=Call;
  14608. end;
  14609. function TPasToJSConverter.RemoveIntfRef(Call: TJSCallExpression;
  14610. AContext: TConvertContext): TJSElement;
  14611. var
  14612. Lit: TJSArrayLiteralElement;
  14613. LitValue: TJSValue;
  14614. FuncContext: TFunctionContext;
  14615. begin
  14616. Lit:=Call.Args.Elements[1];
  14617. Result:=Lit.Expr;
  14618. Lit.Expr:=nil;
  14619. // check if $ir is still needed
  14620. Lit:=Call.Args.Elements[0];
  14621. if (Lit.Expr is TJSLiteral) then
  14622. begin
  14623. LitValue:=TJSLiteral(Lit.Expr).Value;
  14624. FuncContext:=AContext.GetFunctionContext;
  14625. if (FuncContext<>nil)
  14626. and (FuncContext.IntfExprReleaseCount=LitValue.AsNumber) then
  14627. dec(FuncContext.IntfExprReleaseCount);
  14628. end;
  14629. Call.Free;
  14630. end;
  14631. procedure TPasToJSConverter.CreateFunctionTryFinally(
  14632. FuncContext: TFunctionContext);
  14633. begin
  14634. if FuncContext.TrySt<>nil then exit;
  14635. FuncContext.TrySt:=TJSTryFinallyStatement(CreateElement(TJSTryFinallyStatement,FuncContext.PasElement));
  14636. FuncContext.TrySt.Block:=FuncContext.BodySt;
  14637. FuncContext.BodySt:=FuncContext.TrySt;
  14638. end;
  14639. procedure TPasToJSConverter.AddFunctionFinallySt(NewEl: TJSElement;
  14640. PosEl: TPasElement; FuncContext: TFunctionContext);
  14641. begin
  14642. CreateFunctionTryFinally(FuncContext);
  14643. AddToStatementList(FuncContext.FinallyFirst,FuncContext.FinallyLast,NewEl,PosEl);
  14644. FuncContext.TrySt.BFinally:=FuncContext.FinallyFirst;
  14645. end;
  14646. procedure TPasToJSConverter.AddFunctionFinallyRelease(SubEl: TPasElement;
  14647. FuncContext: TFunctionContext);
  14648. // add to finally: rtl._Release(IntfVar)
  14649. var
  14650. Call: TJSCallExpression;
  14651. begin
  14652. Call:=CreateCallExpression(SubEl);
  14653. AddFunctionFinallySt(Call,SubEl,FuncContext);
  14654. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnIntf_Release]]);
  14655. Call.AddArg(CreateReferencePathExpr(SubEl,FuncContext));
  14656. end;
  14657. procedure TPasToJSConverter.AddInFrontOfFunctionTry(NewEl: TJSElement;
  14658. PosEl: TPasElement; FuncContext: TFunctionContext);
  14659. var
  14660. St, OldSt: TJSStatementList;
  14661. begin
  14662. CreateFunctionTryFinally(FuncContext);
  14663. if FuncContext.BodySt=FuncContext.TrySt then
  14664. begin
  14665. St:=TJSStatementList(CreateElement(TJSStatementList,PosEl));
  14666. St.A:=NewEl;
  14667. St.B:=FuncContext.TrySt;
  14668. FuncContext.BodySt:=St;
  14669. end
  14670. else if FuncContext.BodySt is TJSStatementList then
  14671. begin
  14672. OldSt:=TJSStatementList(FuncContext.BodySt);
  14673. while OldSt.B is TJSStatementList do
  14674. OldSt:=TJSStatementList(OldSt.B);
  14675. St:=TJSStatementList(CreateElement(TJSStatementList,PosEl));
  14676. St.A:=NewEl;
  14677. St.B:=OldSt.B;
  14678. OldSt.B:=St;
  14679. end
  14680. else
  14681. RaiseInconsistency(20180402103144,PosEl);
  14682. end;
  14683. procedure TPasToJSConverter.AddInterfaceReleases(FuncContext: TFunctionContext;
  14684. PosEl: TPasElement);
  14685. var
  14686. i: Integer;
  14687. P: TPasElement;
  14688. Call: TJSCallExpression;
  14689. VarSt: TJSVariableStatement;
  14690. begin
  14691. if FuncContext.IntfExprReleaseCount>0 then
  14692. begin
  14693. // add in front of try..finally "var $ir = rtl.createIntfRefs();"
  14694. Call:=CreateCallExpression(PosEl);
  14695. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnIntfExprRefsCreate]]);
  14696. VarSt:=CreateVarStatement(FBuiltInNames[pbivnIntfExprRefs],Call,PosEl);
  14697. AddInFrontOfFunctionTry(VarSt,PosEl,FuncContext);
  14698. // add in finally: "$ir.free();"
  14699. Call:=CreateCallExpression(PosEl);
  14700. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnIntfExprRefs],FBuiltInNames[pbifnIntfExprRefsFree]]);
  14701. AddFunctionFinallySt(Call,PosEl,FuncContext);
  14702. end;
  14703. if FuncContext.IntfElReleases<>nil then
  14704. for i:=0 to FuncContext.IntfElReleases.Count-1 do
  14705. begin
  14706. // enclose body in try..finally and add release statement
  14707. P:=TPasElement(FuncContext.IntfElReleases[i]);
  14708. if P.ClassType=TPasVariable then
  14709. AddFunctionFinallyRelease(P,FuncContext)
  14710. else if P.ClassType=TPasArgument then
  14711. begin
  14712. // add in front of try..finally "rtl._AddRef(arg);"
  14713. Call:=CreateCallExpression(P);
  14714. AddInFrontOfFunctionTry(Call,PosEl,FuncContext);
  14715. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnIntf_AddRef]]);
  14716. Call.AddArg(CreateReferencePathExpr(P,FuncContext));
  14717. // add in finally: "rtl._Release(arg);"
  14718. AddFunctionFinallyRelease(P,FuncContext);
  14719. end
  14720. else
  14721. RaiseInconsistency(20180401165742,P);
  14722. end;
  14723. end;
  14724. procedure TPasToJSConverter.AddRTLVersionCheck(FuncContext: TFunctionContext;
  14725. PosEl: TPasElement);
  14726. var
  14727. St: TJSElement;
  14728. Call: TJSCallExpression;
  14729. NewSt: TJSStatementList;
  14730. begin
  14731. St:=FuncContext.BodySt;
  14732. // rtl.checkVersion(RTLVersion)
  14733. Call:=CreateCallExpression(PosEl);
  14734. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnCheckVersion]]);
  14735. Call.AddArg(CreateLiteralNumber(PosEl,RTLVersion));
  14736. if St=nil then
  14737. FuncContext.BodySt:=Call
  14738. else if St is TJSEmptyBlockStatement then
  14739. begin
  14740. St.Free;
  14741. FuncContext.BodySt:=Call;
  14742. end
  14743. else if St is TJSStatementList then
  14744. begin
  14745. NewSt:=TJSStatementList(CreateElement(TJSStatementList,PosEl));
  14746. NewSt.A:=Call;
  14747. NewSt.B:=St;
  14748. FuncContext.BodySt:=NewSt;
  14749. end
  14750. else
  14751. begin
  14752. {$IFDEF VerbosePas2JS}
  14753. writeln('TPasToJSConverter.AddRTLVersionCheck St=',GetObjName(St));
  14754. {$ENDIF}
  14755. RaiseNotSupported(PosEl,FuncContext,20181002154026,GetObjName(St));
  14756. end;
  14757. end;
  14758. function TPasToJSConverter.ConvertImplBlock(El: TPasImplBlock;
  14759. AContext: TConvertContext): TJSElement;
  14760. begin
  14761. //writeln('TPasToJSConverter.ConvertImplBlock ');
  14762. Result:=Nil;
  14763. if (El is TPasImplStatement) then
  14764. Result:=ConvertStatement(TPasImplStatement(El),AContext)
  14765. else if (El.ClassType=TPasImplIfElse) then
  14766. Result:=ConvertIfStatement(TPasImplIfElse(El),AContext)
  14767. else if (El.ClassType=TPasImplRepeatUntil) then
  14768. Result:=ConvertRepeatStatement(TPasImplRepeatUntil(El),AContext)
  14769. else if (El.ClassType=TPasImplBeginBlock) then
  14770. Result:=ConvertBeginEndStatement(TPasImplBeginBlock(El),AContext,true)
  14771. else if (El.ClassType=TInitializationSection) then
  14772. Result:=ConvertInitializationSection(TInitializationSection(El),AContext)
  14773. else if (El.ClassType=TFinalizationSection) then
  14774. Result:=ConvertFinalizationSection(TFinalizationSection(El),AContext)
  14775. else if (El.ClassType=TPasImplTry) then
  14776. Result:=ConvertTryStatement(TPasImplTry(El),AContext)
  14777. else if (El.ClassType=TPasImplCaseOf) then
  14778. Result:=ConvertCaseOfStatement(TPasImplCaseOf(El),AContext)
  14779. else
  14780. RaiseNotSupported(El,AContext,20161024192156);
  14781. end;
  14782. function TPasToJSConverter.ConvertImplCommand(El: TPasImplCommand;
  14783. AContext: TConvertContext): TJSElement;
  14784. begin
  14785. if El.Command<>'' then
  14786. RaiseNotSupported(El,AContext,20181013224809,El.Command);
  14787. if not (El.Parent is TPasImplIfElse) then
  14788. RaiseNotSupported(El,AContext,20181013224929,GetObjName(El.Parent));
  14789. Result:=nil;
  14790. end;
  14791. function TPasToJSConverter.ConvertPackage(El: TPasPackage;
  14792. AContext: TConvertContext): TJSElement;
  14793. begin
  14794. RaiseNotSupported(El,AContext,20161024192555);
  14795. Result:=Nil;
  14796. // ToDo TPasPackage = class(TPasElement)
  14797. end;
  14798. function TPasToJSConverter.ConvertResString(El: TPasResString;
  14799. AContext: TConvertContext): TJSElement;
  14800. begin
  14801. RaiseNotSupported(El,AContext,20161024192604);
  14802. Result:=Nil;
  14803. // ToDo: TPasResString
  14804. end;
  14805. function TPasToJSConverter.ConvertVariable(El: TPasVariable;
  14806. AContext: TConvertContext): TJSElement;
  14807. Var
  14808. V : TJSVarDeclaration;
  14809. vm: TVariableModifier;
  14810. begin
  14811. for vm in TVariableModifier do
  14812. if (vm in El.VarModifiers) and (not (vm in [vmClass,vmExternal])) then
  14813. RaiseNotSupported(El,AContext,20170208141622,'modifier '+VariableModifierNames[vm]);
  14814. if El.LibraryName<>nil then
  14815. RaiseNotSupported(El,AContext,20170208141844,'library name');
  14816. if El.AbsoluteExpr<>nil then
  14817. RaiseNotSupported(El,AContext,20170208141926,'absolute');
  14818. V:=TJSVarDeclaration(CreateElement(TJSVarDeclaration,El));
  14819. V.Name:=TransformVariableName(El,AContext);
  14820. V.Init:=CreateVarInit(El,AContext);
  14821. Result:=V;
  14822. end;
  14823. function TPasToJSConverter.ConvertProperty(El: TPasProperty;
  14824. AContext: TConvertContext): TJSElement;
  14825. begin
  14826. Result:=Nil;
  14827. if El.DispIDExpr<>nil then
  14828. RaiseNotSupported(El.DispIDExpr,AContext,20170215103029,'property dispid expression');
  14829. // does not need any declaration. Access is redirected to getter/setter.
  14830. // RTTI is created in CreateRTTIClassProperty
  14831. end;
  14832. function TPasToJSConverter.ConvertExportSymbol(El: TPasExportSymbol;
  14833. AContext: TConvertContext): TJSElement;
  14834. begin
  14835. RaiseNotSupported(El,AContext,20161024192650);
  14836. Result:=Nil;
  14837. // ToDo: TPasExportSymbol
  14838. end;
  14839. function TPasToJSConverter.ConvertLabels(El: TPasLabels;
  14840. AContext: TConvertContext): TJSElement;
  14841. begin
  14842. RaiseNotSupported(El,AContext,20161024192701);
  14843. Result:=Nil;
  14844. // ToDo: TPasLabels = class(TPasImplElement)
  14845. end;
  14846. function TPasToJSConverter.ConvertRaiseStatement(El: TPasImplRaise;
  14847. AContext: TConvertContext): TJSElement;
  14848. Var
  14849. E : TJSElement;
  14850. T : TJSThrowStatement;
  14851. begin
  14852. if El.ExceptObject<>Nil then
  14853. E:=ConvertElement(El.ExceptObject,AContext)
  14854. else
  14855. E:=CreatePrimitiveDotExpr(FBuiltInNames[pbivnExceptObject],El);
  14856. T:=TJSThrowStatement(CreateElement(TJSThrowStatement,El));
  14857. T.A:=E;
  14858. Result:=T;
  14859. end;
  14860. function TPasToJSConverter.ConvertAssignStatement(El: TPasImplAssign;
  14861. AContext: TConvertContext): TJSElement;
  14862. procedure NotSupported(AssignContext: TAssignContext; id: TMaxPrecInt);
  14863. begin
  14864. {$IFDEF VerbosePas2JS}
  14865. writeln('NotSupported Left=',GetResolverResultDbg(AssignContext.LeftResolved),
  14866. ' Op=',AssignKindNames[El.Kind],
  14867. ' Right=',GetResolverResultDbg(AssignContext.RightResolved));
  14868. {$ENDIF}
  14869. RaiseNotSupported(El,AContext,id,
  14870. GetResolverResultDbg(AssignContext.LeftResolved)+AssignKindNames[El.Kind]
  14871. +GetResolverResultDbg(AssignContext.RightResolved));
  14872. end;
  14873. function CreateRangeCheck(AssignSt: TJSElement;
  14874. MinVal, MaxVal: TMaxPrecInt; RTLFunc: TPas2JSBuiltInName): TJSElement;
  14875. var
  14876. Call: TJSCallExpression;
  14877. begin
  14878. Call:=CreateCallExpression(El);
  14879. Call.Expr:=CreatePrimitiveDotExpr(FBuiltInNames[pbivnRTL]+'.'+FBuiltInNames[RTLFunc],El);
  14880. if AssignSt.ClassType=TJSSimpleAssignStatement then
  14881. begin
  14882. // LHS:=rtl.rc(RHS,min,max) check before assign
  14883. Result:=AssignSt;
  14884. Call.AddArg(TJSSimpleAssignStatement(AssignSt).Expr);
  14885. TJSSimpleAssignStatement(AssignSt).Expr:=Call;
  14886. end
  14887. else
  14888. begin
  14889. // rtl.rc(LHS+=RHS,min,max) check after assign
  14890. Call.AddArg(AssignSt);
  14891. Result:=Call;
  14892. end;
  14893. Call.AddArg(CreateLiteralNumber(El.right,MinVal));
  14894. Call.AddArg(CreateLiteralNumber(El.right,MaxVal));
  14895. end;
  14896. function CreateRangeCheckType(AssignSt: TJSElement; aType: TPasType): TJSElement;
  14897. var
  14898. Value: TResEvalValue;
  14899. begin
  14900. Result:=AssignSt;
  14901. Value:=AContext.Resolver.EvalTypeRange(aType,[refConst]);
  14902. if Value=nil then
  14903. RaiseNotSupported(El,AContext,20180424110758,'range checking '+GetObjName(aType));
  14904. try
  14905. case Value.Kind of
  14906. revkRangeInt:
  14907. case TResEvalRangeInt(Value).ElKind of
  14908. revskEnum, revskInt:
  14909. Result:=CreateRangeCheck(AssignSt,TResEvalRangeInt(Value).RangeStart,
  14910. TResEvalRangeInt(Value).RangeEnd,pbifnRangeCheckInt);
  14911. revskChar:
  14912. Result:=CreateRangeCheck(AssignSt,TResEvalRangeInt(Value).RangeStart,
  14913. TResEvalRangeInt(Value).RangeEnd,pbifnRangeCheckChar);
  14914. end;
  14915. revkRangeUInt:
  14916. Result:=CreateRangeCheck(AssignSt,TResEvalRangeUInt(Value).RangeStart,
  14917. TResEvalRangeUInt(Value).RangeEnd,pbifnRangeCheckInt);
  14918. else
  14919. RaiseNotSupported(El,AContext,20180424111037,'range checking '+Value.AsDebugString);
  14920. end;
  14921. finally
  14922. ReleaseEvalValue(Value);
  14923. end;
  14924. end;
  14925. Var
  14926. LHS: TJSElement;
  14927. T: TJSAssignStatement;
  14928. AssignContext: TAssignContext;
  14929. Flags: TPasResolverComputeFlags;
  14930. LeftIsProcType, NeedClone: Boolean;
  14931. Call: TJSCallExpression;
  14932. MinVal, MaxVal: TMaxPrecInt;
  14933. RightTypeEl, LeftTypeEl: TPasType;
  14934. aResolver: TPas2JSResolver;
  14935. NewMemE, NewME: TJSNewMemberExpression;
  14936. ObjLit: TJSObjectLiteral;
  14937. GUID: TGUID;
  14938. begin
  14939. Result:=nil;
  14940. LHS:=nil;
  14941. aResolver:=AContext.Resolver;
  14942. AssignContext:=TAssignContext.Create(El,nil,AContext);
  14943. try
  14944. if aResolver<>nil then
  14945. begin
  14946. aResolver.ComputeElement(El.left,AssignContext.LeftResolved,[rcNoImplicitProc]);
  14947. Flags:=[];
  14948. LeftIsProcType:=aResolver.IsProcedureType(AssignContext.LeftResolved,true);
  14949. if LeftIsProcType then
  14950. begin
  14951. if msDelphi in AContext.CurrentModeSwitches then
  14952. Include(Flags,rcNoImplicitProc)
  14953. else
  14954. Include(Flags,rcNoImplicitProcType);
  14955. end;
  14956. aResolver.ComputeElement(El.right,AssignContext.RightResolved,Flags);
  14957. {$IFDEF VerbosePas2JS}
  14958. writeln('TPasToJSConverter.ConvertAssignStatement Left={',GetResolverResultDbg(AssignContext.LeftResolved),'} Right={',GetResolverResultDbg(AssignContext.RightResolved),'}');
  14959. {$ENDIF}
  14960. if LeftIsProcType and (msDelphi in AContext.CurrentModeSwitches)
  14961. and (AssignContext.RightResolved.BaseType=btProc) then
  14962. begin
  14963. // Delphi allows assigning a proc without @: proctype:=proc
  14964. AssignContext.RightSide:=CreateCallback(El.right,AssignContext.RightResolved,AContext);
  14965. end
  14966. else if AssignContext.RightResolved.BaseType=btNil then
  14967. begin
  14968. if aResolver.IsArrayType(AssignContext.LeftResolved) then
  14969. begin
  14970. // array:=nil -> array:=[]
  14971. AssignContext.RightSide:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,El.right));
  14972. end;
  14973. end
  14974. else if AssignContext.LeftResolved.BaseType=btContext then
  14975. begin
  14976. LeftTypeEl:=AssignContext.LeftResolved.LoTypeEl;
  14977. if (LeftTypeEl.ClassType=TPasRecordType)
  14978. and (AssignContext.RightResolved.BaseType in btAllStrings) then
  14979. begin
  14980. if aResolver.GetAssignGUIDString(TPasRecordType(LeftTypeEl),El.right,GUID) then
  14981. begin
  14982. // guidvar:='{...}'; -> guidvar:=new TGUID(){ D1:x12345678, D2:0x1234,...}
  14983. NewMemE:=CreateNewRecord(El,TPasRecordType(LeftTypeEl),AContext);
  14984. AssignContext.RightSide:=NewMemE;
  14985. ObjLit:=CreateGUIDObjLit(TPasRecordType(LeftTypeEl),GUID,El,AContext);
  14986. NewMemE.AddArg(ObjLit);
  14987. end
  14988. else
  14989. RaiseNotSupported(El,AContext,20180415101516);
  14990. end;
  14991. end;
  14992. end;
  14993. if AssignContext.RightSide=nil then
  14994. AssignContext.RightSide:=ConvertElement(El.right,AContext);
  14995. if (AssignContext.RightResolved.BaseType in [btSet,btArrayOrSet])
  14996. and (AssignContext.RightResolved.IdentEl<>nil) then
  14997. begin
  14998. // right side is a set variable -> create reference
  14999. {$IFDEF VerbosePas2JS}
  15000. //writeln('TPasToJSConverter.ConvertAssignStatement SET variable Right={',GetResolverResultDbg(AssignContext.RightResolved),'} AssignContext.RightResolved.IdentEl=',GetObjName(AssignContext.RightResolved.IdentEl));
  15001. {$ENDIF}
  15002. // create rtl.refSet(right)
  15003. AssignContext.RightSide:=CreateReferencedSet(El.right,AssignContext.RightSide);
  15004. end
  15005. else if AssignContext.LeftResolved.BaseType=btCurrency then
  15006. begin
  15007. if AssignContext.RightResolved.BaseType=btCurrency then
  15008. // currency := currency
  15009. else if AssignContext.RightResolved.BaseType in btAllJSFloats then
  15010. begin
  15011. // currency := double -> currency := Math.floor(double*10000)
  15012. AssignContext.RightSide:=CreateMulNumber(El,AssignContext.RightSide,10000);
  15013. AssignContext.RightSide:=CreateMathFloor(El,AssignContext.RightSide);
  15014. end
  15015. else if AssignContext.RightResolved.BaseType in btAllJSInteger then
  15016. begin
  15017. // currency := integer -> currency := double*10000
  15018. AssignContext.RightSide:=CreateMulNumber(El,AssignContext.RightSide,10000);
  15019. end
  15020. else
  15021. RaiseNotSupported(El,AContext,20181016094542,GetResolverResultDbg(AssignContext.RightResolved));
  15022. end
  15023. else if AssignContext.RightResolved.BaseType=btCurrency then
  15024. begin
  15025. // double := currency -> double := currency/10000
  15026. AssignContext.RightSide:=CreateDivideNumber(El,AssignContext.RightSide,10000);
  15027. end
  15028. else if AssignContext.RightResolved.BaseType=btContext then
  15029. begin
  15030. RightTypeEl:=AssignContext.RightResolved.LoTypeEl;
  15031. if RightTypeEl.ClassType=TPasArrayType then
  15032. begin
  15033. if length(TPasArrayType(RightTypeEl).Ranges)>0 then
  15034. begin
  15035. // right side is a static array -> clone
  15036. {$IFDEF VerbosePas2JS}
  15037. writeln('TPasToJSConverter.ConvertAssignStatement STATIC ARRAY variable Right={',GetResolverResultDbg(AssignContext.RightResolved),'} AssignContext.RightResolved.IdentEl=',GetObjName(AssignContext.RightResolved.IdentEl));
  15038. {$ENDIF}
  15039. AssignContext.RightSide:=CreateCloneStaticArray(El.right,
  15040. TPasArrayType(RightTypeEl),AssignContext.RightSide,AContext);
  15041. end;
  15042. end
  15043. else if RightTypeEl.ClassType=TPasClassType then
  15044. begin
  15045. if AssignContext.LeftResolved.BaseType in btAllStrings then
  15046. begin
  15047. if TPasClassType(RightTypeEl).ObjKind=okInterface then
  15048. begin
  15049. // aString:=IntfTypeOrVar -> intfTypeOrVar.$guid
  15050. AssignContext.RightSide:=CreateDotExpression(El,
  15051. AssignContext.RightSide,CreatePrimitiveDotExpr(FBuiltInNames[pbivnIntfGUID],El));
  15052. end;
  15053. end
  15054. else if AssignContext.LeftResolved.BaseType=btContext then
  15055. begin
  15056. LeftTypeEl:=AssignContext.LeftResolved.LoTypeEl;
  15057. if LeftTypeEl.ClassType=TPasRecordType then
  15058. begin
  15059. if (TPasClassType(RightTypeEl).ObjKind=okInterface)
  15060. and SameText(LeftTypeEl.Name,'TGUID') then
  15061. begin
  15062. // GUIDRecord:=IntfTypeOrVar -> new TGuid(rtl.getIntfGUIDR(IntfTypeOrVar))
  15063. NewME:=CreateNewRecord(El,TPasRecordType(LeftTypeEl),AContext);
  15064. Call:=CreateCallExpression(El);
  15065. NewME.AddArg(Call);
  15066. Call.Expr:=CreatePrimitiveDotExpr(FBuiltInNames[pbivnRTL]+'.'+FBuiltInNames[pbifnIntfGetGUIDR],El);
  15067. Call.AddArg(AssignContext.RightSide);
  15068. AssignContext.RightSide:=NewME;
  15069. end
  15070. else
  15071. RaiseNotSupported(El,AContext,20180413194856);
  15072. end
  15073. else if LeftTypeEl.ClassType=TPasClassType then
  15074. case TPasClassType(LeftTypeEl).ObjKind of
  15075. okClass:
  15076. case TPasClassType(RightTypeEl).ObjKind of
  15077. okClass: ; // ClassInstVar:=ClassInstVar
  15078. else
  15079. NotSupported(AssignContext,20180327202735);
  15080. end;
  15081. okInterface:
  15082. case TPasClassType(RightTypeEl).ObjKind of
  15083. okClass:
  15084. begin
  15085. // IntfVar:=ClassInstVar
  15086. if TPasClassType(RightTypeEl).IsExternal then
  15087. RaiseNotSupported(El.right,AContext,20180327210004,'external class instance');
  15088. if AssignContext.LeftResolved.LoTypeEl=nil then
  15089. RaiseNotSupported(El.right,AContext,20180327204021);
  15090. Call:=CreateCallExpression(El.right);
  15091. case TPasClassType(LeftTypeEl).InterfaceType of
  15092. // COM: $ir.ref(id,rtl.queryIntfT(ClassInstVar,IntfVarType))
  15093. citCom:
  15094. begin
  15095. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnIntfQueryIntfT]]);
  15096. Call.AddArg(AssignContext.RightSide);
  15097. AssignContext.RightSide:=Call;
  15098. Call.AddArg(CreateReferencePathExpr(AssignContext.LeftResolved.LoTypeEl,
  15099. AContext));
  15100. Call:=CreateIntfRef(Call,AContext,El);
  15101. AssignContext.RightSide:=Call;
  15102. end;
  15103. // CORBA: rtl.getIntfT(ClassInstVar,IntfVarType)
  15104. citCorba:
  15105. begin
  15106. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnIntfGetIntfT]]);
  15107. Call.AddArg(AssignContext.RightSide);
  15108. AssignContext.RightSide:=Call;
  15109. Call.AddArg(CreateReferencePathExpr(AssignContext.LeftResolved.LoTypeEl,
  15110. AContext));
  15111. end;
  15112. else RaiseNotSupported(El,AContext,20180401225931,InterfaceTypeNames[TPasClassType(RightTypeEl).InterfaceType]);
  15113. end;
  15114. end;
  15115. okInterface: ;// IntfVar:=IntfVar
  15116. else
  15117. NotSupported(AssignContext,20180327203326);
  15118. end;
  15119. else
  15120. NotSupported(AssignContext,20180327203334);
  15121. end;
  15122. end;
  15123. end
  15124. else if RightTypeEl.ClassType=TPasRecordType then
  15125. begin
  15126. // right side is a record
  15127. NeedClone:=true;
  15128. if AssignContext.LeftResolved.BaseType in btAllStrings then
  15129. begin
  15130. if aResolver.IsTGUID(TPasRecordType(RightTypeEl)) then
  15131. begin
  15132. // aString:=GUIDVar -> rtl.guidrToStr(GUIDVar)
  15133. Call:=CreateCallExpression(El);
  15134. Call.Expr:=CreatePrimitiveDotExpr(FBuiltInNames[pbivnRTL]+'.'+FBuiltInNames[pbifnIntfGuidRToStr],El);
  15135. Call.AddArg(AssignContext.RightSide);
  15136. AssignContext.RightSide:=Call;
  15137. NeedClone:=false;
  15138. end;
  15139. end;
  15140. if NeedClone then
  15141. begin
  15142. // -> clone
  15143. {$IFDEF VerbosePas2JS}
  15144. writeln('TPasToJSConverter.ConvertAssignStatement RECORD variable Right={',GetResolverResultDbg(AssignContext.RightResolved),'} AssignContext.RightResolved.IdentEl=',GetObjName(AssignContext.RightResolved.IdentEl));
  15145. {$ENDIF}
  15146. AssignContext.RightSide:=CreateCloneRecord(El.right,
  15147. TPasRecordType(RightTypeEl),AssignContext.RightSide,AContext);
  15148. end;
  15149. end;
  15150. end;
  15151. // convert left side
  15152. LHS:=ConvertElement(El.left,AssignContext);
  15153. if AssignContext.Call<>nil then
  15154. begin
  15155. // left side is a Setter -> RightSide was already inserted as parameter
  15156. if AssignContext.RightSide<>nil then
  15157. RaiseInconsistency(20170207215544,El.left);
  15158. Result:=LHS;
  15159. end
  15160. else
  15161. begin
  15162. // left side is a variable
  15163. if AssignContext.RightSide=nil then
  15164. RaiseInconsistency(20180622211919,El);
  15165. LeftTypeEl:=AssignContext.LeftResolved.LoTypeEl;
  15166. if AssignContext.LeftResolved.BaseType=btContext then
  15167. begin
  15168. if (LeftTypeEl is TPasClassType)
  15169. and (TPasClassType(LeftTypeEl).ObjKind=okInterface)
  15170. and (TPasClassType(LeftTypeEl).InterfaceType=citCom) then
  15171. begin
  15172. // left side is a COM interface variable
  15173. Result:=CreateAssignComIntfVar(AssignContext.LeftResolved,
  15174. LHS,AssignContext.RightSide,AssignContext,El);
  15175. if Result<>nil then exit;
  15176. end;
  15177. end;
  15178. // create normal assign statement
  15179. case El.Kind of
  15180. akDefault: T:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  15181. akAdd: T:=TJSAddEqAssignStatement(CreateElement(TJSAddEqAssignStatement,El));
  15182. akMinus: T:=TJSSubEqAssignStatement(CreateElement(TJSSubEqAssignStatement,El));
  15183. akMul: T:=TJSMulEqAssignStatement(CreateElement(TJSMulEqAssignStatement,El));
  15184. akDivision: T:=TJSDivEqAssignStatement(CreateElement(TJSDivEqAssignStatement,El));
  15185. else RaiseNotSupported(El,AContext,20161107221807);
  15186. end;
  15187. T.Expr:=AssignContext.RightSide;
  15188. AssignContext.RightSide:=nil;
  15189. T.LHS:=LHS;
  15190. Result:=T;
  15191. LHS:=nil;
  15192. if (bsRangeChecks in AContext.ScannerBoolSwitches)
  15193. and not (T.Expr is TJSLiteral) then
  15194. begin
  15195. if AssignContext.LeftResolved.BaseType in btAllJSInteger then
  15196. begin
  15197. if LeftTypeEl is TPasUnresolvedSymbolRef then
  15198. begin
  15199. if not aResolver.GetIntegerRange(AssignContext.LeftResolved.BaseType,MinVal,MaxVal) then
  15200. RaiseNotSupported(El.left,AContext,20180119154120);
  15201. Result:=CreateRangeCheck(Result,MinVal,MaxVal,pbifnRangeCheckInt);
  15202. end
  15203. else if LeftTypeEl.ClassType=TPasRangeType then
  15204. Result:=CreateRangeCheckType(Result,LeftTypeEl);
  15205. end
  15206. else if AssignContext.LeftResolved.BaseType in btAllJSChars then
  15207. Result:=CreateRangeCheckType(Result,LeftTypeEl)
  15208. else if AssignContext.LeftResolved.BaseType=btContext then
  15209. begin
  15210. if LeftTypeEl.ClassType=TPasEnumType then
  15211. Result:=CreateRangeCheckType(Result,LeftTypeEl);
  15212. end
  15213. else if AssignContext.LeftResolved.BaseType=btRange then
  15214. begin
  15215. if AssignContext.LeftResolved.SubType in btAllJSChars then
  15216. Result:=CreateRangeCheckType(Result,LeftTypeEl)
  15217. else if AssignContext.LeftResolved.SubType=btContext then
  15218. Result:=CreateRangeCheckType(Result,LeftTypeEl)
  15219. else
  15220. begin
  15221. {$IFDEF VerbosePas2JS}
  15222. writeln('TPasToJSConverter.ConvertAssignStatement ',GetResolverResultDbg(AssignContext.LeftResolved));
  15223. RaiseNotSupported(El,AContext,20180424121201);
  15224. {$ENDIF}
  15225. end;
  15226. end;
  15227. end;
  15228. end;
  15229. finally
  15230. if Result=nil then
  15231. LHS.Free;
  15232. AssignContext.RightSide.Free;
  15233. AssignContext.Free;
  15234. end;
  15235. end;
  15236. function TPasToJSConverter.ConvertIfStatement(El: TPasImplIfElse;
  15237. AContext: TConvertContext): TJSElement;
  15238. Var
  15239. C, BThen, BElse: TJSElement;
  15240. T: TJSIfStatement;
  15241. begin
  15242. Result:=nil;
  15243. if AContext=nil then ;
  15244. C:=Nil;
  15245. BThen:=Nil;
  15246. BElse:=Nil;
  15247. try
  15248. C:=ConvertElement(El.ConditionExpr,AContext);
  15249. if Assigned(El.IfBranch) then
  15250. BThen:=ConvertElement(El.IfBranch,AContext);
  15251. if Assigned(El.ElseBranch) then
  15252. BElse:=ConvertElement(El.ElseBranch,AContext);
  15253. T:=TJSIfStatement(CreateElement(TJSIfStatement,El));
  15254. T.Cond:=C;
  15255. T.BTrue:=BThen;
  15256. T.BFalse:=BElse;
  15257. Result:=T;
  15258. finally
  15259. if Result=nil then
  15260. begin
  15261. FreeAndNil(C);
  15262. FreeAndNil(BThen);
  15263. FreeAndNil(BElse);
  15264. end;
  15265. end;
  15266. end;
  15267. function TPasToJSConverter.ConvertWhileStatement(El: TPasImplWhileDo;
  15268. AContext: TConvertContext): TJSElement;
  15269. Var
  15270. C : TJSElement;
  15271. B : TJSElement;
  15272. W : TJSWhileStatement;
  15273. ok: Boolean;
  15274. begin
  15275. Result:=Nil;
  15276. C:=Nil;
  15277. B:=Nil;
  15278. ok:=false;
  15279. try
  15280. C:=ConvertElement(EL.ConditionExpr,AContext);
  15281. if Assigned(EL.Body) then
  15282. B:=ConvertElement(EL.Body,AContext)
  15283. else
  15284. B:=TJSEmptyBlockStatement(CreateElement(TJSEmptyBlockStatement,El));
  15285. ok:=true;
  15286. finally
  15287. if not ok then
  15288. begin
  15289. FreeAndNil(B);
  15290. FreeAndNil(C);
  15291. end;
  15292. end;
  15293. W:=TJSWhileStatement(CreateElement(TJSWhileStatement,El));
  15294. W.Cond:=C;
  15295. W.Body:=B;
  15296. Result:=W;
  15297. end;
  15298. function TPasToJSConverter.ConvertRepeatStatement(El: TPasImplRepeatUntil;
  15299. AContext: TConvertContext): TJSElement;
  15300. // do{implblock}while(!untilcondition);
  15301. var
  15302. C : TJSElement;
  15303. W : TJSDoWhileStatement;
  15304. B : TJSElement;
  15305. begin
  15306. Result:=Nil;
  15307. C:=Nil;
  15308. B:=Nil;
  15309. try
  15310. C:=ConvertElement(El.ConditionExpr,AContext);
  15311. if C is TJSUnaryNotExpression then
  15312. begin
  15313. // Note: do..while(condition) checks for truthiness, same as the ! operator
  15314. // therefore do..while(!!expr) is the same as do..while(expr)
  15315. B:=C;
  15316. C:=TJSUnaryNotExpression(B).A;
  15317. TJSUnaryNotExpression(B).A:=nil;
  15318. B.Free;
  15319. B:=nil;
  15320. end
  15321. else
  15322. C:=CreateUnaryNot(C,El.ConditionExpr);
  15323. B:=ConvertImplBlockElements(El,AContext,false);
  15324. W:=TJSDoWhileStatement(CreateElement(TJSDoWhileStatement,El));
  15325. W.Cond:=C;
  15326. W.Body:=B;
  15327. Result:=W;
  15328. finally
  15329. if Result=nil then
  15330. begin
  15331. FreeAndNil(B);
  15332. FreeAndNil(C);
  15333. end;
  15334. end;
  15335. end;
  15336. function TPasToJSConverter.ConvertForStatement(El: TPasImplForLoop;
  15337. AContext: TConvertContext): TJSElement;
  15338. // Creates the following code:
  15339. // for (var $loop1 = <startexpr>, $loopend = <endexpr>; $loop<=$loopend; $loop++){
  15340. // VariableName = $loop;
  15341. // ...Body...
  15342. // }
  15343. //
  15344. // For compatibility:
  15345. // LoopVar can be a varname or programname.varname
  15346. // The StartExpr must be executed exactly once at beginning.
  15347. // The EndExpr must be executed exactly once at beginning.
  15348. // If the loop is not executed the Variable is not set, aka keeps its old value.
  15349. // After the loop the variable has the last value.
  15350. type
  15351. TInKind = (
  15352. ikNone,
  15353. ikEnum,
  15354. ikBool,
  15355. ikChar,
  15356. ikString,
  15357. ikArray,
  15358. ikSetInt,
  15359. ikSetBool,
  15360. ikSetChar,
  15361. ikSetString
  15362. );
  15363. var
  15364. aResolver: TPas2JSResolver;
  15365. function ConvExpr(Expr: TPasExpr): TJSElement; overload;
  15366. var
  15367. ResolvedEl: TPasResolverResult;
  15368. begin
  15369. Result:=ConvertElement(Expr,AContext);
  15370. if Result is TJSLiteral then
  15371. case TJSLiteral(Result).Value.ValueType of
  15372. jstBoolean:
  15373. // convert bool literal to int
  15374. TJSLiteral(Result).Value.AsNumber:=ord(TJSLiteral(Result).Value.AsBoolean);
  15375. jstNumber:
  15376. exit;
  15377. jstString:
  15378. begin
  15379. // convert char literal to int
  15380. ConvertCharLiteralToInt(TJSLiteral(Result),Expr,AContext);
  15381. exit;
  15382. end;
  15383. else
  15384. Result.Free;
  15385. RaiseNotSupported(Expr,AContext,20171112021222);
  15386. end
  15387. else if aResolver<>nil then
  15388. begin
  15389. aResolver.ComputeElement(Expr,ResolvedEl,[]);
  15390. if (ResolvedEl.BaseType in btAllChars)
  15391. or ((ResolvedEl.BaseType=btRange) and (ResolvedEl.SubType in btAllChars)) then
  15392. begin
  15393. // convert char variable to int: append .charCodeAt()
  15394. Result:=CreateCallCharCodeAt(Result,0,Expr);
  15395. end
  15396. else if (ResolvedEl.BaseType in btAllJSBooleans)
  15397. or ((ResolvedEl.BaseType=btRange) and (ResolvedEl.SubType in btAllJSBooleans)) then
  15398. begin
  15399. // convert bool variable to int: +expr
  15400. Result:=CreateUnaryPlus(Result,Expr);
  15401. end;
  15402. end;
  15403. end;
  15404. function GetOrd(Value: TResEvalValue; ErrorEl: TPasElement): TMaxPrecInt; overload;
  15405. var
  15406. OrdValue: TResEvalValue;
  15407. begin
  15408. if Value=nil then
  15409. exit(0);
  15410. OrdValue:=aResolver.ExprEvaluator.OrdValue(Value,ErrorEl);
  15411. case OrdValue.Kind of
  15412. revkInt: Result:=TResEvalInt(OrdValue).Int;
  15413. else
  15414. RaiseNotSupported(ErrorEl,AContext,20171112133917);
  15415. end;
  15416. if Value<>OrdValue then
  15417. ReleaseEvalValue(OrdValue);
  15418. end;
  15419. function GetEnumValue(EnumType: TPasEnumType; Int: TMaxPrecInt): TResEvalValue; overload;
  15420. begin
  15421. if (coEnumNumbers in Options) or (Int<0) or (Int>=EnumType.Values.Count) then
  15422. Result:=TResEvalInt.CreateValue(Int)
  15423. else
  15424. Result:=TResEvalEnum.CreateValue(Int,TObject(EnumType.Values[Int]) as TPasEnumValue);
  15425. end;
  15426. var
  15427. FuncContext: TConvertContext;
  15428. VarResolved, InResolved: TPasResolverResult;
  15429. StartValue, EndValue, InValue: TResEvalValue;
  15430. StartInt, EndInt: TMaxPrecInt;
  15431. HasLoopVar, HasEndVar, HasInVar: Boolean;
  15432. InKind: TInKind;
  15433. ForScope: TPasForLoopScope;
  15434. function InitWithResolver: boolean;
  15435. var
  15436. EnumType: TPasEnumType;
  15437. TypeEl: TPasType;
  15438. ArgResolved, LengthResolved, PropResultResolved: TPasResolverResult;
  15439. begin
  15440. Result:=true;
  15441. aResolver.ComputeElement(El.VariableName,VarResolved,[rcNoImplicitProc]);
  15442. if (not (VarResolved.IdentEl is TPasVariable))
  15443. and not (VarResolved.IdentEl is TPasResultElement) then
  15444. DoError(20170213214404,nXExpectedButYFound,sXExpectedButYFound,['var',
  15445. aResolver.GetResolverResultDescription(VarResolved)],El.VariableName);
  15446. case El.LoopType of
  15447. ltNormal,ltDown:
  15448. begin
  15449. StartValue:=aResolver.Eval(El.StartExpr,[],false);
  15450. StartInt:=GetOrd(StartValue,El.StartExpr);
  15451. EndValue:=aResolver.Eval(El.EndExpr,[],false);
  15452. EndInt:=GetOrd(EndValue,El.EndExpr);
  15453. end;
  15454. ltIn:
  15455. begin
  15456. if ForScope.GetEnumerator<>nil then
  15457. begin
  15458. ConvertForStatement:=CreateGetEnumeratorLoop(El,AContext);
  15459. exit(false);
  15460. end;
  15461. aResolver.ComputeElement(El.StartExpr,InResolved,[]);
  15462. HasInVar:=true;
  15463. InValue:=aResolver.Eval(El.StartExpr,[],false);
  15464. if InValue=nil then
  15465. begin
  15466. if InResolved.IdentEl is TPasType then
  15467. begin
  15468. TypeEl:=aResolver.ResolveAliasType(TPasType(InResolved.IdentEl));
  15469. if TypeEl is TPasArrayType then
  15470. begin
  15471. if length(TPasArrayType(TypeEl).Ranges)=1 then
  15472. InValue:=aResolver.Eval(TPasArrayType(TypeEl).Ranges[0],[refConst]);
  15473. end
  15474. else if TypeEl is TPasSetType then
  15475. InValue:=aResolver.EvalTypeRange(TPasSetType(TypeEl).EnumType,[refConst]);
  15476. end;
  15477. end;
  15478. if InValue<>nil then
  15479. begin
  15480. // for <var> in <constant> do
  15481. case InValue.Kind of
  15482. {$IFDEF FPC_HAS_CPSTRING}
  15483. revkString,
  15484. {$ENDIF}
  15485. revkUnicodeString:
  15486. begin
  15487. // example:
  15488. // for c in 'foo' do ;
  15489. // -> for (var $l1 = 0, $li2 = 'foo'; $l1<=2; $l1++) c = $li2.charAt($l1);
  15490. InKind:=ikString;
  15491. StartInt:=0;
  15492. {$IFDEF FPC_HAS_CPSTRING}
  15493. if InValue.Kind=revkString then
  15494. EndInt:=length(UTF8Decode(TResEvalString(InValue).S))-1
  15495. else
  15496. {$ENDIF}
  15497. EndInt:=length(TResEvalUTF16(InValue).S)-1;
  15498. ReleaseEvalValue(InValue);
  15499. end;
  15500. revkRangeInt,revkSetOfInt:
  15501. begin
  15502. if InValue.Kind=revkSetOfInt then
  15503. begin
  15504. if length(TResEvalSet(InValue).Ranges)=0 then
  15505. exit(false);
  15506. if length(TResEvalSet(InValue).Ranges)>1 then
  15507. begin
  15508. // set, non continuous range
  15509. case TResEvalSet(InValue).ElKind of
  15510. revskEnum,revskInt: InKind:=ikSetInt;
  15511. revskChar: InKind:=ikSetChar;
  15512. revskBool: InKind:=ikSetBool;
  15513. end;
  15514. HasInVar:=false;
  15515. HasLoopVar:=InKind<>ikSetInt;
  15516. HasEndVar:=false;
  15517. exit;
  15518. end;
  15519. end;
  15520. StartInt:=TResEvalRangeInt(InValue).RangeStart;
  15521. EndInt:=TResEvalRangeInt(InValue).RangeEnd;
  15522. HasInVar:=false;
  15523. HasEndVar:=false;
  15524. case TResEvalRangeInt(InValue).ElKind of
  15525. revskEnum:
  15526. if coEnumNumbers in Options then
  15527. InKind:=ikNone
  15528. else
  15529. begin
  15530. InKind:=ikEnum;
  15531. EnumType:=TPasEnumType(TResEvalRangeInt(InValue).ElType);
  15532. StartValue:=GetEnumValue(EnumType,StartInt);
  15533. EndValue:=GetEnumValue(EnumType,EndInt);
  15534. end;
  15535. revskInt:
  15536. InKind:=ikNone;
  15537. revskChar:
  15538. InKind:=ikChar;
  15539. revskBool:
  15540. InKind:=ikBool;
  15541. else
  15542. {$IFDEF VerbosePas2JS}
  15543. writeln('TPasToJSConverter.ConvertForStatement ',GetObjName(El.StartExpr),' InValue=',InValue.AsDebugString);
  15544. {$ENDIF}
  15545. RaiseNotSupported(El.StartExpr,AContext,20171113023419);
  15546. end;
  15547. end
  15548. else
  15549. {$IFDEF VerbosePas2JS}
  15550. writeln('TPasToJSConverter.ConvertForStatement ',GetObjName(El.StartExpr),' InValue=',InValue.AsDebugString);
  15551. {$ENDIF}
  15552. RaiseNotSupported(El.StartExpr,AContext,20171112161527);
  15553. end;
  15554. end
  15555. else if rrfReadable in InResolved.Flags then
  15556. begin
  15557. // for v in <variable> do
  15558. if InResolved.BaseType in btAllStrings then
  15559. begin
  15560. InKind:=ikString;
  15561. StartInt:=0;
  15562. end
  15563. else if InResolved.BaseType=btCustom then
  15564. begin
  15565. if aResolver.IsJSBaseType(InResolved,pbtJSValue) then
  15566. begin
  15567. // for v in jsvalue do
  15568. InKind:=ikSetString;
  15569. HasInVar:=false;
  15570. HasLoopVar:=false;
  15571. HasEndVar:=false;
  15572. exit;
  15573. end;
  15574. end
  15575. else if InResolved.BaseType=btContext then
  15576. begin
  15577. TypeEl:=InResolved.LoTypeEl;
  15578. if TypeEl.ClassType=TPasArrayType then
  15579. begin
  15580. if length(TPasArrayType(TypeEl).Ranges)<=1 then
  15581. begin
  15582. InKind:=ikArray;
  15583. StartInt:=0;
  15584. end
  15585. else
  15586. begin
  15587. {$IFDEF VerbosePas2JS}
  15588. writeln('TPasToJSConverter.ConvertForStatement.InitWithResolver ResolvedIn=',GetResolverResultDbg(InResolved),' length(Ranges)=',length(TPasArrayType(TypeEl).Ranges));
  15589. {$ENDIF}
  15590. RaiseNotSupported(El.StartExpr,AContext,20171220010147);
  15591. end;
  15592. end
  15593. else if (TypeEl.ClassType=TPasClassType) and TPasClassType(TypeEl).IsExternal then
  15594. begin
  15595. if aResolver.IsForInExtArray(El,VarResolved,InResolved,
  15596. ArgResolved,LengthResolved,PropResultResolved) then
  15597. begin
  15598. // for v in JSArray do
  15599. InKind:=ikArray;
  15600. StartInt:=0;
  15601. end
  15602. else
  15603. begin
  15604. // for v in jsobject do -> for(v in jsobject){ }
  15605. InKind:=ikSetString;
  15606. HasInVar:=false;
  15607. HasLoopVar:=false;
  15608. HasEndVar:=false;
  15609. exit;
  15610. end;
  15611. end
  15612. else
  15613. begin
  15614. {$IFDEF VerbosePas2JS}
  15615. writeln('TPasToJSConverter.ConvertForStatement.InitWithResolver El.StartExpr=',GetObjName(El.StartExpr),' ResolvedIn=',GetResolverResultDbg(InResolved));
  15616. {$ENDIF}
  15617. RaiseNotSupported(El.StartExpr,AContext,20171113012226);
  15618. end;
  15619. end
  15620. else if InResolved.BaseType in [btSet,btArrayOrSet] then
  15621. begin
  15622. if InResolved.SubType in btAllJSBooleans then
  15623. InKind:=ikSetBool
  15624. else if InResolved.SubType in btAllChars then
  15625. InKind:=ikSetChar
  15626. else
  15627. InKind:=ikSetInt;
  15628. HasInVar:=false;
  15629. HasLoopVar:=true;
  15630. HasEndVar:=false;
  15631. exit;
  15632. end
  15633. else
  15634. begin
  15635. {$IFDEF VerbosePas2JS}
  15636. writeln('TPasToJSConverter.ConvertForStatement.InitWithResolver ResolvedIn=',GetResolverResultDbg(InResolved));
  15637. {$ENDIF}
  15638. RaiseNotSupported(El.StartExpr,AContext,20171220221747);
  15639. end;
  15640. end
  15641. else
  15642. begin
  15643. {$IFDEF VerbosePas2JS}
  15644. writeln('TPasToJSConverter.ConvertForStatement.InitWithResolver ResolvedIn=',GetResolverResultDbg(InResolved));
  15645. {$ENDIF}
  15646. RaiseNotSupported(El.StartExpr,AContext,20171112195629);
  15647. end;
  15648. end;
  15649. end;
  15650. if EndValue<>nil then
  15651. begin
  15652. HasEndVar:=false;
  15653. if (StartValue<>nil) then
  15654. begin
  15655. if StartInt<=EndInt then
  15656. begin
  15657. // loop is always executed
  15658. if StartValue.Kind in [revkInt,revkUInt,revkEnum] then
  15659. HasLoopVar:=false; // variable can be used as runner
  15660. end
  15661. else
  15662. begin
  15663. // loop is never executed
  15664. if coEliminateDeadCode in Options then exit;
  15665. end;
  15666. end;
  15667. end;
  15668. end;
  15669. function CreateStrictNotEqual0(Left: TJSElement; PosEl: TPasElement): TJSElement;
  15670. var
  15671. SNE: TJSEqualityExpressionSNE;
  15672. begin
  15673. SNE:=TJSEqualityExpressionSNE(CreateElement(TJSEqualityExpressionSNE,PosEl));
  15674. SNE.A:=Left;
  15675. SNE.B:=CreateLiteralNumber(PosEl,0);
  15676. Result:=SNE;
  15677. end;
  15678. Var
  15679. ForSt : TJSBodyStatement;
  15680. List: TJSStatementList;
  15681. SimpleAss : TJSSimpleAssignStatement;
  15682. Incr: TJSUNaryExpression;
  15683. BinExp : TJSBinaryExpression;
  15684. VarStat: TJSVariableStatement;
  15685. CurLoopVarName, CurEndVarName, CurInVarName: String;
  15686. PosEl: TPasElement;
  15687. Statements, V: TJSElement;
  15688. Call: TJSCallExpression;
  15689. Br: TJSBracketMemberExpression;
  15690. begin
  15691. Result:=Nil;
  15692. if AContext.Access<>caRead then
  15693. RaiseInconsistency(20170213213740,El);
  15694. aResolver:=AContext.Resolver;
  15695. ForScope:=El.CustomData as TPasForLoopScope; // can be nil!
  15696. case El.LoopType of
  15697. ltNormal,ltDown: ;
  15698. ltIn:
  15699. if aResolver=nil then
  15700. RaiseNotSupported(El,AContext,20171112160707);
  15701. else
  15702. {$IFDEF VerbosePas2JS}
  15703. writeln('TPasToJSConverter.ConvertForStatement LoopType=',El.LoopType);
  15704. {$ENDIF}
  15705. RaiseNotSupported(El,AContext,20171110141937);
  15706. end;
  15707. // get function context
  15708. FuncContext:=AContext;
  15709. while (FuncContext.Parent<>nil) and (not (FuncContext is TFunctionContext)) do
  15710. FuncContext:=FuncContext.Parent;
  15711. StartValue:=nil;
  15712. StartInt:=0;
  15713. EndValue:=nil;
  15714. EndInt:=0;
  15715. InValue:=nil;
  15716. InKind:=ikNone;
  15717. Statements:=nil;
  15718. try
  15719. HasLoopVar:=true;
  15720. HasEndVar:=true;
  15721. HasInVar:=false;
  15722. if (aResolver<>nil) and not InitWithResolver then
  15723. exit;
  15724. // create unique var names $l, $end, $in
  15725. if HasInVar then
  15726. CurInVarName:=FuncContext.CreateLocalIdentifier(FBuiltInNames[pbivnLoopIn])
  15727. else
  15728. CurInVarName:='';
  15729. if HasLoopVar then
  15730. CurLoopVarName:=FuncContext.CreateLocalIdentifier(FBuiltInNames[pbivnLoop])
  15731. else
  15732. CurLoopVarName:='';
  15733. if HasEndVar then
  15734. CurEndVarName:=FuncContext.CreateLocalIdentifier(FBuiltInNames[pbivnLoopEnd])
  15735. else
  15736. CurEndVarName:='';
  15737. // add "for()"
  15738. if InKind in [ikSetInt,ikSetBool,ikSetChar,ikSetString] then
  15739. ForSt:=TJSForInStatement(CreateElement(TJSForInStatement,El))
  15740. else
  15741. ForSt:=TJSForStatement(CreateElement(TJSForStatement,El));
  15742. Statements:=ForSt;
  15743. PosEl:=El;
  15744. // add in front of for(): variable=<startexpr>
  15745. if (not HasLoopVar) and (HasEndVar or HasInVar) then
  15746. begin
  15747. // for example:
  15748. // i=<startexpr>;
  15749. // for (var $end = <endexpr>; $i<$end; $i++)...
  15750. List:=TJSStatementList(CreateElement(TJSStatementList,El));
  15751. SimpleAss:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El.VariableName));
  15752. List.A:=SimpleAss;
  15753. List.B:=Statements;
  15754. Statements:=List;
  15755. SimpleAss.LHS:=ConvertElement(El.VariableName,AContext);
  15756. if StartValue<>nil then
  15757. SimpleAss.Expr:=CreateLiteralNumber(El.StartExpr,StartInt)
  15758. else
  15759. SimpleAss.Expr:=ConvertElement(El.StartExpr,AContext);
  15760. PosEl:=El.StartExpr;
  15761. end;
  15762. if ForSt.ClassType=TJSForInStatement then
  15763. begin
  15764. if HasLoopVar then
  15765. begin
  15766. // add for("var $l" in <startexpr>)
  15767. VarStat:=TJSVariableStatement(CreateElement(TJSVariableStatement,PosEl));
  15768. VarStat.A:=CreatePrimitiveDotExpr(CurLoopVarName,PosEl);
  15769. TJSForInStatement(ForSt).LHS:=VarStat;
  15770. end
  15771. else
  15772. // add for("<varname>" in <startexpr>)
  15773. TJSForInStatement(ForSt).LHS:=ConvertElement(El.VariableName,AContext);
  15774. // add for(<varname> in "<startexpr>")
  15775. TJSForInStatement(ForSt).List:=ConvertElement(El.StartExpr,AContext);
  15776. end
  15777. else if HasLoopVar or HasEndVar or HasInVar then
  15778. begin
  15779. // add "for(var ..."
  15780. VarStat:=TJSVariableStatement(CreateElement(TJSVariableStatement,El));
  15781. TJSForStatement(ForSt).Init:=VarStat;
  15782. if HasInVar then
  15783. begin
  15784. // add "$in=<InExpr>"
  15785. PosEl:=El.StartExpr;
  15786. if (InValue<>nil) and (InValue.Kind<>revkSetOfInt) then
  15787. V:=ConvertConstValue(InValue,AContext,PosEl)
  15788. else
  15789. V:=ConvertElement(El.StartExpr,AContext);
  15790. V:=CreateVarDecl(CurInVarName,V,PosEl);
  15791. AddToVarStatement(VarStat,V,PosEl);
  15792. end;
  15793. if HasLoopVar then
  15794. begin
  15795. // add "$l=<StartExpr>"
  15796. PosEl:=El.StartExpr;
  15797. if StartValue<>nil then
  15798. V:=CreateLiteralNumber(PosEl,StartInt)
  15799. else if El.LoopType=ltIn then
  15800. V:=CreateLiteralNumber(PosEl,StartInt)
  15801. else
  15802. V:=ConvExpr(El.StartExpr);
  15803. V:=CreateVarDecl(CurLoopVarName,V,PosEl);
  15804. AddToVarStatement(VarStat,V,PosEl);
  15805. end;
  15806. if HasEndVar then
  15807. begin
  15808. // add "$end=<EndExpr>"
  15809. PosEl:=El.EndExpr;
  15810. if PosEl=nil then
  15811. PosEl:=El.StartExpr;
  15812. if EndValue<>nil then
  15813. V:=CreateLiteralNumber(PosEl,EndInt)
  15814. else if El.LoopType=ltIn then
  15815. case InKind of
  15816. ikEnum,ikBool,ikChar:
  15817. V:=CreateLiteralNumber(PosEl,EndInt);
  15818. ikString:
  15819. begin
  15820. // add "$in.length-1"
  15821. V:=TJSAdditiveExpressionMinus(CreateElement(TJSAdditiveExpressionMinus,PosEl));
  15822. TJSAdditiveExpressionMinus(V).A:=CreatePrimitiveDotExpr(CurInVarName+'.length',PosEl);
  15823. TJSAdditiveExpressionMinus(V).B:=CreateLiteralNumber(PosEl,1);
  15824. end;
  15825. ikArray:
  15826. begin
  15827. // add "rtl.length($in)-1"
  15828. Call:=CreateCallExpression(PosEl);
  15829. Call.Expr:=CreatePrimitiveDotExpr(FBuiltInNames[pbivnRTL]+'.'+FBuiltInNames[pbifnArray_Length],PosEl);
  15830. Call.AddArg(CreatePrimitiveDotExpr(CurInVarName,PosEl));
  15831. V:=TJSAdditiveExpressionMinus(CreateElement(TJSAdditiveExpressionMinus,PosEl));
  15832. TJSAdditiveExpressionMinus(V).A:=Call;
  15833. TJSAdditiveExpressionMinus(V).B:=CreateLiteralNumber(PosEl,1);
  15834. end;
  15835. else
  15836. RaiseNotSupported(El.StartExpr,AContext,20171113015445);
  15837. end
  15838. else
  15839. V:=ConvExpr(El.EndExpr);
  15840. V:=CreateVarDecl(CurEndVarName,V,PosEl);
  15841. AddToVarStatement(VarStat,V,PosEl);
  15842. end;
  15843. end
  15844. else
  15845. begin
  15846. // No new vars. For example:
  15847. // for (VariableName = <startexpr>; VariableName <= <EndExpr>; VariableName++)
  15848. SimpleAss:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El.VariableName));
  15849. TJSForStatement(ForSt).Init:=SimpleAss;
  15850. SimpleAss.LHS:=ConvertElement(El.VariableName,AContext);
  15851. if StartValue<>nil then
  15852. SimpleAss.Expr:=CreateLiteralNumber(El.StartExpr,StartInt)
  15853. else
  15854. SimpleAss.Expr:=ConvertElement(El.StartExpr,AContext);
  15855. PosEl:=El.StartExpr;
  15856. end;
  15857. if ForSt.ClassType=TJSForStatement then
  15858. begin
  15859. // add "$l<=$end"
  15860. if (El.EndExpr<>nil) then
  15861. PosEl:=El.EndExpr;
  15862. if El.Down then
  15863. BinExp:=TJSRelationalExpressionGE(CreateElement(TJSRelationalExpressionGE,PosEl))
  15864. else
  15865. BinExp:=TJSRelationalExpressionLE(CreateElement(TJSRelationalExpressionLE,PosEl));
  15866. TJSForStatement(ForSt).Cond:=BinExp;
  15867. if HasLoopVar then
  15868. BinExp.A:=CreatePrimitiveDotExpr(CurLoopVarName,PosEl)
  15869. else
  15870. BinExp.A:=ConvertElement(El.VariableName,AContext);
  15871. if HasEndVar then
  15872. BinExp.B:=CreatePrimitiveDotExpr(CurEndVarName,PosEl)
  15873. else
  15874. BinExp.B:=CreateLiteralNumber(PosEl,EndInt);
  15875. // add "$l++"
  15876. if El.Down then
  15877. Incr:=TJSUnaryPostMinusMinusExpression(CreateElement(TJSUnaryPostMinusMinusExpression,PosEl))
  15878. else
  15879. Incr:=TJSUnaryPostPlusPlusExpression(CreateElement(TJSUnaryPostPlusPlusExpression,PosEl));
  15880. TJSForStatement(ForSt).Incr:=Incr;
  15881. if HasLoopVar then
  15882. Incr.A:=CreatePrimitiveDotExpr(CurLoopVarName,PosEl)
  15883. else
  15884. Incr.A:=ConvertElement(El.VariableName,AContext);
  15885. end;
  15886. // add "VariableName:=$l;"
  15887. if HasLoopVar then
  15888. begin
  15889. PosEl:=El.Body;
  15890. if PosEl=nil then
  15891. PosEl:=El;
  15892. PosEl:=El.VariableName;
  15893. SimpleAss:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,PosEl));
  15894. ForSt.Body:=SimpleAss;
  15895. SimpleAss.LHS:=ConvertElement(El.VariableName,AContext);
  15896. SimpleAss.Expr:=CreatePrimitiveDotExpr(CurLoopVarName,PosEl);
  15897. if aResolver<>nil then
  15898. begin
  15899. if InKind<>ikNone then
  15900. case InKind of
  15901. ikEnum,ikSetInt:
  15902. if ForSt.ClassType=TJSForInStatement then
  15903. // $in=+$l
  15904. SimpleAss.Expr:=CreateUnaryPlus(SimpleAss.Expr,PosEl);
  15905. ikBool,ikSetBool:
  15906. // $in!==0;
  15907. SimpleAss.Expr:=CreateStrictNotEqual0(SimpleAss.Expr,PosEl);
  15908. ikChar,ikSetChar:
  15909. // String.fromCharCode($l)
  15910. SimpleAss.Expr:=CreateCallFromCharCode(SimpleAss.Expr,PosEl);
  15911. ikString:
  15912. begin
  15913. // $in.charAt($l)
  15914. Call:=CreateCallExpression(PosEl);
  15915. Call.Expr:=CreateDotExpression(PosEl,
  15916. CreatePrimitiveDotExpr(CurInVarName,El.StartExpr),
  15917. CreatePrimitiveDotExpr('charAt',PosEl));
  15918. Call.AddArg(SimpleAss.Expr);
  15919. SimpleAss.Expr:=Call;
  15920. end;
  15921. ikArray:
  15922. begin
  15923. // $in[$l]
  15924. Br:=TJSBracketMemberExpression(CreateElement(TJSBracketMemberExpression,PosEl));
  15925. Br.MExpr:=CreatePrimitiveDotExpr(CurInVarName,El.StartExpr);
  15926. Br.Name:=SimpleAss.Expr;
  15927. SimpleAss.Expr:=Br;
  15928. end;
  15929. else
  15930. {$IFDEF VerbosePas2JS}
  15931. writeln('TPasToJSConverter.ConvertForStatement InKind=',InKind);
  15932. {$ENDIF}
  15933. RaiseNotSupported(El.StartExpr,AContext,20171113002550);
  15934. end
  15935. else if (VarResolved.BaseType in btAllChars)
  15936. or ((VarResolved.BaseType=btRange) and (VarResolved.SubType in btAllChars)) then
  15937. begin
  15938. // convert int to char
  15939. SimpleAss.Expr:=CreateCallFromCharCode(SimpleAss.Expr,PosEl);
  15940. end
  15941. else if (VarResolved.BaseType in btAllJSBooleans)
  15942. or ((VarResolved.BaseType=btRange) and (VarResolved.SubType in btAllJSBooleans)) then
  15943. begin
  15944. // convert int to bool -> $l!=0
  15945. SimpleAss.Expr:=CreateStrictNotEqual0(SimpleAss.Expr,PosEl);
  15946. end
  15947. end;
  15948. end;
  15949. // add body
  15950. if El.Body<>nil then
  15951. begin
  15952. V:=ConvertElement(El.Body,AContext);
  15953. if ForSt.Body=nil then
  15954. ForSt.Body:=V
  15955. else
  15956. begin
  15957. List:=TJSStatementList(CreateElement(TJSStatementList,El.Body));
  15958. List.A:=ForSt.Body;
  15959. List.B:=V;
  15960. ForSt.Body:=List;
  15961. end;
  15962. end;
  15963. Result:=Statements;
  15964. finally
  15965. ReleaseEvalValue(StartValue);
  15966. ReleaseEvalValue(EndValue);
  15967. ReleaseEvalValue(InValue);
  15968. if Result=nil then
  15969. Statements.Free;
  15970. end;
  15971. end;
  15972. function TPasToJSConverter.ConvertSimpleStatement(El: TPasImplSimple;
  15973. AContext: TConvertContext): TJSElement;
  15974. Var
  15975. E : TJSElement;
  15976. C: TClass;
  15977. begin
  15978. E:=ConvertElement(EL.Expr,AContext);
  15979. if E=nil then
  15980. exit(nil); // e.g. "inherited;" without ancestor proc
  15981. C:=E.ClassType;
  15982. if (C=TJSExpressionStatement)
  15983. or (C=TJSStatementList) then
  15984. Result:=E
  15985. else
  15986. begin
  15987. Result:=TJSExpressionStatement(CreateElement(TJSExpressionStatement,El));
  15988. TJSExpressionStatement(Result).A:=E;
  15989. end;
  15990. end;
  15991. function TPasToJSConverter.ConvertWithStatement(El: TPasImplWithDo;
  15992. AContext: TConvertContext): TJSElement;
  15993. Var
  15994. B,E , Expr: TJSElement;
  15995. W,W2 : TJSWithStatement;
  15996. I : Integer;
  15997. ok: Boolean;
  15998. PasExpr: TPasElement;
  15999. V: TJSVariableStatement;
  16000. FuncContext: TFunctionContext;
  16001. FirstSt, LastSt: TJSStatementList;
  16002. WithScope: TPasWithScope;
  16003. WithExprScope: TPas2JSWithExprScope;
  16004. begin
  16005. Result:=nil;
  16006. if AContext.Resolver<>nil then
  16007. begin
  16008. // with Resolver:
  16009. // Insert for each expression a local var. Example:
  16010. // with aPoint do X:=3;
  16011. // convert to
  16012. // var $with1 = aPoint;
  16013. // $with1.X = 3;
  16014. FuncContext:=TFunctionContext(AContext.GetContextOfType(TFunctionContext));
  16015. if FuncContext=nil then
  16016. RaiseInconsistency(20170212003759,El);
  16017. FirstSt:=nil;
  16018. LastSt:=nil;
  16019. try
  16020. WithScope:=El.CustomData as TPasWithScope;
  16021. for i:=0 to El.Expressions.Count-1 do
  16022. begin
  16023. PasExpr:=TPasElement(El.Expressions[i]);
  16024. Expr:=ConvertElement(PasExpr,AContext);
  16025. WithExprScope:=WithScope.ExpressionScopes[i] as TPas2JSWithExprScope;
  16026. if (Expr is TJSPrimaryExpressionIdent)
  16027. and IsValidJSIdentifier(TJSPrimaryExpressionIdent(Expr).Name) then
  16028. begin
  16029. // expression is already a local variable
  16030. WithExprScope.WithVarName:=String(TJSPrimaryExpressionIdent(Expr).Name);
  16031. Expr.Free;
  16032. end
  16033. else if Expr is TJSPrimaryExpressionThis then
  16034. begin
  16035. // expression is 'this'
  16036. WithExprScope.WithVarName:='this';
  16037. Expr.Free;
  16038. end
  16039. else
  16040. begin
  16041. // create unique local var name
  16042. WithExprScope.WithVarName:=FuncContext.CreateLocalIdentifier(FBuiltInNames[pbivnWith]);
  16043. // create local "var $with1 = expr;"
  16044. V:=CreateVarStatement(WithExprScope.WithVarName,Expr,PasExpr);
  16045. AddToStatementList(FirstSt,LastSt,V,PasExpr);
  16046. end;
  16047. end;
  16048. if Assigned(El.Body) then
  16049. begin
  16050. B:=ConvertElement(El.Body,AContext);
  16051. AddToStatementList(FirstSt,LastSt,B,El.Body);
  16052. end;
  16053. Result:=FirstSt;
  16054. finally
  16055. if Result=nil then
  16056. FreeAndNil(FirstSt);
  16057. end;
  16058. end
  16059. else
  16060. begin
  16061. // without Resolver use as fallback the JavaScript with(){}
  16062. W:=Nil;
  16063. if Assigned(El.Body) then
  16064. B:=ConvertElement(El.Body,AContext)
  16065. else
  16066. B:=TJSEmptyBlockStatement(CreateElement(TJSEmptyBlockStatement,El));
  16067. ok:=false;
  16068. try
  16069. For I:=0 to El.Expressions.Count-1 do
  16070. begin
  16071. E:=ConvertElement(TPasElement(El.Expressions[i]),AContext);
  16072. W2:=TJSWithStatement(CreateElement(TJSWithStatement,TPasElement(El.Expressions[i])));
  16073. if Not Assigned(Result) then // result is the first
  16074. Result:=W2;
  16075. if Assigned(W) then // Chain
  16076. W.B:=W2;
  16077. W:=W2; // W is the last
  16078. W.A:=E;
  16079. end;
  16080. ok:=true;
  16081. finally
  16082. if not ok then
  16083. begin
  16084. FreeAndNil(E);
  16085. FreeAndNil(Result);
  16086. end;
  16087. end;
  16088. W.B:=B;
  16089. end;
  16090. end;
  16091. function TPasToJSConverter.IsElementUsed(El: TPasElement): boolean;
  16092. begin
  16093. if Assigned(OnIsElementUsed) then
  16094. Result:=OnIsElementUsed(Self,El)
  16095. else
  16096. Result:=true;
  16097. end;
  16098. function TPasToJSConverter.IsSystemUnit(aModule: TPasModule): boolean;
  16099. begin
  16100. Result:=(CompareText(aModule.Name,'system')=0) and (aModule.ClassType=TPasModule);
  16101. end;
  16102. function TPasToJSConverter.HasTypeInfo(El: TPasType; AContext: TConvertContext
  16103. ): boolean;
  16104. begin
  16105. Result:=false;
  16106. if coNoTypeInfo in Options then exit;
  16107. if AContext.Resolver=nil then exit;
  16108. if not AContext.Resolver.HasTypeInfo(El) then exit;
  16109. if Assigned(OnIsTypeInfoUsed) and not OnIsTypeInfoUsed(Self,El) then exit;
  16110. Result:=true;
  16111. end;
  16112. function TPasToJSConverter.IsClassRTTICreatedBefore(aClass: TPasClassType;
  16113. Before: TPasElement; AConText: TConvertContext): boolean;
  16114. var
  16115. Decls: TPasDeclarations;
  16116. i: Integer;
  16117. List: TFPList;
  16118. C: TClass;
  16119. aParent, Decl: TPasElement;
  16120. begin
  16121. Result:=false;
  16122. aParent:=aClass.Parent;
  16123. if aParent<>Before.Parent then
  16124. exit(true);
  16125. if not aParent.InheritsFrom(TPasDeclarations) then
  16126. RaiseInconsistency(20170412101457,aClass);
  16127. Decls:=TPasDeclarations(aParent);
  16128. List:=Decls.Declarations;
  16129. for i:=0 to List.Count-1 do
  16130. begin
  16131. Decl:=TPasElement(List[i]);
  16132. if Decl=Before then exit;
  16133. if Decl=aClass then exit(true);
  16134. C:=Decl.ClassType;
  16135. if C=TPasClassType then
  16136. begin
  16137. if TPasClassType(Decl).IsForward and (Decl.CustomData is TResolvedReference)
  16138. and (TResolvedReference(Decl.CustomData).Declaration=aClass) then
  16139. exit(true);
  16140. end
  16141. else if C=TPasClassOfType then
  16142. begin
  16143. if AConText.Resolver.ResolveAliasType(TPasClassOfType(Decl).DestType)=aClass then
  16144. exit(true);
  16145. end;
  16146. end;
  16147. end;
  16148. procedure TPasToJSConverter.FindAvailableLocalName(var aName: string;
  16149. JSExpr: TJSElement);
  16150. var
  16151. StartJSName, JSName: TJSString;
  16152. n: integer;
  16153. Changed: boolean;
  16154. procedure Next;
  16155. var
  16156. ch: WideChar;
  16157. begin
  16158. Changed:=true;
  16159. // name clash -> change JSName
  16160. if (n=0) and (length(JSName)=1) then
  16161. begin
  16162. // single letter -> choose next single letter
  16163. ch:=JSName[1];
  16164. case ch of
  16165. 'a'..'x': JSName:=succ(ch);
  16166. 'z': JSName:='a';
  16167. end;
  16168. if JSName=StartJSName then
  16169. begin
  16170. n:=1;
  16171. JSName:=StartJSName+TJSString(IntToStr(n));
  16172. end;
  16173. end
  16174. else
  16175. begin
  16176. inc(n);
  16177. JSName:=StartJSName+TJSString(IntToStr(n));
  16178. end;
  16179. end;
  16180. procedure Find(El: TJSElement);
  16181. var
  16182. C: TClass;
  16183. Call: TJSCallExpression;
  16184. i: Integer;
  16185. begin
  16186. if El=nil then exit;
  16187. C:=El.ClassType;
  16188. if C=TJSPrimaryExpressionIdent then
  16189. begin
  16190. if TJSPrimaryExpressionIdent(El).Name=JSName then
  16191. Next;
  16192. end
  16193. else if C.InheritsFrom(TJSMemberExpression) then
  16194. begin
  16195. Find(TJSMemberExpression(El).MExpr);
  16196. if C=TJSBracketMemberExpression then
  16197. Find(TJSBracketMemberExpression(El).Name)
  16198. else if C=TJSNewMemberExpression then
  16199. with TJSNewMemberExpression(El).Args.Elements do
  16200. for i:=0 to Count-1 do
  16201. Find(Elements[i].Expr);
  16202. end
  16203. else if C=TJSCallExpression then
  16204. begin
  16205. Call:=TJSCallExpression(El);
  16206. Find(Call.Expr);
  16207. if Call.Args<>nil then
  16208. with Call.Args.Elements do
  16209. for i:=0 to Count-1 do
  16210. Find(Elements[i].Expr);
  16211. end
  16212. else if C.InheritsFrom(TJSUnary) then
  16213. Find(TJSUnary(El).A)
  16214. else if C.InheritsFrom(TJSBinary) then
  16215. begin
  16216. Find(TJSBinary(El).A);
  16217. Find(TJSBinary(El).B);
  16218. end
  16219. else if C=TJSArrayLiteral then
  16220. begin
  16221. with TJSArrayLiteral(El).Elements do
  16222. for i:=0 to Count-1 do
  16223. Find(Elements[i].Expr);
  16224. end
  16225. else if C=TJSConditionalExpression then
  16226. begin
  16227. Find(TJSConditionalExpression(El).A);
  16228. Find(TJSConditionalExpression(El).B);
  16229. Find(TJSConditionalExpression(El).C);
  16230. end
  16231. else if C.InheritsFrom(TJSAssignStatement) then
  16232. begin
  16233. Find(TJSAssignStatement(El).LHS);
  16234. Find(TJSAssignStatement(El).Expr);
  16235. end
  16236. else if C=TJSVarDeclaration then
  16237. Find(TJSVarDeclaration(El).Init)
  16238. else if C=TJSObjectLiteral then
  16239. begin
  16240. with TJSObjectLiteral(El).Elements do
  16241. for i:=0 to Count-1 do
  16242. Find(Elements[i].Expr);
  16243. end
  16244. else if C=TJSIfStatement then
  16245. begin
  16246. Find(TJSIfStatement(El).Cond);
  16247. Find(TJSIfStatement(El).BTrue);
  16248. Find(TJSIfStatement(El).BFalse);
  16249. end
  16250. else if C.InheritsFrom(TJSBodyStatement) then
  16251. begin
  16252. Find(TJSBodyStatement(El).Body);
  16253. if C.InheritsFrom(TJSCondLoopStatement) then
  16254. begin
  16255. Find(TJSCondLoopStatement(El).Cond);
  16256. if C=TJSForStatement then
  16257. begin
  16258. Find(TJSForStatement(El).Init);
  16259. Find(TJSForStatement(El).Incr);
  16260. end;
  16261. end
  16262. else if C=TJSForInStatement then
  16263. begin
  16264. Find(TJSForInStatement(El).LHS);
  16265. Find(TJSForInStatement(El).List);
  16266. end;
  16267. end
  16268. else if C=TJSSwitchStatement then
  16269. begin
  16270. Find(TJSSwitchStatement(El).Cond);
  16271. with TJSSwitchStatement(El).Cases do
  16272. for i:=0 to Count-1 do
  16273. with Cases[i] do
  16274. begin
  16275. Find(Expr);
  16276. Find(Body);
  16277. end;
  16278. if TJSSwitchStatement(El).TheDefault<>nil then
  16279. with TJSSwitchStatement(El).TheDefault do
  16280. begin
  16281. Find(Expr);
  16282. Find(Body);
  16283. end;
  16284. end;
  16285. end;
  16286. begin
  16287. if JSExpr=nil then exit;
  16288. StartJSName:=TJSString(aName);
  16289. JSName:=StartJSName;
  16290. n:=0;
  16291. Changed:=false;
  16292. Find(JSExpr);
  16293. if not Changed then exit;
  16294. repeat
  16295. Changed:=false;
  16296. Find(JSExpr);
  16297. until not changed;
  16298. aName:=JSStringToString(JSName);
  16299. end;
  16300. function TPasToJSConverter.CreateUnary(Members: array of string; E: TJSElement): TJSUnary;
  16301. var
  16302. unary: TJSUnary;
  16303. asi: TJSSimpleAssignStatement;
  16304. begin
  16305. unary := TJSUnary.Create(0, 0, '');
  16306. asi := TJSSimpleAssignStatement.Create(0, 0, '');
  16307. unary.A := asi;
  16308. asi.Expr := E;
  16309. asi.LHS := CreateMemberExpression(Members);
  16310. Result := unary;
  16311. end;
  16312. function TPasToJSConverter.CreateUnaryPlus(Expr: TJSElement; El: TPasElement
  16313. ): TJSUnaryPlusExpression;
  16314. begin
  16315. Result:=TJSUnaryPlusExpression(CreateElement(TJSUnaryPlusExpression,El));
  16316. Result.A:=Expr;
  16317. end;
  16318. function TPasToJSConverter.CreateMemberExpression(Members: array of string): TJSDotMemberExpression;
  16319. var
  16320. pex: TJSPrimaryExpressionIdent;
  16321. MExpr: TJSDotMemberExpression;
  16322. LastMExpr: TJSDotMemberExpression;
  16323. k: integer;
  16324. begin
  16325. if Length(Members) < 2 then
  16326. DoError(20161024192715,'internal error: member expression with less than two members');
  16327. LastMExpr := nil;
  16328. for k:=High(Members) downto Low(Members)+1 do
  16329. begin
  16330. MExpr := TJSDotMemberExpression.Create(0, 0, '');
  16331. MExpr.Name := TJSString(Members[k]);
  16332. if LastMExpr=nil then
  16333. Result := MExpr
  16334. else
  16335. LastMExpr.MExpr := MExpr;
  16336. LastMExpr := MExpr;
  16337. end;
  16338. pex := TJSPrimaryExpressionIdent.Create(0, 0, '');
  16339. pex.Name := TJSString(Members[Low(Members)]);
  16340. LastMExpr.MExpr := pex;
  16341. end;
  16342. function TPasToJSConverter.CreateCallExpression(El: TPasElement
  16343. ): TJSCallExpression;
  16344. begin
  16345. Result:=TJSCallExpression(CreateElement(TJSCallExpression,El));
  16346. Result.Args:=TJSArguments(CreateElement(TJSArguments,El));
  16347. end;
  16348. function TPasToJSConverter.CreateCallCharCodeAt(Arg: TJSElement;
  16349. aNumber: integer; El: TPasElement): TJSCallExpression;
  16350. begin
  16351. Result:=CreateCallExpression(El);
  16352. Result.Expr:=CreateDotExpression(El,Arg,CreatePrimitiveDotExpr('charCodeAt',El));
  16353. if aNumber<>0 then
  16354. Result.Args.AddElement(CreateLiteralNumber(El,aNumber));
  16355. end;
  16356. function TPasToJSConverter.CreateCallFromCharCode(Arg: TJSElement;
  16357. El: TPasElement): TJSCallExpression;
  16358. begin
  16359. Result:=CreateCallExpression(El);
  16360. Result.Expr:=CreateMemberExpression(['String','fromCharCode']);
  16361. Result.AddArg(Arg);
  16362. end;
  16363. function TPasToJSConverter.CreateUsesList(UsesSection: TPasSection;
  16364. AContext: TConvertContext): TJSArrayLiteral;
  16365. var
  16366. ArgArray: TJSArrayLiteral;
  16367. i: Integer;
  16368. anUnitName: String;
  16369. ArgEx: TJSLiteral;
  16370. UsesClause: TPasUsesClause;
  16371. aModule: TPasModule;
  16372. begin
  16373. UsesClause:=UsesSection.UsesClause;
  16374. ArgArray:=TJSArrayLiteral.Create(0,0);
  16375. for i:=0 to length(UsesClause)-1 do
  16376. begin
  16377. aModule:=UsesClause[i].Module as TPasModule;
  16378. if (not IsElementUsed(aModule)) and not IsSystemUnit(aModule) then
  16379. continue;
  16380. anUnitName := TransformModuleName(aModule,false,AContext);
  16381. ArgEx := CreateLiteralString(UsesSection,anUnitName);
  16382. ArgArray.Elements.AddElement.Expr := ArgEx;
  16383. end;
  16384. Result:=ArgArray;
  16385. end;
  16386. procedure TPasToJSConverter.AddToStatementList(var First,
  16387. Last: TJSStatementList; Add: TJSElement; Src: TPasElement);
  16388. var
  16389. SL2: TJSStatementList;
  16390. begin
  16391. if Add=nil then exit;
  16392. if Add is TJSStatementList then
  16393. begin
  16394. // add list
  16395. if TJSStatementList(Add).A=nil then
  16396. begin
  16397. // empty list -> skip
  16398. if TJSStatementList(Add).B<>nil then
  16399. raise Exception.Create('internal error: AddToStatementList add list A=nil, B<>nil, B='+TJSStatementList(Add).B.ClassName);
  16400. FreeAndNil(Add);
  16401. end
  16402. else if Last=nil then
  16403. begin
  16404. // our list is not yet started -> simply take the extra list
  16405. Last:=TJSStatementList(Add);
  16406. First:=Last;
  16407. end
  16408. else
  16409. begin
  16410. // merge lists (append)
  16411. if Last.B<>nil then
  16412. begin
  16413. // add a nil to the end of chain
  16414. SL2:=TJSStatementList(CreateElement(TJSStatementList,Src));
  16415. SL2.A:=Last.B;
  16416. Last.B:=SL2;
  16417. Last:=SL2;
  16418. // Last.B is now nil
  16419. end;
  16420. Last.B:=Add;
  16421. while Last.B is TJSStatementList do
  16422. Last:=TJSStatementList(Last.B);
  16423. end;
  16424. end
  16425. else
  16426. begin
  16427. if Last=nil then
  16428. begin
  16429. // start list
  16430. Last:=TJSStatementList(CreateElement(TJSStatementList,Src));
  16431. First:=Last;
  16432. Last.A:=Add;
  16433. end
  16434. else if Last.B=nil then
  16435. // second element
  16436. Last.B:=Add
  16437. else
  16438. begin
  16439. // add to chain
  16440. while Last.B is TJSStatementList do
  16441. Last:=TJSStatementList(Last.B);
  16442. SL2:=TJSStatementList(CreateElement(TJSStatementList,Src));
  16443. SL2.A:=Last.B;
  16444. Last.B:=SL2;
  16445. Last:=SL2;
  16446. Last.B:=Add;
  16447. end;
  16448. end;
  16449. end;
  16450. procedure TPasToJSConverter.AddToStatementList(St: TJSStatementList;
  16451. Add: TJSElement; Src: TPasElement);
  16452. var
  16453. First, Last: TJSStatementList;
  16454. begin
  16455. First:=St;
  16456. Last:=St;
  16457. while Last.B is TJSStatementList do
  16458. Last:=TJSStatementList(Last.B);
  16459. AddToStatementList(First,Last,Add,Src);
  16460. end;
  16461. procedure TPasToJSConverter.AddToVarStatement(VarStat: TJSVariableStatement;
  16462. Add: TJSElement; Src: TPasElement);
  16463. var
  16464. List: TJSVariableDeclarationList;
  16465. begin
  16466. if VarStat.A=nil then
  16467. VarStat.A:=Add
  16468. else
  16469. begin
  16470. List:=TJSVariableDeclarationList(CreateElement(TJSVariableDeclarationList,Src));
  16471. List.A:=VarStat.A;
  16472. List.B:=Add;
  16473. VarStat.A:=List;
  16474. end;
  16475. end;
  16476. function TPasToJSConverter.CreateValInit(PasType: TPasType; Expr: TPasExpr;
  16477. El: TPasElement; AContext: TConvertContext): TJSElement;
  16478. var
  16479. T: TPasType;
  16480. Lit: TJSLiteral;
  16481. bt: TResolverBaseType;
  16482. JSBaseType: TPas2jsBaseType;
  16483. C: TClass;
  16484. aResolver: TPas2JSResolver;
  16485. Value: TResEvalValue;
  16486. begin
  16487. T:=PasType;
  16488. aResolver:=AContext.Resolver;
  16489. if aResolver<>nil then
  16490. T:=aResolver.ResolveAliasType(T);
  16491. //writeln('START TPasToJSConverter.CreateValInit PasType=',GetObjName(PasType),' El=',GetObjName(El),' T=',GetObjName(T),' Expr=',GetObjName(Expr));
  16492. if T=nil then
  16493. begin
  16494. // untyped var/const
  16495. if Expr=nil then
  16496. begin
  16497. if aResolver=nil then
  16498. exit(CreateLiteralUndefined(El));
  16499. RaiseInconsistency(20170415185745,El);
  16500. end;
  16501. Result:=ConvertElement(Expr,AContext);
  16502. if Result=nil then
  16503. begin
  16504. {$IFDEF VerbosePas2JS}
  16505. writeln('TPasToJSConverter.CreateValInit PasType=',GetObjName(PasType),' El=',GetObjName(El),' T=',GetObjName(T),' Expr=',GetObjName(Expr));
  16506. {$ENDIF}
  16507. RaiseNotSupported(Expr,AContext,20170415185927);
  16508. end;
  16509. exit;
  16510. end;
  16511. C:=T.ClassType;
  16512. if C=TPasArrayType then
  16513. Result:=CreateArrayInit(TPasArrayType(T),Expr,El,AContext)
  16514. else if C=TPasRecordType then
  16515. Result:=CreateRecordInit(TPasRecordType(T),Expr,El,AContext)
  16516. else if Assigned(Expr) then
  16517. // if there is an expression then simply convert it
  16518. Result:=ConvertElement(Expr,AContext)
  16519. else if C=TPasSetType then
  16520. // a "set" without initial value
  16521. Result:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,El))
  16522. else if (C=TPasRangeType) and (aResolver<>nil) then
  16523. begin
  16524. // a custom range without initial value
  16525. // -> for FPC/Delphi compatibility use 0 even if it is out of range
  16526. Value:=AContext.Resolver.Eval(TPasRangeType(T).RangeExpr.left,[refConst]);
  16527. try
  16528. case Value.Kind of
  16529. revkInt,revkUInt: Result:=CreateLiteralNumber(El,0);
  16530. else
  16531. Result:=ConvertConstValue(Value,AContext,El);
  16532. end;
  16533. finally
  16534. ReleaseEvalValue(Value);
  16535. end;
  16536. end
  16537. else
  16538. begin
  16539. // always init with a default value to create a typed variable (faster and more readable)
  16540. Lit:=TJSLiteral(CreateElement(TJSLiteral,El));
  16541. Result:=Lit;
  16542. if (C=TPasPointerType)
  16543. or (C=TPasClassType)
  16544. or (C=TPasClassOfType)
  16545. or (C=TPasProcedureType)
  16546. or (C=TPasFunctionType) then
  16547. Lit.Value.IsNull:=true
  16548. else if C=TPasStringType then
  16549. Lit.Value.AsString:=''
  16550. else if C=TPasEnumType then
  16551. Lit.Value.AsNumber:=0
  16552. else if C=TPasUnresolvedSymbolRef then
  16553. begin
  16554. if T.CustomData is TResElDataBaseType then
  16555. begin
  16556. bt:=TResElDataBaseType(T.CustomData).BaseType;
  16557. if bt in btAllJSInteger then
  16558. Lit.Value.AsNumber:=0
  16559. else if bt in btAllJSFloats then
  16560. Lit.Value.CustomValue:='0.0'
  16561. else if bt in btAllJSStringAndChars then
  16562. Lit.Value.AsString:=''
  16563. else if bt in btAllJSBooleans then
  16564. Lit.Value.AsBoolean:=false
  16565. else if bt in [btNil,btPointer,btProc] then
  16566. Lit.Value.IsNull:=true
  16567. else if (bt=btCustom) and (T.CustomData is TResElDataPas2JSBaseType) then
  16568. begin
  16569. JSBaseType:=TResElDataPas2JSBaseType(T.CustomData).JSBaseType;
  16570. if JSBaseType=pbtJSValue then
  16571. Lit.Value.IsUndefined:=true;
  16572. end
  16573. else
  16574. begin
  16575. {$IFDEF VerbosePas2JS}
  16576. writeln('TPasToJSConverter.CreateVarInit unknown PasType T=',GetObjName(T),' basetype=',aResolver.BaseTypeNames[bt]);
  16577. {$ENDIF}
  16578. RaiseNotSupported(PasType,AContext,20170208162121);
  16579. end;
  16580. end
  16581. else if aResolver<>nil then
  16582. begin
  16583. {$IFDEF VerbosePas2JS}
  16584. writeln('TPasToJSConverter.CreateValInit PasType=',GetObjName(PasType),' El=',GetObjName(El),' T=',GetObjName(T),' Expr=',GetObjName(Expr));
  16585. {$ENDIF}
  16586. RaiseNotSupported(El,AContext,20170415190259);
  16587. end
  16588. else if (CompareText(T.Name,'longint')=0)
  16589. or (CompareText(T.Name,'int64')=0)
  16590. or (CompareText(T.Name,'real')=0)
  16591. or (CompareText(T.Name,'double')=0)
  16592. or (CompareText(T.Name,'single')=0) then
  16593. Lit.Value.AsNumber:=0.0
  16594. else if (CompareText(T.Name,'boolean')=0) then
  16595. Lit.Value.AsBoolean:=false
  16596. else if (CompareText(T.Name,'string')=0)
  16597. or (CompareText(T.Name,'char')=0)
  16598. then
  16599. Lit.Value.AsString:=''
  16600. else
  16601. begin
  16602. Lit.Value.IsUndefined:=true;
  16603. {$IFDEF VerbosePas2JS}
  16604. writeln('TPasToJSConverter.CreateVarInit unknown PasType class=',T.ClassName,' name=',T.Name);
  16605. {$ENDIF}
  16606. end;
  16607. end
  16608. else
  16609. begin
  16610. {$IFDEF VerbosePas2JS}
  16611. writeln('TPasToJSConverter.CreateValInit unknown PasType ',GetObjName(T));
  16612. {$ENDIF}
  16613. RaiseNotSupported(PasType,AContext,20170208161506);
  16614. end;
  16615. end;
  16616. if Result=nil then
  16617. begin
  16618. {$IFDEF VerbosePas2JS}
  16619. writeln('TPasToJSConverter.CreateValInit PasType=',GetObjName(PasType),' El=',GetObjName(El),' T=',GetObjName(T),' Expr=',GetObjName(Expr));
  16620. {$ENDIF}
  16621. RaiseNotSupported(El,AContext,20170415190103);
  16622. end;
  16623. end;
  16624. function TPasToJSConverter.CreateVarInit(El: TPasVariable;
  16625. AContext: TConvertContext): TJSElement;
  16626. begin
  16627. Result:=CreateValInit(El.VarType,El.Expr,El,AContext);
  16628. end;
  16629. function TPasToJSConverter.CreateVarStatement(const aName: String;
  16630. Init: TJSElement; El: TPasElement): TJSVariableStatement;
  16631. // create "var aname = init"
  16632. begin
  16633. Result:=TJSVariableStatement(CreateElement(TJSVariableStatement,El));
  16634. Result.A:=CreateVarDecl(aName,Init,El);
  16635. end;
  16636. function TPasToJSConverter.CreateVarDecl(const aName: String; Init: TJSElement;
  16637. El: TPasElement): TJSVarDeclaration;
  16638. begin
  16639. Result:=TJSVarDeclaration(CreateElement(TJSVarDeclaration,El));
  16640. Result.Name:=aName;
  16641. Result.Init:=Init;
  16642. end;
  16643. function TPasToJSConverter.CreateLiteralNumber(El: TPasElement;
  16644. const n: TJSNumber): TJSLiteral;
  16645. begin
  16646. Result:=TJSLiteral(CreateElement(TJSLiteral,El));
  16647. Result.Value.AsNumber:=n;
  16648. end;
  16649. function TPasToJSConverter.CreateLiteralHexNumber(El: TPasElement;
  16650. const n: TMaxPrecInt; Digits: byte): TJSLiteral;
  16651. begin
  16652. Result:=TJSLiteral(CreateElement(TJSLiteral,El));
  16653. Result.Value.AsNumber:=n;
  16654. Result.Value.CustomValue:=TJSString('0x'+HexStr(n,Digits));
  16655. end;
  16656. function TPasToJSConverter.CreateLiteralString(El: TPasElement; const s: string
  16657. ): TJSLiteral;
  16658. begin
  16659. Result:=TJSLiteral(CreateElement(TJSLiteral,El));
  16660. Result.Value.AsString:=TJSString(s);
  16661. end;
  16662. function TPasToJSConverter.CreateLiteralJSString(El: TPasElement;
  16663. const s: TJSString): TJSLiteral;
  16664. begin
  16665. Result:=TJSLiteral(CreateElement(TJSLiteral,El));
  16666. Result.Value.AsString:=s;
  16667. end;
  16668. function TPasToJSConverter.CreateLiteralBoolean(El: TPasElement; b: boolean
  16669. ): TJSLiteral;
  16670. begin
  16671. Result:=TJSLiteral(CreateElement(TJSLiteral,El));
  16672. Result.Value.AsBoolean:=b;
  16673. end;
  16674. function TPasToJSConverter.CreateLiteralNull(El: TPasElement): TJSLiteral;
  16675. begin
  16676. Result:=TJSLiteral(CreateElement(TJSLiteral,El));
  16677. Result.Value.IsNull:=true;
  16678. end;
  16679. function TPasToJSConverter.CreateLiteralUndefined(El: TPasElement): TJSLiteral;
  16680. begin
  16681. Result:=TJSLiteral(CreateElement(TJSLiteral,El));
  16682. Result.Value.IsUndefined:=true;
  16683. end;
  16684. function TPasToJSConverter.CreateLiteralCustomValue(El: TPasElement;
  16685. const s: TJSString): TJSLiteral;
  16686. begin
  16687. Result:=TJSLiteral(CreateElement(TJSLiteral,El));
  16688. Result.Value.CustomValue:=s;
  16689. end;
  16690. function TPasToJSConverter.CreateSetLiteralElement(Expr: TPasExpr;
  16691. AContext: TConvertContext): TJSElement;
  16692. var
  16693. LitVal: TJSValue;
  16694. NewEl: TJSElement;
  16695. WS: TJSString;
  16696. ExprResolved: TPasResolverResult;
  16697. Call: TJSCallExpression;
  16698. DotExpr: TJSDotMemberExpression;
  16699. aResolver: TPas2JSResolver;
  16700. begin
  16701. Result:=ConvertElement(Expr,AContext);
  16702. if Result=nil then
  16703. RaiseNotSupported(Expr,AContext,20170415192209);
  16704. if Result.ClassType=TJSLiteral then
  16705. begin
  16706. // argument is a literal -> convert to number
  16707. LitVal:=TJSLiteral(Result).Value;
  16708. case LitVal.ValueType of
  16709. jstBoolean:
  16710. begin
  16711. if LitVal.AsBoolean=LowJSBoolean then
  16712. NewEl:=CreateLiteralNumber(Expr,0)
  16713. else
  16714. NewEl:=CreateLiteralNumber(Expr,1);
  16715. Result.Free;
  16716. exit(NewEl);
  16717. end;
  16718. jstNumber:
  16719. exit;
  16720. jstString:
  16721. begin
  16722. WS:=LitVal.AsString;
  16723. Result.Free;
  16724. if length(WS)<>1 then
  16725. DoError(20170415193254,nXExpectedButYFound,sXExpectedButYFound,['char','string'],Expr);
  16726. Result:=CreateLiteralNumber(Expr,ord(WS[1]));
  16727. exit;
  16728. end;
  16729. else
  16730. RaiseNotSupported(Expr,AContext,20170415205955);
  16731. end;
  16732. end
  16733. else if Result.ClassType=TJSCallExpression then
  16734. begin
  16735. Call:=TJSCallExpression(Result);
  16736. if (Call.Expr is TJSDotMemberExpression) then
  16737. begin
  16738. DotExpr:=TJSDotMemberExpression(Call.Expr);
  16739. if DotExpr.Name='charCodeAt' then
  16740. exit;
  16741. if DotExpr.Name='charAt' then
  16742. begin
  16743. DotExpr.Name:='charCodeAt';
  16744. exit;
  16745. end;
  16746. end;
  16747. end;
  16748. aResolver:=AContext.Resolver;
  16749. if aResolver<>nil then
  16750. begin
  16751. aResolver.ComputeElement(Expr,ExprResolved,[]);
  16752. if (ExprResolved.BaseType in btAllJSStringAndChars)
  16753. or ((ExprResolved.BaseType=btRange) and (ExprResolved.SubType in btAllJSChars)) then
  16754. begin
  16755. // aChar -> aChar.charCodeAt()
  16756. Result:=CreateCallCharCodeAt(Result,0,Expr);
  16757. end
  16758. else if ExprResolved.BaseType in btAllJSInteger then
  16759. begin
  16760. // ok
  16761. end
  16762. else if ExprResolved.BaseType=btContext then
  16763. begin
  16764. if ExprResolved.LoTypeEl.ClassType=TPasEnumType then
  16765. // ok
  16766. else
  16767. RaiseNotSupported(Expr,AContext,20170415191933);
  16768. end
  16769. else
  16770. begin
  16771. {$IFDEF VerbosePas2JS}
  16772. writeln('TPasToJSConverter.CreateSetLiteralElement ',GetResolverResultDbg(ExprResolved));
  16773. {$ENDIF}
  16774. RaiseNotSupported(Expr,AContext,20170415191822);
  16775. end;
  16776. end;
  16777. end;
  16778. function TPasToJSConverter.CreateUnaryNot(El: TJSElement; Src: TPasElement
  16779. ): TJSUnaryNotExpression;
  16780. begin
  16781. Result:=TJSUnaryNotExpression(CreateElement(TJSUnaryNotExpression,Src));
  16782. Result.A:=El;
  16783. end;
  16784. procedure TPasToJSConverter.ConvertCharLiteralToInt(Lit: TJSLiteral;
  16785. ErrorEl: TPasElement; AContext: TConvertContext);
  16786. var
  16787. JS: TJSString;
  16788. begin
  16789. if Lit.Value.ValueType<>jstString then
  16790. RaiseInconsistency(20171112020856,ErrorEl);
  16791. if Lit.Value.CustomValue<>'' then
  16792. JS:=Lit.Value.CustomValue
  16793. else
  16794. JS:=Lit.Value.AsString;
  16795. if length(JS)<>1 then
  16796. RaiseNotSupported(ErrorEl,AContext,20171112021003);
  16797. Lit.Value.AsNumber:=ord(JS[1]);
  16798. end;
  16799. function TPasToJSConverter.ClonePrimaryExpression(El: TJSPrimaryExpression;
  16800. Src: TPasElement): TJSPrimaryExpression;
  16801. begin
  16802. Result:=TJSPrimaryExpression(CreateElement(TJSElementClass(El.ClassType),Src));
  16803. if Result.ClassType=TJSPrimaryExpressionIdent then
  16804. TJSPrimaryExpressionIdent(Result).Name:=TJSPrimaryExpressionIdent(El).Name;
  16805. end;
  16806. function TPasToJSConverter.CreateMulNumber(El: TPasElement; JS: TJSElement;
  16807. n: TMaxPrecInt): TJSElement;
  16808. // create JS*n
  16809. var
  16810. Mul: TJSMultiplicativeExpressionMul;
  16811. Value: TJSValue;
  16812. begin
  16813. if JS is TJSLiteral then
  16814. begin
  16815. Value:=TJSLiteral(JS).Value;
  16816. case Value.ValueType of
  16817. jstUNDEFINED:
  16818. begin
  16819. // undefined * number -> NaN
  16820. Value.AsNumber:=NaN;
  16821. exit(JS);
  16822. end;
  16823. jstNull:
  16824. begin
  16825. // null*number -> 0
  16826. Value.AsNumber:=0;
  16827. exit(JS);
  16828. end;
  16829. jstBoolean:
  16830. begin
  16831. // true is 1, false is 0
  16832. if Value.AsBoolean then
  16833. Value.AsNumber:=n
  16834. else
  16835. Value.AsNumber:=0;
  16836. exit(JS);
  16837. end;
  16838. jstNumber:
  16839. if IsNan(Value.AsNumber) or IsInfinite(Value.AsNumber) then
  16840. else
  16841. begin
  16842. Value.AsNumber:=Value.AsNumber*n;
  16843. exit(JS);
  16844. end;
  16845. end;
  16846. end;
  16847. Mul:=TJSMultiplicativeExpressionMul(CreateElement(TJSMultiplicativeExpressionMul,El));
  16848. Result:=Mul;
  16849. Mul.A:=JS;
  16850. Mul.B:=CreateLiteralNumber(El,n);
  16851. end;
  16852. function TPasToJSConverter.CreateDivideNumber(El: TPasElement; JS: TJSElement;
  16853. n: TMaxPrecInt): TJSElement;
  16854. // create JS/n
  16855. var
  16856. Mul: TJSMultiplicativeExpressionDiv;
  16857. Value: TJSValue;
  16858. begin
  16859. if (n<>0) and (JS is TJSLiteral) then
  16860. begin
  16861. Value:=TJSLiteral(JS).Value;
  16862. case Value.ValueType of
  16863. jstUNDEFINED:
  16864. begin
  16865. // undefined / number -> NaN
  16866. Value.AsNumber:=NaN;
  16867. exit(JS);
  16868. end;
  16869. jstNull:
  16870. begin
  16871. // null / number -> 0
  16872. Value.AsNumber:=0;
  16873. exit(JS);
  16874. end;
  16875. jstBoolean:
  16876. begin
  16877. // true is 1, false is 0
  16878. if Value.AsBoolean then
  16879. Value.AsNumber:=1/n
  16880. else
  16881. Value.AsNumber:=0;
  16882. exit(JS);
  16883. end;
  16884. jstNumber:
  16885. if IsNan(Value.AsNumber) or IsInfinite(Value.AsNumber) then
  16886. else
  16887. begin
  16888. Value.AsNumber:=Value.AsNumber / n;
  16889. exit(JS);
  16890. end;
  16891. end;
  16892. end;
  16893. Mul:=TJSMultiplicativeExpressionDiv(CreateElement(TJSMultiplicativeExpressionDiv,El));
  16894. Result:=Mul;
  16895. Mul.A:=JS;
  16896. Mul.B:=CreateLiteralNumber(El,n);
  16897. end;
  16898. function TPasToJSConverter.CreateMathFloor(El: TPasElement; JS: TJSElement
  16899. ): TJSElement;
  16900. // create Math.floor(JS)
  16901. var
  16902. Value: TJSValue;
  16903. begin
  16904. if JS is TJSLiteral then
  16905. begin
  16906. Value:=TJSLiteral(JS).Value;
  16907. case Value.ValueType of
  16908. jstUNDEFINED:
  16909. begin
  16910. // Math.floor(undefined) -> NaN
  16911. Value.AsNumber:=NaN;
  16912. exit(JS);
  16913. end;
  16914. jstNull:
  16915. begin
  16916. // Math.floor(null) -> 0
  16917. Value.AsNumber:=0;
  16918. exit(JS);
  16919. end;
  16920. jstBoolean:
  16921. begin
  16922. // true is 1, false is 0
  16923. if Value.AsBoolean then
  16924. Value.AsNumber:=1
  16925. else
  16926. Value.AsNumber:=0;
  16927. exit(JS);
  16928. end;
  16929. jstNumber:
  16930. if IsNan(Value.AsNumber) or IsInfinite(Value.AsNumber) then
  16931. exit(JS)
  16932. else
  16933. begin
  16934. Value.AsNumber:=Trunc(Value.AsNumber);
  16935. exit(JS);
  16936. end;
  16937. end;
  16938. end;
  16939. Result:=CreateCallExpression(El);
  16940. TJSCallExpression(Result).Expr:=CreatePrimitiveDotExpr('Math.floor',El);
  16941. TJSCallExpression(Result).AddArg(JS);
  16942. end;
  16943. function TPasToJSConverter.CreateDotExpression(aParent: TPasElement; Left,
  16944. Right: TJSElement; CheckRightIntfRef: boolean): TJSElement;
  16945. var
  16946. Dot: TJSDotMemberExpression;
  16947. RightParent, Expr: TJSElement;
  16948. ok: Boolean;
  16949. Call: TJSCallExpression;
  16950. begin
  16951. Result:=nil;
  16952. if Left=nil then
  16953. RaiseInconsistency(20170201140827,aParent);
  16954. if Right=nil then
  16955. RaiseInconsistency(20170211192018,aParent);
  16956. if CheckRightIntfRef and IsInterfaceRef(Right) then
  16957. begin
  16958. // right was an implicit call
  16959. // convert "$ir.ref(id,Expr)" -> $ir.ref(id,Left.Expr)
  16960. Call:=TJSCallExpression(Right);
  16961. Expr:=Call.Args.Elements[1].Expr;
  16962. Call.Args.Elements[1].Expr:=CreateDotExpression(aParent,Left,Expr);
  16963. Result:=Call;
  16964. exit;
  16965. end;
  16966. ok:=false;
  16967. try
  16968. // create a TJSDotMemberExpression of Left and the left-most identifier of Right
  16969. // Left becomes the new left-most element of Right.
  16970. Result:=Right;
  16971. RightParent:=nil;
  16972. repeat
  16973. if (Right.ClassType=TJSCallExpression) then
  16974. begin
  16975. RightParent:=Right;
  16976. Right:=TJSCallExpression(Right).Expr;
  16977. if Right=nil then
  16978. begin
  16979. // left-most is nil -> insert Left
  16980. TJSCallExpression(RightParent).Expr:=Left;
  16981. ok:=true;
  16982. exit;
  16983. end;
  16984. end
  16985. else if (Right.ClassType=TJSBracketMemberExpression) then
  16986. begin
  16987. RightParent:=Right;
  16988. Right:=TJSBracketMemberExpression(Right).MExpr;
  16989. if Right=nil then
  16990. begin
  16991. // left-most is nil -> insert Left
  16992. TJSBracketMemberExpression(RightParent).MExpr:=Left;
  16993. ok:=true;
  16994. exit;
  16995. end;
  16996. end
  16997. else if (Right.ClassType=TJSDotMemberExpression) then
  16998. begin
  16999. RightParent:=Right;
  17000. Right:=TJSDotMemberExpression(Right).MExpr;
  17001. if Right=nil then
  17002. begin
  17003. // left-most is nil -> insert Left
  17004. TJSDotMemberExpression(RightParent).MExpr:=Left;
  17005. ok:=true;
  17006. exit;
  17007. end;
  17008. end
  17009. else if (Right.ClassType=TJSPrimaryExpressionIdent) then
  17010. begin
  17011. // left-most identifier found
  17012. // -> replace it
  17013. Dot := TJSDotMemberExpression(CreateElement(TJSDotMemberExpression, aParent));
  17014. if Result=Right then
  17015. Result:=Dot
  17016. else if RightParent is TJSBracketMemberExpression then
  17017. TJSBracketMemberExpression(RightParent).MExpr:=Dot
  17018. else if RightParent is TJSCallExpression then
  17019. TJSCallExpression(RightParent).Expr:=Dot
  17020. else if RightParent is TJSDotMemberExpression then
  17021. TJSDotMemberExpression(RightParent).MExpr:=Dot
  17022. else
  17023. begin
  17024. Dot.Free;
  17025. {$IFDEF VerbosePas2JS}
  17026. writeln('TPasToJSConverter.CreateDotExpression Right=',GetObjName(Right),' RightParent=',GetObjName(RightParent),' Result=',GetObjName(Result));
  17027. {$ENDIF}
  17028. RaiseInconsistency(20170129141307,aParent);
  17029. end;
  17030. Dot.MExpr := Left;
  17031. Dot.Name := TJSPrimaryExpressionIdent(Right).Name;
  17032. FreeAndNil(Right);
  17033. break;
  17034. end
  17035. else
  17036. begin
  17037. {$IFDEF VerbosePas2JS}
  17038. writeln('CreateDotExpression Right=',Right.ClassName);
  17039. {$ENDIF}
  17040. DoError(20161024191240,nMemberExprMustBeIdentifier,sMemberExprMustBeIdentifier,[],aParent);
  17041. end;
  17042. until false;
  17043. ok:=true;
  17044. finally
  17045. if not ok then
  17046. begin
  17047. Left.Free;
  17048. FreeAndNil(Result);
  17049. end;
  17050. end;
  17051. end;
  17052. function TPasToJSConverter.CreateReferencePath(El: TPasElement;
  17053. AContext: TConvertContext; Kind: TRefPathKind; Full: boolean;
  17054. Ref: TResolvedReference): string;
  17055. { Notes:
  17056. - local var, argument or result variable, even higher lvl does not need a reference path
  17057. local vars are also argument, result var, result variable
  17058. - with context uses the local $withnnn var
  17059. - auto created local var
  17060. otherwise use absolute path
  17061. }
  17062. function IsLocalVar: boolean;
  17063. begin
  17064. Result:=false;
  17065. if El.ClassType=TPasArgument then
  17066. exit(true);
  17067. if El.ClassType=TPasResultElement then
  17068. exit(true);
  17069. if AContext.Resolver=nil then
  17070. exit(true);
  17071. if El.Parent=nil then
  17072. RaiseNotSupported(El,AContext,20170203121306,GetObjName(El));
  17073. if El.Parent.ClassType=TPasImplExceptOn then
  17074. exit(true);
  17075. if not (El.Parent is TProcedureBody) then exit;
  17076. Result:=true;
  17077. end;
  17078. procedure Prepend(var aPath: string; Prefix: string);
  17079. begin
  17080. if (aPath<>'') and (aPath[1]<>'[') then
  17081. aPath:='.'+aPath;
  17082. aPath:=Prefix+aPath;
  17083. end;
  17084. function IsClassFunction(Proc: TPasElement): boolean;
  17085. var
  17086. C: TClass;
  17087. begin
  17088. if Proc=nil then exit(false);
  17089. C:=Proc.ClassType;
  17090. Result:=(C=TPasClassFunction) or (C=TPasClassProcedure)
  17091. or (C=TPasClassConstructor) or (C=TPasClassDestructor);
  17092. end;
  17093. procedure Append_GetClass(Member: TPasElement);
  17094. begin
  17095. if (Member.Parent as TPasClassType).IsExternal then
  17096. exit;
  17097. if Result<>'' then
  17098. Result:=Result+'.'+FBuiltInNames[pbivnPtrClass]
  17099. else
  17100. Result:=FBuiltInNames[pbivnPtrClass];
  17101. end;
  17102. function GetAbsoluteAlias: string;
  17103. var
  17104. AbsolResolved: TPasResolverResult;
  17105. begin
  17106. AContext.Resolver.ComputeElement(TPasVariable(El).AbsoluteExpr,AbsolResolved,[rcNoImplicitProc]);
  17107. Result:=CreateReferencePath(AbsolResolved.IdentEl,AContext,Kind,Full,Ref);
  17108. end;
  17109. function ImplToDecl(El: TPasElement): TPasElement;
  17110. var
  17111. ProcScope: TPasProcedureScope;
  17112. begin
  17113. Result:=El;
  17114. if El.CustomData is TPasProcedureScope then
  17115. begin
  17116. // proc: always use the declaration, not the body
  17117. ProcScope:=TPasProcedureScope(El.CustomData);
  17118. if ProcScope.DeclarationProc<>nil then
  17119. Result:=ProcScope.DeclarationProc;
  17120. end;
  17121. end;
  17122. function IsA(SrcType, DstType: TPasType): boolean;
  17123. begin
  17124. while SrcType<>nil do
  17125. begin
  17126. if SrcType=DstType then exit(true);
  17127. if SrcType.ClassType=TPasClassType then
  17128. SrcType:=TPas2JSClassScope(SrcType.CustomData).DirectAncestor
  17129. else if (SrcType.ClassType=TPasAliasType)
  17130. or (SrcType.ClassType=TPasTypeAliasType) then
  17131. SrcType:=TPasAliasType(SrcType).DestType
  17132. else
  17133. exit(false);
  17134. end;
  17135. Result:=false;
  17136. end;
  17137. var
  17138. FoundModule: TPasModule;
  17139. ParentEl: TPasElement;
  17140. Dot: TDotContext;
  17141. WithData: TPas2JSWithExprScope;
  17142. ShortName: String;
  17143. SelfContext: TFunctionContext;
  17144. ElClass: TClass;
  17145. begin
  17146. Result:='';
  17147. {$IFDEF VerbosePas2JS}
  17148. //writeln('TPasToJSConverter.CreateReferencePath START El=',GetObjName(El),' Parent=',GetObjName(El.Parent),' Context=',GetObjName(AContext),' SelfContext=',GetObjName(AContext.GetSelfContext));
  17149. //AContext.WriteStack;
  17150. {$ENDIF}
  17151. if (El is TPasType) and (AContext<>nil) then
  17152. El:=AContext.Resolver.ResolveAliasType(TPasType(El));
  17153. ElClass:=El.ClassType;
  17154. if ElClass.InheritsFrom(TPasVariable) and (TPasVariable(El).AbsoluteExpr<>nil)
  17155. and (AContext.Resolver<>nil) then
  17156. exit(GetAbsoluteAlias);
  17157. if AContext is TDotContext then
  17158. begin
  17159. Dot:=TDotContext(AContext);
  17160. if Dot.Resolver<>nil then
  17161. begin
  17162. if ElClass.InheritsFrom(TPasVariable) then
  17163. begin
  17164. //writeln('TPasToJSConverter.CreateReferencePath Left=',GetResolverResultDbg(Dot.LeftResolved),' Right=class var ',GetObjName(El));
  17165. if (ClassVarModifiersType*TPasVariable(El).VarModifiers<>[])
  17166. and (Dot.Access=caAssign)
  17167. and Dot.Resolver.ResolvedElIsClassInstance(Dot.LeftResolved) then
  17168. begin
  17169. // writing a class var
  17170. Append_GetClass(El);
  17171. end;
  17172. end
  17173. else if IsClassFunction(El) then
  17174. begin
  17175. if Dot.Resolver.ResolvedElIsClassInstance(Dot.LeftResolved) then
  17176. // accessing a class method from an object, 'this' must be the class
  17177. Append_GetClass(El);
  17178. end;
  17179. end;
  17180. end
  17181. else if (Ref<>nil) and (Ref.WithExprScope<>nil) then
  17182. begin
  17183. // using local WITH var
  17184. WithData:=Ref.WithExprScope as TPas2JSWithExprScope;
  17185. Prepend(Result,WithData.WithVarName);
  17186. end
  17187. else if IsLocalVar then
  17188. begin
  17189. // El is local var -> does not need path
  17190. end
  17191. else if ElClass.InheritsFrom(TPasProcedure) and (TPasProcedure(El).LibrarySymbolName<>nil)
  17192. and not (El.Parent is TPasClassType) then
  17193. begin
  17194. // an external function -> use the literal
  17195. if Kind=rpkPathAndName then
  17196. Result:=ComputeConstString(TPasProcedure(El).LibrarySymbolName,AContext,true)
  17197. else
  17198. Result:='';
  17199. exit;
  17200. end
  17201. else if ElClass.InheritsFrom(TPasVariable) and (TPasVariable(El).ExportName<>nil)
  17202. and not (El.Parent is TPasClassType) then
  17203. begin
  17204. // an external var -> use the literal
  17205. if Kind=rpkPathAndName then
  17206. Result:=ComputeConstString(TPasVariable(El).ExportName,AContext,true)
  17207. else
  17208. Result:='';
  17209. exit;
  17210. end
  17211. else if (ElClass=TPasClassType) and TPasClassType(El).IsExternal then
  17212. begin
  17213. // an external class -> use the literal
  17214. Result:=TPasClassType(El).ExternalName;
  17215. exit;
  17216. end
  17217. else
  17218. begin
  17219. // need full path
  17220. if El.Parent=nil then
  17221. RaiseNotSupported(El,AContext,20170201172141,GetObjName(El));
  17222. El:=ImplToDecl(El);
  17223. ParentEl:=El.Parent;
  17224. while ParentEl<>nil do
  17225. begin
  17226. ParentEl:=ImplToDecl(ParentEl);
  17227. // check if there is a local var
  17228. ShortName:=AContext.GetLocalName(ParentEl);
  17229. if ParentEl.ClassType=TImplementationSection then
  17230. begin
  17231. // element is in an implementation section (not program/library section)
  17232. if ShortName<>'' then
  17233. Prepend(Result,ShortName)
  17234. else
  17235. begin
  17236. // in other unit -> use pas.unitname.$impl
  17237. FoundModule:=El.GetModule;
  17238. if FoundModule=nil then
  17239. RaiseInconsistency(20161024192755,El);
  17240. Prepend(Result,TransformModuleName(FoundModule,true,AContext)
  17241. +'.'+FBuiltInNames[pbivnImplementation]);
  17242. end;
  17243. break;
  17244. end
  17245. else if ParentEl is TPasModule then
  17246. begin
  17247. // element is in an unit interface or program/library section
  17248. if ShortName<>'' then
  17249. Prepend(Result,ShortName)
  17250. else
  17251. Prepend(Result,TransformModuleName(TPasModule(ParentEl),true,AContext));
  17252. break;
  17253. end
  17254. else if (ParentEl.ClassType=TPasClassType)
  17255. or (ParentEl.ClassType=TPasRecordType) then
  17256. begin
  17257. // parent is a class or record declaration
  17258. if Full then
  17259. Prepend(Result,ParentEl.Name)
  17260. else
  17261. begin
  17262. // Not in a Pascal dotscope and accessing a class member.
  17263. // Possible results: this.v, module.path.path.v, this.path.v
  17264. // In nested proc 'this' can have another name, e.g. '$Self'
  17265. SelfContext:=AContext.GetSelfContext;
  17266. if ShortName<>'' then
  17267. Prepend(Result,ShortName)
  17268. else if (El.Parent<>ParentEl) or (El is TPasType) then
  17269. Prepend(Result,ParentEl.Name)
  17270. else if (SelfContext<>nil)
  17271. and IsA(TPasType(SelfContext.ThisPas),TPasType(ParentEl)) then
  17272. begin
  17273. ShortName:=SelfContext.GetLocalName(SelfContext.ThisPas);
  17274. Prepend(Result,ShortName);
  17275. end
  17276. else
  17277. begin
  17278. // missing JS var for Self
  17279. {$IFDEF VerbosePas2JS}
  17280. {AllowWriteln}
  17281. writeln('TPasToJSConverter.CreateReferencePath missing JS var for Self: El=',GetElementDbgPath(El),':',El.ClassName,' CurParentEl=',GetElementDbgPath(ParentEl),':',ParentEl.ClassName,' AContext:');
  17282. AContext.WriteStack;
  17283. if Ref<>nil then
  17284. writeln('TPasToJSConverter.CreateReferencePath Ref=',GetObjName(Ref.Element),' at ',AContext.Resolver.GetElementSourcePosStr(Ref.Element));
  17285. {AllowWriteln-}
  17286. {$ENDIF}
  17287. RaiseNotSupported(El,AContext,20180125004049);
  17288. end;
  17289. if (El.Parent=ParentEl) and (SelfContext<>nil)
  17290. and not IsClassFunction(SelfContext.PasElement) then
  17291. begin
  17292. // inside a method -> Self is a class instance
  17293. if El is TPasVariable then
  17294. begin
  17295. //writeln('TPasToJSConverter.CreateReferencePath class var ',GetObjName(El),' This=',GetObjName(This));
  17296. // Note: reading a class var does not need accessing the class
  17297. // For example: read v -> this.v
  17298. // write v -> this.$class.v
  17299. if (ClassVarModifiersType*TPasVariable(El).VarModifiers<>[])
  17300. and (AContext.Access=caAssign) then
  17301. begin
  17302. Append_GetClass(El); // writing a class var
  17303. end;
  17304. end
  17305. else if IsClassFunction(El) then
  17306. Append_GetClass(El); // accessing a class function
  17307. end;
  17308. if ShortName<>'' then
  17309. break;
  17310. end;
  17311. end
  17312. else if ParentEl.ClassType=TPasEnumType then
  17313. begin
  17314. if (ShortName<>'') and not Full then
  17315. begin
  17316. Prepend(Result,ShortName);
  17317. break;
  17318. end
  17319. else
  17320. Prepend(Result,ParentEl.Name);
  17321. end;
  17322. ParentEl:=ParentEl.Parent;
  17323. if ParentEl is TProcedureBody then break;
  17324. end;
  17325. end;
  17326. case Kind of
  17327. rpkPathWithDot:
  17328. if Result<>'' then Result:=Result+'.';
  17329. rpkPathAndName:
  17330. begin
  17331. ShortName:=TransformVariableName(El,AContext);
  17332. if Result='' then
  17333. Result:=ShortName
  17334. else if (ShortName<>'') and (ShortName[1] in ['[','(']) then
  17335. Result:=Result+ShortName
  17336. else
  17337. Result:=Result+'.'+ShortName;
  17338. end;
  17339. end;
  17340. end;
  17341. function TPasToJSConverter.CreateReferencePathExpr(El: TPasElement;
  17342. AContext: TConvertContext; Full: boolean; Ref: TResolvedReference
  17343. ): TJSElement;
  17344. var
  17345. Name: String;
  17346. Src: TPasElement;
  17347. begin
  17348. {$IFDEF VerbosePas2JS}
  17349. writeln('TPasToJSConverter.CreateReferencePathExpr El="',GetObjName(El),'" El.Parent=',GetObjName(El.Parent),' ',GetObjName(AContext));
  17350. {$ENDIF}
  17351. Name:=CreateReferencePath(El,AContext,rpkPathAndName,Full,Ref);
  17352. if Ref<>nil then
  17353. Src:=Ref.Element
  17354. else
  17355. Src:=nil;
  17356. Result:=CreatePrimitiveDotExpr(Name,Src);
  17357. end;
  17358. procedure TPasToJSConverter.CreateProcedureCall(var Call: TJSCallExpression;
  17359. Args: TParamsExpr; TargetProc: TPasProcedureType; AContext: TConvertContext);
  17360. // create a call, adding call by reference and default values
  17361. begin
  17362. if Call=nil then
  17363. Call:=TJSCallExpression(CreateElement(TJSCallExpression,Args));
  17364. if ((Args=nil) or (length(Args.Params)=0))
  17365. and ((TargetProc=nil) or (TargetProc.Args.Count=0)) then
  17366. exit;
  17367. if Call.Args=nil then
  17368. Call.Args:=TJSArguments(CreateElement(TJSArguments,Args));
  17369. CreateProcedureCallArgs(Call.Args.Elements,Args,TargetProc,AContext);
  17370. end;
  17371. procedure TPasToJSConverter.CreateProcedureCallArgs(
  17372. Elements: TJSArrayLiteralElements; Args: TParamsExpr;
  17373. TargetProc: TPasProcedureType; AContext: TConvertContext);
  17374. // Add call arguments. Handle call by reference and default values
  17375. var
  17376. ArgContext: TConvertContext;
  17377. i: Integer;
  17378. Arg: TJSElement;
  17379. TargetArgs: TFPList;
  17380. TargetArg: TPasArgument;
  17381. OldAccess: TCtxAccess;
  17382. begin
  17383. // get context
  17384. ArgContext:=AContext.GetNonDotContext;
  17385. i:=0;
  17386. OldAccess:=ArgContext.Access;
  17387. if TargetProc<>nil then
  17388. TargetArgs:=TargetProc.Args
  17389. else
  17390. TargetArgs:=nil;
  17391. // add params
  17392. if Args<>nil then
  17393. while i<length(Args.Params) do
  17394. begin
  17395. if (TargetArgs<>nil) and (i<TargetArgs.Count) then
  17396. TargetArg:=TPasArgument(TargetArgs[i])
  17397. else
  17398. TargetArg:=nil;
  17399. Arg:=CreateProcCallArg(Args.Params[i],TargetArg,ArgContext);
  17400. Elements.AddElement.Expr:=Arg;
  17401. inc(i);
  17402. end;
  17403. // fill up default values
  17404. if TargetProc<>nil then
  17405. begin
  17406. while i<TargetArgs.Count do
  17407. begin
  17408. TargetArg:=TPasArgument(TargetArgs[i]);
  17409. if TargetArg.ValueExpr=nil then
  17410. begin
  17411. {$IFDEF VerbosePas2JS}
  17412. writeln('TPasToJSConverter.CreateProcedureCallArgs missing default value: TargetProc=',TargetProc.Name,' i=',i);
  17413. {$ENDIF}
  17414. RaiseNotSupported(Args,AContext,20170201193601);
  17415. end;
  17416. AContext.Access:=caRead;
  17417. Arg:=ConvertElement(TargetArg.ValueExpr,ArgContext);
  17418. Elements.AddElement.Expr:=Arg;
  17419. inc(i);
  17420. end;
  17421. end;
  17422. ArgContext.Access:=OldAccess;
  17423. end;
  17424. function TPasToJSConverter.CreateProcCallArg(El: TPasExpr;
  17425. TargetArg: TPasArgument; AContext: TConvertContext): TJSElement;
  17426. var
  17427. ExprResolved, ArgResolved: TPasResolverResult;
  17428. ExprFlags: TPasResolverComputeFlags;
  17429. NeedVar, ArgTypeIsArray: Boolean;
  17430. ArgTypeEl, ExprTypeEl: TPasType;
  17431. Call: TJSCallExpression;
  17432. aResolver: TPas2JSResolver;
  17433. begin
  17434. Result:=nil;
  17435. if TargetArg=nil then
  17436. begin
  17437. // simple conversion
  17438. AContext.Access:=caRead;
  17439. Result:=ConvertElement(El,AContext);
  17440. exit;
  17441. end;
  17442. if not (TargetArg.Access in [argDefault,argVar,argOut,argConst]) then
  17443. DoError(20170213220927,nPasElementNotSupported,sPasElementNotSupported,
  17444. [AccessNames[TargetArg.Access]],El);
  17445. aResolver:=AContext.Resolver;
  17446. NeedVar:=TargetArg.Access in [argVar,argOut];
  17447. aResolver.ComputeElement(TargetArg,ArgResolved,[]);
  17448. ArgTypeEl:=ArgResolved.LoTypeEl;
  17449. ExprFlags:=[];
  17450. if NeedVar then
  17451. Include(ExprFlags,rcNoImplicitProc)
  17452. else if aResolver.IsProcedureType(ArgResolved,true) then
  17453. Include(ExprFlags,rcNoImplicitProcType);
  17454. ArgTypeIsArray:=ArgTypeEl is TPasArrayType;
  17455. aResolver.ComputeElement(El,ExprResolved,ExprFlags);
  17456. // consider TargetArg access
  17457. if NeedVar then
  17458. Result:=CreateProcCallArgRef(El,ExprResolved,TargetArg,AContext)
  17459. else
  17460. begin
  17461. // pass as default, const or constref
  17462. AContext.Access:=caRead;
  17463. if ArgTypeIsArray then
  17464. begin
  17465. if ExprResolved.BaseType=btNil then
  17466. begin
  17467. // nil to array -> pass []
  17468. Result:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,El));
  17469. exit;
  17470. end;
  17471. // array as argument
  17472. Result:=CreateArrayInit(TPasArrayType(ArgTypeEl),El,El,AContext);
  17473. end;
  17474. if Result=nil then
  17475. Result:=ConvertElement(El,AContext);
  17476. if (ExprResolved.BaseType=btSet) and (ExprResolved.IdentEl<>nil) then
  17477. begin
  17478. // pass a set variable
  17479. if TargetArg.Access=argDefault then
  17480. begin
  17481. // pass set with argDefault -> create reference rtl.refSet(right)
  17482. {$IFDEF VerbosePas2JS}
  17483. writeln('TPasToJSConverter.CreateProcedureCallArg create reference of SET variable Right={',GetResolverResultDbg(ExprResolved),'} AssignContext.RightResolved.IdentEl=',GetObjName(ExprResolved.IdentEl));
  17484. {$ENDIF}
  17485. Result:=CreateReferencedSet(El,Result);
  17486. end;
  17487. end
  17488. else if ArgResolved.BaseType=btCurrency then
  17489. begin
  17490. if ExprResolved.BaseType<>btCurrency then
  17491. begin
  17492. // pass double to currency -> *10000
  17493. Result:=CreateMulNumber(El,Result,10000);
  17494. end;
  17495. end
  17496. else if ExprResolved.BaseType=btCurrency then
  17497. begin
  17498. if ArgResolved.BaseType<>btCurrency then
  17499. begin
  17500. // pass currency to double -> /10000
  17501. Result:=CreateDivideNumber(El,Result,10000);
  17502. end;
  17503. end
  17504. else if ExprResolved.BaseType in btAllStrings then
  17505. begin
  17506. if ArgTypeEl=nil then
  17507. // string to untyped
  17508. else if ArgTypeEl.ClassType=TPasRecordType then
  17509. begin
  17510. if aResolver.IsTGUID(TPasRecordType(ArgTypeEl)) then
  17511. begin
  17512. // pass aString to TGuid -> rtl.strToGUIDR(aString)
  17513. Call:=CreateCallExpression(El);
  17514. Call.Expr:=CreatePrimitiveDotExpr(FBuiltInNames[pbivnRTL]+'.'+FBuiltInNames[pbifnIntfStrToGUIDR],El);
  17515. Call.AddArg(Result);
  17516. Result:=Call;
  17517. end;
  17518. end;
  17519. end
  17520. else if ExprResolved.BaseType=btContext then
  17521. begin
  17522. ExprTypeEl:=ExprResolved.LoTypeEl;
  17523. if (ExprTypeEl.ClassType=TPasArrayType) then
  17524. begin
  17525. if length(TPasArrayType(ExprTypeEl).Ranges)>0 then
  17526. begin
  17527. if TargetArg.Access=argDefault then
  17528. begin
  17529. // pass static array with argDefault -> clone
  17530. Result:=CreateCloneStaticArray(El,TPasArrayType(ExprTypeEl),Result,AContext);
  17531. end;
  17532. end;
  17533. end
  17534. else if ExprTypeEl.ClassType=TPasClassType then
  17535. begin
  17536. if ArgTypeEl=nil then
  17537. // class to untyped
  17538. else if ArgResolved.BaseType in btAllStrings then
  17539. begin
  17540. if TPasClassType(ExprTypeEl).ObjKind=okInterface then
  17541. begin
  17542. // pass IntfVarOrType to string -> IntfVarOrType.$guid
  17543. Result:=CreateDotExpression(El,Result,
  17544. CreatePrimitiveDotExpr(FBuiltInNames[pbivnIntfGUID],El));
  17545. end;
  17546. end
  17547. else if ArgTypeEl.ClassType=TPasRecordType then
  17548. begin
  17549. if (TPasClassType(ExprTypeEl).ObjKind=okInterface)
  17550. and aResolver.IsTGUID(TPasRecordType(ArgTypeEl)) then
  17551. begin
  17552. // pass IntfTypeOrVar to GUIDRecord -> rtl.getIntfGUIDR(IntfTypeOrVar)
  17553. Call:=CreateCallExpression(El);
  17554. Call.Expr:=CreatePrimitiveDotExpr(FBuiltInNames[pbivnRTL]+'.'+FBuiltInNames[pbifnIntfGetGUIDR],El);
  17555. Call.AddArg(Result);
  17556. Result:=Call;
  17557. if TargetArg.Access=argDefault then
  17558. begin
  17559. // pass record with argDefault -> "new TGuid(RightRecord)"
  17560. {$IFDEF VerbosePas2JS}
  17561. writeln('TPasToJSConverter.CreateProcedureCallArg clone RECORD TGuid variable Right={',GetResolverResultDbg(ExprResolved),'} AssignContext.RightResolved.IdentEl=',GetObjName(ExprResolved.IdentEl));
  17562. {$ENDIF}
  17563. Result:=CreateCloneRecord(El,TPasRecordType(ArgTypeEl),Result,AContext);
  17564. end;
  17565. end
  17566. else
  17567. RaiseNotSupported(El,AContext,20180410160008);
  17568. end
  17569. else if ArgTypeEl.ClassType=TPasClassType then
  17570. case TPasClassType(ExprTypeEl).ObjKind of
  17571. okClass:
  17572. case TPasClassType(ArgTypeEl).ObjKind of
  17573. okClass: ; // pass ClassInstVar to ClassType
  17574. okInterface:
  17575. begin
  17576. // pass ClassInstVar to IntfType
  17577. Call:=CreateCallExpression(El);
  17578. case TPasClassType(ArgTypeEl).InterfaceType of
  17579. citCom:
  17580. begin
  17581. // COM: $ir.ref(id,rtl.queryIntfT(Expr,IntfType))
  17582. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnIntfQueryIntfT]]);
  17583. Call.AddArg(Result);
  17584. Result:=Call;
  17585. Call.AddArg(CreateReferencePathExpr(ArgTypeEl,AContext));
  17586. Call:=CreateIntfRef(Call,AContext,El);
  17587. Result:=Call;
  17588. end;
  17589. citCorba:
  17590. begin
  17591. // CORBA: rtl.getIntfT(Expr,IntfType)
  17592. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnIntfGetIntfT]]);
  17593. Call.AddArg(Result);
  17594. Result:=Call;
  17595. Call.AddArg(CreateReferencePathExpr(ArgTypeEl,AContext));
  17596. end;
  17597. else RaiseNotSupported(El,AContext,20180401230251,InterfaceTypeNames[TPasClassType(ArgTypeEl).InterfaceType]);
  17598. end;
  17599. end
  17600. else
  17601. RaiseNotSupported(El,AContext,20180328134244,ObjKindNames[TPasClassType(ArgTypeEl).ObjKind]);
  17602. end;
  17603. okInterface:
  17604. case TPasClassType(ExprTypeEl).ObjKind of
  17605. okInterface: ; // pass IntfVar to IntfType
  17606. else
  17607. RaiseNotSupported(El,AContext,20180328134305,ObjKindNames[TPasClassType(ArgTypeEl).ObjKind]);
  17608. end;
  17609. else
  17610. RaiseNotSupported(El,AContext,20180328134146,ObjKindNames[TPasClassType(ExprTypeEl).ObjKind]);
  17611. end;
  17612. end
  17613. else if ExprTypeEl.ClassType=TPasRecordType then
  17614. begin
  17615. // right side is a record
  17616. if (ArgResolved.BaseType in btAllStrings)
  17617. and aResolver.IsTGUID(TPasRecordType(ExprTypeEl)) then
  17618. begin
  17619. // pass GuidVar to string -> rtl.guidrToStr(GuidVar)
  17620. Call:=CreateCallExpression(El);
  17621. Call.Expr:=CreatePrimitiveDotExpr(FBuiltInNames[pbivnRTL]+'.'+FBuiltInNames[pbifnIntfGuidRToStr],El);
  17622. Call.AddArg(Result);
  17623. Result:=Call;
  17624. exit;
  17625. end;
  17626. if TargetArg.Access=argDefault then
  17627. begin
  17628. // pass record with argDefault -> "new RightRecordType(RightRecord)"
  17629. {$IFDEF VerbosePas2JS}
  17630. writeln('TPasToJSConverter.CreateProcedureCallArg clone RECORD variable Right={',GetResolverResultDbg(ExprResolved),'} AssignContext.RightResolved.IdentEl=',GetObjName(ExprResolved.IdentEl));
  17631. {$ENDIF}
  17632. Result:=CreateCloneRecord(El,TPasRecordType(ExprTypeEl),Result,AContext);
  17633. end;
  17634. end;
  17635. end;
  17636. end;
  17637. end;
  17638. function TPasToJSConverter.CreateProcCallArgRef(El: TPasExpr;
  17639. ResolvedEl: TPasResolverResult; TargetArg: TPasArgument;
  17640. AContext: TConvertContext): TJSElement;
  17641. const
  17642. GetPathName = 'p';
  17643. SetPathName = 's';
  17644. ParamName = 'a';
  17645. var
  17646. Obj: TJSObjectLiteral;
  17647. procedure AddVar(const aName: string; var Expr: TJSElement);
  17648. var
  17649. ObjLit: TJSObjectLiteralElement;
  17650. begin
  17651. if Expr=nil then exit;
  17652. ObjLit:=Obj.Elements.AddElement;
  17653. ObjLit.Name:=TJSString(aName);
  17654. ObjLit.Expr:=Expr;
  17655. Expr:=nil;
  17656. end;
  17657. var
  17658. ParamContext: TParamContext;
  17659. FullGetter, GetPathExpr, SetPathExpr, GetExpr, SetExpr, ParamExpr,
  17660. RHS: TJSElement;
  17661. AssignSt: TJSSimpleAssignStatement;
  17662. ObjLit: TJSObjectLiteralElement;
  17663. FuncSt: TJSFunctionDeclarationStatement;
  17664. RetSt: TJSReturnStatement;
  17665. GetDotPos, SetDotPos: Integer;
  17666. GetPath, SetPath: String;
  17667. BracketExpr: TJSBracketMemberExpression;
  17668. DotExpr: TJSDotMemberExpression;
  17669. SetterArgName: String;
  17670. TypeEl: TPasType;
  17671. FuncContext: TFunctionContext;
  17672. IsCOMIntf: Boolean;
  17673. begin
  17674. // pass reference -> create a temporary JS object with a FullGetter and setter
  17675. Obj:=nil;
  17676. FullGetter:=nil;
  17677. ParamContext:=TParamContext.Create(El,nil,AContext);
  17678. GetPathExpr:=nil;
  17679. SetPathExpr:=nil;
  17680. GetExpr:=nil;
  17681. SetExpr:=nil;
  17682. SetterArgName:=TempRefObjSetterArgName;
  17683. try
  17684. // create FullGetter and setter
  17685. ParamContext.Access:=caByReference;
  17686. ParamContext.Arg:=TargetArg;
  17687. ParamContext.Expr:=El;
  17688. ParamContext.ResolvedExpr:=ResolvedEl;
  17689. FullGetter:=ConvertElement(El,ParamContext);
  17690. // FullGetter is now a full JS expression to retrieve the value.
  17691. if ParamContext.ReusingReference then
  17692. begin
  17693. // result is already a reference
  17694. Result:=FullGetter;
  17695. exit;
  17696. end;
  17697. // if ParamContext.Getter is set then
  17698. // ParamContext.Getter is the last part of the FullGetter
  17699. // FullSetter is created from FullGetter by replacing the Getter with the Setter
  17700. {$IFDEF VerbosePas2JS}
  17701. writeln('TPasToJSConverter.CreateProcedureCallArg VAR FullGetter=',GetObjName(FullGetter),' Getter=',GetObjName(ParamContext.Getter),' Setter=',GetObjName(ParamContext.Setter));
  17702. {$ENDIF}
  17703. if (ParamContext.Getter=nil)<>(ParamContext.Setter=nil) then
  17704. begin
  17705. {$IFDEF VerbosePas2JS}
  17706. writeln('TPasToJSConverter.CreateProcedureCallArg FullGetter=',GetObjName(FullGetter),' Getter=',GetObjName(ParamContext.Getter),' Setter=',GetObjName(ParamContext.Setter));
  17707. {$ENDIF}
  17708. RaiseInconsistency(20170213222941,El);
  17709. end;
  17710. // create "{p:Result,get:function(){return this.p.Getter},set:function(v){this.p.Setter(v);}}"
  17711. Obj:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,El));
  17712. if FullGetter.ClassType=TJSPrimaryExpressionIdent then
  17713. begin
  17714. // create "{get:function(){return FullGetter;},set:function(v){FullGetter=v;}}"
  17715. if (ParamContext.Getter<>nil) and (ParamContext.Getter<>FullGetter) then
  17716. RaiseInconsistency(20170213224339,El);
  17717. GetPath:=String(TJSPrimaryExpressionIdent(FullGetter).Name);
  17718. GetDotPos:=PosLast('.',GetPath);
  17719. if GetDotPos>0 then
  17720. begin
  17721. // e.g. path1.path2.readvar
  17722. // create
  17723. // GetPathExpr: path1.path2
  17724. // GetExpr: this.p.readvar
  17725. // Will create "{p:GetPathExpr, get:function(){return GetExpr;},
  17726. // set:function(v){GetExpr = v;}}"
  17727. GetPathExpr:=CreatePrimitiveDotExpr(LeftStr(GetPath,GetDotPos-1),El);
  17728. GetExpr:=CreatePrimitiveDotExpr('this.'+GetPathName+'.'+copy(GetPath,GetDotPos+1),El);
  17729. if ParamContext.Setter=nil then
  17730. SetExpr:=CreatePrimitiveDotExpr('this.'+GetPathName+'.'+copy(GetPath,GetDotPos+1),El);
  17731. end
  17732. else
  17733. begin
  17734. // local var
  17735. GetExpr:=FullGetter;
  17736. FullGetter:=nil;
  17737. if ParamContext.Setter=nil then
  17738. SetExpr:=CreatePrimitiveDotExpr(GetPath,El);
  17739. end;
  17740. if ParamContext.Setter<>nil then
  17741. begin
  17742. // custom Setter
  17743. SetExpr:=ParamContext.Setter;
  17744. ParamContext.Setter:=nil;
  17745. if SetExpr.ClassType=TJSPrimaryExpressionIdent then
  17746. begin
  17747. SetPath:=String(TJSPrimaryExpressionIdent(SetExpr).Name);
  17748. SetDotPos:=PosLast('.',SetPath);
  17749. FreeAndNil(SetExpr);
  17750. if LeftStr(GetPath,GetDotPos)=LeftStr(SetPath,SetDotPos) then
  17751. begin
  17752. // use GetPathExpr for setter
  17753. SetExpr:=CreatePrimitiveDotExpr('this.'+GetPathName+'.'+copy(SetPath,GetDotPos+1),El);
  17754. end
  17755. else
  17756. begin
  17757. // setter needs its own SetPathExpr
  17758. SetPathExpr:=CreatePrimitiveDotExpr(LeftStr(SetPath,SetDotPos-1),El);
  17759. SetExpr:=CreatePrimitiveDotExpr('this.'+SetPathName+'.'+copy(SetPath,GetDotPos+1),El);
  17760. end;
  17761. end;
  17762. end;
  17763. end
  17764. else if FullGetter.ClassType=TJSDotMemberExpression then
  17765. begin
  17766. if ParamContext.Setter<>nil then
  17767. RaiseNotSupported(El,AContext,20170214231900);
  17768. // convert this.r.i to
  17769. // {p:this.r,
  17770. // get:function{return this.p.i;},
  17771. // set:function(v){this.p.i=v;}
  17772. // }
  17773. // GetPathExpr: this.r
  17774. // GetExpr: this.p.i
  17775. // SetExpr: this.p.i
  17776. DotExpr:=TJSDotMemberExpression(FullGetter);
  17777. GetPathExpr:=DotExpr.MExpr;
  17778. DotExpr.MExpr:=CreatePrimitiveDotExpr('this.'+GetPathName,El);
  17779. GetExpr:=DotExpr;
  17780. FullGetter:=nil;
  17781. SetExpr:=CreatePrimitiveDotExpr('this.'+GetPathName+'.'+String(DotExpr.Name),El);
  17782. end
  17783. else if FullGetter.ClassType=TJSBracketMemberExpression then
  17784. begin
  17785. if ParamContext.Setter<>nil then
  17786. RaiseNotSupported(El,AContext,20170214215150);
  17787. // convert this.arr[value] to
  17788. // {a:value,
  17789. // p:this.arr,
  17790. // get:function{return this.p[this.a];},
  17791. // set:function(v){this.p[this.a]=v;}
  17792. // }
  17793. BracketExpr:=TJSBracketMemberExpression(FullGetter);
  17794. ParamExpr:=BracketExpr.Name;
  17795. // create "a:value"
  17796. BracketExpr.Name:=CreatePrimitiveDotExpr('this.'+ParamName,El);
  17797. AddVar(ParamName,ParamExpr);
  17798. // create GetPathExpr "this.arr"
  17799. GetPathExpr:=BracketExpr.MExpr;
  17800. BracketExpr.MExpr:=CreatePrimitiveDotExpr('this.'+GetPathName,El);
  17801. // GetExpr "this.p[this.a]"
  17802. GetExpr:=BracketExpr;
  17803. FullGetter:=nil;
  17804. // SetExpr "this.p[this.a]"
  17805. BracketExpr:=TJSBracketMemberExpression(CreateElement(TJSBracketMemberExpression,El));
  17806. SetExpr:=BracketExpr;
  17807. BracketExpr.MExpr:=CreatePrimitiveDotExpr('this.'+GetPathName,El);
  17808. BracketExpr.Name:=CreatePrimitiveDotExpr('this.'+ParamName,El);
  17809. end
  17810. else
  17811. begin
  17812. {$IFDEF VerbosePas2JS}
  17813. writeln('TPasToJSConverter.CreateProcedureCallArg FullGetter=',GetObjName(FullGetter),' Getter=',GetObjName(ParamContext.Getter),' Setter=',GetObjName(ParamContext.Setter));
  17814. {$ENDIF}
  17815. RaiseNotSupported(El,AContext,20170213230336);
  17816. end;
  17817. if (SetExpr.ClassType=TJSPrimaryExpressionIdent)
  17818. or (SetExpr.ClassType=TJSDotMemberExpression)
  17819. or (SetExpr.ClassType=TJSBracketMemberExpression) then
  17820. begin
  17821. // create setter
  17822. FindAvailableLocalName(SetterArgName,SetExpr);
  17823. RHS:=CreatePrimitiveDotExpr(SetterArgName,El);
  17824. TypeEl:=ResolvedEl.LoTypeEl;
  17825. IsCOMIntf:=(TypeEl is TPasClassType)
  17826. and (TPasClassType(TypeEl).ObjKind=okInterface)
  17827. and (TPasClassType(TypeEl).InterfaceType=citCom);
  17828. if IsCOMIntf and (TargetArg.ArgType<>nil) then
  17829. begin
  17830. // create rtl.setIntfP(path,"IntfVar",v)
  17831. SetExpr:=CreateAssignComIntfVar(ResolvedEl,SetExpr,RHS,AContext,El);
  17832. end
  17833. else
  17834. begin
  17835. // create SetExpr = v;
  17836. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  17837. AssignSt.LHS:=SetExpr;
  17838. AssignSt.Expr:=RHS;
  17839. SetExpr:=AssignSt;
  17840. if IsCOMIntf and (TargetArg.ArgType=nil) then
  17841. begin
  17842. // IntfVar is passed to an untyped parameter
  17843. // This must not call AddRef, but the IntfVar must still be
  17844. // released at the end of the function
  17845. FuncContext:=AContext.GetFunctionContext;
  17846. if ResolvedEl.IdentEl is TPasResultElement then
  17847. FuncContext.ResultNeedsIntfRelease:=true
  17848. else
  17849. FuncContext.Add_InterfaceRelease(ResolvedEl.IdentEl);
  17850. end;
  17851. end;
  17852. end
  17853. else if (SetExpr.ClassType=TJSCallExpression) then
  17854. // has already the form Func(v)
  17855. else
  17856. RaiseInconsistency(20170213225940,El);
  17857. // add p:GetPathExpr
  17858. AddVar(GetPathName,GetPathExpr);
  17859. // add get:function(){ return GetExpr; }
  17860. ObjLit:=Obj.Elements.AddElement;
  17861. ObjLit.Name:=TempRefObjGetterName;
  17862. FuncSt:=CreateFunctionSt(El);
  17863. ObjLit.Expr:=FuncSt;
  17864. RetSt:=TJSReturnStatement(CreateElement(TJSReturnStatement,El));
  17865. FuncSt.AFunction.Body.A:=RetSt;
  17866. RetSt.Expr:=GetExpr;
  17867. GetExpr:=nil;
  17868. // add s:SetPathExpr
  17869. AddVar(SetPathName,SetPathExpr);
  17870. // add set:function(v){ SetExpr }
  17871. ObjLit:=Obj.Elements.AddElement;
  17872. ObjLit.Name:=TempRefObjSetterName;
  17873. FuncSt:=CreateFunctionSt(El);
  17874. ObjLit.Expr:=FuncSt;
  17875. FuncSt.AFunction.Params.Add(SetterArgName);
  17876. FuncSt.AFunction.Body.A:=SetExpr;
  17877. SetExpr:=nil;
  17878. Result:=Obj;
  17879. finally
  17880. if Result=nil then
  17881. begin
  17882. GetPathExpr.Free;
  17883. SetPathExpr.Free;
  17884. GetExpr.Free;
  17885. SetExpr.Free;
  17886. Obj.Free;
  17887. ParamContext.Setter.Free;
  17888. FullGetter.Free;
  17889. end;
  17890. ParamContext.Free;
  17891. end;
  17892. end;
  17893. function TPasToJSConverter.CreateArrayEl(El: TPasExpr; JS: TJSElement;
  17894. AContext: TConvertContext): TJSElement;
  17895. // call this function for every element of an array literal
  17896. // e.g. [aSet,aStaticArray]
  17897. var
  17898. ResolvedEl: TPasResolverResult;
  17899. ArrayType: TPasArrayType;
  17900. TypeEl: TPasType;
  17901. begin
  17902. Result:=JS;
  17903. AContext.Resolver.ComputeElement(El,ResolvedEl,[rcNoImplicitProcType]);
  17904. if ResolvedEl.IdentEl<>nil then
  17905. begin
  17906. // pass a variable
  17907. if ResolvedEl.BaseType=btSet then
  17908. begin
  17909. // pass a set variable -> create reference rtl.refSet(Expr)
  17910. Result:=CreateReferencedSet(El,Result);
  17911. end
  17912. else if ResolvedEl.BaseType=btContext then
  17913. begin
  17914. TypeEl:=ResolvedEl.LoTypeEl;
  17915. if TypeEl.ClassType=TPasArrayType then
  17916. begin
  17917. ArrayType:=TPasArrayType(TypeEl);
  17918. if length(ArrayType.Ranges)>0 then
  17919. // pass static array variable -> clone
  17920. Result:=CreateCloneStaticArray(El,ArrayType,Result,AContext);
  17921. end
  17922. else if TypeEl.ClassType=TPasRecordType then
  17923. begin
  17924. // pass record variable -> clone "new RightRecordType(RightRecord)"
  17925. Result:=CreateCloneRecord(El,TPasRecordType(TypeEl),Result,AContext);
  17926. end;
  17927. end;
  17928. end;
  17929. end;
  17930. function TPasToJSConverter.CreateArgumentAccess(Arg: TPasArgument;
  17931. AContext: TConvertContext; PosEl: TPasElement): TJSElement;
  17932. var
  17933. Call: TJSCallExpression;
  17934. AssignContext: TAssignContext;
  17935. ParamContext: TParamContext;
  17936. Name: String;
  17937. begin
  17938. if Arg.Access in [argVar,argOut] then
  17939. begin
  17940. // Arg is a reference object
  17941. case AContext.Access of
  17942. caRead:
  17943. begin
  17944. // create arg.get()
  17945. Call:=CreateCallExpression(PosEl);
  17946. Call.Expr:=CreateDotExpression(PosEl,
  17947. CreateIdentifierExpr(Arg.Name,true,PosEl,AContext),
  17948. CreatePrimitiveDotExpr(TempRefObjGetterName,PosEl));
  17949. Result:=Call;
  17950. exit;
  17951. end;
  17952. caAssign:
  17953. begin
  17954. // create arg.set(RHS)
  17955. AssignContext:=AContext.AccessContext as TAssignContext;
  17956. if AssignContext.Call<>nil then
  17957. RaiseNotSupported(Arg,AContext,20170214120606);
  17958. Call:=CreateCallExpression(PosEl);
  17959. AssignContext.Call:=Call;
  17960. Call.Expr:=CreateDotExpression(PosEl,
  17961. CreateIdentifierExpr(Arg.Name,true,PosEl,AContext),
  17962. CreatePrimitiveDotExpr(TempRefObjSetterName,PosEl));
  17963. Call.AddArg(AssignContext.RightSide);
  17964. AssignContext.RightSide:=nil;
  17965. Result:=Call;
  17966. exit;
  17967. end;
  17968. caByReference:
  17969. begin
  17970. // simply pass the reference
  17971. ParamContext:=AContext.AccessContext as TParamContext;
  17972. ParamContext.ReusingReference:=true;
  17973. Result:=CreateIdentifierExpr(Arg.Name,true,PosEl,AContext);
  17974. exit;
  17975. end;
  17976. else
  17977. RaiseNotSupported(Arg,AContext,20170214120739);
  17978. end;
  17979. end;
  17980. if (CompareText(Arg.Name,'Self')=0) and (AContext.GetSelfContext<>nil) then
  17981. Name:=AContext.GetLocalName(Arg)
  17982. else
  17983. Name:=TransformVariableName(Arg,Arg.Name,true,AContext);
  17984. Result:=CreatePrimitiveDotExpr(Name,PosEl);
  17985. end;
  17986. function TPasToJSConverter.ConvertExceptOn(El: TPasImplExceptOn;
  17987. AContext: TConvertContext): TJSElement;
  17988. // convert "on T do ;" to "if(T.isPrototypeOf(exceptObject)){}"
  17989. // convert "on E:T do ;" to "if(T.isPrototypeOf(exceptObject)){ var E=exceptObject; }"
  17990. Var
  17991. IfSt : TJSIfStatement;
  17992. ListFirst , ListLast: TJSStatementList;
  17993. DotExpr: TJSDotMemberExpression;
  17994. Call: TJSCallExpression;
  17995. V: TJSVariableStatement;
  17996. begin
  17997. Result:=nil;
  17998. // create "if()"
  17999. IfSt:=TJSIfStatement(CreateElement(TJSIfStatement,El));
  18000. try
  18001. // create "T.isPrototypeOf"
  18002. DotExpr:=TJSDotMemberExpression(CreateElement(TJSDotMemberExpression,El));
  18003. DotExpr.MExpr:=CreateReferencePathExpr(El.TypeEl,AContext);
  18004. DotExpr.Name:='isPrototypeOf';
  18005. // create "T.isPrototypeOf(exceptObject)"
  18006. Call:=CreateCallExpression(El);
  18007. Call.Expr:=DotExpr;
  18008. Call.AddArg(CreatePrimitiveDotExpr(FBuiltInNames[pbivnExceptObject],El));
  18009. IfSt.Cond:=Call;
  18010. if El.VarEl<>nil then
  18011. begin
  18012. // add "var E=exceptObject;"
  18013. ListFirst:=TJSStatementList(CreateElement(TJSStatementList,El.Body));
  18014. ListLast:=ListFirst;
  18015. IfSt.BTrue:=ListFirst;
  18016. V:=CreateVarStatement(TransformVariableName(El,El.VariableName,true,AContext),
  18017. CreatePrimitiveDotExpr(FBuiltInNames[pbivnExceptObject],El),El);
  18018. ListFirst.A:=V;
  18019. // add statements
  18020. if El.Body<>nil then
  18021. AddToStatementList(ListFirst,ListLast,ConvertElement(El.Body,AContext),El);
  18022. end
  18023. else if El.Body<>nil then
  18024. // add statements
  18025. IfSt.BTrue:=ConvertElement(El.Body,AContext);
  18026. Result:=IfSt;
  18027. finally
  18028. if Result=nil then
  18029. IfSt.Free;
  18030. end;
  18031. end;
  18032. function TPasToJSConverter.ConvertStatement(El: TPasImplStatement;
  18033. AContext: TConvertContext): TJSElement;
  18034. begin
  18035. Result:=Nil;
  18036. if (El is TPasImplRaise) then
  18037. Result:=ConvertRaiseStatement(TPasImplRaise(El),AContext)
  18038. else if (El is TPasImplAssign) then
  18039. Result:=ConvertAssignStatement(TPasImplAssign(El),AContext)
  18040. else if (El is TPasImplWhileDo) then
  18041. Result:=ConvertWhileStatement(TPasImplWhileDo(El),AContext)
  18042. else if (El is TPasImplSimple) then
  18043. Result:=ConvertSimpleStatement(TPasImplSimple(El),AContext)
  18044. else if (El is TPasImplWithDo) then
  18045. Result:=ConvertWithStatement(TPasImplWithDo(El),AContext)
  18046. else if (El is TPasImplExceptOn) then
  18047. Result:=ConvertExceptOn(TPasImplExceptOn(El),AContext)
  18048. else if (El is TPasImplForLoop) then
  18049. Result:=ConvertForStatement(TPasImplForLoop(El),AContext)
  18050. else if (El is TPasImplAsmStatement) then
  18051. Result:=ConvertAsmStatement(TPasImplAsmStatement(El),AContext)
  18052. else
  18053. RaiseNotSupported(El,AContext,20161024192759);
  18054. {
  18055. TPasImplCaseStatement = class(TPasImplStatement)
  18056. }
  18057. end;
  18058. function TPasToJSConverter.ConvertConst(El: TPasConst; AContext: TConvertContext
  18059. ): TJSElement;
  18060. // Important: returns nil if const was added to higher context
  18061. Var
  18062. AssignSt: TJSSimpleAssignStatement;
  18063. Obj: TJSObjectLiteral;
  18064. ObjLit: TJSObjectLiteralElement;
  18065. ConstContext: TFunctionContext;
  18066. C: TJSElement;
  18067. V: TJSVariableStatement;
  18068. Src: TJSSourceElements;
  18069. Proc: TPasProcedure;
  18070. ProcScope: TPas2JSProcedureScope;
  18071. begin
  18072. Result:=nil;
  18073. if El.AbsoluteExpr<>nil then
  18074. exit; // absolute: do not add a declaration
  18075. if vmExternal in El.VarModifiers then
  18076. exit; // external: do not add a declaration
  18077. if not AContext.IsGlobal then
  18078. begin
  18079. // local const are stored in interface/implementation
  18080. ConstContext:=AContext.GetGlobalFunc;
  18081. if not (ConstContext.JSElement is TJSSourceElements) then
  18082. begin
  18083. {$IFDEF VerbosePas2JS}
  18084. writeln('TPasToJSConverter.CreateConstDecl ConstContext=',GetObjName(ConstContext),' JSElement=',GetObjName(ConstContext.JSElement));
  18085. {$ENDIF}
  18086. RaiseNotSupported(El,AContext,20170220153216);
  18087. end;
  18088. Src:=TJSSourceElements(ConstContext.JSElement);
  18089. C:=ConvertVariable(El,AContext);
  18090. if C=nil then
  18091. RaiseInconsistency(20180501114422,El);
  18092. V:=TJSVariableStatement(CreateElement(TJSVariableStatement,El));
  18093. V.A:=C;
  18094. AddToSourceElements(Src,V);
  18095. if (coStoreImplJS in Options) and (AContext.Resolver<>nil) then
  18096. begin
  18097. Proc:=AContext.Resolver.GetTopLvlProc(AContext.PasElement);
  18098. if Proc<>nil then
  18099. begin
  18100. ProcScope:=TPas2JSProcedureScope(Proc.CustomData);
  18101. ProcScope.AddGlobalJS(CreatePrecompiledJS(V));
  18102. end;
  18103. end;
  18104. end
  18105. else if AContext is TObjectContext then
  18106. begin
  18107. // create 'A: initvalue'
  18108. Obj:=TObjectContext(AContext).JSElement as TJSObjectLiteral;
  18109. ObjLit:=Obj.Elements.AddElement;
  18110. ObjLit.Name:=TJSString(TransformVariableName(El,AContext));
  18111. ObjLit.Expr:=CreateVarInit(El,AContext);
  18112. end
  18113. else
  18114. begin
  18115. // create 'this.A=initvalue'
  18116. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  18117. Result:=AssignSt;
  18118. AssignSt.LHS:=CreateSubDeclNameExpr(El,AContext);
  18119. AssignSt.Expr:=CreateVarInit(El,AContext);
  18120. end;
  18121. end;
  18122. function TPasToJSConverter.ConvertLabelMark(El: TPasImplLabelMark;
  18123. AContext: TConvertContext): TJSElement;
  18124. begin
  18125. RaiseNotSupported(El,AContext,20161024192857);
  18126. Result:=Nil;
  18127. // ToDo: TPasImplLabelMark = class(TPasImplLabelMark) then
  18128. end;
  18129. function TPasToJSConverter.ConvertElement(El: TPasElement;
  18130. AContext: TConvertContext): TJSElement;
  18131. var
  18132. C: TClass;
  18133. begin
  18134. {$IFDEF VerbosePas2JS}
  18135. writeln('TPasToJSConverter.ConvertElement El=',GetObjName(El),' Context=',GetObjName(AContext));
  18136. {$ENDIF}
  18137. if El=nil then
  18138. begin
  18139. Result:=nil;
  18140. RaiseInconsistency(20161024190203,El);
  18141. end;
  18142. C:=El.ClassType;
  18143. if (C=TPasConst) then
  18144. Result:=ConvertConst(TPasConst(El),AContext)
  18145. else if (C=TPasProperty) then
  18146. Result:=ConvertProperty(TPasProperty(El),AContext)
  18147. else if (C=TPasVariable) then
  18148. Result:=ConvertVariable(TPasVariable(El),AContext)
  18149. else if (C=TPasResString) then
  18150. Result:=ConvertResString(TPasResString(El),AContext)
  18151. else if (C=TPasExportSymbol) then
  18152. Result:=ConvertExportSymbol(TPasExportSymbol(El),AContext)
  18153. else if (C=TPasLabels) then
  18154. Result:=ConvertLabels(TPasLabels(El),AContext)
  18155. else if (C=TPasImplLabelMark) then
  18156. Result:=ConvertLabelMark(TPasImplLabelMark(El),AContext)
  18157. else if C.InheritsFrom(TPasExpr) then
  18158. Result:=ConvertExpression(TPasExpr(El),AContext)
  18159. else if C.InheritsFrom(TPasDeclarations) then
  18160. Result:=ConvertDeclarations(TPasDeclarations(El),AContext)
  18161. else if C.InheritsFrom(TPasProcedure) then
  18162. Result:=ConvertProcedure(TPasProcedure(El),AContext)
  18163. else if C.InheritsFrom(TPasImplBlock) then
  18164. Result:=ConvertImplBlock(TPasImplBlock(El),AContext)
  18165. else if C=TPasImplCommand then
  18166. Result:=ConvertImplCommand(TPasImplCommand(El),AContext)
  18167. else if C.InheritsFrom(TPasModule) then
  18168. Result:=ConvertModule(TPasModule(El),AContext)
  18169. else If (C=TPasPackage) then
  18170. Result:=ConvertPackage(TPasPackage(El),AContext)
  18171. else
  18172. begin
  18173. Result:=nil;
  18174. RaiseNotSupported(El, AContext, 20161024190449);
  18175. end;
  18176. {$IFDEF VerbosePas2JS}
  18177. writeln('TPasToJSConverter.ConvertElement END ',GetObjName(El));
  18178. {$ENDIF}
  18179. end;
  18180. function TPasToJSConverter.ConvertRecordType(El: TPasRecordType;
  18181. AContext: TConvertContext): TJSElement;
  18182. (*
  18183. type
  18184. TMyRecord = record
  18185. i: longint;
  18186. s: string;
  18187. d: double;
  18188. r: TOtherRecord;
  18189. end;
  18190. this.TMyRecord=function(s) {
  18191. if (s){
  18192. this.i = s.i;
  18193. this.s = s.s;
  18194. this.d = s.d;
  18195. this.r = new this.TOtherRecord(s.r);
  18196. } else {
  18197. this.i = 0;
  18198. this.s = "";
  18199. this.d = 0.0;
  18200. this.r = new this.TOtherRecord();
  18201. };
  18202. this.$equal = function(b){
  18203. return (this.i == b.i) && (this.s == b.s) && (this.d == b.d)
  18204. && (this.r.$equal(b.r))
  18205. };
  18206. };
  18207. *)
  18208. const
  18209. SrcParamName = 's';
  18210. EqualParamName = 'b';
  18211. procedure AddCloneStatements(IfSt: TJSIfStatement;
  18212. FuncContext: TFunctionContext);
  18213. var
  18214. i: Integer;
  18215. PasVar: TPasVariable;
  18216. VarAssignSt: TJSSimpleAssignStatement;
  18217. First, Last: TJSStatementList;
  18218. VarDotExpr: TJSDotMemberExpression;
  18219. PasVarType: TPasType;
  18220. VarName: String;
  18221. begin
  18222. // init members with s
  18223. First:=nil;
  18224. Last:=nil;
  18225. for i:=0 to El.Members.Count-1 do
  18226. begin
  18227. PasVar:=TPasVariable(El.Members[i]);
  18228. if not IsElementUsed(PasVar) then continue;
  18229. // create 'this.A = s.A;'
  18230. VarName:=TransformVariableName(PasVar,FuncContext);
  18231. VarAssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,PasVar));
  18232. AddToStatementList(First,Last,VarAssignSt,PasVar);
  18233. if IfSt.BTrue=nil then
  18234. IfSt.BTrue:=First;
  18235. VarAssignSt.LHS:=CreateSubDeclNameExpr(PasVar,VarName,FuncContext);
  18236. VarDotExpr:=TJSDotMemberExpression(CreateElement(TJSDotMemberExpression,PasVar));
  18237. VarAssignSt.Expr:=VarDotExpr;
  18238. VarDotExpr.MExpr:=CreatePrimitiveDotExpr(SrcParamName,PasVar);
  18239. VarDotExpr.Name:=TJSString(VarName);
  18240. if (AContext.Resolver<>nil) then
  18241. begin
  18242. PasVarType:=AContext.Resolver.ResolveAliasType(PasVar.VarType);
  18243. if PasVarType.ClassType=TPasArrayType then
  18244. begin
  18245. if length(TPasArrayType(PasVarType).Ranges)>0 then
  18246. begin
  18247. // clone sub static array
  18248. VarAssignSt.Expr:=CreateCloneStaticArray(PasVar,TPasArrayType(PasVarType),
  18249. VarDotExpr,FuncContext);
  18250. end;
  18251. end
  18252. else if PasVarType.ClassType=TPasRecordType then
  18253. begin
  18254. // clone sub record
  18255. VarAssignSt.Expr:=CreateCloneRecord(PasVar,TPasRecordType(PasVarType),
  18256. VarDotExpr,FuncContext);
  18257. end
  18258. else if PasVarType.ClassType=TPasSetType then
  18259. begin
  18260. // clone sub set
  18261. VarAssignSt.Expr:=CreateReferencedSet(PasVar,VarDotExpr);
  18262. end
  18263. end;
  18264. end;
  18265. end;
  18266. procedure AddInitDefaultStatements(IfSt: TJSIfStatement;
  18267. FuncContext: TFunctionContext);
  18268. var
  18269. i: Integer;
  18270. PasVar: TPasVariable;
  18271. JSVar: TJSElement;
  18272. First, Last: TJSStatementList;
  18273. begin
  18274. // the "else" part:
  18275. // when there is no s parameter, init members with default value
  18276. First:=nil;
  18277. Last:=nil;
  18278. for i:=0 to El.Members.Count-1 do
  18279. begin
  18280. PasVar:=TPasVariable(El.Members[i]);
  18281. if not IsElementUsed(PasVar) then continue;
  18282. JSVar:=CreateVarDecl(PasVar,FuncContext);
  18283. AddToStatementList(First,Last,JSVar,PasVar);
  18284. if IfSt.BFalse=nil then
  18285. IfSt.BFalse:=First;
  18286. end;
  18287. end;
  18288. procedure Add_AndExpr_ToReturnSt(RetSt: TJSReturnStatement;
  18289. PasVar: TPasVariable; var LastAndExpr: TJSLogicalAndExpression;
  18290. Expr: TJSElement);
  18291. var
  18292. AndExpr: TJSLogicalAndExpression;
  18293. begin
  18294. if RetSt.Expr=nil then
  18295. RetSt.Expr:=Expr
  18296. else
  18297. begin
  18298. AndExpr:=TJSLogicalAndExpression(CreateElement(TJSLogicalAndExpression,PasVar));
  18299. if LastAndExpr=nil then
  18300. begin
  18301. AndExpr.A:=RetSt.Expr;
  18302. RetSt.Expr:=AndExpr;
  18303. end
  18304. else
  18305. begin
  18306. AndExpr.A:=LastAndExpr.B;
  18307. LastAndExpr.B:=AndExpr;
  18308. end;
  18309. AndExpr.B:=Expr;
  18310. LastAndExpr:=AndExpr;
  18311. end;
  18312. end;
  18313. procedure AddEqualFunction(var BodyFirst, BodyLast: TJSStatementList;
  18314. FuncContext: TFunctionContext);
  18315. // add equal function:
  18316. // this.$equal = function(b){
  18317. // return (this.member1 == b.member1);
  18318. // };
  18319. var
  18320. AssignSt: TJSSimpleAssignStatement;
  18321. FD: TJSFuncDef;
  18322. RetSt: TJSReturnStatement;
  18323. i: Integer;
  18324. PasVar: TPasVariable;
  18325. FDS: TJSFunctionDeclarationStatement;
  18326. EqExpr: TJSEqualityExpressionSEQ;
  18327. LastAndExpr: TJSLogicalAndExpression;
  18328. VarType: TPasType;
  18329. Call: TJSCallExpression;
  18330. VarName: String;
  18331. begin
  18332. // add "this.$equal ="
  18333. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  18334. AssignSt.LHS:=CreateMemberExpression(['this',FBuiltInNames[pbifnRecordEqual]]);
  18335. AddToStatementList(BodyFirst,BodyLast,AssignSt,El);
  18336. // add "function(b){"
  18337. FDS:=CreateFunctionSt(El);
  18338. AssignSt.Expr:=FDS;
  18339. FD:=FDS.AFunction;
  18340. FD.Params.Add(EqualParamName);
  18341. // add "return "
  18342. RetSt:=TJSReturnStatement(CreateElement(TJSReturnStatement,El));
  18343. FD.Body.A:=RetSt;
  18344. LastAndExpr:=nil;
  18345. for i:=0 to El.Members.Count-1 do
  18346. begin
  18347. PasVar:=TPasVariable(El.Members[i]);
  18348. if not IsElementUsed(PasVar) then continue;
  18349. // "this.member = b.member;"
  18350. VarType:=PasVar.VarType;
  18351. if FuncContext.Resolver<>nil then
  18352. VarType:=FuncContext.Resolver.ResolveAliasType(VarType);
  18353. VarName:=TransformVariableName(PasVar,FuncContext);
  18354. if VarType.ClassType=TPasRecordType then
  18355. begin
  18356. // record
  18357. // add "this.member.$equal(b.member)"
  18358. Call:=CreateCallExpression(PasVar);
  18359. Add_AndExpr_ToReturnSt(RetSt,PasVar,LastAndExpr,Call);
  18360. Call.Expr:=CreateMemberExpression(['this',VarName,FBuiltInNames[pbifnRecordEqual]]);
  18361. Call.AddArg(CreateMemberExpression([EqualParamName,VarName]));
  18362. end
  18363. else if VarType.ClassType=TPasSetType then
  18364. begin
  18365. // set
  18366. // add "rtl.eqSet(this.member,b.member)"
  18367. Call:=CreateCallExpression(PasVar);
  18368. Add_AndExpr_ToReturnSt(RetSt,PasVar,LastAndExpr,Call);
  18369. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnSet_Equal]]);
  18370. Call.AddArg(CreateMemberExpression(['this',VarName]));
  18371. Call.AddArg(CreateMemberExpression([EqualParamName,VarName]));
  18372. end
  18373. else if VarType is TPasProcedureType then
  18374. begin
  18375. // proc type
  18376. // add "rtl.eqCallback(this.member,b.member)"
  18377. Call:=CreateCallExpression(PasVar);
  18378. Add_AndExpr_ToReturnSt(RetSt,PasVar,LastAndExpr,Call);
  18379. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnProcType_Equal]]);
  18380. Call.AddArg(CreateMemberExpression(['this',VarName]));
  18381. Call.AddArg(CreateMemberExpression([EqualParamName,VarName]));
  18382. end
  18383. else if (VarType.ClassType=TPasArrayType)
  18384. and (length(TPasArrayType(VarType).Ranges)>0) then
  18385. begin
  18386. // static array
  18387. // add "rtl.arrayEq(this.member,b.member)"
  18388. Call:=CreateCallExpression(PasVar);
  18389. Add_AndExpr_ToReturnSt(RetSt,PasVar,LastAndExpr,Call);
  18390. Call.Expr:=CreateMemberExpression([FBuiltInNames[pbivnRTL],FBuiltInNames[pbifnArray_Equal]]);
  18391. Call.AddArg(CreateMemberExpression(['this',VarName]));
  18392. Call.AddArg(CreateMemberExpression([EqualParamName,VarName]));
  18393. end
  18394. else
  18395. begin
  18396. // default: use simple equal "=="
  18397. EqExpr:=TJSEqualityExpressionSEQ(CreateElement(TJSEqualityExpressionSEQ,PasVar));
  18398. Add_AndExpr_ToReturnSt(RetSt,PasVar,LastAndExpr,EqExpr);
  18399. EqExpr.A:=CreateMemberExpression(['this',VarName]);
  18400. EqExpr.B:=CreateMemberExpression([EqualParamName,VarName]);
  18401. end;
  18402. end;
  18403. if RetSt.Expr=nil then
  18404. RetSt.Expr:=CreateLiteralBoolean(El,true);
  18405. end;
  18406. procedure AddRTTIFields(Args: TJSArguments; var First, Last: TJSStatementList);
  18407. var
  18408. i: Integer;
  18409. PasVar: TPasVariable;
  18410. VarType: TPasType;
  18411. begin
  18412. for i:=0 to El.Members.Count-1 do
  18413. begin
  18414. PasVar:=TPasVariable(El.Members[i]);
  18415. if not IsElementUsed(PasVar) then continue;
  18416. VarType:=PasVar.VarType;
  18417. if VarType.Name='' then
  18418. CreateRTTIAnonymous(VarType,AContext,First,Last);
  18419. // add quoted "fieldname"
  18420. Args.AddElement(CreateLiteralString(PasVar,TransformVariableName(PasVar,AContext)));
  18421. // add typeinfo ref
  18422. Args.AddElement(CreateTypeInfoRef(VarType,AContext,PasVar));
  18423. end;
  18424. end;
  18425. var
  18426. AssignSt: TJSSimpleAssignStatement;
  18427. FDS: TJSFunctionDeclarationStatement;
  18428. FD: TJSFuncDef;
  18429. BodyFirst, BodyLast, ListFirst, ListLast: TJSStatementList;
  18430. FuncContext: TFunctionContext;
  18431. ObjLit: TJSObjectLiteral;
  18432. IfSt: TJSIfStatement;
  18433. Call, Call2: TJSCallExpression;
  18434. ok: Boolean;
  18435. begin
  18436. Result:=nil;
  18437. FuncContext:=nil;
  18438. ListFirst:=nil;
  18439. ListLast:=nil;
  18440. ok:=false;
  18441. try
  18442. FDS:=CreateFunctionSt(El);
  18443. FD:=FDS.AFunction;
  18444. if El.Parent is TProcedureBody then
  18445. begin
  18446. // ToDo: elevate to non local scope
  18447. // add 'function TypeName(){}'
  18448. Result:=FDS;
  18449. FD.Name:=TJSString(TransformVariableName(El,AContext));
  18450. end
  18451. else
  18452. begin
  18453. // add 'this.TypeName = function(){}'
  18454. AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
  18455. Result:=AssignSt;
  18456. AssignSt.LHS:=CreateSubDeclNameExpr(El,AContext);
  18457. AssignSt.Expr:=FDS;
  18458. end;
  18459. // add param s
  18460. FD.Params.Add(SrcParamName);
  18461. // create function body
  18462. FuncContext:=TFunctionContext.Create(El,FD.Body,AContext);
  18463. FuncContext.ThisPas:=El;
  18464. FuncContext.IsGlobal:=true;
  18465. BodyFirst:=nil;
  18466. BodyLast:=nil;
  18467. if El.Members.Count>0 then
  18468. begin
  18469. // add if(s)
  18470. IfSt:=TJSIfStatement(CreateElement(TJSIfStatement,El));
  18471. AddToStatementList(BodyFirst,BodyLast,IfSt,El);
  18472. FD.Body.A:=BodyFirst;
  18473. IfSt.Cond:=CreatePrimitiveDotExpr(SrcParamName,El);
  18474. // add clone statements
  18475. AddCloneStatements(IfSt,FuncContext);
  18476. // add init default statements
  18477. AddInitDefaultStatements(IfSt,FuncContext);
  18478. end;
  18479. // add equal function
  18480. AddEqualFunction(BodyFirst,BodyLast,FuncContext);
  18481. if FD.Body.A=nil then
  18482. FD.Body.A:=BodyFirst;
  18483. if HasTypeInfo(El,AContext) then
  18484. begin
  18485. // add $rtti as second statement
  18486. if not (AContext is TFunctionContext) then
  18487. RaiseNotSupported(El,AContext,20170412120012);
  18488. AddToStatementList(ListFirst,ListLast,Result,El);
  18489. Result:=nil;
  18490. // module.$rtti.$Record("typename",{});
  18491. Call:=CreateRTTINewType(El,FBuiltInNames[pbifnRTTINewRecord],false,AContext,ObjLit);
  18492. if ObjLit=nil then
  18493. RaiseInconsistency(20170412124804,El);
  18494. if El.Members.Count>0 then
  18495. begin
  18496. // module.$rtti.$Record("typename",{}).addFields(
  18497. // "fieldname1",type1,"fieldname2",type2,...
  18498. // );
  18499. Call2:=CreateCallExpression(El);
  18500. Call2.Expr:=CreateDotExpression(El,Call,
  18501. CreatePrimitiveDotExpr(FBuiltInNames[pbifnRTTIAddFields],El));
  18502. Call:=Call2;
  18503. AddRTTIFields(Call.Args,ListFirst,ListLast);
  18504. end;
  18505. AddToStatementList(ListFirst,ListLast,Call,El);
  18506. Result:=ListFirst;
  18507. ListFirst:=nil;
  18508. ListLast:=nil;
  18509. end;
  18510. ok:=true;
  18511. finally
  18512. FuncContext.Free;
  18513. if ListFirst<>nil then
  18514. FreeAndNil(ListFirst)
  18515. else if not ok then
  18516. FreeAndNil(Result);
  18517. end;
  18518. end;
  18519. procedure TPasToJSConverter.DoError(Id: TMaxPrecInt; const Msg: String);
  18520. var
  18521. E: EPas2JS;
  18522. begin
  18523. E:=EPas2JS.Create(Msg);
  18524. E.Id:=Id;
  18525. E.MsgType:=mtError;
  18526. Raise E;
  18527. end;
  18528. procedure TPasToJSConverter.DoError(Id: TMaxPrecInt; const Msg: String;
  18529. const Args: array of {$IFDEF pas2js}jsvalue{$ELSE}const{$ENDIF});
  18530. var
  18531. E: EPas2JS;
  18532. begin
  18533. E:=EPas2JS.CreateFmt(Msg,Args);
  18534. E.Id:=Id;
  18535. E.MsgType:=mtError;
  18536. Raise E;
  18537. end;
  18538. procedure TPasToJSConverter.DoError(Id: TMaxPrecInt; MsgNumber: integer;
  18539. const MsgPattern: string;
  18540. const Args: array of {$IFDEF pas2js}jsvalue{$ELSE}const{$ENDIF};
  18541. El: TPasElement);
  18542. var
  18543. E: EPas2JS;
  18544. begin
  18545. E:=EPas2JS.CreateFmt(MsgPattern,Args);
  18546. {$IFDEF VerbosePas2JS}
  18547. writeln('TPasToJSConverter.DoError ',id,' ',GetElementDbgPath(El),':',El.ClassName,' Msg="',E.Message,'"');
  18548. {$ENDIF}
  18549. E.PasElement:=El;
  18550. E.MsgNumber:=MsgNumber;
  18551. E.Id:=Id;
  18552. E.MsgType:=mtError;
  18553. CreateMsgArgs(E.Args,Args);
  18554. raise E;
  18555. end;
  18556. procedure TPasToJSConverter.RaiseNotSupported(El: TPasElement;
  18557. AContext: TConvertContext; Id: TMaxPrecInt; const Msg: string);
  18558. var
  18559. E: EPas2JS;
  18560. begin
  18561. {$IFDEF VerbosePas2JS}
  18562. writeln('TPasToJSConverter.RaiseNotSupported ',id,' ',GetElementDbgPath(El),':',El.ClassName,' Msg="',Msg,'"');
  18563. {$ENDIF}
  18564. if AContext=nil then ;
  18565. E:=EPas2JS.CreateFmt(sPasElementNotSupported,[GetObjName(El)+' ['+IntToStr(Id)+']']);
  18566. if Msg<>'' then
  18567. E.Message:=E.Message+': '+Msg;
  18568. E.PasElement:=El;
  18569. E.MsgNumber:=nPasElementNotSupported;
  18570. SetLength(E.Args,1);
  18571. E.Args[0]:=El.ClassName;
  18572. E.Id:=Id;
  18573. E.MsgType:=mtError;
  18574. raise E;
  18575. end;
  18576. procedure TPasToJSConverter.RaiseIdentifierNotFound(Identifier: string;
  18577. El: TPasElement; Id: TMaxPrecInt);
  18578. var
  18579. E: EPas2JS;
  18580. begin
  18581. E:=EPas2JS.CreateFmt(sIdentifierNotFound,[Identifier]);
  18582. E.PasElement:=El;
  18583. E.MsgNumber:=nIdentifierNotFound;
  18584. SetLength(E.Args,1);
  18585. E.Args[0]:=Identifier;
  18586. E.Id:=Id;
  18587. E.MsgType:=mtError;
  18588. raise E;
  18589. end;
  18590. procedure TPasToJSConverter.RaiseInconsistency(Id: TMaxPrecInt; El: TPasElement);
  18591. var
  18592. s: String;
  18593. begin
  18594. s:='TPasToJSConverter.RaiseInconsistency['+IntToStr(Id)+']: you found a bug';
  18595. if El<>nil then
  18596. begin
  18597. s:=s+GetElementDbgPath(El);
  18598. if El.Name<>'' then
  18599. s:=s+El.Name
  18600. else
  18601. s:=s+GetElementTypeName(El);
  18602. s:=s+' at '+TPas2JSResolver.GetDbgSourcePosStr(El);
  18603. end;
  18604. raise Exception.Create(s);
  18605. end;
  18606. function TPasToJSConverter.TransformVariableName(ErrorEl: TPasElement;
  18607. const AName: String; CheckGlobal: boolean; AContext: TConvertContext): String;
  18608. // CheckGlobal: check name clashes with global identifiers too
  18609. var
  18610. i: Integer;
  18611. c: Char;
  18612. begin
  18613. if AContext=nil then ;
  18614. if Pos('.',AName)>0 then
  18615. RaiseInconsistency(20170203164711,ErrorEl);
  18616. if UseLowerCase then
  18617. Result:=LowerCase(AName)
  18618. else
  18619. Result:=AName;
  18620. if not IsReservedWord(Result,CheckGlobal) then
  18621. exit;
  18622. for i:=1 to length(Result) do
  18623. begin
  18624. c:=Result[i];
  18625. case c of
  18626. 'a'..'z','A'..'Z':
  18627. begin
  18628. Result[i]:=chr(ord(c) xor 32);
  18629. if not IsReservedWord(Result,CheckGlobal) then
  18630. exit;
  18631. end;
  18632. end;
  18633. end;
  18634. RaiseNotSupported(ErrorEl,AContext,20170203131832);
  18635. end;
  18636. function TPasToJSConverter.TransformVariableName(El: TPasElement;
  18637. AContext: TConvertContext): String;
  18638. var
  18639. aType: TPasType;
  18640. begin
  18641. if (El is TPasProcedure) and (TPasProcedure(El).LibrarySymbolName<>nil) then
  18642. Result:=ComputeConstString(TPasProcedure(El).LibrarySymbolName,AContext,true)
  18643. else if (El is TPasVariable) and (TPasVariable(El).ExportName<>nil) then
  18644. Result:=ComputeConstString(TPasVariable(El).ExportName,AContext,true)
  18645. else if (El is TPasType) then
  18646. begin
  18647. if AContext.Resolver<>nil then
  18648. aType:=AContext.Resolver.ResolveAliasType(TPasType(El))
  18649. else
  18650. aType:=TPasType(El);
  18651. Result:=TransformVariableName(El,aType.Name,CanClashWithGlobal(aType),AContext);
  18652. end
  18653. else
  18654. Result:=TransformVariableName(El,GetOverloadName(El,AContext),
  18655. CanClashWithGlobal(El),AContext);
  18656. end;
  18657. function TPasToJSConverter.TransformModuleName(El: TPasModule;
  18658. AddModulesPrefix: boolean; AContext: TConvertContext): String;
  18659. var
  18660. p, StartP: Integer;
  18661. aName, Part: String;
  18662. begin
  18663. if El is TPasProgram then
  18664. Result:='program'
  18665. else
  18666. begin
  18667. Result:='';
  18668. aName:=El.Name;
  18669. p:=1;
  18670. while p<=length(aName) do
  18671. begin
  18672. StartP:=p;
  18673. while (p<=length(aName)) and (aName[p]<>'.') do inc(p);
  18674. Part:=copy(aName,StartP,p-StartP);
  18675. Part:=TransformVariableName(El,Part,false,AContext);
  18676. if Result<>'' then Result:=Result+'.';
  18677. Result:=Result+Part;
  18678. inc(p);
  18679. end;
  18680. end;
  18681. if AddModulesPrefix then
  18682. begin
  18683. if Pos('.',Result)>0 then
  18684. Result:=FBuiltInNames[pbivnModules]+'["'+Result+'"]'
  18685. else
  18686. Result:=FBuiltInNames[pbivnModules]+'.'+Result;
  18687. end;
  18688. end;
  18689. function TPasToJSConverter.IsReservedWord(const aName: string;
  18690. CheckGlobal: boolean): boolean;
  18691. var
  18692. l, r, m, cmp: Integer;
  18693. begin
  18694. Result:=true;
  18695. if aName=FBuiltInNames[pbivnModules] then exit;
  18696. if aName=FBuiltInNames[pbivnRTL] then exit;
  18697. // search default list
  18698. l:=low(JSReservedWords);
  18699. r:=high(JSReservedWords);
  18700. while l<=r do
  18701. begin
  18702. m:=(l+r) div 2;
  18703. cmp:=CompareStr(aName,JSReservedWords[m]);
  18704. //writeln('TPasToJSConverter.IsReservedWord Name="',aName,'" l=',l,' r=',r,' m=',m,' JSReservedWords[m]=',JSReservedWords[m],' cmp=',cmp);
  18705. if cmp>0 then
  18706. l:=m+1
  18707. else if cmp<0 then
  18708. r:=m-1
  18709. else
  18710. exit;
  18711. end;
  18712. // search user list
  18713. l:=0;
  18714. r:=length(FReservedWords)-1;
  18715. while l<=r do
  18716. begin
  18717. m:=(l+r) div 2;
  18718. cmp:=CompareStr(aName,FReservedWords[m]);
  18719. //writeln('TPasToJSConverter.IsReservedWord Name="',aName,'" l=',l,' r=',r,' m=',m,' FReservedWords[m]=',FReservedWords[m],' cmp=',cmp);
  18720. if cmp>0 then
  18721. l:=m+1
  18722. else if cmp<0 then
  18723. r:=m-1
  18724. else
  18725. exit;
  18726. end;
  18727. if CheckGlobal then
  18728. begin
  18729. // search default global list
  18730. l:=low(JSReservedGlobalWords);
  18731. r:=high(JSReservedGlobalWords);
  18732. while l<=r do
  18733. begin
  18734. m:=(l+r) div 2;
  18735. cmp:=CompareStr(aName,JSReservedGlobalWords[m]);
  18736. //writeln('TPasToJSConverter.IsReservedWord Name="',aName,'" l=',l,' r=',r,' m=',m,' JSReservedGlobalWords[m]=',JSReservedGlobalWords[m],' cmp=',cmp);
  18737. if cmp>0 then
  18738. l:=m+1
  18739. else if cmp<0 then
  18740. r:=m-1
  18741. else
  18742. exit;
  18743. end;
  18744. end;
  18745. Result:=false;
  18746. end;
  18747. function TPasToJSConverter.GetTypeInfoName(El: TPasType;
  18748. AContext: TConvertContext; ErrorEl: TPasElement): String;
  18749. var
  18750. C: TClass;
  18751. bt: TResolverBaseType;
  18752. jbt: TPas2jsBaseType;
  18753. CurEl: TPasElement;
  18754. aName: String;
  18755. begin
  18756. Result:='';
  18757. El:=ResolveSimpleAliasType(El);
  18758. if El=nil then
  18759. RaiseInconsistency(20170409172756,El);
  18760. if El=AContext.PasElement then
  18761. begin
  18762. // referring to itself
  18763. if El is TPasClassType then
  18764. begin
  18765. // use this
  18766. Result:=FBuiltInNames[pbivnRTTILocal];
  18767. exit;
  18768. end
  18769. else
  18770. RaiseNotSupported(ErrorEl,AContext,20170905150746,'cannot typeinfo itself');
  18771. end;
  18772. C:=El.ClassType;
  18773. if C=TPasUnresolvedSymbolRef then
  18774. begin
  18775. if El.Name='' then
  18776. DoError(20170905150752,nTypeXCannotBePublished,sTypeXCannotBePublished,
  18777. ['typeinfo of anonymous '+El.ElementTypeName],ErrorEl);
  18778. if El.CustomData is TResElDataBaseType then
  18779. begin
  18780. bt:=TResElDataBaseType(El.CustomData).BaseType;
  18781. case bt of
  18782. btShortInt,btByte,
  18783. btSmallInt,btWord,
  18784. btLongint,btLongWord,
  18785. btIntDouble,btUIntDouble,
  18786. btString,btChar,
  18787. btDouble,
  18788. btBoolean,
  18789. btPointer:
  18790. begin
  18791. // create rtl.basename
  18792. Result:=FBuiltInNames[pbivnRTL]+'.'+lowercase(AContext.Resolver.BaseTypeNames[bt]);
  18793. exit;
  18794. end;
  18795. btCurrency:
  18796. begin
  18797. Result:=FBuiltInNames[pbivnRTL]+'.'+lowercase(AContext.Resolver.BaseTypeNames[btIntDouble]);
  18798. exit;
  18799. end;
  18800. btCustom:
  18801. if El.CustomData is TResElDataPas2JSBaseType then
  18802. begin
  18803. jbt:=TResElDataPas2JSBaseType(El.CustomData).JSBaseType;
  18804. case jbt of
  18805. pbtJSValue:
  18806. begin
  18807. // create rtl.basename
  18808. Result:=FBuiltInNames[pbivnRTL]+'.'+lowercase(Pas2jsBaseTypeNames[jbt]);
  18809. exit;
  18810. end;
  18811. else
  18812. {$IFDEF VerbosePas2JS}
  18813. writeln('TPasToJSConverter.CreateTypeInfoRef [20170905150833] El=',GetObjName(El),' El.CustomData=',GetObjName(El.CustomData),' jbt=',Pas2jsBaseTypeNames[jbt]);
  18814. {$ENDIF}
  18815. end;
  18816. end
  18817. else
  18818. begin
  18819. {$IFDEF VerbosePas2JS}
  18820. writeln('TPasToJSConverter.CreateTypeInfoRef [20170905150840] El=',GetObjName(El),' El.CustomData=',GetObjName(El.CustomData),' bt=',AContext.Resolver.BaseTypeNames[bt]);
  18821. {$ENDIF}
  18822. end
  18823. else
  18824. {$IFDEF VerbosePas2JS}
  18825. writeln('TPasToJSConverter.CreateTypeInfoRef [20170905150842] El=',GetObjName(El),' El.CustomData=',GetObjName(El.CustomData),' bt=',AContext.Resolver.BaseTypeNames[bt]);
  18826. {$ENDIF}
  18827. end;
  18828. end
  18829. else
  18830. begin
  18831. {$IFDEF VerbosePas2JS}
  18832. writeln('TPasToJSConverter.CreateTypeInfoRef [20170905150844] El=',GetObjName(El),' El.CustomData=',GetObjName(El.CustomData));
  18833. {$ENDIF}
  18834. end;
  18835. end
  18836. else if (C=TPasEnumType)
  18837. or (C=TPasSetType)
  18838. or (C=TPasClassType)
  18839. or (C=TPasClassOfType)
  18840. or (C=TPasArrayType)
  18841. or (C=TPasProcedureType)
  18842. or (C=TPasFunctionType)
  18843. or (C=TPasPointerType)
  18844. or (C=TPasTypeAliasType)
  18845. or (C=TPasRecordType)
  18846. or (C=TPasRangeType)
  18847. then
  18848. begin
  18849. // user type -> module.$rtti[typename]
  18850. // Notes:
  18851. // a nested type gets the parent types prepended: classnameA.ElName
  18852. // an anonymous type gets for each level '$a' prepended
  18853. // an anonymous type of a variable/argument gets the variable name prepended
  18854. CurEl:=El;
  18855. repeat
  18856. if CurEl.Name<>'' then
  18857. begin
  18858. if CurEl.ClassType=TPasTypeAliasType then
  18859. aName:=TransformVariableName(CurEl,CurEl.Name,true,AContext)
  18860. else
  18861. aName:=TransformVariableName(CurEl,AContext);
  18862. if aName='' then
  18863. RaiseNotSupported(CurEl,AContext,20170905144902,'name conversion failed');
  18864. Result:=aName+Result;
  18865. end
  18866. else
  18867. begin
  18868. // anonymous type -> prepend '$a'
  18869. // for example:
  18870. // "var AnArray: array of array of char;" becomes AnArray$a$a
  18871. Result:=FBuiltInNames[pbitnAnonymousPostfix]+Result;
  18872. end;
  18873. CurEl:=CurEl.Parent;
  18874. if CurEl=nil then
  18875. break;
  18876. C:=CurEl.ClassType;
  18877. if (C=TPasClassType)
  18878. or (C=TPasRecordType) then
  18879. // nested
  18880. Result:='.'+Result
  18881. else if C.InheritsFrom(TPasType)
  18882. or (C=TPasVariable)
  18883. or (C=TPasConst)
  18884. or (C=TPasArgument)
  18885. or (C=TPasProperty) then
  18886. begin
  18887. // for example: var a: array of longint;
  18888. end
  18889. else
  18890. break;
  18891. until false;
  18892. if CurEl is TPasSection then
  18893. exit;
  18894. end;
  18895. aName:=El.Name;
  18896. if aName='' then aName:=El.ClassName;
  18897. DoError(20170409173329,nTypeXCannotBePublished,sTypeXCannotBePublished,
  18898. [aName],ErrorEl);
  18899. end;
  18900. function TPasToJSConverter.ConvertPasElement(El: TPasElement;
  18901. Resolver: TPas2JSResolver): TJSElement;
  18902. var
  18903. aContext: TRootContext;
  18904. begin
  18905. aContext:=TRootContext.Create(El,nil,nil);
  18906. try
  18907. aContext.Resolver:=Resolver;
  18908. if (El.ClassType=TPasImplBeginBlock) then
  18909. Result:=ConvertBeginEndStatement(TPasImplBeginBlock(El),AContext,false)
  18910. else
  18911. Result:=ConvertElement(El,aContext);
  18912. finally
  18913. FreeAndNil(aContext);
  18914. end;
  18915. end;
  18916. var
  18917. i: integer;
  18918. initialization
  18919. for i:=low(JSReservedWords) to High(JSReservedWords)-1 do
  18920. if CompareStr(JSReservedWords[i],JSReservedWords[i+1])>=0 then
  18921. raise Exception.Create('20170203135442 '+JSReservedWords[i]+' >= '+JSReservedWords[i+1]);
  18922. for i:=low(JSReservedGlobalWords) to High(JSReservedGlobalWords)-1 do
  18923. if CompareStr(JSReservedGlobalWords[i],JSReservedGlobalWords[i+1])>=0 then
  18924. raise Exception.Create('20170203135443 '+JSReservedGlobalWords[i]+' >= '+JSReservedGlobalWords[i+1]);
  18925. end.