pas2jscompiler.pp 175 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698
  1. { Author: Mattias Gaertner 2021 [email protected]
  2. Abstract:
  3. TPas2jsCompiler is the wheel boss of the pas2js compiler.
  4. It can be used in a command line program or compiled into an application.
  5. TPas2jsCompiler does not have understanding of the file system.
  6. DO NOT ADD filesystem related calls to this unit.
  7. The file system is abstracted out in TPas2JSFS (unit pas2jsfs)
  8. Add high-level calls to TPas2JSFS instead or create virtual methods that can be overridden.
  9. FileSystem specific things should go in Pas2JSFileCache and Pas2JSFSCompiler.
  10. Compiler-ToDos:
  11. Warn if -Ju and -Fu intersect
  12. -Fa<x>[,y] (for a program) load units <x> and [y] before uses is parsed
  13. Add Windows macros, see InitMacros.
  14. }
  15. unit Pas2jsCompiler;
  16. {$mode objfpc}{$H+}
  17. {$I pas2js_defines.inc}
  18. {$IF defined(VerboseUnitQueue) or defined(VerbosePCUFiler)}
  19. {$DEFINE ReallyVerbose}
  20. {$ENDIF}
  21. interface
  22. uses
  23. {$IFDEF Pas2js}
  24. JS,
  25. {$ELSE}
  26. RtlConsts,
  27. {$ENDIF}
  28. // !! No filesystem units here.
  29. Classes, SysUtils, contnrs,
  30. jsbase, jstree, jswriter, JSSrcMap, fpjson,
  31. PScanner, PParser, PasTree, PasResolver, PasResolveEval, PasUseAnalyzer,
  32. Pas2JSUtils,
  33. pas2jsresstrfile, pas2jsresources, pas2jshtmlresources, pas2jsjsresources,
  34. FPPas2Js, FPPJsSrcMap, Pas2jsLogger, Pas2jsFS, Pas2jsPParser, Pas2jsUseAnalyzer;
  35. const
  36. VersionMajor = 2;
  37. VersionMinor = 2;
  38. VersionRelease = 1;
  39. VersionExtra = '';
  40. DefaultConfigFile = 'pas2js.cfg';
  41. //------------------------------------------------------------------------------
  42. // Messages
  43. const
  44. nOptionIsEnabled = 101; sOptionIsEnabled = 'Option "%s" is %s';
  45. nSyntaxModeIs = 102; sSyntaxModeIs = 'Syntax mode is %s';
  46. nModeswitchXisY = 103; sModeswitchXisY = 'Modeswitch %s is %s';
  47. // 104 in unit Pas2JSFS
  48. // 105 in unit Pas2JSFS
  49. nNameValue = 106; sNameValue = '%s: %s';
  50. nReadingOptionsFromFile = 107; sReadingOptionsFromFile = 'Reading options from file %s';
  51. nEndOfReadingConfigFile = 108; sEndOfReadingConfigFile = 'End of reading config file %s';
  52. nInterpretingFileOption = 109; sInterpretingFileOption = 'interpreting file option %s';
  53. nSourceFileNotFound = 110; sSourceFileNotFound = 'source file not found %s';
  54. nFileIsFolder = 111; sFileIsFolder = 'expected file, but found directory %s';
  55. nConfigFileSearch = 112; sConfigFileSearch = 'Configfile search: %s';
  56. nHandlingOption = 113; sHandlingOption = 'handling option %s';
  57. nQuickHandlingOption = 114; sQuickHandlingOption = 'quick handling option %s';
  58. nOutputDirectoryNotFound = 115; sOutputDirectoryNotFound = 'output directory not found: %s';
  59. nUnableToWriteFile = 116; sUnableToWriteFile = 'Unable to write file %s';
  60. nWritingFile = 117; sWritingFile = 'Writing file %s ...';
  61. nCompilationAborted = 118; sCompilationAborted = 'Compilation aborted';
  62. nCfgDirective = 119; sCfgDirective = 'cfg directive %s: %s';
  63. nUnitCycle = 120; sUnitCycle = 'Unit cycle found %s';
  64. nOptionForbidsCompile = 121; sOptionForbidsCompile = 'Option -Ju forbids to compile unit "%s"';
  65. nUnitNeedsCompileDueToUsedUnit = 122; sUnitsNeedCompileDueToUsedUnit = 'Unit "%s" needs compile due to used unit "%s"';
  66. nUnitNeedsCompileDueToOption = 123; sUnitsNeedCompileDueToOption = 'Unit "%s" needs compile due to option "%s"';
  67. nUnitNeedsCompileJSMissing = 124; sUnitsNeedCompileJSMissing = 'Unit "%s" needs compile, js file missing "%s"';
  68. nUnitNeedsCompilePasHasChanged = 125; sUnitsNeedCompilePasHasChanged = 'Unit "%s" needs compile, Pascal file has changed, js is %s';
  69. nParsingFile = 126; sParsingFile = 'Parsing %s ...';
  70. nCompilingFile = 127; sCompilingFile = 'Compiling %s ...';
  71. nExpectedButFound = 128; sExpectedButFound = 'Illegal unit name: Expected "%s", but found "%s"';
  72. nLinesInFilesCompiled = 129; sLinesInFilesCompiled = '%s lines in %s files compiled, %s sec%s';
  73. nTargetPlatformIs = 130; sTargetPlatformIs = 'Target platform is %s';
  74. nTargetProcessorIs = 131; sTargetProcessorIs = 'Target processor is %s';
  75. nMessageEncodingIs = 132; sMessageEncodingIs = 'Message encoding is %s';
  76. nUnableToTranslatePathToDir = 133; sUnableToTranslatePathToDir = 'Unable to translate path %s to directory %s';
  77. nSrcMapSourceRootIs = 134; sSrcMapSourceRootIs = 'source map "sourceRoot" is %s';
  78. nSrcMapBaseDirIs = 135; sSrcMapBaseDirIs = 'source map "local base directory" is %s';
  79. nUnitFileNotFound = 136; sUnitFileNotFound = 'unit file not found %s';
  80. nClassInterfaceStyleIs = 137; sClassInterfaceStyleIs = 'Class interface style is %s';
  81. nHandlingEnvOpts = 138; sHandlingEnvOpts = 'handling environment options %s';
  82. nPostProcessorInfoX = 139; sPostProcessorInfoX = 'Post processor: %s';
  83. nPostProcessorRunX = 140; sPostProcessorRunX = 'Run post processor: %s';
  84. nPostProcessorFailX = 141; sPostProcessorFailX = 'Post processor failed: %s';
  85. nPostProcessorWarnX = 142; sPostProcessorWarnX = 'Post processor: %s';
  86. nPostProcessorFinished = 143; sPostProcessorFinished = 'Post processor finished';
  87. nRTLIdentifierChanged = 144; sRTLIdentifierChanged = 'RTL identifier %s changed from %s to %s';
  88. nSkipNoConstResourcestring = 145; sSkipNoConstResourcestring = 'Resource string %s is not a constant, not adding to resourcestrings file.';
  89. nUnknownOptimizationOption = 146; sUnknownOptimizationOption = 'unknown -Oo option %s';
  90. // Note: error numbers 201+ are used by Pas2jsFileCache
  91. //------------------------------------------------------------------------------
  92. // Options
  93. type
  94. TP2jsCompilerOption = (
  95. coSkipDefaultConfigs,
  96. coBuildAll,
  97. // verbosity
  98. coShowLogo,
  99. coShowErrors,
  100. coShowWarnings,
  101. coShowNotes,
  102. coShowHints,
  103. coShowInfos,
  104. coShowLineNumbers,
  105. coShowTriedUsedFiles,
  106. coShowConditionals,
  107. coShowUsedTools,
  108. coShowDebug,
  109. coShowMessageNumbers, // not in "show all"
  110. // checks
  111. coOverflowChecks,
  112. coRangeChecks,
  113. coObjectChecks,
  114. coAssertions,
  115. // features
  116. coAllowCAssignments,
  117. coAllowMacros,
  118. coWriteableConst,
  119. // output
  120. coLowerCase,
  121. coUseStrict,
  122. coWriteDebugLog,
  123. coWriteMsgToStdErr,
  124. coPrecompile, // create precompile file
  125. // optimizations
  126. coEnumValuesAsNumbers, // -O1
  127. coKeepNotUsedPrivates, // -O-
  128. coKeepNotUsedDeclarationsWPO, // -O-
  129. coShortRefGlobals, // -O2
  130. coObfuscateLocalIdentifiers, // -O2
  131. // source map
  132. coSourceMapCreate,
  133. coSourceMapInclude,
  134. coSourceMapFilenamesAbsolute,
  135. coSourceMapXSSIHeader
  136. );
  137. TP2jsCompilerOptions = set of TP2jsCompilerOption;
  138. TP2jsOptimization = coEnumValuesAsNumbers..coKeepNotUsedDeclarationsWPO;
  139. TP2jsRTLVersionCheck = (
  140. rvcNone,
  141. rvcMain,
  142. rvcSystem,
  143. rvcUnit
  144. );
  145. TP2JSResourceStringFile = (rsfNone,rsfUnit,rsfProgram);
  146. TResourceMode = (Skip,rmNone,rmHTML,rmJS);
  147. const
  148. DefaultP2jsCompilerOptions = [coShowErrors,coWriteableConst,coUseStrict,coSourceMapXSSIHeader];
  149. DefaultP2JSResourceStringFile = rsfProgram;
  150. DefaultP2jsRTLVersionCheck = rvcNone;
  151. DefaultResourceMode = rmHTML;
  152. coShowAll = [coShowErrors..coShowDebug];
  153. coAllOptimizations = [coEnumValuesAsNumbers..coObfuscateLocalIdentifiers];
  154. coO0 = [coKeepNotUsedPrivates,coKeepNotUsedDeclarationsWPO];
  155. coO1 = [coEnumValuesAsNumbers];
  156. coO2 = coO1+[coShortRefGlobals
  157. {$IFDEF EnableObfuscateIdentifiers},coObfuscateLocalIdentifiers{$ENDIF}];
  158. p2jscoCaption: array[TP2jsCompilerOption] of string = (
  159. // only used by experts or programs parsing the pas2js output, no need for resourcestrings
  160. 'Skip default configs',
  161. 'Build all',
  162. 'Show logo',
  163. 'Show errors',
  164. 'Show warnings',
  165. 'Show notes',
  166. 'Show hints',
  167. 'Show infos',
  168. 'Show line numbers',
  169. 'Show tried/used files',
  170. 'Show conditionals',
  171. 'Show used tools',
  172. 'Show debug',
  173. 'Show message numbers',
  174. 'Overflow checking',
  175. 'Range checking',
  176. 'Method call checking',
  177. 'Assertions',
  178. 'Allow C assignments',
  179. 'Allow macros',
  180. 'Allows typed constants to be writeable',
  181. 'Lowercase identifiers',
  182. 'Use strict',
  183. 'Write pas2jsdebug.log',
  184. 'Write messages to StdErr',
  185. 'Create precompiled units',
  186. 'Enum values as numbers',
  187. 'Keep not used private declarations',
  188. 'Keep not used declarations (WPO)',
  189. 'Create short local variables for globals',
  190. 'Obfuscate local identifiers',
  191. 'Create source map',
  192. 'Include Pascal sources in source map',
  193. 'Do not shorten filenames in source map',
  194. 'Prepend XSSI protection )]} to source map'
  195. );
  196. //------------------------------------------------------------------------------
  197. // $mode and $modeswitches
  198. type
  199. TP2jsMode = (
  200. p2jmObjFPC,
  201. p2jmDelphi
  202. );
  203. TP2jsModes = set of TP2jsMode;
  204. const
  205. p2jscModeNames: array[TP2jsMode] of string = (
  206. 'ObjFPC',
  207. 'Delphi'
  208. );
  209. p2jsMode_SwitchSets: array[TP2jsMode] of TModeSwitches = (
  210. OBJFPCModeSwitches*msAllPas2jsModeSwitches+msAllPas2jsModeSwitchesReadOnly,
  211. DelphiModeSwitches*msAllPas2jsModeSwitches+msAllPas2jsModeSwitchesReadOnly
  212. );
  213. //------------------------------------------------------------------------------
  214. // param macros
  215. type
  216. EPas2jsMacro = class(Exception);
  217. TOnSubstituteMacro = function(Sender: TObject; var Params: string; Lvl: integer): boolean of object;
  218. { TPas2jsMacro }
  219. TPas2jsMacro = class
  220. public
  221. Name: string;
  222. Description: string;
  223. Value: string;
  224. CanHaveParams: boolean;
  225. OnSubstitute: TOnSubstituteMacro;
  226. end;
  227. { TPas2jsMacroEngine }
  228. TPas2jsMacroEngine = class
  229. private
  230. fMacros: TObjectList; // list of TPas2jsMacro
  231. FMaxLevel: integer;
  232. function GetMacros(Index: integer): TPas2jsMacro;
  233. public
  234. constructor Create;
  235. destructor Destroy; override;
  236. function Count: integer;
  237. function AddValue(const aName, aDescription, aValue: string): TPas2jsMacro;
  238. function AddFunction(const aName, aDescription: string;
  239. const OnSubstitute: TOnSubstituteMacro; CanHaveParams: boolean): TPas2jsMacro;
  240. function IndexOf(const aName: string): integer;
  241. procedure Delete(Index: integer);
  242. function FindMacro(const aName: string): TPas2jsMacro;
  243. procedure Substitute(var s: string; Sender: TObject = nil; Lvl: integer = 0);
  244. property Macros[Index: integer]: TPas2jsMacro read GetMacros; default;
  245. property MaxLevel: integer read FMaxLevel write FMaxLevel;
  246. end;
  247. //------------------------------------------------------------------------------
  248. // Module file
  249. type
  250. ECompilerTerminate = class(Exception);
  251. TPas2jsCompiler = class;
  252. TPas2JSCompilerFile = Class;
  253. TUsedBySection = (
  254. ubMainSection,
  255. ubImplSection
  256. );
  257. TPas2jsReaderState = (
  258. prsNone,
  259. prsReading,
  260. prsWaitingForUsedUnits,
  261. prsCanContinue,
  262. prsFinished,
  263. prsError
  264. );
  265. { TPCUSupport }
  266. TPCUSupport = Class(TObject)
  267. private
  268. FFile: TPas2JSCompilerFile;
  269. Protected
  270. procedure RaiseInternalError(id: TMaxPrecInt; Msg: string);
  271. Procedure SetPasModule(aModule: TPasModule);
  272. Procedure SetReaderState(aReaderState: TPas2JSReaderState);
  273. Procedure SetPCUFileName(Const FN: String);
  274. public
  275. constructor Create(aCompilerFile: TPas2JSCompilerFile);
  276. function HandleException(E: Exception): Boolean; virtual; abstract;
  277. procedure CreatePCUReader; virtual; abstract;
  278. function HasReader: Boolean; virtual; abstract;
  279. function ReadContinue: Boolean; virtual; abstract;
  280. function ReadCanContinue: Boolean; virtual; abstract;
  281. function FindPCU(const UseUnitName: string): string; virtual; abstract;
  282. procedure SetInitialCompileFlags; virtual; abstract;
  283. procedure WritePCU; virtual; abstract;
  284. procedure ReadUnit; virtual; abstract;
  285. property MyFile: TPas2JSCompilerFile Read FFile;
  286. end;
  287. { TFindUnitInfo }
  288. TFindUnitInfo = Record
  289. FileName: String;
  290. UnitName: String;
  291. isPCU: Boolean;
  292. isForeign: Boolean;
  293. end;
  294. { TLoadUnitInfo }
  295. TLoadUnitInfo = Record
  296. UseFilename, // pas or pcu filename, see IsPCU
  297. UseUnitname,
  298. InFilename: String; // can be ''
  299. NameExpr, InFileExpr: TPasExpr; // can be nil
  300. UseIsForeign: boolean;
  301. IsPCU: Boolean;
  302. end;
  303. { TPas2JSCompilerSupport }
  304. TPas2JSCompilerSupport = Class
  305. private
  306. FCompiler: TPas2JSCompiler;
  307. Public
  308. Constructor Create(aCompiler: TPas2JSCompiler); virtual;
  309. Property Compiler: TPas2JSCompiler read FCompiler;
  310. end;
  311. { TPas2jsCompilerFile }
  312. TPas2jsCompilerFile = class(TPas2JSCompilerSupport)
  313. private
  314. FConverter: TPasToJSConverter;
  315. FFileResolver: TPas2jsFSResolver;
  316. FIsForeign: boolean;
  317. FIsMainFile: boolean;
  318. FJSFilename: string;
  319. FJSModule: TJSElement;
  320. FLog: TPas2jsLogger;
  321. FNeedBuild: Boolean;
  322. FParser: TPas2jsPasParser;
  323. FPasFileName: String;
  324. FPasModule: TPasModule;
  325. FPasResolver: TPas2jsCompilerResolver;
  326. FPasUnitName: string;
  327. FPCUFilename: string;
  328. FPCUSupport: TPCUSupport;
  329. FReaderState: TPas2jsReaderState;
  330. FResourceHandler: TPas2jsResourceHandler;
  331. FScanner: TPas2jsPasScanner;
  332. FShowDebug: boolean;
  333. FUnitFilename: string;
  334. FUseAnalyzer: TPas2JSAnalyzer;
  335. FUsedBy: array[TUsedBySection] of TFPList; // list of TPas2jsCompilerFile
  336. function GetUsedBy(Section: TUsedBySection; Index: integer): TPas2jsCompilerFile;
  337. function GetUsedByCount(Section: TUsedBySection): integer;
  338. procedure HandleResources(Sender: TObject; const aFileName: String; aOptions: TStrings);
  339. function OnConverterIsElementUsed(Sender: TObject; El: TPasElement): boolean;
  340. function OnConverterIsTypeInfoUsed(Sender: TObject; El: TPasElement): boolean;
  341. procedure OnPasResolverLog(Sender: TObject; const Msg: String);
  342. procedure OnParserLog(Sender: TObject; const Msg: String);
  343. procedure OnScannerLog(Sender: TObject; const Msg: String);
  344. procedure OnUseAnalyzerMessage(Sender: TObject; Msg: TPAMessage);
  345. procedure HandleEParserError(E: EParserError);
  346. procedure HandleEPasResolve(E: EPasResolve);
  347. procedure HandleEPas2JS(E: EPas2JS);
  348. procedure HandleUnknownException(E: Exception);
  349. procedure HandleException(E: Exception);
  350. {$IFDEF Pas2js}
  351. procedure HandleJSException(Msg: string; E: jsvalue);
  352. {$ENDIF}
  353. procedure DoLogMsgAtEl(MsgType: TMessageType; const Msg: string;
  354. MsgNumber: integer; El: TPasElement);
  355. procedure RaiseInternalError(id: TMaxPrecInt; Msg: string);
  356. procedure ReaderFinished;
  357. public
  358. constructor Create(aCompiler: TPas2jsCompiler;
  359. const aPasFilename, aPCUFilename: string); reintroduce;
  360. destructor Destroy; override;
  361. Function CreatePCUSupport: TPCUSupport; virtual;
  362. function GetInitialModeSwitches: TModeSwitches;
  363. function IsUnitReadFromPCU: Boolean; // unit was read from pcu
  364. function GetInitialBoolSwitches: TBoolSwitches;
  365. function GetInitialConverterOptions: TPasToJsConverterOptions;
  366. procedure CreateScannerAndParser(aFileResolver: TPas2jsFSResolver);
  367. procedure CreateConverter;
  368. function OnResolverFindModule(const UseUnitName, InFilename: String; NameExpr,
  369. InFileExpr: TPasExpr): TPasModule;
  370. procedure OnResolverCheckSrcName(const Element: TPasElement);
  371. procedure OpenFile(aFilename: string);// beware: this changes FileResolver.BaseDirectory
  372. procedure ReadUnit;
  373. function ReadContinue: boolean; // true=finished
  374. function ReaderState: TPas2jsReaderState;
  375. procedure CreateJS;
  376. procedure EmitModuleHints;
  377. function GetPasFirstSection: TPasSection;
  378. function GetPasImplSection: TPasSection;
  379. function GetPasMainUsesClause: TPasUsesClause;
  380. function GetPasImplUsesClause: TPasUsesClause;
  381. function GetCurPasModule: TPasModule;
  382. function GetModuleName: string;
  383. class function GetFile(aModule: TPasModule): TPas2jsCompilerFile;
  384. public
  385. Property ResourceHandler : TPas2jsResourceHandler Read FResourceHandler Write FResourceHandler;
  386. property PasFileName: String Read FPasFileName;
  387. property PasUnitName: string read FPasUnitName write FPasUnitName;// unit name in source, initialized from UnitFilename
  388. property Converter: TPasToJSConverter read FConverter;
  389. property FileResolver: TPas2jsFSResolver read FFileResolver;
  390. property IsForeign: boolean read FIsForeign write FIsForeign;// true = do not build
  391. property IsMainFile: boolean read FIsMainFile write FIsMainFile;
  392. property JSFilename: string read FJSFilename write FJSFilename;
  393. property JSModule: TJSElement read FJSModule;
  394. property Log: TPas2jsLogger read FLog;
  395. property NeedBuild: Boolean read FNeedBuild write FNeedBuild;
  396. property Parser: TPas2jsPasParser read FParser;
  397. property PascalResolver: TPas2jsCompilerResolver read FPasResolver;
  398. property PasModule: TPasModule read FPasModule;
  399. property PCUFilename: string read FPCUFilename;
  400. property PCUSupport: TPCUSupport Read FPCUSupport;
  401. property Scanner: TPas2jsPasScanner read FScanner;
  402. property ShowDebug: boolean read FShowDebug write FShowDebug;
  403. property UnitFilename: string read FUnitFilename;
  404. property UseAnalyzer: TPas2JSAnalyzer read FUseAnalyzer; // unit analysis
  405. property UsedByCount[Section: TUsedBySection]: integer read GetUsedByCount;
  406. property UsedBy[Section: TUsedBySection; Index: integer]: TPas2jsCompilerFile read GetUsedBy;
  407. end;
  408. { TPas2JSCompilerSupport }
  409. TPas2JSPostProcessorSupport = Class(TPas2JSCompilerSupport)
  410. Public
  411. Procedure WriteUsedTools; virtual; abstract;
  412. Procedure Clear; virtual; abstract;
  413. Procedure AddPostProcessor(Const Cmd: String); virtual; abstract;
  414. Procedure CallPostProcessors(Const JSFileName: String; aWriter: TPas2JSMapper); virtual; abstract;
  415. end;
  416. { TPas2JSConfigSupport }
  417. TPas2JSConfigSupport = Class(TPas2JSCompilerSupport)
  418. private
  419. FConditionEval: TCondDirectiveEvaluator;
  420. FCurrentCfgFilename: string;
  421. FCurrentCfgLineNumber: integer;
  422. Protected
  423. procedure CfgSyntaxError(const Msg: string);
  424. function ConditionEvalVariable(Sender: TCondDirectiveEvaluator; aName: String; out Value: string): boolean;
  425. procedure ConditionEvalLog(Sender: TCondDirectiveEvaluator; Args: array of const);
  426. property ConditionEvaluator: TCondDirectiveEvaluator read FConditionEval;
  427. property CurrentCfgFilename: string read FCurrentCfgFilename;
  428. property CurrentCfgLineNumber: integer read FCurrentCfgLineNumber;
  429. Protected
  430. // These must be overridden in descendents
  431. function FindDefaultConfig: String; virtual; abstract;
  432. function GetReader(aFileName: string): TSourceLineReader; virtual; abstract;
  433. Public
  434. constructor Create(aCompiler: TPas2jsCompiler); override;
  435. destructor Destroy; override;
  436. procedure LoadDefaultConfig;
  437. procedure LoadConfig(Const aFileName: String);virtual;
  438. property Compiler: TPas2jsCompiler Read FCompiler;
  439. end;
  440. { TPas2jsCompiler }
  441. TPas2jsCompiler = class
  442. private
  443. FAllJSIntoMainJS: Boolean;
  444. FCompilerExe: string;
  445. FConfigSupport: TPas2JSConfigSupport;
  446. FConverterGlobals: TPasToJSConverterGlobals;
  447. FDefines: TStrings; // Objects can be TMacroDef
  448. FFiles: TPasAnalyzerKeySet; // set of TPas2jsCompilerFile, key is UnitFilename
  449. FFS: TPas2jsFS;
  450. FHasShownEncoding: boolean;
  451. FHasShownLogo: boolean;
  452. FInsertFilenames: TStringList;
  453. FAppendFilenames: TStringList;
  454. FInterfaceType: TPasClassInterfaceType;
  455. FLog: TPas2jsLogger;
  456. FMainFile: TPas2jsCompilerFile;
  457. FMainJSFile: String;
  458. FMainJSFileIsResolved: Boolean;
  459. FMainJSFileResolved: String;
  460. FMainSrcFile: String;
  461. FModeSwitches: TModeSwitches;
  462. FNamespaces: TStringList;
  463. FNamespacesFromCmdLine: integer;
  464. FOptions: TP2jsCompilerOptions;
  465. FOwnsFS: boolean;
  466. FParamMacros: TPas2jsMacroEngine;
  467. FPostProcessorSupport: TPas2JSPostProcessorSupport;
  468. FPrecompileGUID: TGUID;
  469. FReadingModules: TFPList; // list of TPas2jsCompilerFile ordered by uses sections
  470. FResolverHub: TPas2JSResolverHub;
  471. FRTLVersionCheck: TP2jsRTLVersionCheck;
  472. FSrcMapBaseDir: string;
  473. FSrcMapSourceRoot: string;
  474. FUnits: TPasAnalyzerKeySet; // set of TPas2jsCompilerFile, key is PasUnitName
  475. FWPOAnalyzer: TPas2JSAnalyzer;
  476. FResourceMode : TResourceMode;
  477. FResources : TPas2JSResourceHandler;
  478. FResourceStrings : TResourceStringsFile;
  479. FResourceStringFile : TP2JSResourceStringFile;
  480. FImports : TJSSourceElements;
  481. procedure AddInsertJSFilename(const aFilename: string);
  482. procedure AddAppendJSFilename(const aFilename: string);
  483. Procedure AddNamespaces(const Paths: string; FromCmdLine: boolean);
  484. procedure AddUnitResourceStrings(aFile: TPas2jsCompilerFile);
  485. function CreateFileWriter(aFile: TPas2jsCompilerFile; const aFilename: string): TPas2JSMapper;
  486. procedure EmitJavaScript(aFile: TPas2jsCompilerFile; aFileWriter: TPas2JSMapper);
  487. function GetDefaultNamespace: String;
  488. function GetFileCount: integer;
  489. function GetResolvedMainJSFile: string;
  490. function GetShowDebug: boolean;
  491. function GetShowFullPaths: boolean;
  492. function GetShowLogo: Boolean; inline;
  493. function GetShowTriedUsedFiles: boolean;
  494. function GetShowUsedTools: boolean; inline;
  495. function GetSkipDefaultConfig: Boolean; inline;
  496. function GetSrcMapEnable: boolean;
  497. function GetSrcMapInclude: boolean;
  498. function GetSrcMapFilenamesAbsolute: boolean;
  499. function GetSrcMapXSSIHeader: boolean;
  500. function GetTargetPlatform: TPasToJsPlatform;
  501. function GetTargetProcessor: TPasToJsProcessor;
  502. function GetWriteDebugLog: boolean;
  503. function GetWriteMsgToStdErr: boolean;
  504. function IndexOfInsertJSFilename(const aFilename: string): integer;
  505. function IndexOfAppendJSFilename(const aFilename: string): integer;
  506. procedure InsertCustomJSFiles(aWriter: TPas2JSMapper);
  507. procedure AppendCustomJSFiles(aWriter: TPas2JSMapper);
  508. procedure InsertImportSection(aFileWriter: TPas2JSMapper);
  509. function LoadUsedUnit(Info: TLoadUnitInfo; Context: TPas2jsCompilerFile): TPas2jsCompilerFile;
  510. function OnMacroCfgDir(Sender: TObject; var Params: string; Lvl: integer): boolean;
  511. procedure RemoveInsertJSFilename(const aFilename: string);
  512. procedure RemoveAppendJSFilename(const aFilename: string);
  513. function ResolvedMainJSFile: string;
  514. procedure SetAllJSIntoMainJS(AValue: Boolean);
  515. procedure SetConverterGlobals(const AValue: TPasToJSConverterGlobals);
  516. procedure SetCompilerExe(AValue: string);
  517. procedure SetFS(AValue: TPas2jsFS);
  518. procedure SetMode(AValue: TP2jsMode);
  519. procedure SetModeSwitches(const AValue: TModeSwitches);
  520. procedure SetOptions(AValue: TP2jsCompilerOptions);
  521. procedure SetShowDebug(AValue: boolean);
  522. procedure SetShowFullPaths(AValue: boolean);
  523. procedure SetShowLogo(AValue: Boolean);
  524. procedure SetShowTriedUsedFiles(AValue: boolean);
  525. procedure SetShowUsedTools(AValue: boolean);
  526. procedure SetSkipDefaultConfig(AValue: Boolean);
  527. procedure SetSrcMapBaseDir(const AValue: string);
  528. procedure SetSrcMapEnable(const AValue: boolean);
  529. procedure SetSrcMapInclude(const AValue: boolean);
  530. procedure SetSrcMapFilenamesAbsolute(const AValue: boolean);
  531. procedure SetSrcMapXSSIHeader(const AValue: boolean);
  532. procedure SetTargetPlatform(const AValue: TPasToJsPlatform);
  533. procedure SetTargetProcessor(const AValue: TPasToJsProcessor);
  534. procedure SetWriteDebugLog(const AValue: boolean);
  535. procedure SetWriteMsgToStdErr(const AValue: boolean);
  536. procedure WriteJSToFile(const MapFileName: string; aFileWriter: TPas2JSMapper);
  537. procedure WriteResourceStrings(aFileName: String);
  538. procedure WriteResources(aFileName: String);
  539. procedure WriteSrcMap(const MapFileName: string; aFileWriter: TPas2JSMapper);
  540. private
  541. procedure AddDefinesForTargetPlatform;
  542. procedure AddDefinesForTargetProcessor;
  543. procedure AddReadingModule(aFile: TPas2jsCompilerFile);
  544. procedure RemoveReadingModule(aFile: TPas2jsCompilerFile);
  545. procedure RegisterMessages;
  546. private
  547. // params, cfg files
  548. FCurParam: string;
  549. FResourceOutputFile: String;
  550. procedure LoadConfig(CfgFilename: string);
  551. procedure ReadEnvironment;
  552. procedure ReadParam(Param: string; Quick, FromCmdLine: boolean);
  553. procedure ReadSingleLetterOptions(const Param: string; p: integer;
  554. const Allowed: string; out Enabled, Disabled: string);
  555. procedure ReadCodeGenerationFlags(Param: String; p: integer);
  556. procedure ReadSyntaxFlags(Param: String; p: integer);
  557. procedure ReadVerbosityFlags(Param: String; p: integer);
  558. protected
  559. // Create various other classes. Virtual so they can be overridden in descendents
  560. function CreateImportList : TJSSourceElements;
  561. function CreateImportStatement : TJSImportStatement;
  562. function CreateJSMapper: TPas2JSMapper; virtual;
  563. function CreateJSWriter(aFileWriter: TPas2JSMapper): TJSWriter; virtual;
  564. function CreateLog: TPas2jsLogger; virtual;
  565. function CreateMacroEngine: TPas2jsMacroEngine;virtual;
  566. function CreateSrcMap(const aFileName: String): TPas2JSSrcMap; virtual;
  567. function CreateOptimizer: TPas2JSAnalyzer;
  568. function CreateSetOfCompilerFiles(keyType: TKeyCompareType): TPasAnalyzerKeySet; virtual; abstract;// mandatory !
  569. function CreateFS: TPas2JSFS; virtual; abstract; // mandatory !
  570. function FormatPath(Const aPath: String): String;
  571. function FullFormatPath(Const aPath: String): String;
  572. procedure WritePrecompiledFormats; virtual;
  573. procedure WriteHelpLine(S: String);
  574. function LoadFile(Filename: string; Binary: boolean = false): TPas2jsFile;
  575. // Override these for PCU format
  576. procedure HandleLinkLibStatement(Sender: TObject; const aLibName, aLibAlias, aLibOptions: String; var Handled: boolean);
  577. function CreateCompilerFile(const PasFileName, PCUFilename: String): TPas2jsCompilerFile; virtual;
  578. // Command-line option handling
  579. procedure HandleOptionPCUFormat(aValue: String); virtual;
  580. function HandleOptionPaths(C: Char; aValue: String; FromCmdLine: Boolean): Boolean; virtual;
  581. function HandleOptionJ(C: Char; aValue: String; Quick,FromCmdLine: Boolean): Boolean; virtual;
  582. function HandleOptionM(aValue: String; Quick: Boolean): Boolean; virtual;
  583. procedure HandleOptionConfigFile(aPos: Integer; const aFileName: string); virtual;
  584. procedure HandleOptionInfo(aValue: string);
  585. function HandleOptionOptimization(C: Char; aValue: String): Boolean;
  586. // DoWriteJSFile: return false to use the default write function.
  587. function DoWriteJSFile(const DestFilename, MapFilename: String; aWriter: TPas2JSMapper): Boolean; virtual;
  588. procedure Compile(StartTime: TDateTime);
  589. procedure ProcessQueue;
  590. function MarkNeedBuilding(aFile: TPas2jsCompilerFile;
  591. Checked: TPasAnalyzerKeySet { set of TPas2jsCompilerFile, key is UnitFilename };
  592. var SrcFileCount: integer): boolean;
  593. procedure OptimizeProgram(aFile: TPas2jsCompilerFile); virtual;
  594. procedure CreateJavaScript(aFile: TPas2jsCompilerFile;
  595. Checked: TPasAnalyzerKeySet { set of TPas2jsCompilerFile, key is UnitFilename });
  596. procedure FinishSrcMap(SrcMap: TPas2JSSrcMap); virtual;
  597. // WriteSingleJSFile does not recurse
  598. procedure WriteSingleJSFile(aFile: TPas2jsCompilerFile; CombinedFileWriter: TPas2JSMapper);
  599. // WriteJSFiles recurses uses clause
  600. procedure WriteJSFiles(aFile: TPas2jsCompilerFile;
  601. CombinedFileWriter: TPas2JSMapper;
  602. Checked: TPasAnalyzerKeySet { set of TPas2jsCompilerFile, key is UnitFilename });
  603. procedure InitParamMacros;virtual;
  604. procedure ClearDefines;
  605. procedure RaiseInternalError(id: TMaxPrecInt; Msg: string);
  606. {$IFDEF Pas2js}
  607. procedure HandleJSException(Msg: string; E: jsvalue; TerminateInternal: boolean = true);
  608. {$ENDIF}
  609. function GetExitCode: Longint; virtual;
  610. procedure SetExitCode(Value: Longint); virtual;
  611. Procedure SetWorkingDir(const aDir: String); virtual;
  612. Procedure CreateResourceSupport; virtual;
  613. public
  614. constructor Create; virtual;
  615. destructor Destroy; override;
  616. procedure Reset; virtual;
  617. procedure ParamFatal(Msg: string);
  618. procedure Run(
  619. aCompilerExe: string; // needed for default config and help
  620. aWorkingDir: string;
  621. ParamList: TStrings;
  622. DoReset: boolean = true);
  623. procedure Terminate(TheExitCode: integer);
  624. class function GetVersion(ShortVersion: boolean): string;
  625. procedure WriteHelp;
  626. procedure WriteLogo;
  627. procedure WriteEncoding;
  628. procedure WriteVersionLine;
  629. procedure WriteOptions;
  630. procedure WriteDefines;
  631. procedure WriteUsedTools;
  632. procedure WriteFoldersAndSearchPaths;
  633. procedure WriteInfo;
  634. function GetShownMsgTypes: TMessageTypes;
  635. procedure AddDefine(const aName: String);
  636. procedure AddDefine(const aName, Value: String);
  637. procedure RemoveDefine(const aName: String);
  638. function IsDefined(const aName: String): boolean;
  639. procedure SetOption(Flag: TP2jsCompilerOption; Enable: boolean);
  640. function GetUnitInfo(UseUnitName, InFileName, ModuleDir: String;
  641. PCUSupport: TPCUSupport): TFindUnitInfo;
  642. procedure CheckUnitAlias(var UseUnitName: string); virtual;
  643. function FindFileWithUnitFilename(UnitFilename: string): TPas2jsCompilerFile;
  644. procedure LoadModuleFile(UnitFilename, UseUnitName: string;
  645. out aFile: TPas2jsCompilerFile; isPCU: Boolean);
  646. Function FindUnitJSFileName(aFileName: String): String;
  647. function FindLoadedUnit(const TheUnitName: string): TPas2jsCompilerFile;
  648. procedure AddUsedUnit(aFile: TPas2jsCompilerFile);
  649. function ExpandFileName(const Filename: string): string;
  650. public
  651. property CompilerExe: string read FCompilerExe write SetCompilerExe;
  652. property DefaultNamespace: String read GetDefaultNamespace;
  653. property Defines: TStrings read FDefines;
  654. property FS: TPas2jsFS read FFS write SetFS;
  655. property OwnsFS: boolean read FOwnsFS write FOwnsFS; // true = auto free FS when compiler is freed
  656. property FileCount: integer read GetFileCount;
  657. property InterfaceType: TPasClassInterfaceType read FInterfaceType write FInterfaceType; // default interface type
  658. property Log: TPas2jsLogger read FLog;
  659. property MainFile: TPas2jsCompilerFile read FMainFile;
  660. property ModeSwitches: TModeSwitches read FModeSwitches write SetModeSwitches;
  661. property Options: TP2jsCompilerOptions read FOptions write SetOptions;
  662. property ConverterGlobals: TPasToJSConverterGlobals read FConverterGlobals write SetConverterGlobals;
  663. property ResolverHub: TPas2JSResolverHub read FResolverHub;
  664. property ParamMacros: TPas2jsMacroEngine read FParamMacros;
  665. property PrecompileGUID: TGUID read FPrecompileGUID write FPrecompileGUID;
  666. property RTLVersionCheck: TP2jsRTLVersionCheck read FRTLVersionCheck write FRTLVersionCheck;
  667. property SrcMapEnable: boolean read GetSrcMapEnable write SetSrcMapEnable;
  668. property SrcMapSourceRoot: string read FSrcMapSourceRoot write FSrcMapSourceRoot;
  669. property SrcMapInclude: boolean read GetSrcMapInclude write SetSrcMapInclude;
  670. property SrcMapXSSIHeader: boolean read GetSrcMapXSSIHeader write SetSrcMapXSSIHeader;
  671. property SrcMapFilenamesAbsolute: boolean read GetSrcMapFilenamesAbsolute write SetSrcMapFilenamesAbsolute;
  672. property ShowDebug: boolean read GetShowDebug write SetShowDebug;
  673. property ShowFullPaths: boolean read GetShowFullPaths write SetShowFullPaths;
  674. property ShowLogo: Boolean read GetShowLogo write SetShowLogo;
  675. property ShowTriedUsedFiles: boolean read GetShowTriedUsedFiles write SetShowTriedUsedFiles;
  676. property ShowUsedTools: boolean read GetShowUsedTools write SetShowUsedTools;
  677. property SkipDefaultConfig: Boolean read GetSkipDefaultConfig write SetSkipDefaultConfig;
  678. property TargetPlatform: TPasToJsPlatform read GetTargetPlatform write SetTargetPlatform;
  679. property TargetProcessor: TPasToJsProcessor read GetTargetProcessor write SetTargetProcessor;
  680. property WPOAnalyzer: TPas2JSAnalyzer read FWPOAnalyzer; // Whole Program Optimization
  681. property WriteDebugLog: boolean read GetWriteDebugLog write SetWriteDebugLog;
  682. property WriteMsgToStdErr: boolean read GetWriteMsgToStdErr write SetWriteMsgToStdErr;
  683. property AllJSIntoMainJS: Boolean Read FAllJSIntoMainJS Write SetAllJSIntoMainJS;
  684. property ExitCode: longint read GetExitCode write SetExitCode;
  685. property InsertFilenames : TStringList read FInsertFilenames;
  686. Property AppendFileNames : TStringList read FAppendFileNames;
  687. property MainJSFile: String Read FMainJSFile Write FMainJSFile;
  688. property MainSrcFile: String Read FMainSrcFile Write FMainSrcFile;
  689. property SrcMapBaseDir: string read FSrcMapBaseDir write SetSrcMapBaseDir; // includes trailing pathdelim
  690. property Namespaces: TStringList read FNamespaces;
  691. property NamespacesFromCmdLine: integer read FNamespacesFromCmdLine;
  692. Property ResourceMode : TResourceMode Read FResourceMode Write FResourceMode;
  693. Property ResourceOutputFile : String Read FResourceOutputFile Write FResourceOutputFile;
  694. // can be set optionally, will be freed by compiler
  695. property ConfigSupport: TPas2JSConfigSupport Read FConfigSupport Write FConfigSupport;
  696. property PostProcessorSupport: TPas2JSPostProcessorSupport Read FPostProcessorSupport Write FPostProcessorSupport;
  697. end;
  698. function GetCompiledDate: string;
  699. function GetCompiledVersion: string;
  700. function GetCompiledTargetOS: string;
  701. function GetCompiledTargetCPU: string;
  702. implementation
  703. // !! No filesystem units here.
  704. //uses ;
  705. function GetCompiledDate: string;
  706. begin
  707. Result:={$I %Date%};
  708. end;
  709. function GetCompiledVersion: string;
  710. begin
  711. Result:={$I %FPCVERSION%};
  712. end;
  713. function GetCompiledTargetOS: string;
  714. begin
  715. Result:=lowerCase({$I %FPCTARGETOS%});
  716. end;
  717. function GetCompiledTargetCPU: string;
  718. begin
  719. Result:=lowerCase({$I %FPCTARGETCPU%});
  720. end;
  721. { TPas2JSCompilerSupport }
  722. constructor TPas2JSCompilerSupport.Create(aCompiler: TPas2JSCompiler);
  723. begin
  724. FCompiler:=aCompiler;
  725. end;
  726. { TPas2JSConfigSupport }
  727. constructor TPas2JSConfigSupport.Create(aCompiler: TPas2jsCompiler);
  728. begin
  729. Inherited Create(aCompiler);
  730. FConditionEval:=TCondDirectiveEvaluator.Create;
  731. FConditionEval.OnLog:=@ConditionEvalLog;
  732. FConditionEval.OnEvalVariable:=@ConditionEvalVariable;
  733. end;
  734. destructor TPas2JSConfigSupport.Destroy;
  735. begin
  736. FreeAndNil(FConditionEval);
  737. inherited Destroy;
  738. end;
  739. { TPCUSupport }
  740. procedure TPCUSupport.RaiseInternalError(id: TMaxPrecInt; Msg: string);
  741. begin
  742. MyFile.RaiseInternalError(id,msg);
  743. end;
  744. procedure TPCUSupport.SetPasModule(aModule: TPasModule);
  745. begin
  746. MyFile.FPasModule:=aModule;
  747. end;
  748. procedure TPCUSupport.SetReaderState(aReaderState: TPas2JSReaderState);
  749. begin
  750. MyFile.FReaderState:=aReaderState;
  751. end;
  752. procedure TPCUSupport.SetPCUFileName(const FN: String);
  753. begin
  754. FFile.FPCUFilename:=FN;
  755. end;
  756. constructor TPCUSupport.Create(aCompilerFile: TPas2JSCompilerFile);
  757. begin
  758. FFile:=aCompilerFile;
  759. end;
  760. { TPas2jsMacroEngine }
  761. function TPas2jsMacroEngine.GetMacros(Index: integer): TPas2jsMacro;
  762. begin
  763. Result:=TPas2jsMacro(fMacros[Index]);
  764. end;
  765. constructor TPas2jsMacroEngine.Create;
  766. begin
  767. fMacros:=TObjectList.Create(true);
  768. FMaxLevel:=10;
  769. end;
  770. destructor TPas2jsMacroEngine.Destroy;
  771. begin
  772. FreeAndNil(fMacros);
  773. inherited Destroy;
  774. end;
  775. function TPas2jsMacroEngine.Count: integer;
  776. begin
  777. Result:=fMacros.Count;
  778. end;
  779. function TPas2jsMacroEngine.AddValue(const aName, aDescription, aValue: string
  780. ): TPas2jsMacro;
  781. begin
  782. if not IsValidIdent(aName) then
  783. raise EPas2jsMacro.Create('invalid macro name "'+aName+'"');
  784. if IndexOf(aName)>=0 then
  785. raise EPas2jsMacro.Create('duplicate macro name "'+aName+'"');
  786. Result:=TPas2jsMacro.Create;
  787. Result.Name:=aName;
  788. Result.Description:=aDescription;
  789. Result.Value:=aValue;
  790. fMacros.Add(Result);
  791. end;
  792. function TPas2jsMacroEngine.AddFunction(const aName, aDescription: string;
  793. const OnSubstitute: TOnSubstituteMacro; CanHaveParams: boolean): TPas2jsMacro;
  794. begin
  795. if not IsValidIdent(aName) then
  796. raise EPas2jsMacro.Create('invalid macro name "'+aName+'"');
  797. if IndexOf(aName)>=0 then
  798. raise EPas2jsMacro.Create('duplicate macro name "'+aName+'"');
  799. Result:=TPas2jsMacro.Create;
  800. Result.Name:=aName;
  801. Result.Description:=aDescription;
  802. Result.CanHaveParams:=CanHaveParams;
  803. Result.OnSubstitute:=OnSubstitute;
  804. fMacros.Add(Result);
  805. end;
  806. function TPas2jsMacroEngine.IndexOf(const aName: string): integer;
  807. var
  808. i: Integer;
  809. begin
  810. for i:=0 to Count-1 do
  811. if CompareText(Macros[i].Name,aName)=0 then
  812. exit(i);
  813. Result:=-1;
  814. end;
  815. procedure TPas2jsMacroEngine.Delete(Index: integer);
  816. begin
  817. fMacros.Delete(Index);
  818. end;
  819. function TPas2jsMacroEngine.FindMacro(const aName: string): TPas2jsMacro;
  820. var
  821. i: Integer;
  822. begin
  823. i:=IndexOf(aName);
  824. if i>=0 then
  825. Result:=Macros[i]
  826. else
  827. Result:=nil;
  828. end;
  829. procedure TPas2jsMacroEngine.Substitute(var s: string; Sender: TObject;
  830. Lvl: integer);
  831. // Rules:
  832. // $macro or $macro$
  833. // if Macro.OnSubstitute is set then optional brackets are allowed: $macro(params)
  834. var
  835. p, StartP, BracketLvl, ParamStartP: Integer;
  836. MacroName, NewValue: String;
  837. Macro: TPas2jsMacro;
  838. begin
  839. if Lvl>=MaxLevel then
  840. raise EPas2jsMacro.Create('macro cycle detected: "'+s+'"');
  841. p:=1;
  842. while p<length(s) do begin
  843. if (s[p]='$') and (s[p+1] in ['_','a'..'z','A'..'Z']) then
  844. begin
  845. StartP:=p;
  846. inc(p,2);
  847. while (p<=length(s)) and (s[p] in ['_','a'..'z','A'..'Z','0'..'9']) do
  848. inc(p);
  849. MacroName:=copy(s,StartP+1,p-StartP-1);
  850. Macro:=FindMacro(MacroName);
  851. if Macro=nil then
  852. raise EPas2jsMacro.Create('macro not found "'+MacroName+'" in "'+s+'"');
  853. NewValue:='';
  854. if Macro.CanHaveParams and (p<=length(s)) and (s[p]='(') then
  855. begin
  856. // read NewValue
  857. inc(p);
  858. ParamStartP:=p;
  859. BracketLvl:=1;
  860. repeat
  861. if p>length(s) then
  862. raise EPas2jsMacro.Create('missing closing bracket ) in "'+s+'"');
  863. case s[p] of
  864. '(': inc(BracketLvl);
  865. ')':
  866. if BracketLvl=1 then
  867. begin
  868. NewValue:=copy(s,ParamStartP,p-ParamStartP);
  869. break;
  870. end else begin
  871. dec(BracketLvl);
  872. end;
  873. end;
  874. until false;
  875. end else if (p<=length(s)) and (s[p]='$') then
  876. inc(p);
  877. if Assigned(Macro.OnSubstitute) then
  878. begin
  879. if not Macro.OnSubstitute(Sender,NewValue,Lvl+1) then
  880. raise EPas2jsMacro.Create('macro "'+MacroName+'" failed in "'+s+'"');
  881. end else
  882. NewValue:=Macro.Value;
  883. s:=LeftStr(s,StartP-1)+NewValue+copy(s,p,length(s));
  884. p:=StartP;
  885. end;
  886. inc(p);
  887. end;
  888. end;
  889. { TPas2jsCompilerFile }
  890. constructor TPas2jsCompilerFile.Create(aCompiler: TPas2jsCompiler;
  891. const aPasFilename, aPCUFilename: string);
  892. var
  893. ub: TUsedBySection;
  894. begin
  895. inherited Create(aCompiler);
  896. FPasFileName:=aPasFilename;
  897. FPCUFilename:=aPCUFilename;
  898. if FPasFileName<>'' then
  899. FUnitFilename:=FPasFileName
  900. else
  901. FUnitFilename:=FPCUFilename;
  902. FLog:=Compiler.Log;
  903. FPasResolver:=TPas2jsCompilerResolver.Create;
  904. FPasResolver.Owner:=Self;
  905. FPasResolver.OnFindModule:=@OnResolverFindModule;
  906. FPasResolver.OnCheckSrcName:=@OnResolverCheckSrcName;
  907. FPasResolver.OnLog:=@OnPasResolverLog;
  908. FPasResolver.Log:=Log;
  909. FPasResolver.Hub:=aCompiler.ResolverHub;
  910. FPasResolver.AddObjFPCBuiltInIdentifiers(btAllJSBaseTypes,bfAllJSBaseProcs);
  911. FIsMainFile:=Compiler.FS.SameFileName(Compiler.MainSrcFile,PasFilename);
  912. for ub in TUsedBySection do
  913. FUsedBy[ub]:=TFPList.Create;
  914. FUseAnalyzer:=TPas2JSAnalyzer.Create;
  915. FUseAnalyzer.OnMessage:=@OnUseAnalyzerMessage;
  916. FUseAnalyzer.Resolver:=FPasResolver;
  917. FPCUSupport:=CreatePCUSupport;
  918. end;
  919. destructor TPas2jsCompilerFile.Destroy;
  920. var
  921. ub: TUsedBySection;
  922. begin
  923. FreeAndNil(FPCUSupport);
  924. FreeAndNil(FUseAnalyzer);
  925. for ub in TUsedBySection do
  926. FreeAndNil(FUsedBy[ub]);
  927. FreeAndNil(FJSModule);
  928. FreeAndNil(FConverter);
  929. FreeAndNil(FParser);
  930. FreeAndNil(FScanner);
  931. FreeAndNil(FFileResolver);
  932. FreeAndNil(FPasResolver);
  933. if FPasModule<>nil then
  934. FPasModule.ReleaseUsedUnits;
  935. ReleaseAndNil(TPasElement(FPasModule){$IFDEF CheckPasTreeRefCount},'CreateElement'{$ENDIF});
  936. inherited Destroy;
  937. end;
  938. function TPas2jsCompilerFile.CreatePCUSupport: TPCUSupport;
  939. begin
  940. Result:=Nil;
  941. end;
  942. function TPas2jsCompilerFile.GetInitialModeSwitches: TModeSwitches;
  943. begin
  944. Result:=Compiler.ModeSwitches;
  945. end;
  946. function TPas2jsCompilerFile.GetInitialBoolSwitches: TBoolSwitches;
  947. var
  948. bs: TBoolSwitches;
  949. begin
  950. bs:=[bsLongStrings,bsWriteableConst];
  951. if coShowHints in Compiler.Options then
  952. Include(bs,bsHints);
  953. if coShowNotes in Compiler.Options then
  954. Include(bs,bsNotes);
  955. if coShowWarnings in Compiler.Options then
  956. Include(bs,bsWarnings);
  957. if coOverflowChecks in Compiler.Options then
  958. Include(bs,bsOverflowChecks);
  959. if coRangeChecks in Compiler.Options then
  960. Include(bs,bsRangeChecks);
  961. if coObjectChecks in Compiler.Options then
  962. Include(bs,bsObjectChecks);
  963. if coAssertions in Compiler.Options then
  964. Include(bs,bsAssertions);
  965. if coAllowMacros in Compiler.Options then
  966. Include(bs,bsMacro);
  967. if not (coWriteableConst in Compiler.Options) then
  968. Exclude(bs,bsWriteableConst);
  969. Result:=bs;
  970. end;
  971. function TPas2jsCompilerFile.
  972. GetInitialConverterOptions: TPasToJsConverterOptions;
  973. begin
  974. Result:=DefaultPasToJSOptions;
  975. if coUseStrict in Compiler.Options then
  976. Include(Result,fppas2js.coUseStrict)
  977. else
  978. Exclude(Result,fppas2js.coUseStrict);
  979. if coEnumValuesAsNumbers in Compiler.Options then
  980. Include(Result,fppas2js.coEnumNumbers);
  981. if (coShortRefGlobals in Compiler.Options) or IsUnitReadFromPCU then
  982. Include(Result,fppas2js.coShortRefGlobals);
  983. if coObfuscateLocalIdentifiers in Compiler.Options then
  984. Include(Result,fppas2js.coObfuscateLocalIdentifiers);
  985. if coLowerCase in Compiler.Options then
  986. Include(Result,fppas2js.coLowerCase)
  987. else
  988. Exclude(Result,fppas2js.coLowerCase);
  989. case Compiler.RTLVersionCheck of
  990. rvcNone: ;
  991. rvcMain: Include(Result,fppas2js.coRTLVersionCheckMain);
  992. rvcSystem: Include(Result,fppas2js.coRTLVersionCheckSystem);
  993. rvcUnit: Include(Result,fppas2js.coRTLVersionCheckUnit);
  994. end;
  995. end;
  996. procedure TPas2jsCompilerFile.CreateScannerAndParser(aFileResolver: TPas2jsFSResolver);
  997. var
  998. aUnitName: String;
  999. i: Integer;
  1000. M: TMacroDef;
  1001. begin
  1002. FFileResolver:=aFileResolver;
  1003. // scanner
  1004. if FScanner<>nil then
  1005. RaiseInternalError(20180707193258,UnitFilename);
  1006. FScanner := TPas2jsPasScanner.Create(FileResolver);
  1007. Scanner.LogEvents:=PascalResolver.ScannerLogEvents;
  1008. Scanner.OnLog:=@OnScannerLog;
  1009. Scanner.OnFormatPath:[email protected];
  1010. Scanner.RegisterResourceHandler('*',@HandleResources);
  1011. // create parser (Note: this sets some scanner options to defaults)
  1012. FParser := TPas2jsPasParser.Create(Scanner, FileResolver, PascalResolver);
  1013. // set options
  1014. Scanner.Options:=Scanner.Options+[po_StopOnErrorDirective];
  1015. Scanner.AllowedModeSwitches:=msAllPas2jsModeSwitches;
  1016. Scanner.ReadOnlyModeSwitches:=msAllPas2jsModeSwitchesReadOnly;
  1017. Scanner.CurrentModeSwitches:=GetInitialModeSwitches;
  1018. Scanner.AllowedBoolSwitches:=bsAllPas2jsBoolSwitches;
  1019. Scanner.ReadOnlyBoolSwitches:=bsAllPas2jsBoolSwitchesReadOnly;
  1020. Scanner.CurrentBoolSwitches:=GetInitialBoolSwitches;
  1021. Scanner.AllowedValueSwitches:=vsAllPas2jsValueSwitches;
  1022. Scanner.ReadOnlyValueSwitches:=vsAllPas2jsValueSwitchesReadOnly;
  1023. Scanner.CurrentValueSwitch[vsInterfaces]:=InterfaceTypeNames[Compiler.InterfaceType];
  1024. if coAllowCAssignments in Compiler.Options then
  1025. Scanner.Options:=Scanner.Options+[po_cassignments];
  1026. if Compiler.ResourceMode=rmNone then
  1027. Scanner.Options:= Scanner.Options+[po_DisableResources];
  1028. // Note: some Scanner.Options are set by TPasResolver
  1029. for i:=0 to Compiler.Defines.Count-1 do
  1030. begin
  1031. M:=TMacroDef(Compiler.Defines.Objects[i]);
  1032. if M=nil then
  1033. Scanner.AddDefine(Compiler.Defines[i])
  1034. else
  1035. Scanner.AddMacro(M.Name,M.Value);
  1036. end;
  1037. Scanner.CompilerVersion:=Compiler.GetVersion(true);
  1038. Scanner.TargetPlatform:=Compiler.TargetPlatform;
  1039. Scanner.TargetProcessor:=Compiler.TargetProcessor;
  1040. Scanner.Resolver:=PascalResolver;
  1041. // parser
  1042. Parser.LogEvents:=PascalResolver.ParserLogEvents;
  1043. Parser.OnLog:=@OnParserLog;
  1044. Parser.Log:=Log;
  1045. PascalResolver.P2JParser:=Parser;
  1046. if not IsMainFile then
  1047. begin
  1048. aUnitName:=ExtractFilenameOnly(UnitFilename);
  1049. if CompareText(aUnitName,'system')=0 then
  1050. Parser.ImplicitUses.Clear;
  1051. end;
  1052. end;
  1053. procedure TPas2jsCompilerFile.CreateConverter;
  1054. begin
  1055. if FConverter<>nil then exit;
  1056. FConverter:=TPasToJSConverter.Create;
  1057. FConverter.Globals:=Compiler.ConverterGlobals;
  1058. FConverter.Options:=GetInitialConverterOptions;
  1059. end;
  1060. procedure TPas2jsCompilerFile.OnResolverCheckSrcName(const Element: TPasElement);
  1061. var
  1062. SrcName, ExpectedSrcName: String;
  1063. begin
  1064. //writeln('TPas2jsCompilerFile.OnPasTreeCheckSrcName ',UnitFilename,' Name=',Element.Name,' IsMainFile=',IsMainFile);
  1065. if (Element.ClassType=TPasUnitModule) or (Element.ClassType=TPasModule) then
  1066. begin
  1067. SrcName:=Element.Name;
  1068. if IsMainFile then
  1069. begin
  1070. // main source is an unit
  1071. if PasUnitName='' then
  1072. begin
  1073. {$IFDEF VerboseSetPasUnitName}
  1074. writeln('TPas2jsCompilerFile.OnPasTreeCheckSrcName ',UnitFilename,' Name=',Element.Name,' IsMainFile=',IsMainFile);
  1075. {$ENDIF}
  1076. PasUnitName:=SrcName;
  1077. Compiler.AddUsedUnit(Self);
  1078. end;
  1079. end else begin
  1080. // an unit name must fit its filename
  1081. ExpectedSrcName:=ExtractFilenameOnly(UnitFilename);
  1082. if CompareText(SrcName,ExpectedSrcName)=0 then
  1083. exit; // ok
  1084. Parser.RaiseParserError(nExpectedButFound,[ExpectedSrcName,SrcName]);
  1085. end;
  1086. end;
  1087. end;
  1088. function TPas2jsCompilerFile.GetUsedBy(Section: TUsedBySection; Index: integer
  1089. ): TPas2jsCompilerFile;
  1090. begin
  1091. Result:=TPas2jsCompilerFile(FUsedBy[Section][Index]);
  1092. end;
  1093. function TPas2jsCompilerFile.GetUsedByCount(Section: TUsedBySection): integer;
  1094. begin
  1095. Result:=FUsedBy[Section].Count;
  1096. end;
  1097. procedure TPas2jsCompilerFile.HandleResources(Sender: TObject; const aFileName: String; aOptions: TStrings);
  1098. begin
  1099. // maybe emit message ?
  1100. FResourceHandler.StartUnit(PasModule.Name);
  1101. FResourceHandler.HandleResource(aFileName,aOptions);
  1102. if Sender=nil then ;
  1103. end;
  1104. function TPas2jsCompilerFile.OnConverterIsElementUsed(Sender: TObject;
  1105. El: TPasElement): boolean;
  1106. begin
  1107. if (Compiler.WPOAnalyzer<>nil)
  1108. and not (coKeepNotUsedDeclarationsWPO in Compiler.Options) then
  1109. Result:=Compiler.WPOAnalyzer.IsUsed(El)
  1110. else if not (coKeepNotUsedPrivates in Compiler.Options) then
  1111. Result:=UseAnalyzer.IsUsed(El)
  1112. else
  1113. Result:=true;
  1114. if Sender=nil then ;
  1115. end;
  1116. function TPas2jsCompilerFile.OnConverterIsTypeInfoUsed(Sender: TObject;
  1117. El: TPasElement): boolean;
  1118. begin
  1119. if (Compiler.WPOAnalyzer<>nil)
  1120. and not (coKeepNotUsedDeclarationsWPO in Compiler.Options) then
  1121. Result:=Compiler.WPOAnalyzer.IsTypeInfoUsed(El)
  1122. else if not (coKeepNotUsedPrivates in Compiler.Options) then
  1123. Result:=UseAnalyzer.IsTypeInfoUsed(El)
  1124. else
  1125. Result:=true;
  1126. if Sender=nil then ;
  1127. end;
  1128. procedure TPas2jsCompilerFile.OnPasResolverLog(Sender: TObject; const Msg: String);
  1129. var
  1130. aResolver: TPasResolver;
  1131. begin
  1132. if Msg='' then ; // ignore standard formatted message
  1133. aResolver:=TPasResolver(Sender);
  1134. DoLogMsgAtEl(aResolver.LastMsgType,aResolver.LastMsg,aResolver.LastMsgNumber,
  1135. aResolver.LastElement);
  1136. if Sender=nil then ;
  1137. end;
  1138. procedure TPas2jsCompilerFile.OnParserLog(Sender: TObject; const Msg: String);
  1139. var
  1140. aParser: TPasParser;
  1141. aScanner: TPascalScanner;
  1142. begin
  1143. if Msg='' then ; // ignore standard formatted message
  1144. aParser:=TPasParser(Sender);
  1145. aScanner:=aParser.Scanner;
  1146. Log.Log(aParser.LastMsgType,aParser.LastMsg,aParser.LastMsgNumber,
  1147. aScanner.CurFilename,aScanner.CurRow,aScanner.CurColumn);
  1148. if Sender=nil then ;
  1149. end;
  1150. procedure TPas2jsCompilerFile.OnScannerLog(Sender: TObject; const Msg: String);
  1151. var
  1152. aScanner: TPas2jsPasScanner;
  1153. begin
  1154. if Msg='' then ; // ignore standard formatted message
  1155. aScanner:=TPas2jsPasScanner(Sender);
  1156. Log.Log(aScanner.LastMsgType,aScanner.LastMsg,aScanner.LastMsgNumber,
  1157. aScanner.CurFilename,aScanner.CurRow,aScanner.CurColumn);
  1158. if Sender=nil then ;
  1159. end;
  1160. procedure TPas2jsCompilerFile.OnUseAnalyzerMessage(Sender: TObject;
  1161. Msg: TPAMessage);
  1162. begin
  1163. Log.Log(Msg.MsgType,Msg.MsgText,Msg.MsgNumber,Msg.Filename,Msg.Row,Msg.Col);
  1164. if Sender=nil then ;
  1165. end;
  1166. procedure TPas2jsCompilerFile.HandleEParserError(E: EParserError);
  1167. begin
  1168. Log.Log(Parser.LastMsgType,Parser.LastMsg,Parser.LastMsgNumber,
  1169. E.Filename,E.Row,E.Column);
  1170. Compiler.Terminate(ExitCodeSyntaxError);
  1171. end;
  1172. procedure TPas2jsCompilerFile.HandleEPasResolve(E: EPasResolve);
  1173. var
  1174. aFilename: String;
  1175. aRow, aColumn: integer;
  1176. begin
  1177. if E.PasElement<>nil then
  1178. begin
  1179. aFilename:=E.PasElement.SourceFilename;
  1180. PascalResolver.UnmangleSourceLineNumber(E.PasElement.SourceLinenumber,aRow,aColumn);
  1181. end else begin
  1182. aFilename:=Scanner.CurFilename;
  1183. aRow:=Scanner.CurRow;
  1184. aColumn:=Scanner.CurColumn;
  1185. end;
  1186. Log.Log(E.MsgType,E.Message,E.MsgNumber,aFilename,aRow,aColumn);
  1187. Compiler.Terminate(ExitCodeSyntaxError);
  1188. end;
  1189. procedure TPas2jsCompilerFile.HandleEPas2JS(E: EPas2JS);
  1190. var
  1191. aFilename: String;
  1192. aRow, aColumn: integer;
  1193. begin
  1194. if E.PasElement<>nil then
  1195. begin
  1196. aFilename:=E.PasElement.SourceFilename;
  1197. PascalResolver.UnmangleSourceLineNumber(E.PasElement.SourceLinenumber,aRow,aColumn);
  1198. Log.Log(E.MsgType,E.Message,E.MsgNumber,aFilename,aRow,aColumn);
  1199. end else begin
  1200. Log.Log(E.MsgType,E.Message,E.MsgNumber);
  1201. end;
  1202. Compiler.Terminate(ExitCodeConverterError);
  1203. end;
  1204. procedure TPas2jsCompilerFile.HandleUnknownException(E: Exception);
  1205. begin
  1206. if not (E is ECompilerTerminate) then
  1207. Log.Log(mtFatal,'bug: uncaught '+E.ClassName+': '+E.Message,0); // must use on E:ECompilerTerminate do raise;
  1208. Log.Log(mtFatal,E.ClassName+': '+E.Message,0);
  1209. Compiler.Terminate(ExitCodeErrorInternal);
  1210. // Note: a "raise E" is not allowed by caught exceptions, try..except will free it
  1211. end;
  1212. procedure TPas2jsCompilerFile.HandleException(E: Exception);
  1213. begin
  1214. {$IFDEF ReallyVerbose}
  1215. writeln('TPas2jsCompilerFile.HandleException ',E.ClassName,' ',E.Message);
  1216. {$ENDIF}
  1217. if ShowDebug then
  1218. Log.LogExceptionBackTrace(E);
  1219. if E is EScannerError then
  1220. begin
  1221. Log.Log(Scanner.LastMsgType,Scanner.LastMsg,Scanner.LastMsgNumber,
  1222. Scanner.CurFilename,Scanner.CurRow,Scanner.CurColumn);
  1223. Compiler.Terminate(ExitCodeSyntaxError);
  1224. end else if E is EParserError then
  1225. HandleEParserError(EParserError(E))
  1226. else if E is EPasResolve then
  1227. HandleEPasResolve(EPasResolve(E))
  1228. else if E is EPas2JS then
  1229. HandleEPas2JS(EPas2JS(E))
  1230. else if E is EFileNotFoundError then
  1231. begin
  1232. if (E.Message<>'') or (Log.LastMsgType<>mtFatal) then
  1233. Log.Log(mtFatal,E.Message);
  1234. Compiler.Terminate(ExitCodeFileNotFound);
  1235. end
  1236. else if E is EPas2jsFS then
  1237. begin
  1238. Log.Log(mtFatal,E.Message);
  1239. Compiler.Terminate(ExitCodeFileNotFound);
  1240. end
  1241. else if Assigned(PCUSupport) and PCUSupport.HandleException(E) then
  1242. else
  1243. HandleUnknownException(E);
  1244. end;
  1245. {$IFDEF Pas2js}
  1246. procedure TPas2jsCompilerFile.HandleJSException(Msg: string; E: jsvalue);
  1247. begin
  1248. Compiler.HandleJSException(Msg,E,true);
  1249. end;
  1250. {$ENDIF}
  1251. procedure TPas2jsCompilerFile.DoLogMsgAtEl(MsgType: TMessageType;
  1252. const Msg: string; MsgNumber: integer; El: TPasElement);
  1253. var
  1254. Line, Col: integer;
  1255. Filename: String;
  1256. begin
  1257. if (El<>nil) then
  1258. begin
  1259. Filename:=El.SourceFilename;
  1260. TPasResolver.UnmangleSourceLineNumber(El.SourceLinenumber,Line,Col);
  1261. end else begin
  1262. Filename:='';
  1263. Line:=0;
  1264. Col:=0;
  1265. end;
  1266. Log.Log(MsgType,Msg,MsgNumber,Filename,Line,Col);
  1267. end;
  1268. procedure TPas2jsCompilerFile.RaiseInternalError(id: TMaxPrecInt; Msg: string);
  1269. begin
  1270. Compiler.RaiseInternalError(id,Msg);
  1271. end;
  1272. function TPas2jsCompilerFile.IsUnitReadFromPCU: Boolean;
  1273. begin
  1274. Result:=Assigned(PCUSupport) and PCUSupport.HasReader;
  1275. end;
  1276. procedure TPas2jsCompilerFile.ReaderFinished;
  1277. begin
  1278. FReaderState:=prsFinished;
  1279. try
  1280. Compiler.RemoveReadingModule(Self);
  1281. if coWriteDebugLog in Compiler.Options then
  1282. begin
  1283. Log.DebugLogWriteLn('Pas-Module:');
  1284. Log.DebugLogWriteLn(PasModule.GetDeclaration(true));
  1285. end;
  1286. if Assigned(PCUSupport) and not PCUSupport.HasReader then
  1287. UseAnalyzer.Options:=UseAnalyzer.Options+[paoImplReferences];
  1288. {$IFDEF VerboseUnitQueue}
  1289. writeln('TPas2jsCompilerFile.ReaderFinished analyzing ',UnitFilename,' ...');
  1290. {$ENDIF}
  1291. UseAnalyzer.AnalyzeModule(FPasModule);
  1292. {$IFDEF ReallyVerbose}
  1293. writeln('TPas2jsCompilerFile.ReaderFinished analyzed ',UnitFilename,' ScopeModule=',GetObjName(UseAnalyzer.ScopeModule));
  1294. {$ENDIF}
  1295. if Assigned(PCUSupport) and Not PCUSupport.HasReader
  1296. and (coPrecompile in Compiler.Options) then
  1297. PCUSupport.WritePCU;
  1298. except
  1299. on E: ECompilerTerminate do
  1300. raise;
  1301. on E: Exception do
  1302. HandleException(E);
  1303. {$IFDEF pas2js}
  1304. else
  1305. HandleJSException('[20181031190529] TPas2jsCompilerFile.ReaderFinished File="'+UnitFilename+'"',
  1306. JSExceptValue);
  1307. {$ENDIF}
  1308. end;
  1309. end;
  1310. procedure TPas2jsCompilerFile.OpenFile(aFilename: string);
  1311. begin
  1312. FPasFilename:=aFilename;
  1313. try
  1314. Scanner.OpenFile(PasFilename);
  1315. except
  1316. on E: ECompilerTerminate do
  1317. raise;
  1318. on E: Exception do
  1319. HandleException(E);
  1320. {$IFDEF pas2js}
  1321. else HandleJSException('[20181031190536] TPas2jsCompilerFile.OpenFile "'+aFilename+'"',JSExceptValue);
  1322. {$ENDIF}
  1323. end;
  1324. end;
  1325. procedure TPas2jsCompilerFile.ReadUnit;
  1326. begin
  1327. if ShowDebug then
  1328. Log.LogMsg(nParsingFile,[QuoteStr(UnitFilename)]);
  1329. if FPasModule<>nil then
  1330. Compiler.RaiseInternalError(20180305190321,UnitFilename);
  1331. FReaderState:=prsReading;
  1332. try
  1333. {$IFDEF VerboseUnitQueue}
  1334. writeln('TPas2jsCompilerFile.ReadUnit ',UnitFilename,' START');
  1335. {$ENDIF}
  1336. Compiler.AddReadingModule(Self);
  1337. PascalResolver.InterfaceOnly:=IsForeign;
  1338. if IsUnitReadFromPCU then
  1339. PCUSupport.ReadUnit
  1340. else
  1341. begin
  1342. if IsMainFile then
  1343. Parser.ParseMain(FPasModule)
  1344. else
  1345. Parser.ParseSubModule(FPasModule);
  1346. if Parser.CurModule=nil then
  1347. ReaderFinished
  1348. else
  1349. FReaderState:=prsWaitingForUsedUnits;
  1350. end;
  1351. {$IFDEF VerboseUnitQueue}
  1352. writeln('TPas2jsCompilerFile.ReadUnit ',UnitFilename,' ReaderState=',ReaderState);
  1353. {$ENDIF}
  1354. except
  1355. on E: ECompilerTerminate do
  1356. raise;
  1357. on E: Exception do
  1358. HandleException(E);
  1359. {$IFDEF pas2js}
  1360. else
  1361. HandleJSException('[20181031190541] TPas2jsCompilerFile.ReadUnit File="'+UnitFilename+'"',
  1362. JSExceptValue);
  1363. {$ENDIF}
  1364. end;
  1365. if FReaderState=prsReading then
  1366. FReaderState:=prsError;
  1367. if (PasModule<>nil) and (PasModule.CustomData=nil) then
  1368. PasModule.CustomData:=Self;
  1369. end;
  1370. function TPas2jsCompilerFile.ReadContinue: boolean;
  1371. begin
  1372. Result:=true;
  1373. if ShowDebug then
  1374. Log.LogPlain(['Debug: Continue reading unit "',UnitFilename,'"...']);
  1375. if FPasModule=nil then
  1376. Compiler.RaiseInternalError(20180305190338,UnitFilename);
  1377. FReaderState:=prsReading;
  1378. try
  1379. {$IFDEF VerboseUnitQueue}
  1380. writeln('TPas2jsCompilerFile.ReadContinue ',UnitFilename);
  1381. {$ENDIF}
  1382. if Assigned(PCUSupport) and PCUSupport.HasReader then
  1383. Result:=PCUSupport.ReadContinue
  1384. else
  1385. begin
  1386. Parser.ParseContinue;
  1387. Result:=Parser.CurModule=nil;
  1388. end;
  1389. {$IFDEF VerboseUnitQueue}
  1390. writeln('TPas2jsCompilerFile.ReadContinue ',UnitFilename,' finished=',Result);
  1391. {$ENDIF}
  1392. if Result then
  1393. ReaderFinished
  1394. else
  1395. FReaderState:=prsWaitingForUsedUnits;
  1396. except
  1397. on E: ECompilerTerminate do
  1398. raise;
  1399. on E: Exception do
  1400. HandleException(E);
  1401. {$IFDEF pas2js}
  1402. else
  1403. HandleJSException('[20181031190545] TPas2jsCompilerFile.ReadContinue File="'+UnitFilename+'"',
  1404. JSExceptValue);
  1405. {$ENDIF}
  1406. end;
  1407. if FReaderState=prsReading then
  1408. FReaderState:=prsError;
  1409. end;
  1410. function TPas2jsCompilerFile.ReaderState: TPas2jsReaderState;
  1411. var
  1412. Section: TPasSection;
  1413. begin
  1414. Result:=FReaderState;
  1415. if Result=prsWaitingForUsedUnits then
  1416. begin
  1417. if Assigned(PCUSupport) and PCUSupport.HasReader then
  1418. begin
  1419. If PCUSupport.ReadCanContinue then
  1420. Result:=prsCanContinue;
  1421. end
  1422. else
  1423. begin
  1424. if Parser.CanParseContinue(Section) then
  1425. Result:=prsCanContinue;
  1426. end;
  1427. end;
  1428. end;
  1429. procedure TPas2jsCompilerFile.CreateJS;
  1430. begin
  1431. //writeln('TPas2jsCompilerFile.CreateJS START ',UnitFilename,' JS=',GetObjName(FJSModule));
  1432. try
  1433. // convert
  1434. CreateConverter;
  1435. Converter.OnIsElementUsed:=@OnConverterIsElementUsed;
  1436. Converter.OnIsTypeInfoUsed:=@OnConverterIsTypeInfoUsed;
  1437. FJSModule:=Converter.ConvertPasElement(PasModule,PascalResolver);
  1438. if FResourceHandler.Outputmode=romJS then
  1439. FJSModule:=FResourceHandler.WriteJS(PasUnitName,FJSModule);
  1440. except
  1441. on E: ECompilerTerminate do
  1442. raise;
  1443. on E: Exception do
  1444. HandleException(E);
  1445. {$IFDEF pas2js}
  1446. else
  1447. HandleJSException('[20181031190549] TPas2jsCompilerFile.CreateJS File="'+UnitFilename+'"',
  1448. JSExceptValue);
  1449. {$ENDIF}
  1450. end;
  1451. //writeln('TPas2jsCompilerFile.CreateJS END ',UnitFilename,' JS=',GetObjName(FJSModule));
  1452. end;
  1453. procedure TPas2jsCompilerFile.EmitModuleHints;
  1454. begin
  1455. try
  1456. // show hints only for units with sources
  1457. if (PCUSupport=nil) or not PCUSupport.HasReader then
  1458. begin
  1459. //writeln('TPas2jsCompilerFile.EmitModuleHints ',UnitFilename);
  1460. UseAnalyzer.EmitModuleHints(PasModule);
  1461. end;
  1462. except
  1463. on E: ECompilerTerminate do
  1464. raise;
  1465. on E: Exception do
  1466. HandleException(E);
  1467. {$IFDEF pas2js}
  1468. else
  1469. HandleJSException('[20190226183324] TPas2jsCompilerFile.EmitModuleHints File="'+UnitFilename+'"',
  1470. JSExceptValue);
  1471. {$ENDIF}
  1472. end;
  1473. end;
  1474. function TPas2jsCompilerFile.GetPasFirstSection: TPasSection;
  1475. var
  1476. aModule: TPasModule;
  1477. begin
  1478. aModule:=GetCurPasModule;
  1479. if aModule=nil then exit;
  1480. if aModule.ClassType=TPasProgram then
  1481. Result:=TPasProgram(aModule).ProgramSection
  1482. else if aModule.ClassType=TPasLibrary then
  1483. Result:=TPasLibrary(aModule).LibrarySection
  1484. else
  1485. Result:=aModule.InterfaceSection;
  1486. end;
  1487. function TPas2jsCompilerFile.GetPasImplSection: TPasSection;
  1488. var
  1489. aModule: TPasModule;
  1490. begin
  1491. Result:=nil;
  1492. aModule:=GetCurPasModule;
  1493. if aModule=nil then exit;
  1494. Result:=aModule.ImplementationSection;
  1495. end;
  1496. function TPas2jsCompilerFile.GetPasMainUsesClause: TPasUsesClause;
  1497. var
  1498. aModule: TPasModule;
  1499. IntfSection: TInterfaceSection;
  1500. PrgSection: TProgramSection;
  1501. LibSection: TLibrarySection;
  1502. begin
  1503. Result:=nil;
  1504. aModule:=GetCurPasModule;
  1505. if aModule=nil then exit;
  1506. if aModule.ClassType=TPasModule then
  1507. begin
  1508. IntfSection:=TPasModule(aModule).InterfaceSection;
  1509. if IntfSection<>nil then
  1510. Result:=IntfSection.UsesClause;
  1511. end else if aModule.ClassType=TPasProgram then
  1512. begin
  1513. PrgSection:=TPasProgram(aModule).ProgramSection;
  1514. if PrgSection<>nil then
  1515. Result:=PrgSection.UsesClause;
  1516. end else if aModule.ClassType=TPasLibrary then
  1517. begin
  1518. LibSection:=TPasLibrary(aModule).LibrarySection;
  1519. if LibSection<>nil then
  1520. Result:=LibSection.UsesClause;
  1521. end;
  1522. end;
  1523. function TPas2jsCompilerFile.GetPasImplUsesClause: TPasUsesClause;
  1524. var
  1525. aModule: TPasModule;
  1526. begin
  1527. Result:=nil;
  1528. aModule:=GetCurPasModule;
  1529. if aModule=nil then exit;
  1530. if aModule.ImplementationSection<>nil then
  1531. Result:=aModule.ImplementationSection.UsesClause;
  1532. end;
  1533. function TPas2jsCompilerFile.GetCurPasModule: TPasModule;
  1534. begin
  1535. if PasModule<>nil then
  1536. Result:=PasModule
  1537. else if (PascalResolver<>nil) and (PascalResolver.RootElement<>nil) then
  1538. Result:=PascalResolver.RootElement
  1539. else if Parser<>nil then
  1540. Result:=Parser.CurModule
  1541. else
  1542. Result:=nil;
  1543. end;
  1544. function TPas2jsCompilerFile.GetModuleName: string;
  1545. var
  1546. aModule: TPasModule;
  1547. begin
  1548. aModule:=GetCurPasModule;
  1549. if aModule<>nil then
  1550. Result:=aModule.Name
  1551. else
  1552. Result:='';
  1553. if Result='' then
  1554. Result:=ExtractFilenameOnly(UnitFilename);
  1555. end;
  1556. class function TPas2jsCompilerFile.GetFile(aModule: TPasModule
  1557. ): TPas2jsCompilerFile;
  1558. var
  1559. Scope: TPasModuleScope;
  1560. Resolver: TPas2jsCompilerResolver;
  1561. begin
  1562. Result:=nil;
  1563. if (aModule=nil) or (aModule.CustomData=nil) then exit;
  1564. if aModule.CustomData is TPas2jsCompilerFile then
  1565. Result:=TPas2jsCompilerFile(aModule.CustomData)
  1566. else if aModule.CustomData is TPasModuleScope then
  1567. begin
  1568. Scope:=TPasModuleScope(aModule.CustomData);
  1569. Resolver:=NoNil(Scope.Owner) as TPas2jsCompilerResolver;
  1570. Result:=Resolver.Owner as TPas2jsCompilerFile;
  1571. end;
  1572. end;
  1573. function TPas2jsCompilerFile.OnResolverFindModule(const UseUnitName,
  1574. InFilename: String; NameExpr, InFileExpr: TPasExpr): TPasModule;
  1575. var
  1576. aFile: TPas2jsCompilerFile;
  1577. UnitInfo: TFindUnitInfo;
  1578. LoadInfo: TLoadUnitInfo;
  1579. ModuleDir: String;
  1580. begin
  1581. Result:=nil;
  1582. aFile:=Nil;
  1583. // check duplicate identifier or unit cycle
  1584. if CompareText(ExtractFilenameOnly(UnitFilename),UseUnitname)=0 then
  1585. Parser.RaiseParserError(nUnitCycle,[UseUnitname]);
  1586. ModuleDir:=ExtractFilePath(PasFileName);
  1587. UnitInfo:=Compiler.GetUnitInfo(UseUnitName,InFileName,ModuleDir,PCUSupport);
  1588. if UnitInfo.FileName<>'' then
  1589. begin
  1590. LoadInfo.UseFilename:=UnitInfo.FileName;
  1591. LoadInfo.UseUnitname:=UnitInfo.UnitName;
  1592. LoadInfo.NameExpr:=NameExpr;
  1593. LoadInfo.IsPCU:=UnitInfo.isPCU;
  1594. if UnitInfo.isPCU then
  1595. begin
  1596. LoadInfo.InFilename:='';
  1597. LoadInfo.InFileExpr:=Nil;
  1598. LoadInfo.UseIsForeign:=False;
  1599. end
  1600. else
  1601. begin
  1602. LoadInfo.InFilename:=InFileName;
  1603. LoadInfo.InFileExpr:=InFileExpr;
  1604. LoadInfo.UseIsForeign:=UnitInfo.isForeign;
  1605. end;
  1606. aFile:=Compiler.LoadUsedUnit(LoadInfo,Self);
  1607. end;
  1608. if aFile<>nil then
  1609. Result:=aFile.PasModule;
  1610. // if Result=nil resolver will give a nice error position, so don't do it here
  1611. end;
  1612. { TPas2JSConfigSupport }
  1613. procedure TPas2JSConfigSupport.CfgSyntaxError(const Msg: string);
  1614. begin
  1615. Compiler.Log.Log(mtError,Msg,0,CurrentCfgFilename,CurrentCfgLineNumber,0);
  1616. Compiler.Terminate(ExitCodeErrorInConfig);
  1617. end;
  1618. procedure TPas2JSConfigSupport.LoadConfig(Const aFileName: String);
  1619. type
  1620. TSkip = (
  1621. skipNone,
  1622. skipIf,
  1623. skipElse
  1624. );
  1625. const
  1626. IdentChars = ['a'..'z','A'..'Z','_','0'..'9'];
  1627. var
  1628. Line: String;
  1629. l, p, StartP: integer;
  1630. function GetWord: String;
  1631. begin
  1632. StartP:=p;
  1633. while (p<=l) and ((Line[p] in IdentChars) or (Line[p]>#127)) do inc(p);
  1634. Result:=copy(Line,StartP,p-StartP);
  1635. while (p<=l) and (Line[p] in [' ',#9]) do inc(p);
  1636. end;
  1637. procedure DebugCfgDirective(const s: string);
  1638. begin
  1639. Compiler.Log.LogMsg(nCfgDirective,[QuoteStr(Line),s],CurrentCfgFilename,CurrentCfgLineNumber,1,false);
  1640. end;
  1641. var
  1642. OldCfgFilename, Directive, aName, Expr: String;
  1643. aFile: TSourceLineReader;
  1644. IfLvl, SkipLvl, OldCfgLineNumber: Integer;
  1645. Skip: TSkip;
  1646. begin
  1647. if Compiler.ShowDebug or Compiler.ShowTriedUsedFiles then
  1648. Compiler.Log.LogMsgIgnoreFilter(nReadingOptionsFromFile,[QuoteStr(aFilename)]);
  1649. IfLvl:=0;
  1650. SkipLvl:=0;
  1651. Skip:=skipNone;
  1652. aFile:=nil;
  1653. try
  1654. OldCfgFilename:=FCurrentCfgFilename;
  1655. FCurrentCfgFilename:=aFilename;
  1656. OldCfgLineNumber:=FCurrentCfgLineNumber;
  1657. aFile:=GetReader(aFileName);
  1658. while not aFile.IsEOF do begin
  1659. Line:=aFile.ReadLine;
  1660. FCurrentCfgLineNumber:=aFile.LineNumber;
  1661. if Compiler.ShowDebug then
  1662. Compiler.Log.LogMsgIgnoreFilter(nInterpretingFileOption,[QuoteStr(Line)]);
  1663. if Line='' then continue;
  1664. l:=length(Line);
  1665. p:=1;
  1666. while (p<=l) and (Line[p] in [' ',#9]) do inc(p);
  1667. if p>l then continue; // empty line
  1668. if (p<=l) and (Line[p]='#') then
  1669. begin
  1670. // cfg directive
  1671. inc(p);
  1672. if (p>l) or (Line[p] in [#0,#9,' ','-']) then continue; // comment
  1673. Directive:=lowercase(GetWord);
  1674. case Directive of
  1675. 'ifdef','ifndef':
  1676. begin
  1677. inc(IfLvl);
  1678. if Skip=skipNone then
  1679. begin
  1680. aName:=GetWord;
  1681. if Compiler.IsDefined(aName)=(Directive='ifdef') then
  1682. begin
  1683. // execute block
  1684. if Compiler.ShowDebug then
  1685. DebugCfgDirective('true -> execute');
  1686. end else begin
  1687. // skip block
  1688. if Compiler.ShowDebug then
  1689. DebugCfgDirective('false -> skip');
  1690. SkipLvl:=IfLvl;
  1691. Skip:=skipIf;
  1692. end;
  1693. end;
  1694. end;
  1695. 'if':
  1696. begin
  1697. inc(IfLvl);
  1698. if Skip=skipNone then
  1699. begin
  1700. Expr:=copy(Line,p,length(Line));
  1701. if ConditionEvaluator.Eval(Expr) then
  1702. begin
  1703. // execute block
  1704. if Compiler.ShowDebug then
  1705. DebugCfgDirective('true -> execute');
  1706. end else begin
  1707. // skip block
  1708. if Compiler.ShowDebug then
  1709. DebugCfgDirective('false -> skip');
  1710. SkipLvl:=IfLvl;
  1711. Skip:=skipIf;
  1712. end;
  1713. end;
  1714. end;
  1715. 'else':
  1716. begin
  1717. if IfLvl=0 then
  1718. CfgSyntaxError('"'+Directive+'" without #ifdef');
  1719. if (Skip=skipElse) and (IfLvl=SkipLvl) then
  1720. CfgSyntaxError('"there was already an #else');
  1721. if (Skip=skipIf) and (IfLvl=SkipLvl) then
  1722. begin
  1723. // if-block was skipped -> execute else block
  1724. if Compiler.ShowDebug then
  1725. DebugCfgDirective('execute');
  1726. SkipLvl:=0;
  1727. Skip:=skipNone;
  1728. end else if Skip=skipNone then
  1729. begin
  1730. // if-block was executed -> skip else block
  1731. if Compiler.ShowDebug then
  1732. DebugCfgDirective('skip');
  1733. Skip:=skipElse;
  1734. SkipLvl:=IfLvl;
  1735. end;
  1736. end;
  1737. 'elseif':
  1738. begin
  1739. if IfLvl=0 then
  1740. CfgSyntaxError('"'+Directive+'" without #ifdef');
  1741. if (Skip=skipIf) and (IfLvl=SkipLvl) then
  1742. begin
  1743. // if-block was skipped -> try this elseif
  1744. Expr:=copy(Line,p,length(Line));
  1745. if ConditionEvaluator.Eval(Expr) then
  1746. begin
  1747. // execute elseif block
  1748. if Compiler.ShowDebug then
  1749. DebugCfgDirective('true -> execute');
  1750. SkipLvl:=0;
  1751. Skip:=skipNone;
  1752. end else begin
  1753. // skip elseif block
  1754. if Compiler.ShowDebug then
  1755. DebugCfgDirective('false -> skip');
  1756. end;
  1757. end else if Skip=skipNone then
  1758. begin
  1759. // if-block was executed -> skip without test
  1760. if Compiler.ShowDebug then
  1761. DebugCfgDirective('no test -> skip');
  1762. Skip:=skipIf;
  1763. end;
  1764. end;
  1765. 'endif':
  1766. begin
  1767. if IfLvl=0 then
  1768. CfgSyntaxError('"'+Directive+'" without #ifdef');
  1769. dec(IfLvl);
  1770. if IfLvl<SkipLvl then
  1771. begin
  1772. // end block
  1773. if Compiler.ShowDebug then
  1774. DebugCfgDirective('end block');
  1775. SkipLvl:=0;
  1776. Skip:=skipNone;
  1777. end;
  1778. end;
  1779. 'error':
  1780. Compiler.ParamFatal('user defined: '+copy(Line,p,length(Line)))
  1781. else
  1782. if Skip=skipNone then
  1783. CfgSyntaxError('unknown directive "#'+Directive+'"')
  1784. else
  1785. DebugCfgDirective('skipping unknown directive');
  1786. end;
  1787. end else if Skip=skipNone then
  1788. begin
  1789. // option line
  1790. Line:=copy(Line,p,length(Line));
  1791. Compiler.ReadParam(Line,false,false);
  1792. end;
  1793. end;
  1794. finally
  1795. FCurrentCfgFilename:=OldCfgFilename;
  1796. FCurrentCfgLineNumber:=OldCfgLineNumber;
  1797. aFile.Free;
  1798. end;
  1799. if Compiler.ShowDebug or Compiler.ShowTriedUsedFiles then
  1800. Compiler.Log.LogMsgIgnoreFilter(nEndOfReadingConfigFile,[QuoteStr(aFilename)]);
  1801. end;
  1802. procedure TPas2JSConfigSupport.LoadDefaultConfig;
  1803. var
  1804. aFileName: string;
  1805. begin
  1806. aFileName:=FindDefaultConfig;
  1807. if aFileName<>'' then
  1808. LoadConfig(aFilename);
  1809. end;
  1810. procedure TPas2JSConfigSupport.ConditionEvalLog(Sender: TCondDirectiveEvaluator;
  1811. Args: array of const);
  1812. begin
  1813. CfgSyntaxError(SafeFormat(Sender.MsgPattern,Args));
  1814. end;
  1815. function TPas2JSConfigSupport.ConditionEvalVariable(Sender: TCondDirectiveEvaluator;
  1816. aName: String; out Value: string): boolean;
  1817. var
  1818. i: Integer;
  1819. M: TMacroDef;
  1820. ms: TModeSwitch;
  1821. begin
  1822. // check defines
  1823. i:=Compiler.Defines.IndexOf(aName);
  1824. if i>=0 then
  1825. begin
  1826. M:=TMacroDef(Compiler.Defines.Objects[i]);
  1827. if M=nil then
  1828. Value:=CondDirectiveBool[true]
  1829. else
  1830. Value:=M.Value;
  1831. exit(true);
  1832. end;
  1833. // check modeswitches
  1834. ms:=StrToModeSwitch(aName);
  1835. if (ms<>msNone) and (ms in Compiler.ModeSwitches) then
  1836. begin
  1837. Value:=CondDirectiveBool[true];
  1838. exit(true);
  1839. end;
  1840. if Sender=nil then ;
  1841. Result:=false;
  1842. end;
  1843. { TPas2jsCompiler }
  1844. procedure TPas2jsCompiler.SetFS(AValue: TPas2jsFS);
  1845. begin
  1846. if FFS=AValue then Exit;
  1847. FOwnsFS:=false;
  1848. FFS:=AValue;
  1849. end;
  1850. function TPas2jsCompiler.GetFileCount: integer;
  1851. begin
  1852. Result:=FFiles.Count;
  1853. end;
  1854. function TPas2jsCompiler.GetDefaultNamespace: String;
  1855. var
  1856. C: TClass;
  1857. begin
  1858. Result:='';
  1859. if FMainFile=nil then exit;
  1860. if FMainFile.PasModule=nil then exit;
  1861. C:=FMainFile.PasModule.ClassType;
  1862. if (C=TPasProgram) or (C=TPasLibrary) or (C=TPasPackage) then
  1863. Result:=FMainFile.PascalResolver.DefaultNameSpace;
  1864. end;
  1865. procedure TPas2jsCompiler.Compile(StartTime: TDateTime);
  1866. var
  1867. Checked: TPasAnalyzerKeySet;
  1868. CombinedFileWriter: TPas2JSMapper;
  1869. SrcFileCount: integer;
  1870. Seconds: TDateTime;
  1871. ok: Boolean;
  1872. begin
  1873. if FMainFile<>nil then
  1874. RaiseInternalError(20170504192137,'');
  1875. Checked:=nil;
  1876. CombinedFileWriter:=nil;
  1877. SrcFileCount:=0;
  1878. CreateGUID(FPrecompileGUID);
  1879. ok:=false;
  1880. try
  1881. // load main Pascal file
  1882. LoadModuleFile(MainSrcFile,'',FMainFile,False);
  1883. if MainFile=nil then exit;
  1884. // parse and load Pascal files recursively
  1885. FMainFile.ReadUnit;
  1886. ProcessQueue;
  1887. // whole program optimization
  1888. if MainFile.PasModule is TPasProgram then
  1889. OptimizeProgram(MainFile);
  1890. // check what files need building
  1891. Checked:=CreateSetOfCompilerFiles(kcFilename);
  1892. MarkNeedBuilding(MainFile,Checked,SrcFileCount);
  1893. SrcFileCount:=Checked.Count;// all modules, including skipped modules
  1894. FreeAndNil(Checked);
  1895. // convert all Pascal to JavaScript
  1896. Checked:=CreateSetOfCompilerFiles(kcFilename);
  1897. CreateJavaScript(MainFile,Checked);
  1898. FreeAndNil(Checked);
  1899. // write .js files
  1900. Checked:=CreateSetOfCompilerFiles(kcFilename);
  1901. WriteJSFiles(MainFile,Nil,Checked);
  1902. FreeAndNil(Checked);
  1903. // write success message
  1904. if ExitCode=0 then
  1905. begin
  1906. Seconds:=(Now-StartTime)*86400;
  1907. Log.LogMsgIgnoreFilter(nLinesInFilesCompiled,
  1908. [IntToStr(FS.ReadLineCounter),IntToStr(SrcFileCount),
  1909. FormatFloat('0.0',Seconds),'s']);
  1910. ok:=true;
  1911. end;
  1912. finally
  1913. Checked.Free;
  1914. if not Ok then
  1915. Log.LogMsgIgnoreFilter(nCompilationAborted,[]);
  1916. CombinedFileWriter.Free;
  1917. end;
  1918. end;
  1919. procedure TPas2jsCompiler.ProcessQueue;
  1920. var
  1921. i: Integer;
  1922. aFile: TPas2jsCompilerFile;
  1923. Found: Boolean;
  1924. Section: TPasSection;
  1925. begin
  1926. // parse til exception or all modules have finished
  1927. repeat
  1928. {$IF defined(VerbosePasResolver) or defined(VerboseUnitQueue)}
  1929. writeln('TPas2jsCompiler.ProcessQueue FParsingModules.Count=',FReadingModules.Count);
  1930. {$ENDIF}
  1931. Found:=false;
  1932. for i:=FReadingModules.Count-1 downto 0 do
  1933. begin
  1934. aFile:=TPas2jsCompilerFile(FReadingModules[i]);
  1935. if aFile.ReaderState<>prsCanContinue then
  1936. begin
  1937. {$IF defined(VerbosePasResolver) or defined(VerboseUnitQueue)}
  1938. writeln('TPas2jsCompiler.ProcessQueue aFile=',aFile.UnitFilename,' NOT YET READY');
  1939. {$ENDIF}
  1940. if (not aFile.IsUnitReadFromPCU) and (aFile.Parser.CurModule=nil) then
  1941. RaiseInternalError(20180306111410,'File='+aFile.UnitFilename+' Parser.CurModule=nil');
  1942. continue;
  1943. end;
  1944. Found:=true;
  1945. {$IF defined(VerbosePasResolver) or defined(VerboseUnitQueue)}
  1946. writeln('TPas2jsCompiler.ProcessQueue aFile=',aFile.UnitFilename);
  1947. {$ENDIF}
  1948. aFile.ReadContinue;
  1949. if aFile.ReaderState=prsCanContinue then
  1950. begin
  1951. {$IF defined(VerbosePasResolver) or defined(VerboseUnitQueue)}
  1952. writeln('TPas2jsCompiler.ProcessQueue aFile=',aFile.UnitFilename,' ReadContinue buggy');
  1953. {$ENDIF}
  1954. RaiseInternalError(20180313130300,'File='+aFile.UnitFilename+' ReadContinue buggy');
  1955. end;
  1956. break;
  1957. end;
  1958. until not Found;
  1959. {$IF defined(VerbosePasResolver) or defined(VerboseUnitQueue)}
  1960. writeln('TPas2jsCompiler.ProcessQueue END FParsingModules.Count=',FReadingModules.Count);
  1961. {$ENDIF}
  1962. // check consistency
  1963. for i:=0 to FReadingModules.Count-1 do
  1964. begin
  1965. aFile:=TPas2jsCompilerFile(FReadingModules[i]);
  1966. if aFile.PascalResolver=nil then
  1967. RaiseInternalError(20180313124125,aFile.UnitFilename);
  1968. if (Not aFile.IsUnitReadFromPCU) and (aFile.Parser.CurModule<>nil) then
  1969. begin
  1970. {$IF defined(VerbosePasResolver) or defined(VerboseUnitQueue)}
  1971. writeln('TPas2jsCompiler.ProcessQueue aFile=',aFile.UnitFilename,' was not finished');
  1972. {$ENDIF}
  1973. RaiseInternalError(20180305185342,aFile.UnitFilename);
  1974. end;
  1975. Section:=aFile.PascalResolver.GetLastSection;
  1976. if Section=nil then
  1977. RaiseInternalError(20180313124207,aFile.UnitFilename);
  1978. if Section.PendingUsedIntf<>nil then
  1979. RaiseInternalError(20180313124226,aFile.UnitFilename+' '+GetObjName(Section)+' PendingUsedIntf='+GetObjName(Section.PendingUsedIntf));
  1980. end;
  1981. end;
  1982. function TPas2jsCompiler.MarkNeedBuilding(aFile: TPas2jsCompilerFile;
  1983. Checked: TPasAnalyzerKeySet; var SrcFileCount: integer): boolean;
  1984. procedure Mark(MsgNumber: integer;
  1985. Args: array of const);
  1986. begin
  1987. if aFile.NeedBuild then exit;
  1988. aFile.NeedBuild:=true;
  1989. inc(SrcFileCount);
  1990. if ShowDebug or ShowTriedUsedFiles then
  1991. Log.LogMsg(MsgNumber,Args,'',0,0,false);
  1992. end;
  1993. procedure CheckUsesClause(UsesClause: TPasUsesClause);
  1994. var
  1995. i: Integer;
  1996. UsedFile: TPas2jsCompilerFile;
  1997. aModule: TPasModule;
  1998. begin
  1999. if length(UsesClause)=0 then exit;
  2000. for i:=0 to length(UsesClause)-1 do begin
  2001. aModule:=UsesClause[i].Module as TPasModule;
  2002. UsedFile:=TPas2jsCompilerFile.GetFile(aModule);
  2003. if UsedFile=nil then
  2004. RaiseInternalError(20171214121631,aModule.Name);
  2005. if MarkNeedBuilding(UsedFile,Checked,SrcFileCount) then
  2006. begin
  2007. if not aFile.NeedBuild then
  2008. Mark(nUnitNeedsCompileDueToUsedUnit,
  2009. [aFile.GetModuleName,UsedFile.GetModuleName]);
  2010. end;
  2011. end;
  2012. end;
  2013. begin
  2014. Result:=false;
  2015. //writeln('TPas2jsCompiler.MarkNeedBuilding ',aFile.UnitFilename);
  2016. // check each file only once
  2017. if Checked.FindItem(aFile)<>nil then
  2018. exit(aFile.NeedBuild);
  2019. Checked.Add(aFile);
  2020. if AllJSIntoMainJS and (WPOAnalyzer<>nil)
  2021. and not WPOAnalyzer.IsUsed(aFile.PasModule) then
  2022. begin
  2023. {$IFDEF REALLYVERBOSE}
  2024. writeln('TPas2jsCompiler.MarkNeedBuilding module not used by WPO: ',aFile.UnitFilename);
  2025. {$ENDIF}
  2026. exit(false);
  2027. end;
  2028. // check dependencies
  2029. //writeln('TPas2jsCompiler.MarkNeedBuilding CheckUsesClause ',aFile.UnitFilename,' MainUses');
  2030. CheckUsesClause(aFile.GetPasMainUsesClause);
  2031. //writeln('TPas2jsCompiler.MarkNeedBuilding CheckUsesClause ',aFile.UnitFilename,' ImplUses');
  2032. CheckUsesClause(aFile.GetPasImplUsesClause);
  2033. if (not aFile.NeedBuild) and (not aFile.IsForeign) then
  2034. begin
  2035. // this unit can be compiled
  2036. if aFile.IsMainFile then
  2037. Mark(nUnitNeedsCompileDueToOption,[aFile.GetModuleName,'<main source file>'])
  2038. else if coBuildAll in Options then
  2039. Mark(nUnitNeedsCompileDueToOption,[aFile.GetModuleName,'-B'])
  2040. else if AllJSIntoMainJS then
  2041. Mark(nUnitNeedsCompileDueToOption,[aFile.GetModuleName,'-Jc'])
  2042. else if (aFile.JSFilename<>'') and (not FS.FileExists(aFile.JSFilename)) then
  2043. Mark(nUnitNeedsCompileJSMissing,[aFile.GetModuleName,FormatPath(aFile.JSFilename)])
  2044. else if (aFile.JSFilename<>'')
  2045. and FS.File1IsNewer(aFile.UnitFilename,aFile.JSFilename) then
  2046. begin
  2047. Mark(nUnitNeedsCompilePasHasChanged,[aFile.GetModuleName,FullFormatPath(aFile.JSFilename)])
  2048. end;
  2049. end;
  2050. if aFile.NeedBuild then
  2051. begin
  2052. // unit needs compile
  2053. if aFile.IsForeign then
  2054. begin
  2055. // ... but is forbidden to compile
  2056. Log.LogMsg(nOptionForbidsCompile,[aFile.GetModuleName]);
  2057. Terminate(ExitCodeWriteError);
  2058. end;
  2059. end;
  2060. Result:=aFile.NeedBuild;
  2061. end;
  2062. function TPas2jsCompiler.CreateOptimizer: TPas2JSAnalyzer;
  2063. begin
  2064. Result:=TPas2JSAnalyzer.Create;
  2065. end;
  2066. procedure TPas2jsCompiler.OptimizeProgram(aFile: TPas2jsCompilerFile);
  2067. begin
  2068. if not AllJSIntoMainJS then exit;
  2069. if coKeepNotUsedDeclarationsWPO in Options then exit;
  2070. if not (aFile.PasModule is TPasProgram) then exit;
  2071. FWPOAnalyzer:=CreateOptimizer;
  2072. FWPOAnalyzer.Resolver:=aFile.PascalResolver;
  2073. FWPOAnalyzer.Options:=FWPOAnalyzer.Options+[paoOnlyExports];
  2074. FWPOAnalyzer.AnalyzeWholeProgram(TPasProgram(aFile.PasModule));
  2075. end;
  2076. procedure TPas2jsCompiler.CreateJavaScript(aFile: TPas2jsCompilerFile;
  2077. Checked: TPasAnalyzerKeySet);
  2078. procedure CheckUsesClause(UsesClause: TPasUsesClause);
  2079. var
  2080. i: Integer;
  2081. UsedFile: TPas2jsCompilerFile;
  2082. aModule: TPasModule;
  2083. begin
  2084. if length(UsesClause)=0 then exit;
  2085. for i:=0 to length(UsesClause)-1 do begin
  2086. aModule:=UsesClause[i].Module as TPasModule;
  2087. UsedFile:=TPas2jsCompilerFile.GetFile(aModule);
  2088. if UsedFile=nil then
  2089. RaiseInternalError(20171214121720,aModule.Name);
  2090. CreateJavaScript(UsedFile,Checked);
  2091. end;
  2092. end;
  2093. begin
  2094. //writeln('TPas2jsCompiler.CreateJavaScript ',aFile.UnitFilename,' JS=',GetObjName(aFile.JSModule),' Need=',aFile.NeedBuild);
  2095. if aFile.JSModule<>nil then exit; // already created
  2096. // check each file only once
  2097. if Checked.ContainsItem(aFile) then exit;
  2098. Checked.Add(aFile);
  2099. // emit module hints
  2100. aFile.EmitModuleHints;
  2101. if not aFile.NeedBuild then exit;
  2102. Log.LogMsg(nCompilingFile,[FullFormatPath(aFile.UnitFilename)],'',0,0,
  2103. not (coShowLineNumbers in Options));
  2104. // convert dependencies
  2105. CheckUsesClause(aFile.GetPasMainUsesClause);
  2106. CheckUsesClause(aFile.GetPasImplUsesClause);
  2107. aFile.CreateJS;
  2108. end;
  2109. procedure TPas2jsCompiler.FinishSrcMap(SrcMap: TPas2JSSrcMap);
  2110. var
  2111. LocalFilename, MapFilename, BaseDir: String;
  2112. aFile: TPas2jsFile;
  2113. i: Integer;
  2114. begin
  2115. if SrcMapBaseDir<>'' then
  2116. BaseDir:=SrcMapBaseDir
  2117. else
  2118. BaseDir:=ExtractFilePath(ExtractFilePath(SrcMap.LocalFilename));
  2119. for i:=0 to SrcMap.SourceCount-1 do begin
  2120. LocalFilename:=SrcMap.SourceFiles[i];
  2121. if LocalFilename='' then continue;
  2122. if SrcMapInclude and FS.FileExists(LocalFilename) then
  2123. begin
  2124. // include source in SrcMap
  2125. aFile:=LoadFile(LocalFilename);
  2126. SrcMap.SourceContents[i]:=aFile.Source;
  2127. end;
  2128. // translate local file name
  2129. MapFilename:=LocalFilename;
  2130. if (BaseDir<>'') and not SrcMapFilenamesAbsolute then
  2131. begin
  2132. if not FS.TryCreateRelativePath(LocalFilename,BaseDir,true,false,MapFilename) then
  2133. begin
  2134. // e.g. file is on another partition
  2135. if not SrcMapInclude then
  2136. begin
  2137. Log.Log(mtError,
  2138. SafeFormat(sUnableToTranslatePathToDir,[QuoteStr(LocalFilename),QuoteStr(BaseDir)]),
  2139. nUnableToTranslatePathToDir);
  2140. Terminate(ExitCodeConverterError);
  2141. end;
  2142. // the source is included, do not translate the filename
  2143. MapFilename:=LocalFilename;
  2144. end;
  2145. end;
  2146. if FilenameIsAbsolute(MapFilename)
  2147. and SameText(SrcMapSourceRoot,'file://') then
  2148. begin
  2149. // Firefox needs the "file://" schema with every file
  2150. MapFilename:='file://'+MapFilename;
  2151. end;
  2152. {$IFNDEF Unix}
  2153. // use / as PathDelim
  2154. if PathDelim<>'/' then
  2155. MapFilename:=StringReplace(MapFilename,PathDelim,'/',[rfReplaceAll]);
  2156. {$ENDIF}
  2157. if LocalFilename<>MapFilename then
  2158. SrcMap.SourceTranslatedFiles[i]:=MapFilename;
  2159. end;
  2160. end;
  2161. function TPas2jsCompiler.DoWriteJSFile(const DestFilename, MapFilename: String;
  2162. aWriter: TPas2JSMapper): Boolean;
  2163. begin
  2164. Result:=False;
  2165. if DestFilename='' then ;
  2166. if MapFilename='' then ;
  2167. if aWriter=nil then ;
  2168. end;
  2169. function TPas2jsCompiler.CreateJSWriter(aFileWriter: TPas2JSMapper): TJSWriter;
  2170. begin
  2171. Result:=TJSWriter.Create(aFileWriter);
  2172. end;
  2173. function TPas2jsCompiler.CreateJSMapper: TPas2JSMapper;
  2174. begin
  2175. Result:=TPas2JSMapper.Create(4096);
  2176. end;
  2177. function TPas2jsCompiler.CreateSrcMap(const aFileName: String): TPas2JSSrcMap;
  2178. begin
  2179. Result:=TPas2JSSrcMap.Create(aFileName);
  2180. end;
  2181. function TPas2jsCompiler.CreateFileWriter(aFile: TPas2jsCompilerFile;
  2182. const aFilename: string): TPas2JSMapper;
  2183. var
  2184. SrcMap: TPas2JSSrcMap;
  2185. DestFileName : String;
  2186. begin
  2187. DestFileName:=AFileName;
  2188. if DestFileName='' then
  2189. DestFileName:=aFile.JSFilename;
  2190. Result:=CreateJSMapper;
  2191. Result.DestFileName:=DestFileName;
  2192. if SrcMapEnable then
  2193. begin
  2194. SrcMap:=CreateSrcMap(ExtractFilename(DestFilename));
  2195. Result.SrcMap:=SrcMap;
  2196. SrcMap.Release;// release the refcount from the Create
  2197. SrcMap.SourceRoot:=SrcMapSourceRoot;
  2198. SrcMap.LocalFilename:=aFile.JSFilename;
  2199. if SrcMapXSSIHeader then
  2200. SrcMap.Options:=SrcMap.Options+[smoSafetyHeader]
  2201. else
  2202. SrcMap.Options:=SrcMap.Options-[smoSafetyHeader];
  2203. SrcMap.Options:=SrcMap.Options+[smoAllowSrcLine0];
  2204. end;
  2205. end;
  2206. procedure TPas2jsCompiler.HandleLinkLibStatement(Sender: TObject; const aLibName, aLibAlias, aLibOptions: String;
  2207. var Handled: boolean);
  2208. Var
  2209. Imp : TJSImportStatement;
  2210. PasLib : TJSSimpleAssignStatement;
  2211. dmAlias,dmimp : TJSDotMemberExpression;
  2212. pePas,peAlias : TJSPrimaryExpressionIdent;
  2213. LibModuleName : String;
  2214. begin
  2215. Handled:=true;
  2216. if aLibOptions<>'' then
  2217. ParamFatal('[20210919141030] linklib options not supported');
  2218. Imp:=CreateImportStatement;
  2219. Imp.NameSpaceImport:=TJSString(aLibAlias);
  2220. LibModuleName:=aLibName;
  2221. if ExtractFileExt(LibModuleName)='' then
  2222. LibModuleName:=LibModuleName+'.js';
  2223. Imp.ModuleName:=TJSString(LibModuleName);
  2224. // pas.$imports.libalias:=libalias
  2225. // LHS
  2226. pePas:=TJSPrimaryExpressionIdent.Create(0,0,'');
  2227. pePas.Name:='pas';
  2228. dmImp:=TJSDotMemberExpression.Create(0,0,'');
  2229. dmImp.Name:='$libimports';
  2230. dmImp.MExpr:=pePas;
  2231. dmAlias:=TJSDotMemberExpression.Create(0,0,'');
  2232. dmAlias.Name:=TJSString(alibAlias);
  2233. dmAlias.MExpr:=dmImp;
  2234. peAlias:=TJSPrimaryExpressionIdent.Create(0,0,'');
  2235. peAlias.Name:=TJSString(aLibAlias);
  2236. // Put all together
  2237. PasLib:=TJSSimpleAssignStatement.Create(0,0,'');
  2238. PasLib.LHS:=dmAlias;
  2239. pasLib.Expr:=peAlias;
  2240. // Add to statements
  2241. FImports.Statements.AddNode.Node:=Imp;
  2242. FImports.Statements.AddNode.Node:=PasLib;
  2243. end;
  2244. procedure TPas2jsCompiler.EmitJavaScript(aFile: TPas2jsCompilerFile;
  2245. aFileWriter: TPas2JSMapper);
  2246. var
  2247. aJSWriter: TJSWriter;
  2248. begin
  2249. // write JavaScript
  2250. aJSWriter:=CreateJSWriter(aFileWriter);
  2251. try
  2252. aJSWriter.Options:=DefaultJSWriterOptions;
  2253. aJSWriter.IndentSize:=2;
  2254. try
  2255. aJSWriter.WriteJS(aFile.JSModule);
  2256. except
  2257. on E: Exception do begin
  2258. if ShowDebug then
  2259. Log.LogExceptionBackTrace(E);
  2260. Log.LogPlain('[20180204193420] Error while creating JavaScript '+FullFormatPath(aFileWriter.DestFilename)+': '+E.Message);
  2261. Terminate(ExitCodeErrorInternal);
  2262. end
  2263. {$IFDEF Pas2js}
  2264. else HandleJSException('[20181031190520] TPas2jsCompiler.WriteJSFiles Error while creating JavaScript',JSExceptValue);
  2265. {$ENDIF}
  2266. end;
  2267. Finally
  2268. aJSWriter.Free;
  2269. end;
  2270. end;
  2271. procedure TPas2jsCompiler.WriteJSToFile(const MapFileName: string;
  2272. aFileWriter: TPas2JSMapper);
  2273. Var
  2274. {$IFDEF Pas2js}
  2275. buf: TJSArray;
  2276. {$ELSE}
  2277. buf: TMemoryStream;
  2278. {$ENDIF}
  2279. WithUTF8BOM: Boolean;
  2280. begin
  2281. // write js
  2282. try
  2283. {$IFDEF Pas2js}
  2284. buf:=TJSArray.new;
  2285. {$ELSE}
  2286. buf:=TMemoryStream.Create;
  2287. {$ENDIF}
  2288. try
  2289. WithUTF8BOM:=(Log.Encoding='') or (Log.Encoding='utf8');
  2290. aFileWriter.SaveJSToStream(WithUTF8BOM,ExtractFilename(MapFilename),buf);
  2291. {$IFDEF Pas2js}
  2292. {$ELSE}
  2293. buf.Position:=0;
  2294. {$ENDIF}
  2295. FS.SaveToFile(buf,aFileWriter.DestFilename);
  2296. finally
  2297. {$IFDEF Pas2js}
  2298. buf:=nil;
  2299. {$ELSE}
  2300. buf.Free;
  2301. {$ENDIF}
  2302. end;
  2303. except
  2304. on E: Exception do begin
  2305. if ShowDebug then
  2306. Log.LogExceptionBackTrace(E);
  2307. {$IFDEF FPC}
  2308. if E.Message<>SafeFormat(SFCreateError,[aFileWriter.DestFileName]) then
  2309. {$ENDIF}
  2310. Log.LogPlain('Error: '+E.Message);
  2311. Log.LogMsg(nUnableToWriteFile,[FullFormatPath(aFileWriter.DestFilename)]);
  2312. Terminate(ExitCodeWriteError);
  2313. end
  2314. {$IFDEF Pas2js}
  2315. else HandleJSException('[20181031190637] TPas2jsCompiler.WriteJSFiles',JSExceptValue,true);
  2316. {$ENDIF}
  2317. end;
  2318. end;
  2319. procedure TPas2jsCompiler.WriteSrcMap(const MapFileName: string;
  2320. aFileWriter: TPas2JSMapper);
  2321. Var
  2322. {$IFDEF Pas2js}
  2323. buf: TJSArray;
  2324. {$ELSE}
  2325. buf: TMemoryStream;
  2326. {$ENDIF}
  2327. begin
  2328. Log.LogMsg(nWritingFile,[FullFormatPath(MapFilename)],'',0,0,
  2329. not (coShowLineNumbers in Options));
  2330. FinishSrcMap(aFileWriter.SrcMap);
  2331. try
  2332. {$IFDEF Pas2js}
  2333. buf:=TJSArray.new;
  2334. {$ELSE}
  2335. buf:=TMemoryStream.Create;
  2336. {$ENDIF}
  2337. try
  2338. // Note: No UTF-8 BOM in source map, Chrome 59 gives an error
  2339. aFileWriter.SrcMap.SaveToStream(buf);
  2340. {$IFDEF Pas2js}
  2341. {$ELSE}
  2342. buf.Position:=0;
  2343. {$ENDIF}
  2344. FS.SaveToFile(buf,MapFilename);
  2345. finally
  2346. {$IFDEF Pas2js}
  2347. buf:=nil;
  2348. {$ELSE}
  2349. buf.Free;
  2350. {$ENDIF}
  2351. end;
  2352. except
  2353. on E: Exception do begin
  2354. if ShowDebug then
  2355. Log.LogExceptionBackTrace(E);
  2356. {$IFDEF FPC}
  2357. if E.Message<>SafeFormat(SFCreateError,[aFileWriter.DestFileName]) then
  2358. {$ENDIF}
  2359. Log.LogPlain('Error: '+E.Message);
  2360. Log.LogMsg(nUnableToWriteFile,[FullFormatPath(MapFilename)]);
  2361. Terminate(ExitCodeWriteError);
  2362. end
  2363. {$IFDEF Pas2js}
  2364. else HandleJSException('[20181031190737] TPas2jsCompiler.WriteJSFiles',JSExceptValue);
  2365. {$ENDIF}
  2366. end;
  2367. end;
  2368. procedure TPas2jsCompiler.AddUnitResourceStrings(aFile : TPas2jsCompilerFile);
  2369. Var
  2370. ResList : TFPList;
  2371. Procedure AddToList(aList : TFPList);
  2372. var
  2373. I : integer;
  2374. begin
  2375. For I:=0 to aList.Count-1 do
  2376. ResList.Add(aList[i]);
  2377. end;
  2378. Procedure AddUsedToList(aList : TFPList);
  2379. var
  2380. I : integer;
  2381. begin
  2382. For I:=0 to aList.Count-1 do
  2383. if aFile.UseAnalyzer.IsUsed(TPasElement(aList[i])) then
  2384. ResList.Add(aList[i]);
  2385. end;
  2386. Procedure CheckSection(aSection : TPasSection);
  2387. begin
  2388. if not (Assigned(aSection) and Assigned(aSection.ResStrings)) then
  2389. exit;
  2390. if FResourceStringFile=rsfProgram then
  2391. AddUsedToList(aSection.ResStrings)
  2392. else
  2393. AddToList(aSection.ResStrings);
  2394. end;
  2395. Var
  2396. I : Integer;
  2397. Res : TPasResString;
  2398. aValue : TResEvalValue;
  2399. begin
  2400. if FResourceStringFile=rsfUnit then
  2401. FResourceStrings.Clear;
  2402. ResList:=TFPList.Create;
  2403. try
  2404. // Program ?
  2405. if aFile.pasModule is TPasProgram then
  2406. CheckSection(TPasProgram(aFile.pasModule).ProgramSection)
  2407. else if aFile.pasModule is TPasLibrary then // Library ?
  2408. CheckSection(TPasLibrary(aFile.pasModule).LibrarySection)
  2409. else
  2410. begin
  2411. // Interface
  2412. CheckSection(aFile.PasModule.InterfaceSection);
  2413. // Implementation
  2414. CheckSection(aFile.PasModule.ImplementationSection);
  2415. end;
  2416. // Now add to file
  2417. if ResList.Count>0 then
  2418. begin
  2419. FResourceStrings.StartUnit(aFile.GetModuleName);
  2420. For I:=0 to ResList.Count-1 do
  2421. begin
  2422. Res:=TPasResString(ResList[i]);
  2423. aValue:=aFile.PascalResolver.Eval(Res.Expr,[refConst],False);
  2424. case aValue.Kind of
  2425. {$IFDEF FPC_HAS_CPSTRING}
  2426. revkString:
  2427. FResourceStrings.AddString(Res.Name,TResEvalString(aValue).S);
  2428. {$ENDIF}
  2429. revkUnicodeString:
  2430. FResourceStrings.AddString(Res.Name,TJSONStringType(TResEvalUTF16(aValue).S))
  2431. else
  2432. Log.Log(mtNote,sSkipNoConstResourcestring,nSkipNoConstResourcestring,aFile.PasFileName);
  2433. end;
  2434. ReleaseEvalValue(aValue);
  2435. end;
  2436. end;
  2437. finally
  2438. ResList.Free;
  2439. end;
  2440. end;
  2441. procedure TPas2jsCompiler.WriteResourceStrings(aFileName : String);
  2442. Var
  2443. {$IFDEF Pas2js}
  2444. buf: TJSArray;
  2445. {$ELSE}
  2446. buf: TMemoryStream;
  2447. {$ENDIF}
  2448. S : TJSONStringType;
  2449. begin
  2450. Log.LogMsg(nWritingFile,[FullFormatPath(aFilename)],'',0,0,False);
  2451. try
  2452. {$IFDEF Pas2js}
  2453. buf:=TJSArray.new;
  2454. {$ELSE}
  2455. buf:=TMemoryStream.Create;
  2456. {$ENDIF}
  2457. try
  2458. // Note: No UTF-8 BOM in source map, Chrome 59 gives an error
  2459. S:=FResourceStrings.AsString;
  2460. {$ifdef pas2js}
  2461. buf.push(S);
  2462. {$else}
  2463. buf.Write(S[1],length(S));
  2464. {$endif}
  2465. FS.SaveToFile(buf,aFilename);
  2466. finally
  2467. {$IFDEF Pas2js}
  2468. buf:=nil;
  2469. {$ELSE}
  2470. buf.Free;
  2471. {$ENDIF}
  2472. end;
  2473. except
  2474. on E: Exception do begin
  2475. if ShowDebug then
  2476. Log.LogExceptionBackTrace(E);
  2477. {$IFDEF FPC}
  2478. if E.Message<>SafeFormat(SFCreateError,[aFileName]) then
  2479. {$ENDIF}
  2480. Log.LogPlain('Error: '+E.Message);
  2481. Log.LogMsg(nUnableToWriteFile,[FullFormatPath(aFilename)]);
  2482. Terminate(ExitCodeWriteError);
  2483. end
  2484. {$IFDEF Pas2js}
  2485. else HandleJSException('[20181031190737] TPas2jsCompiler.WriteJSFiles',JSExceptValue);
  2486. {$ENDIF}
  2487. end;
  2488. end;
  2489. procedure TPas2jsCompiler.WriteResources(aFileName: String);
  2490. Var
  2491. {$IFDEF Pas2js}
  2492. buf: TJSArray;
  2493. {$ELSE}
  2494. buf: TMemoryStream;
  2495. {$ENDIF}
  2496. S : TJSONStringType;
  2497. begin
  2498. Log.LogMsg(nWritingFile,[FullFormatPath(aFilename)],'',0,0,False);
  2499. try
  2500. {$IFDEF Pas2js}
  2501. buf:=TJSArray.new;
  2502. {$ELSE}
  2503. buf:=TMemoryStream.Create;
  2504. {$ENDIF}
  2505. try
  2506. S:=FResources.AsString;
  2507. {$ifdef pas2js}
  2508. buf.push(S);
  2509. {$else}
  2510. buf.Write(S[1],length(S));
  2511. {$endif}
  2512. FS.SaveToFile(buf,aFilename);
  2513. finally
  2514. {$IFDEF Pas2js}
  2515. buf:=nil;
  2516. {$ELSE}
  2517. buf.Free;
  2518. {$ENDIF}
  2519. end;
  2520. except
  2521. on E: Exception do begin
  2522. if ShowDebug then
  2523. Log.LogExceptionBackTrace(E);
  2524. {$IFDEF FPC}
  2525. if E.Message<>SafeFormat(SFCreateError,[aFileName]) then
  2526. {$ENDIF}
  2527. Log.LogPlain('Error: '+E.Message);
  2528. Log.LogMsg(nUnableToWriteFile,[FullFormatPath(aFilename)]);
  2529. Terminate(ExitCodeWriteError);
  2530. end
  2531. {$IFDEF Pas2js}
  2532. else HandleJSException('[20181031190737] TPas2jsCompiler.WriteJSFiles',JSExceptValue);
  2533. {$ENDIF}
  2534. end;
  2535. end;
  2536. procedure TPas2jsCompiler.WriteSingleJSFile(aFile: TPas2jsCompilerFile; CombinedFileWriter: TPas2JSMapper);
  2537. Procedure WriteToStandardOutput(aFileWriter : TPas2JSMapper);
  2538. begin
  2539. // write to stdout
  2540. {$IFDEF HasStdErr}
  2541. Log.WriteMsgToStdErr:=false;
  2542. {$ENDIF}
  2543. try
  2544. Log.LogRaw(aFileWriter.AsString);
  2545. finally
  2546. {$IFDEF HasStdErr}
  2547. Log.WriteMsgToStdErr:=coWriteMsgToStdErr in Options;
  2548. {$ENDIF}
  2549. end;
  2550. end;
  2551. Procedure CheckOutputDir(Const DestFileName : String);
  2552. Var
  2553. DestDir : String;
  2554. begin
  2555. // check output directory
  2556. DestDir:=ChompPathDelim(ExtractFilePath(DestFilename));
  2557. if (DestDir<>'') and not FS.DirectoryExists(DestDir) then
  2558. begin
  2559. Log.LogMsg(nOutputDirectoryNotFound,[FullFormatPath(DestDir)]);
  2560. Terminate(ExitCodeFileNotFound);
  2561. end;
  2562. if FS.DirectoryExists(DestFilename) then
  2563. begin
  2564. Log.LogMsg(nFileIsFolder,[FullFormatPath(DestFilename)]);
  2565. Terminate(ExitCodeWriteError);
  2566. end;
  2567. end;
  2568. Var
  2569. aFileWriter: TPas2JSMapper;
  2570. isSingleFile, JSFileWritten: Boolean;
  2571. ResFileName,MapFilename: String;
  2572. begin
  2573. aFileWriter:=CombinedFileWriter;
  2574. try
  2575. isSingleFile:=aFileWriter=nil;
  2576. if isSingleFile then
  2577. // create local writer for this file
  2578. begin
  2579. aFileWriter:=CreateFileWriter(aFile,'');
  2580. if aFile.IsMainFile and Not AllJSIntoMainJS then
  2581. begin
  2582. InsertCustomJSFiles(aFileWriter);
  2583. if FResources.OutputMode=romExtraJS then
  2584. aFileWriter.WriteFile(FResources.AsString,GetResolvedMainJSFile);
  2585. end;
  2586. end;
  2587. if FResourceStringFile<>rsfNone then
  2588. AddUnitResourceStrings(aFile);
  2589. FResources.DoneUnit(aFile.isMainFile);
  2590. EmitJavaScript(aFile,aFileWriter);
  2591. if isSingleFile or aFile.isMainFile then
  2592. begin
  2593. if aFile.IsMainFile then
  2594. AppendCustomJSFiles(aFileWriter);
  2595. if Assigned(PostProcessorSupport) then
  2596. PostProcessorSupport.CallPostProcessors(aFile.JSFilename,aFileWriter);
  2597. if SrcMapEnable then
  2598. MapFilename:=aFileWriter.DestFilename+'.map'
  2599. else
  2600. MapFilename:='';
  2601. CheckOutputDir(aFileWriter.DestFileName);
  2602. // Give chance to descendants to write file
  2603. JSFileWritten:=DoWriteJSFile(aFile.JSFilename,MapFilename,aFileWriter);
  2604. if (aFile.JSFilename='') and (MainJSFile='.') then
  2605. WriteToStandardOutput(aFileWriter);
  2606. //writeln('TPas2jsCompiler.WriteJSFiles ',aFile.UnitFilename,' ',aFile.JSFilename);
  2607. Log.LogMsg(nWritingFile,[FullFormatPath(aFileWriter.DestFilename)],'',0,0, not (coShowLineNumbers in Options));
  2608. if not JSFileWritten then
  2609. WriteJSToFile(MapFileName,aFileWriter);
  2610. if (FResourceStringFile=rsfUnit) or (aFile.IsMainFile and (FResourceStringFile<>rsfNone)) then
  2611. if FResourceStrings.StringsCount>0 then
  2612. WriteResourceStrings(ChangeFileExt(aFileWriter.DestFileName,'.jrs'));
  2613. // Writeln('IsSingleFile ',isSingleFile,' mainfile: ',aFile.IsMainFile,' filename: ', aFileWriter.DestFileName);
  2614. if aFile.isMainFile and (FResources.OutputMode=romFile) and (FResources.ResourceCount>0) then
  2615. begin
  2616. ResFileName:=FResourceOutputFile;
  2617. if ResFileName='' then
  2618. // default is projectname-res.ext, to avoid projectname.html, used in web projects in Lazarus IDE
  2619. ResFileName:=ChangeFileExt(aFileWriter.DestFileName,'-res'+FResources.OutputFileExtension);
  2620. WriteResources(ResFileName);
  2621. end;
  2622. // write source map
  2623. if aFileWriter.SrcMap<>nil then
  2624. WriteSrcMap(MapFileName,aFileWriter);
  2625. end;
  2626. finally
  2627. if isSingleFile then
  2628. aFileWriter.Free;
  2629. end;
  2630. end;
  2631. procedure TPas2jsCompiler.InsertImportSection(aFileWriter : TPas2JSMapper);
  2632. var
  2633. aJSWriter: TJSWriter;
  2634. begin
  2635. if FImports.Statements.Count=0 then
  2636. exit;
  2637. // write JavaScript
  2638. aJSWriter:=CreateJSWriter(aFileWriter);
  2639. try
  2640. aJSWriter.Options:=DefaultJSWriterOptions;
  2641. aJSWriter.IndentSize:=2;
  2642. try
  2643. aJSWriter.WriteJS(FImports);
  2644. except
  2645. on E: Exception do begin
  2646. if ShowDebug then
  2647. Log.LogExceptionBackTrace(E);
  2648. Log.LogPlain('[20210911104700] Error while creating JavaScript '+FullFormatPath(aFileWriter.DestFilename)+': '+E.Message);
  2649. Terminate(ExitCodeErrorInternal);
  2650. end
  2651. {$IFDEF Pas2js}
  2652. else HandleJSException('[20210911104700] TPas2jsCompiler.WriteJSFiles Error while creating JavaScript',JSExceptValue);
  2653. {$ENDIF}
  2654. end;
  2655. Finally
  2656. aJSWriter.Free;
  2657. end;
  2658. end;
  2659. procedure TPas2jsCompiler.WriteJSFiles(aFile: TPas2jsCompilerFile; CombinedFileWriter: TPas2JSMapper; Checked: TPasAnalyzerKeySet);
  2660. procedure CheckUsesClause(aFileWriter: TPas2JSMapper; UsesClause: TPasUsesClause);
  2661. var
  2662. i: Integer;
  2663. UsedFile: TPas2jsCompilerFile;
  2664. aModule: TPasModule;
  2665. begin
  2666. if length(UsesClause)=0 then exit;
  2667. for i:=0 to length(UsesClause)-1 do begin
  2668. aModule:=UsesClause[i].Module as TPasModule;
  2669. UsedFile:=TPas2jsCompilerFile.GetFile(aModule);
  2670. if UsedFile=nil then
  2671. RaiseInternalError(20171214121720,aModule.Name);
  2672. WriteJSFiles(UsedFile,aFileWriter,Checked);
  2673. end;
  2674. end;
  2675. Var
  2676. aFileWriter : TPas2JSMapper;
  2677. begin
  2678. // writeln('TPas2jsCompiler.WriteJSFiles START ',aFile.UnitFilename,' Need=',aFile.NeedBuild,' Checked=',Checked.ContainsItem(aFile),' JSModule=',GetObjName(aFile.JSModule));
  2679. if (aFile.JSModule=nil) or (not aFile.NeedBuild) then exit;
  2680. // check each file only once
  2681. if Checked.ContainsItem(aFile) then exit;
  2682. Checked.Add(aFile);
  2683. aFileWriter:=CombinedFileWriter;
  2684. if AllJSIntoMainJS and (aFileWriter=nil) then
  2685. begin
  2686. // create CombinedFileWriter
  2687. aFileWriter:=CreateFileWriter(aFile,GetResolvedMainJSFile);
  2688. InsertCustomJSFiles(aFileWriter);
  2689. if TargetPlatform in [PlatformNodeJS,PlatformModule] then
  2690. InsertImportSection(aFileWriter);
  2691. if FResources.OutputMode=romExtraJS then
  2692. aFileWriter.WriteFile(FResources.AsString,GetResolvedMainJSFile);
  2693. end;
  2694. Try
  2695. // convert dependencies
  2696. CheckUsesClause(aFileWriter,aFile.GetPasMainUsesClause);
  2697. CheckUsesClause(aFileWriter,aFile.GetPasImplUsesClause);
  2698. // Write me...
  2699. WriteSingleJSFile(aFile,aFileWriter);
  2700. finally
  2701. if aFileWriter<>CombinedFileWriter then
  2702. aFileWriter.Free;
  2703. end;
  2704. end;
  2705. procedure TPas2jsCompiler.InitParamMacros;
  2706. begin
  2707. ParamMacros.AddValue('Pas2jsFullVersion','major.minor.release<extra>',GetVersion(false));
  2708. ParamMacros.AddValue('Pas2jsVersion','major.minor.release',GetVersion(true));
  2709. ParamMacros.AddFunction('CfgDir','Use within a config file. The directory of this config file',@OnMacroCfgDir,false);
  2710. // Additionally, under windows the following special variables are recognized:
  2711. { ToDo:
  2712. LOCAL_APPDATA
  2713. Usually the directory ”Local settings/Application Data” under the user’s home directory.
  2714. APPDATA
  2715. Usually the directory ”Application Data” under the user’s home directory.
  2716. COMMON_APPDATA
  2717. Usually the directory ”Application Data” under the ’All users’ directory.
  2718. PERSONAL
  2719. Usually the ”My documents” directory of the user.
  2720. PROGRAM_FILES
  2721. Usually ”program files” directory on the system drive
  2722. PROGRAM_FILES_COMMON
  2723. Usually the ”Common files” directory under the program files directory.
  2724. PROFILE
  2725. The user’s home directory. }
  2726. end;
  2727. procedure TPas2jsCompiler.ClearDefines;
  2728. var
  2729. i: Integer;
  2730. M: TMacroDef;
  2731. begin
  2732. for i:=0 to FDefines.Count-1 do
  2733. begin
  2734. M:=TMacroDef(FDefines.Objects[i]);
  2735. M.Free;
  2736. end;
  2737. FDefines.Clear;
  2738. end;
  2739. procedure TPas2jsCompiler.RaiseInternalError(id: TMaxPrecInt; Msg: string);
  2740. begin
  2741. Log.LogPlain('['+IntToStr(id)+'] '+Msg);
  2742. raise Exception.Create(Msg);
  2743. end;
  2744. {$IFDEF Pas2js}
  2745. procedure TPas2jsCompiler.HandleJSException(Msg: string; E: jsvalue;
  2746. TerminateInternal: boolean);
  2747. var
  2748. obj: JS.TJSObject;
  2749. Exc: Exception;
  2750. begin
  2751. if isObject(E) then
  2752. begin
  2753. obj:=js.TJSObject(E);
  2754. if isExt(obj,TJSError) then
  2755. begin
  2756. {AllowWriteln}
  2757. if obj['stack'] then
  2758. writeln(obj['stack']);
  2759. {AllowWriteln-}
  2760. Log.Log(mtFatal,Msg+': '+String(obj['message']));
  2761. end else if isExt(obj,TObject) then
  2762. begin
  2763. if TObject(obj) is Exception then
  2764. begin
  2765. Exc:=Exception(TObject(obj));
  2766. {$ifdef NodeJS}
  2767. {AllowWriteln}
  2768. if Exc.NodeJSError<>nil then
  2769. writeln(Exc.NodeJSError.stack);
  2770. {AllowWriteln-}
  2771. {$endif}
  2772. Log.Log(mtFatal,Msg+': ('+Exc.ClassName+') '+Exc.Message);
  2773. end else begin
  2774. Log.Log(mtFatal,Msg+': ('+TObject(obj).ClassName+')');
  2775. end;
  2776. end else
  2777. Log.Log(mtFatal,Msg+': '+String(E));
  2778. end else begin
  2779. Log.Log(mtFatal,Msg+': '+String(E));
  2780. end;
  2781. if TerminateInternal then
  2782. Terminate(ExitCodeErrorInternal);
  2783. end;
  2784. {$ENDIF}
  2785. function TPas2jsCompiler.GetExitCode: Longint;
  2786. begin
  2787. Result:=System.ExitCode;
  2788. end;
  2789. procedure TPas2jsCompiler.SetExitCode(Value: Longint);
  2790. begin
  2791. System.ExitCode:=Value;
  2792. end;
  2793. procedure TPas2jsCompiler.SetWorkingDir(const aDir: String);
  2794. begin
  2795. // Do nothing
  2796. if aDir='' then ;
  2797. end;
  2798. procedure TPas2jsCompiler.CreateResourceSupport;
  2799. begin
  2800. Case FResourceMode of
  2801. rmNone : FResources:=TNoResources.Create(FS);
  2802. rmHTML : FResources:=THTMLResourceLinkHandler.Create(FS);
  2803. rmJS : FResources:=TJSResourceHandler.Create(FS);
  2804. end;
  2805. end;
  2806. procedure TPas2jsCompiler.Terminate(TheExitCode: integer);
  2807. begin
  2808. ExitCode:=TheExitCode;
  2809. if Log<>nil then Log.Flush;
  2810. raise ECompilerTerminate.Create('TPas2jsCompiler.Terminate');
  2811. end;
  2812. function TPas2jsCompiler.GetShowDebug: boolean;
  2813. begin
  2814. Result:=coShowDebug in Options;
  2815. end;
  2816. function TPas2jsCompiler.GetShowFullPaths: boolean;
  2817. begin
  2818. Result:=FS.ShowFullPaths;
  2819. end;
  2820. function TPas2jsCompiler.GetShowLogo: Boolean;
  2821. begin
  2822. Result:=coShowLogo in FOptions;
  2823. end;
  2824. function TPas2jsCompiler.GetShowTriedUsedFiles: boolean;
  2825. begin
  2826. Result:=coShowTriedUsedFiles in FOptions;
  2827. end;
  2828. function TPas2jsCompiler.GetShowUsedTools: boolean;
  2829. begin
  2830. Result:=coShowUsedTools in Options;
  2831. end;
  2832. function TPas2jsCompiler.GetSkipDefaultConfig: Boolean;
  2833. begin
  2834. Result:=coSkipDefaultConfigs in FOptions;
  2835. end;
  2836. function TPas2jsCompiler.GetSrcMapEnable: boolean;
  2837. begin
  2838. Result:=coSourceMapCreate in FOptions;
  2839. end;
  2840. function TPas2jsCompiler.GetSrcMapInclude: boolean;
  2841. begin
  2842. Result:=coSourceMapInclude in FOptions;
  2843. end;
  2844. function TPas2jsCompiler.GetSrcMapFilenamesAbsolute: boolean;
  2845. begin
  2846. Result:=coSourceMapFilenamesAbsolute in FOptions;
  2847. end;
  2848. function TPas2jsCompiler.GetSrcMapXSSIHeader: boolean;
  2849. begin
  2850. Result:=coSourceMapXSSIHeader in FOptions;
  2851. end;
  2852. function TPas2jsCompiler.GetTargetPlatform: TPasToJsPlatform;
  2853. begin
  2854. Result:=FConverterGlobals.TargetPlatform;
  2855. end;
  2856. function TPas2jsCompiler.GetTargetProcessor: TPasToJsProcessor;
  2857. begin
  2858. Result:=FConverterGlobals.TargetProcessor;
  2859. end;
  2860. function TPas2jsCompiler.GetWriteDebugLog: boolean;
  2861. begin
  2862. Result:=coWriteDebugLog in FOptions;
  2863. end;
  2864. function TPas2jsCompiler.GetWriteMsgToStdErr: boolean;
  2865. begin
  2866. Result:=coWriteMsgToStdErr in FOptions;
  2867. end;
  2868. procedure TPas2jsCompiler.SetCompilerExe(AValue: string);
  2869. begin
  2870. if AValue<>'' then
  2871. AValue:=ExpandFileName(AValue);
  2872. if FCompilerExe=AValue then Exit;
  2873. FCompilerExe:=AValue;
  2874. end;
  2875. procedure TPas2jsCompiler.SetMode(AValue: TP2jsMode);
  2876. begin
  2877. SetModeSwitches(p2jsMode_SwitchSets[AValue]);
  2878. case AValue of
  2879. p2jmObjFPC: Options:=Options-[coAllowCAssignments];
  2880. p2jmDelphi: Options:=Options-[coAllowCAssignments];
  2881. end;
  2882. end;
  2883. procedure TPas2jsCompiler.SetModeSwitches(const AValue: TModeSwitches);
  2884. begin
  2885. if FModeSwitches=AValue then Exit;
  2886. FModeSwitches:=AValue;
  2887. end;
  2888. procedure TPas2jsCompiler.SetOptions(AValue: TP2jsCompilerOptions);
  2889. begin
  2890. if FOptions=AValue then Exit;
  2891. FOptions:=AValue;
  2892. Log.ShowMsgNumbers:=coShowMessageNumbers in FOptions;
  2893. Log.ShowMsgTypes:=GetShownMsgTypes;
  2894. FS.ShowTriedUsedFiles:=coShowTriedUsedFiles in FOptions;
  2895. end;
  2896. procedure TPas2jsCompiler.SetShowDebug(AValue: boolean);
  2897. begin
  2898. if AValue then
  2899. FOptions:=FOptions+[coShowNotes,coShowInfos,coShowDebug]
  2900. else
  2901. Exclude(FOptions,coShowNotes);
  2902. end;
  2903. procedure TPas2jsCompiler.SetShowFullPaths(AValue: boolean);
  2904. begin
  2905. FS.ShowFullPaths:=AValue;
  2906. end;
  2907. procedure TPas2jsCompiler.SetShowLogo(AValue: Boolean);
  2908. begin
  2909. SetOption(coShowLogo,AValue);
  2910. end;
  2911. procedure TPas2jsCompiler.SetShowTriedUsedFiles(AValue: boolean);
  2912. begin
  2913. FS.ShowTriedUsedFiles:=AValue;
  2914. SetOption(coShowTriedUsedFiles,AValue);
  2915. end;
  2916. procedure TPas2jsCompiler.SetShowUsedTools(AValue: boolean);
  2917. begin
  2918. SetOption(coShowUsedTools,AValue);
  2919. end;
  2920. procedure TPas2jsCompiler.SetSkipDefaultConfig(AValue: Boolean);
  2921. begin
  2922. SetOption(coSkipDefaultConfigs,AValue);
  2923. end;
  2924. procedure TPas2jsCompiler.SetSrcMapBaseDir(const AValue: string);
  2925. var
  2926. NewValue: String;
  2927. begin
  2928. NewValue:=FS.ExpandDirectory(AValue);
  2929. if FSrcMapBaseDir=NewValue then Exit;
  2930. FSrcMapBaseDir:=NewValue;
  2931. end;
  2932. procedure TPas2jsCompiler.SetSrcMapEnable(const AValue: boolean);
  2933. begin
  2934. SetOption(coSourceMapCreate,AValue);
  2935. end;
  2936. procedure TPas2jsCompiler.SetSrcMapInclude(const AValue: boolean);
  2937. begin
  2938. SetOption(coSourceMapInclude,AValue);
  2939. end;
  2940. procedure TPas2jsCompiler.SetSrcMapFilenamesAbsolute(const AValue: boolean);
  2941. begin
  2942. SetOption(coSourceMapFilenamesAbsolute,AValue);
  2943. end;
  2944. procedure TPas2jsCompiler.SetSrcMapXSSIHeader(const AValue: boolean);
  2945. begin
  2946. SetOption(coSourceMapXSSIHeader,AValue);
  2947. end;
  2948. procedure TPas2jsCompiler.SetTargetPlatform(const AValue: TPasToJsPlatform);
  2949. var
  2950. OldPlatform: TPasToJsPlatform;
  2951. begin
  2952. OldPlatform:=FConverterGlobals.TargetPlatform;
  2953. if OldPlatform=AValue then Exit;
  2954. RemoveDefine(PasToJsPlatformNames[OldPlatform]);
  2955. FConverterGlobals.TargetPlatform:=AValue;
  2956. if AValue in [PlatformNodeJS,PlatformModule] then
  2957. AllJSIntoMainJS:=true;
  2958. AddDefinesForTargetPlatform;
  2959. end;
  2960. procedure TPas2jsCompiler.SetTargetProcessor(const AValue: TPasToJsProcessor);
  2961. var
  2962. OldTargetProcessor: TPasToJsProcessor;
  2963. begin
  2964. OldTargetProcessor:=FConverterGlobals.TargetProcessor;
  2965. if OldTargetProcessor=AValue then Exit;
  2966. RemoveDefine(PasToJsProcessorNames[OldTargetProcessor]);
  2967. FConverterGlobals.TargetProcessor:=AValue;
  2968. AddDefinesForTargetProcessor;
  2969. end;
  2970. procedure TPas2jsCompiler.SetWriteDebugLog(const AValue: boolean);
  2971. begin
  2972. SetOption(coWriteDebugLog,AValue);
  2973. end;
  2974. procedure TPas2jsCompiler.SetWriteMsgToStdErr(const AValue: boolean);
  2975. begin
  2976. SetOption(coWriteMsgToStdErr,AValue);
  2977. {$IFDEF HasStdErr}
  2978. Log.WriteMsgToStdErr:=AValue;
  2979. {$ENDIF}
  2980. end;
  2981. procedure TPas2jsCompiler.AddDefinesForTargetPlatform;
  2982. begin
  2983. AddDefine(PasToJsPlatformNames[TargetPlatform]);
  2984. AddDefine('Pas2JSTargetOS',PasToJsPlatformNames[TargetPlatform]);
  2985. end;
  2986. procedure TPas2jsCompiler.AddDefinesForTargetProcessor;
  2987. begin
  2988. AddDefine(PasToJsProcessorNames[TargetProcessor]);
  2989. AddDefine('Pas2JSTargetCPU',PasToJsProcessorNames[TargetProcessor]);
  2990. case TargetProcessor of
  2991. ProcessorECMAScript5: AddDefine('ECMAScript', '5');
  2992. ProcessorECMAScript6: AddDefine('ECMAScript', '6');
  2993. end;
  2994. end;
  2995. procedure TPas2jsCompiler.AddReadingModule(aFile: TPas2jsCompilerFile);
  2996. begin
  2997. if FReadingModules.IndexOf(aFile)>=0 then
  2998. exit;
  2999. FReadingModules.Add(aFile);
  3000. end;
  3001. procedure TPas2jsCompiler.RemoveReadingModule(aFile: TPas2jsCompilerFile);
  3002. begin
  3003. FReadingModules.Remove(aFile);
  3004. end;
  3005. procedure TPas2jsCompiler.RegisterMessages;
  3006. var
  3007. LastMsgNumber: integer;
  3008. procedure r(MsgType: TMessageType; MsgNumber: integer; const MsgPattern: string);
  3009. var
  3010. s: String;
  3011. begin
  3012. if (LastMsgNumber>=0) and (MsgNumber<>LastMsgNumber+1) then
  3013. begin
  3014. if MsgNumber>LastMsgNumber+1 then
  3015. s:='TPas2jsCompiler.RegisterMessages: gap in registered message numbers: '+IntToStr(LastMsgNumber+1)+' '+IntToStr(MsgNumber)
  3016. else
  3017. s:='TPas2jsCompiler.RegisterMessages: not ascending order in registered message numbers: Last='+IntToStr(LastMsgNumber)+' New='+IntToStr(MsgNumber);
  3018. RaiseInternalError(20170504161422,s);
  3019. end;
  3020. Log.RegisterMsg(MsgType,MsgNumber,MsgPattern);
  3021. LastMsgNumber:=MsgNumber;
  3022. end;
  3023. begin
  3024. LastMsgNumber:=-1;
  3025. r(mtInfo,nOptionIsEnabled,sOptionIsEnabled);
  3026. r(mtInfo,nSyntaxModeIs,sSyntaxModeIs);
  3027. r(mtInfo,nModeswitchXisY,sModeswitchXisY);
  3028. LastMsgNumber:=-1; // was nMacroDefined 103
  3029. r(mtInfo,nUsingPath,sUsingPath);
  3030. r(mtNote,nFolderNotFound,sFolderNotFound);
  3031. r(mtInfo,nNameValue,sNameValue);
  3032. r(mtInfo,nReadingOptionsFromFile,sReadingOptionsFromFile);
  3033. r(mtInfo,nEndOfReadingConfigFile,sEndOfReadingConfigFile);
  3034. r(mtDebug,nInterpretingFileOption,sInterpretingFileOption);
  3035. r(mtFatal,nSourceFileNotFound,sSourceFileNotFound);
  3036. r(mtFatal,nFileIsFolder,sFileIsFolder);
  3037. r(mtInfo,nConfigFileSearch,sConfigFileSearch);
  3038. r(mtDebug,nHandlingOption,sHandlingOption);
  3039. r(mtDebug,nQuickHandlingOption,sQuickHandlingOption);
  3040. r(mtFatal,nOutputDirectoryNotFound,sOutputDirectoryNotFound);
  3041. r(mtError,nUnableToWriteFile,sUnableToWriteFile);
  3042. r(mtInfo,nWritingFile,sWritingFile);
  3043. r(mtFatal,nCompilationAborted,sCompilationAborted);
  3044. r(mtDebug,nCfgDirective,sCfgDirective);
  3045. r(mtError,nUnitCycle,sUnitCycle);
  3046. r(mtError,nOptionForbidsCompile,sOptionForbidsCompile);
  3047. r(mtInfo,nUnitNeedsCompileDueToUsedUnit,sUnitsNeedCompileDueToUsedUnit);
  3048. r(mtInfo,nUnitNeedsCompileDueToOption,sUnitsNeedCompileDueToOption);
  3049. r(mtInfo,nUnitNeedsCompileJSMissing,sUnitsNeedCompileJSMissing);
  3050. r(mtInfo,nUnitNeedsCompilePasHasChanged,sUnitsNeedCompilePasHasChanged);
  3051. r(mtInfo,nParsingFile,sParsingFile);
  3052. r(mtInfo,nCompilingFile,sCompilingFile);
  3053. r(mtError,nExpectedButFound,sExpectedButFound);
  3054. r(mtInfo,nLinesInFilesCompiled,sLinesInFilesCompiled);
  3055. r(mtInfo,nTargetPlatformIs,sTargetPlatformIs);
  3056. r(mtInfo,nTargetProcessorIs,sTargetProcessorIs);
  3057. r(mtInfo,nMessageEncodingIs,sMessageEncodingIs);
  3058. r(mtError,nUnableToTranslatePathToDir,sUnableToTranslatePathToDir);
  3059. r(mtInfo,nSrcMapSourceRootIs,sSrcMapSourceRootIs);
  3060. r(mtInfo,nSrcMapBaseDirIs,sSrcMapBaseDirIs);
  3061. r(mtFatal,nUnitFileNotFound,sUnitFileNotFound);
  3062. r(mtInfo,nClassInterfaceStyleIs,sClassInterfaceStyleIs);
  3063. r(mtInfo,nHandlingEnvOpts,sHandlingEnvOpts);
  3064. r(mtInfo,nPostProcessorInfoX,sPostProcessorInfoX);
  3065. r(mtInfo,nPostProcessorRunX,sPostProcessorRunX);
  3066. r(mtError,nPostProcessorFailX,sPostProcessorFailX);
  3067. r(mtWarning,nPostProcessorWarnX,sPostProcessorWarnX);
  3068. r(mtInfo,nPostProcessorFinished,sPostProcessorFinished);
  3069. r(mtInfo,nRTLIdentifierChanged,sRTLIdentifierChanged);
  3070. r(mtNote,nSkipNoConstResourcestring,sSkipNoConstResourcestring);
  3071. r(mtWarning,nUnknownOptimizationOption,sUnknownOptimizationOption);
  3072. Pas2jsPParser.RegisterMessages(Log);
  3073. end;
  3074. procedure TPas2jsCompiler.LoadConfig(CfgFilename: string);
  3075. begin
  3076. ConfigSupport.LoadConfig(CfgFileName);
  3077. end;
  3078. procedure TPas2jsCompiler.ReadEnvironment;
  3079. var
  3080. s: String;
  3081. List: TStrings;
  3082. begin
  3083. s:=GetEnvironmentVariable('PAS2JS_OPTS');
  3084. if s='' then exit;
  3085. if ShowDebug then
  3086. Log.LogMsgIgnoreFilter(nHandlingEnvOpts,['PAS2JS_OPTS=['+s+']']);
  3087. List:=TStringList.Create;
  3088. try
  3089. SplitCmdLineParams(s,List);
  3090. for s in List do
  3091. if s<>'' then
  3092. ReadParam(s,false,false);
  3093. finally
  3094. List.Free;
  3095. end;
  3096. end;
  3097. procedure TPas2jsCompiler.ParamFatal(Msg: string);
  3098. begin
  3099. if FCurParam<>'' then
  3100. Msg:='parameter '+FCurParam+': '+Msg;
  3101. if Assigned(ConfigSupport) and (ConfigSupport.CurrentCfgFilename<>'') then
  3102. Log.Log(mtFatal,Msg,0,ConfigSupport.CurrentCfgFilename,ConfigSupport.CurrentCfgLineNumber,0)
  3103. else
  3104. Log.LogPlain(['Fatal: ',Msg]);
  3105. Terminate(ExitCodeErrorInParams);
  3106. end;
  3107. procedure TPas2jsCompiler.HandleOptionPCUFormat(aValue: String);
  3108. begin
  3109. ParamFatal('No support in this compiler for precompiled format '+aValue);
  3110. end;
  3111. function TPas2jsCompiler.HandleOptionPaths(C: Char; aValue: String;
  3112. FromCmdLine: Boolean): Boolean;
  3113. Var
  3114. ErrorMsg: String;
  3115. begin
  3116. Result:=True;
  3117. case c of
  3118. 'N': AddNamespaces(aValue,FromCmdLine);
  3119. 'r': Log.Log(mtNote,'-Fr not yet implemented');
  3120. 'e': Log.OutputFilename:=aValue;
  3121. else
  3122. ErrorMsg:=FS.HandleOptionPaths(C,aValue,FromCmdLine);
  3123. if ErrorMsg<>'' then
  3124. ParamFatal(ErrorMsg);
  3125. end;
  3126. end;
  3127. function TPas2jsCompiler.HandleOptionJ(C: Char; aValue: String;
  3128. Quick, FromCmdLine: Boolean): Boolean;
  3129. Var
  3130. S, ErrorMsg, aName: String;
  3131. i: Integer;
  3132. enable: Boolean;
  3133. pbi: TPas2JSBuiltInName;
  3134. begin
  3135. Result:=True;
  3136. case c of
  3137. 'c': // -Jc concatenate
  3138. begin
  3139. if aValue='' then
  3140. AllJSIntoMainJS:=true
  3141. else if (AValue='-') then
  3142. AllJSIntoMainJS:=false
  3143. else
  3144. ParamFatal('invalid value (-Jc) "'+aValue+'"');
  3145. end;
  3146. 'e': // -Je<encoding>
  3147. begin
  3148. S:=NormalizeEncoding(aValue);
  3149. case S of
  3150. {$IFDEF FPC_HAS_CPSTRING}
  3151. 'console','system',
  3152. {$ENDIF}
  3153. 'utf8', 'json':
  3154. if Log.Encoding<>S then begin
  3155. Log.Encoding:=S;
  3156. if FHasShownEncoding then begin
  3157. FHasShownEncoding:=false;
  3158. WriteEncoding;
  3159. end;
  3160. end;
  3161. else ParamFatal('invalid encoding (-Je) "'+aValue+'"');
  3162. end;
  3163. end;
  3164. 'a', // -Ja<js-file>
  3165. 'i': // -Ji<js-file>
  3166. if aValue='' then
  3167. if c='a' then
  3168. ParamFatal('missing append file "'+aValue+'"')
  3169. else
  3170. ParamFatal('missing insertion file "'+aValue+'"')
  3171. else if not Quick then
  3172. begin
  3173. if aValue='' then
  3174. Result:=false
  3175. else if aValue[length(aValue)]='-' then
  3176. begin
  3177. Delete(aValue,length(aValue),1);
  3178. if aValue='' then
  3179. Result:=False
  3180. else if c='i' then
  3181. RemoveInsertJSFilename(aValue)
  3182. else
  3183. RemoveAppendJSFileName(aValue);
  3184. end
  3185. else
  3186. if C='i' then
  3187. AddInsertJSFilename(aValue)
  3188. else
  3189. addAppendJSFileName(aValue)
  3190. end;
  3191. 'l': // -Jl
  3192. SetOption(coLowercase,aValue<>'-');
  3193. 'm': // -Jm source map options
  3194. if aValue='' then
  3195. SrcMapEnable:=true
  3196. else if aValue[1]='-' then
  3197. begin
  3198. if aValue<>'-' then
  3199. Result:=False
  3200. else
  3201. SrcMapEnable:=false;
  3202. end else
  3203. begin
  3204. case aValue of
  3205. 'include':
  3206. SrcMapInclude:=true;
  3207. 'include-':
  3208. SrcMapInclude:=false;
  3209. 'absolute':
  3210. SrcMapFilenamesAbsolute:=true;
  3211. 'absolute-':
  3212. SrcMapFilenamesAbsolute:=false;
  3213. 'xssiheader':
  3214. SrcMapXSSIHeader:=true;
  3215. 'xssiheader-':
  3216. SrcMapXSSIHeader:=false;
  3217. else
  3218. begin
  3219. i:=Pos('=',aValue);
  3220. if i<1 then
  3221. ParamFatal('unknown -Jm parameter "'+aValue+'"')
  3222. else
  3223. begin
  3224. S:=LeftStr(aValue,i-1);
  3225. Delete(aValue,1,i);
  3226. Case s of
  3227. 'sourceroot': SrcMapSourceRoot:=aValue;
  3228. 'basedir': SrcMapBaseDir:=aValue;
  3229. else
  3230. ParamFatal('unknown -Jm parameter "'+s+'"')
  3231. end;
  3232. end;
  3233. end;
  3234. end;
  3235. // enable source maps when setting any -Jm<x> option
  3236. SrcMapEnable:=true;
  3237. end;
  3238. 'o': // -Jo<flag>
  3239. begin
  3240. S:=aValue;
  3241. if aValue='' then
  3242. ParamFatal('missing value of -Jo option');
  3243. if SameText(LeftStr(S,4),'rtl-') then
  3244. begin
  3245. // -Jortl-<name>=<value> set rtl identifier
  3246. i:=5;
  3247. while (i<=length(S)) and (S[i] in ['a'..'z','A'..'Z','0'..'9','_']) do
  3248. inc(i);
  3249. if (i>length(S)) or (S[i]<>'=') then
  3250. ParamFatal('expected -Jortl-name=value');
  3251. aName:='pbi'+copy(S,5,i-5);
  3252. S:=copy(S,i+1,255);
  3253. val(aName,pbi,i);
  3254. if i<>0 then
  3255. ParamFatal('unknown rtl identifier "'+aName+'"');
  3256. if IsValidJSIdentifier(TJSString(ConverterGlobals.BuiltInNames[pbi]))
  3257. and not IsValidJSIdentifier(TJSString(S)) then
  3258. ParamFatal('JavaScript identifier expected');
  3259. if not Quick then
  3260. ConverterGlobals.BuiltInNames[pbi]:=S;
  3261. end else begin
  3262. Enable:=true;
  3263. c:=S[length(S)];
  3264. if c in ['+','-'] then
  3265. begin
  3266. Enable:=c='+';
  3267. Delete(S,length(S),1);
  3268. end;
  3269. Case lowercase(S) of
  3270. 'searchlikefpc': FS.SearchLikeFPC:=Enable;
  3271. 'usestrict': SetOption(coUseStrict,Enable);
  3272. 'checkversion=main': RTLVersionCheck:=rvcMain;
  3273. 'checkversion=system': RTLVersionCheck:=rvcSystem;
  3274. 'checkversion=unit': RTLVersionCheck:=rvcUnit;
  3275. else
  3276. Result:=False;
  3277. end;
  3278. end;
  3279. end;
  3280. 'p': // -Jp<...>
  3281. begin
  3282. if not Assigned(PostProcessorSupport) then
  3283. ParamFatal('-Jp: No postprocessor support available');
  3284. Result:=copy(aValue,1,3)='cmd';
  3285. if Result then
  3286. begin
  3287. delete(aValue,1,3);
  3288. if not Quick then
  3289. PostProcessorSupport.AddPostProcessor(aValue);
  3290. end;
  3291. end;
  3292. 'r': // -Jr<...>
  3293. begin
  3294. S:=aValue;
  3295. if aValue='' then
  3296. ParamFatal('missing value for -Jr option')
  3297. else if (S='none') then
  3298. FResourceStringFile:=rsfNone
  3299. else if (S='unit') then
  3300. FResourceStringFile:=rsfunit
  3301. else if (S='program') then
  3302. FResourceStringFile:=rsfProgram
  3303. else
  3304. ParamFatal('invalid resource string file format (-Jr) "'+aValue+'"');
  3305. end;
  3306. 'R': // -JR<...>
  3307. begin
  3308. I:=Pos('=',aValue);
  3309. if I=0 then
  3310. I:=Length(aValue)+1;
  3311. S:=Copy(aValue,1,I-1);
  3312. if S='' then
  3313. ParamFatal('missing value for -JR option')
  3314. else if (S='none') then
  3315. FResourceMode:=rmNone
  3316. else if (S='js') then
  3317. FResourceMode:= rmJS
  3318. else if (S='html') then
  3319. begin
  3320. FResourceMode:=rmHTML;
  3321. S:=Copy(aValue,I+1,Length(aValue)-I);
  3322. FResourceOutputFile:=S;
  3323. if (FResourceOutputFile<>'') and (ExtractFileExt(FResourceOutputFile)='') then
  3324. FResourceOutputFile:=FResourceOutputFile+'.html';
  3325. end;
  3326. end;
  3327. 'u': // -Ju<foreign path>
  3328. if not Quick then
  3329. begin
  3330. ErrorMsg:=FS.AddForeignUnitPath(aValue,FromCmdLine);
  3331. if ErrorMsg<>'' then
  3332. ParamFatal('invalid foreign unit path (-Ju) "'+ErrorMsg+'"');
  3333. end;
  3334. 'U': // -JU...
  3335. HandleOptionPCUFormat(aValue);
  3336. else
  3337. Result:=False;
  3338. end;
  3339. end;
  3340. function TPas2jsCompiler.HandleOptionM(aValue: String; Quick: Boolean): Boolean;
  3341. var
  3342. Negated: Boolean;
  3343. ms: TModeSwitch;
  3344. begin
  3345. Result:=True;
  3346. if aValue='' then
  3347. ParamFatal('invalid syntax mode (-M<x>) "'+aValue+'"');
  3348. if Quick then exit;
  3349. case lowerCase(aValue) of
  3350. 'delphi': SetMode(p2jmDelphi);
  3351. 'objfpc': SetMode(p2jmObjFPC);
  3352. else
  3353. if aValue[length(aValue)]='-' then
  3354. begin
  3355. aValue:=LeftStr(aValue,length(aValue)-1);
  3356. Negated:=true;
  3357. end else
  3358. Negated:=false;
  3359. for ms in TModeSwitch do
  3360. if (ms in msAllPas2jsModeSwitches)
  3361. and SameText(SModeSwitchNames[ms],aValue) then
  3362. begin
  3363. if (ms in ModeSwitches)<>Negated then
  3364. begin
  3365. // already set
  3366. exit;
  3367. end else if ms in msAllPas2jsModeSwitchesReadOnly then
  3368. ParamFatal('modeswitch is read only -M"'+aValue+'"')
  3369. else begin
  3370. // switch
  3371. if Negated then
  3372. ModeSwitches:=ModeSwitches-[ms]
  3373. else
  3374. ModeSwitches:=ModeSwitches+[ms];
  3375. exit;
  3376. end;
  3377. end;
  3378. ParamFatal('invalid syntax mode (-M) "'+aValue+'"');
  3379. end;
  3380. end;
  3381. procedure TPas2jsCompiler.HandleOptionConfigFile(aPos: Integer; const aFileName: string);
  3382. Var
  3383. FN: String;
  3384. begin
  3385. // load extra config file
  3386. if aFilename='' then
  3387. ParamFatal('invalid config file at param position '+IntToStr(aPos));
  3388. FN:=ExpandFileName(aFilename);
  3389. if not FS.FileExists(FN) then
  3390. ParamFatal('config file not found: "'+aFileName+'"');
  3391. LoadConfig(FN);
  3392. end;
  3393. procedure TPas2jsCompiler.HandleOptionInfo(aValue: string);
  3394. Var
  3395. InfoMsg: String;
  3396. procedure AppendInfo(Add: string);
  3397. begin
  3398. if InfoMsg<>'' then
  3399. InfoMsg:=InfoMsg+' ';
  3400. InfoMsg:=InfoMsg+Add;
  3401. end;
  3402. Var
  3403. P,L: integer;
  3404. C,c2: Char;
  3405. pr: TPasToJsProcessor;
  3406. pl: TPasToJsPlatform;
  3407. s: string;
  3408. pbi: TPas2JSBuiltInName;
  3409. ms: TModeSwitch;
  3410. begin
  3411. // write information and halt
  3412. InfoMsg:='';
  3413. if aValue='' then
  3414. begin
  3415. WriteInfo;
  3416. Terminate(0);
  3417. exit;
  3418. end;
  3419. P:=1;
  3420. L:=Length(aValue);
  3421. while p<=l do
  3422. begin
  3423. C:=aValue[P];
  3424. case C of
  3425. 'D': // wite compiler date
  3426. AppendInfo(GetCompiledDate);
  3427. 'V': // write short version
  3428. AppendInfo(GetVersion(true));
  3429. 'W': // write long version
  3430. AppendInfo(GetVersion(false));
  3431. 'S':
  3432. begin
  3433. inc(p);
  3434. if p>l then
  3435. ParamFatal('missing info option after S in "'+aValue+'".');
  3436. C2:=aValue[p];
  3437. case C2 of
  3438. 'O': // write source OS
  3439. AppendInfo(GetCompiledTargetOS);
  3440. 'P': // write source processor
  3441. AppendInfo(GetCompiledTargetCPU);
  3442. else
  3443. ParamFatal('unknown info option S"'+C2+'" in "'+aValue+'".');
  3444. end;
  3445. end;
  3446. 'T':
  3447. begin
  3448. inc(p);
  3449. if p>l then
  3450. ParamFatal('missing info option after T in "'+aValue+'".');
  3451. C2:=aValue[p];
  3452. case C2 of
  3453. 'O': // write target platform
  3454. AppendInfo(PasToJsPlatformNames[TargetPlatform]);
  3455. 'P': // write target processor
  3456. AppendInfo(PasToJsProcessorNames[TargetProcessor]);
  3457. else
  3458. ParamFatal('unknown info option S"'+C2+'" in "'+aValue+'".');
  3459. end;
  3460. end;
  3461. 'c':
  3462. // write list of supported JS processors
  3463. for pr in TPasToJsProcessor do
  3464. Log.LogPlain(PasToJsProcessorNames[pr]);
  3465. 'm':
  3466. begin
  3467. // write list of supported modeswitches
  3468. for ms in (msAllPas2jsModeSwitches-AllLanguageModes) do
  3469. Log.LogPlain(SModeSwitchNames[ms]);
  3470. end;
  3471. 'o':
  3472. begin
  3473. // write list of optimizations
  3474. Log.LogPlain('EnumNumbers');
  3475. Log.LogPlain('RemoveNotUsedPrivates');
  3476. Log.LogPlain('RemoveNotUsedDeclarations');
  3477. Log.LogPlain('ShortRefGlobals');
  3478. end;
  3479. 't':
  3480. // write list of supported targets
  3481. for pl in TPasToJsPlatform do
  3482. Log.LogPlain(PasToJsPlatformNames[pl]);
  3483. 'J':
  3484. // write list of RTL identifiers
  3485. begin
  3486. Log.LogPlain('-JoRTL-<x> identifiers:');
  3487. for pbi in TPas2JSBuiltInName do
  3488. begin
  3489. str(pbi,s);
  3490. Delete(s,1,3);
  3491. Log.LogPlain('-JoRTL-'+s+'='+Pas2JSBuiltInNames[pbi]);
  3492. end;
  3493. end
  3494. else
  3495. ParamFatal('unknown info option "'+C+'" in "'+aValue+'".');
  3496. end;
  3497. inc(p);
  3498. end;
  3499. if InfoMsg<>'' then
  3500. Log.LogPlain(InfoMsg);
  3501. end;
  3502. function TPas2jsCompiler.HandleOptionOptimization(C: Char; aValue: String): Boolean;
  3503. Var
  3504. Enable: Boolean;
  3505. begin
  3506. Result:=True;
  3507. case C of
  3508. '-': Options:=Options-coAllOptimizations+coO0;
  3509. '1': Options:=Options-coAllOptimizations+coO1;
  3510. '2': Options:=Options-coAllOptimizations+coO2;
  3511. 'o':
  3512. begin
  3513. if aValue='' then
  3514. ParamFatal('missing -Oo option');
  3515. Enable:=true;
  3516. c:=aValue[length(aValue)];
  3517. if c in ['+','-'] then
  3518. begin
  3519. Enable:=c='+';
  3520. Delete(aValue,length(aValue),1);
  3521. end
  3522. else if lowercase(LeftStr(aValue,2))='no' then begin
  3523. Enable:=false;
  3524. Delete(aValue,1,2);
  3525. end;
  3526. Case LowerCase(aValue) of
  3527. 'enumnumbers': SetOption(coEnumValuesAsNumbers,Enable);
  3528. 'removenotusedprivates': SetOption(coKeepNotUsedPrivates,not Enable);
  3529. 'removenotuseddeclarations': SetOption(coKeepNotUsedDeclarationsWPO,not Enable);
  3530. 'shortrefglobals': SetOption(coShortRefGlobals,Enable);
  3531. 'obfuscatelocalidentifiers': SetOption(coObfuscateLocalIdentifiers,Enable);
  3532. else
  3533. Log.LogMsgIgnoreFilter(nUnknownOptimizationOption,[QuoteStr(aValue)]);
  3534. end;
  3535. end;
  3536. else
  3537. Result:=False;
  3538. end;
  3539. end;
  3540. procedure TPas2jsCompiler.ReadParam(Param: string; Quick, FromCmdLine: boolean);
  3541. procedure UnknownParam;
  3542. begin
  3543. ParamFatal('unknown parameter "'+Param+'". Use -h for help.');
  3544. end;
  3545. var
  3546. EnabledFlags, DisabledFlags, Identifier, aValue: string;
  3547. p, l, i: Integer;
  3548. c: Char;
  3549. aProc: TPasToJsProcessor;
  3550. aPlatform: TPasToJsPlatform;
  3551. begin
  3552. //writeln('TPas2jsCompiler.ReadParam ',Param,' ',Quick,' ',FromCmdLine);
  3553. if ShowDebug then
  3554. if Quick then
  3555. Log.LogMsgIgnoreFilter(nQuickHandlingOption,[QuoteStr(Param)])
  3556. else
  3557. Log.LogMsgIgnoreFilter(nHandlingOption,[QuoteStr(Param)]);
  3558. if Param='' then exit;
  3559. FCurParam:=Param;
  3560. ParamMacros.Substitute(Param,Self);
  3561. if Param='' then exit;
  3562. if Quick and ((Param='-h') or (Param='-?') or (Param='--help')) then
  3563. begin
  3564. WriteHelp;
  3565. Terminate(0);
  3566. end;
  3567. l:=length(Param);
  3568. p:=1;
  3569. case Param[p] of
  3570. '-':
  3571. begin
  3572. inc(p);
  3573. if p>l then
  3574. UnknownParam;
  3575. aValue:=Copy(Param,P+1,Length(Param));
  3576. case Param[p] of
  3577. 'i':
  3578. begin
  3579. HandleOptionInfo(aValue);
  3580. Terminate(0);
  3581. end;
  3582. 'B','l','n':
  3583. begin
  3584. ReadSingleLetterOptions(Param,p,'Bln',EnabledFlags,DisabledFlags);
  3585. for i:=1 to length(EnabledFlags) do begin
  3586. case EnabledFlags[i] of
  3587. 'B': Options:=Options+[coBuildAll];
  3588. 'l': ShowLogo:=true;
  3589. 'n': SkipDefaultConfig:=true;
  3590. end;
  3591. end;
  3592. for i:=1 to length(DisabledFlags) do begin
  3593. case DisabledFlags[i] of
  3594. 'B': Options:=Options-[coBuildAll];
  3595. 'l': ShowLogo:=false;
  3596. 'n': SkipDefaultConfig:=false;
  3597. end;
  3598. end;
  3599. end;
  3600. 'C': // code generation
  3601. ReadCodeGenerationFlags(aValue,1);
  3602. 'd': // define
  3603. if not Quick then
  3604. begin
  3605. Identifier:=aValue;
  3606. i:=Pos(':=',Identifier);
  3607. if i>0 then
  3608. begin
  3609. aValue:=copy(Identifier,i+2,length(Identifier));
  3610. Identifier:=LeftStr(Identifier,i-1);
  3611. if not IsValidIdent(Identifier) then
  3612. ParamFatal('invalid define name (-d): "'+Param+'"');
  3613. AddDefine(Identifier,aValue);
  3614. end else begin
  3615. if not IsValidIdent(Identifier) then
  3616. ParamFatal('invalid define (-d): "'+Param+'"');
  3617. AddDefine(Identifier);
  3618. end;
  3619. end;
  3620. 'F': // folders and search paths
  3621. begin
  3622. if aValue='' then
  3623. UnknownParam;
  3624. c:=aValue[1];
  3625. Delete(aValue,1,1);
  3626. if not HandleOptionPaths(c,aValue,fromCmdLine) then
  3627. UnknownParam;
  3628. end;
  3629. 'I': // include path, same as -Fi
  3630. if not Quick then
  3631. begin
  3632. if not HandleOptionPaths('i',aValue,fromCmdLine) then
  3633. UnknownParam;
  3634. end;
  3635. 'J': // extra pas2js options
  3636. begin
  3637. if aValue='' then
  3638. UnknownParam;
  3639. c:=aValue[1];
  3640. Delete(aValue,1,1);
  3641. if not HandleOptionJ(c,aValue,Quick,FromCmdLine) then
  3642. UnknownParam;
  3643. end;
  3644. 'M': // syntax mode
  3645. if not HandleOptionM(aValue,Quick) then
  3646. UnknownParam;
  3647. 'N':
  3648. begin
  3649. if aValue='' then
  3650. UnknownParam;
  3651. case aValue[1] of
  3652. 'S':
  3653. begin
  3654. Log.Log(mtWarning,'obsolete option -NS, use -FN instead');
  3655. Delete(aValue,1,1);
  3656. HandleOptionPaths('N',aValue,FromCmdLine);
  3657. end;
  3658. else UnknownParam;
  3659. end;
  3660. end;
  3661. 'o': // output file, main JavaScript file
  3662. begin
  3663. if aValue='' then
  3664. ParamFatal('invalid empty output file (-o)')
  3665. else if aValue='..' then
  3666. ParamFatal('invalid output file (-o) "'+aValue+'"')
  3667. else if aValue='.' then
  3668. // ok, stdout
  3669. else
  3670. aValue:=ExpandFileName(aValue);
  3671. MainJSFile:=aValue;
  3672. end;
  3673. 'O': // optimizations
  3674. begin
  3675. if aValue='' then
  3676. UnknownParam;
  3677. C:=aValue[1];
  3678. Delete(aValue,1,1);
  3679. if not HandleOptionOptimization(C,aValue) then
  3680. UnknownParam;
  3681. end;
  3682. 'P': // target processor
  3683. begin
  3684. for aProc in TPasToJsProcessor do
  3685. if SameText(aValue,PasToJsProcessorNames[aProc]) then
  3686. begin
  3687. TargetProcessor:=aProc;
  3688. aValue:='';
  3689. break;
  3690. end;
  3691. if aValue<>'' then
  3692. ParamFatal('invalid target processor (-P) "'+aValue+'"');
  3693. end;
  3694. 'S': // Syntax
  3695. begin
  3696. inc(p);
  3697. if (p<=l) and (Param[p]='I') then
  3698. begin
  3699. Identifier:=copy(Param,p,length(Param));
  3700. if SameText(Identifier,'com') then
  3701. InterfaceType:=citCom
  3702. else if SameText(Identifier,'corba') then
  3703. InterfaceType:=citCorba
  3704. else
  3705. ParamFatal('invalid interface style (-SI) "'+Identifier+'"');
  3706. end
  3707. else
  3708. ReadSyntaxFlags(Param,p);
  3709. end;
  3710. 'T': // target platform
  3711. begin
  3712. inc(p);
  3713. Identifier:=copy(Param,p,length(Param));
  3714. for aPlatform in TPasToJsPlatform do
  3715. if SameText(Identifier,PasToJsPlatformNames[aPlatform]) then
  3716. begin
  3717. TargetPlatform:=aPlatform;
  3718. Identifier:='';
  3719. break;
  3720. end;
  3721. if Identifier<>'' then
  3722. ParamFatal('invalid target platform (-T) "'+Identifier+'"');
  3723. end;
  3724. 'u': // undefine
  3725. if not Quick then
  3726. begin
  3727. if not IsValidIdent(aValue) then
  3728. ParamFatal('invalid undefine (-u): "'+aValue+'"');
  3729. RemoveDefine(aValue);
  3730. end;
  3731. 'v': // verbose
  3732. begin
  3733. inc(p);
  3734. ReadVerbosityFlags(Param,p);
  3735. end;
  3736. else
  3737. UnknownParam;
  3738. end;
  3739. end;
  3740. '@':
  3741. if not Quick then
  3742. HandleOptionConfigFile(i,copy(Param,2,length(Param)));
  3743. else
  3744. // filename
  3745. if (not Quick) then
  3746. begin
  3747. if not FromCmdLine then
  3748. ConfigSupport.CfgSyntaxError('invalid parameter');
  3749. if MainSrcFile<>'' then
  3750. ParamFatal('Only one Pascal file is supported, but got "'+MainSrcFile+'" and "'+Param+'".');
  3751. MainSrcFile:=ExpandFileName(Param);
  3752. end;
  3753. end;
  3754. end;
  3755. procedure TPas2jsCompiler.ReadSingleLetterOptions(const Param: string;
  3756. p: integer; const Allowed: string; out Enabled, Disabled: string);
  3757. // e.g. 'B' 'lB' 'l-' 'l+B-'
  3758. var
  3759. Letter: Char;
  3760. i, l: Integer;
  3761. begin
  3762. l:=length(Param);
  3763. if p>l then
  3764. ParamFatal('Invalid option "'+Param+'"');
  3765. Enabled:='';
  3766. Disabled:='';
  3767. while p<=l do
  3768. begin
  3769. Letter:=Param[p];
  3770. if Letter='-' then
  3771. ParamFatal('Invalid option "'+Param+'"');
  3772. if Pos(Letter,Allowed)<1 then
  3773. ParamFatal('unknown option "'+Param+'". Use -h for help.');
  3774. inc(p);
  3775. if (p<=l) and (Param[p]='-') then
  3776. begin
  3777. // disable
  3778. if Pos(Letter,Disabled)<1 then Disabled+=Letter;
  3779. i:=Pos(Letter,Enabled);
  3780. if i>0 then Delete(Enabled,i,1);
  3781. inc(p);
  3782. end else begin
  3783. // enable
  3784. if Pos(Letter,Enabled)<1 then Enabled+=Letter;
  3785. i:=Pos(Letter,Disabled);
  3786. if i>0 then Delete(Disabled,i,1);
  3787. if (p<=l) and (Param[p]='+') then inc(p);
  3788. end;
  3789. end;
  3790. end;
  3791. procedure TPas2jsCompiler.ReadCodeGenerationFlags(Param: String; p: integer);
  3792. var
  3793. Enabled, Disabled: string;
  3794. i: Integer;
  3795. begin
  3796. ReadSingleLetterOptions(Param,p,'orR',Enabled,Disabled);
  3797. for i:=1 to length(Enabled) do begin
  3798. case Enabled[i] of
  3799. 'o': Options:=Options+[coOverflowChecks];
  3800. 'r': Options:=Options+[coRangeChecks];
  3801. 'R': Options:=Options+[coObjectChecks];
  3802. end;
  3803. end;
  3804. for i:=1 to length(Disabled) do begin
  3805. case Disabled[i] of
  3806. 'o': Options:=Options-[coOverflowChecks];
  3807. 'r': Options:=Options-[coRangeChecks];
  3808. 'R': Options:=Options-[coObjectChecks];
  3809. end;
  3810. end;
  3811. end;
  3812. procedure TPas2jsCompiler.ReadSyntaxFlags(Param: String; p: integer);
  3813. var
  3814. Enabled, Disabled: string;
  3815. i: Integer;
  3816. begin
  3817. ReadSingleLetterOptions(Param,p,'2acdmj',Enabled,Disabled);
  3818. for i:=1 to length(Enabled) do begin
  3819. case Enabled[i] of
  3820. '2': SetMode(p2jmObjFPC);
  3821. 'a': Options:=Options+[coAssertions];
  3822. 'c': Options:=Options+[coAllowCAssignments];
  3823. 'd': SetMode(p2jmDelphi);
  3824. 'm': Options:=Options+[coAllowMacros];
  3825. 'j': Options:=Options+[coWriteableConst];
  3826. end;
  3827. end;
  3828. for i:=1 to length(Disabled) do begin
  3829. case Disabled[i] of
  3830. '2': ;
  3831. 'a': Options:=Options-[coAssertions];
  3832. 'c': Options:=Options-[coAllowCAssignments];
  3833. 'd': ;
  3834. 'm': Options:=Options-[coAllowMacros];
  3835. 'j': Options:=Options-[coWriteableConst];
  3836. end;
  3837. end;
  3838. end;
  3839. procedure TPas2jsCompiler.ReadVerbosityFlags(Param: String; p: integer);
  3840. var
  3841. Enabled, Disabled: string;
  3842. i, l: Integer;
  3843. begin
  3844. l:=length(Param);
  3845. if p>l then exit;
  3846. if Param[p]='m' then
  3847. begin
  3848. // read m-flags
  3849. repeat
  3850. inc(p);
  3851. if (p>l) or not (Param[p] in ['0'..'9']) then
  3852. ParamFatal('missing number in "'+Param+'"');
  3853. i:=0;
  3854. while (p<=l) and (Param[p] in ['0'..'9']) do
  3855. begin
  3856. i:=i*10+ord(Param[p])-ord('0');
  3857. if i>99999 then
  3858. ParamFatal('Invalid -vm parameter in "'+Param+'"');
  3859. inc(p);
  3860. end;
  3861. if (p<=l) and (Param[p]='-') then
  3862. begin
  3863. inc(p);
  3864. Log.MsgNumberDisabled[i]:=false;
  3865. end else
  3866. Log.MsgNumberDisabled[i]:=true;
  3867. if p>l then break;
  3868. if Param[p]<>',' then
  3869. ParamFatal('Invalid option "'+Param+'"');
  3870. until false;
  3871. exit;
  3872. end;
  3873. // read other flags
  3874. ReadSingleLetterOptions(Param,p,'ewnhila0bctdqxvz',Enabled,Disabled);
  3875. for i:=1 to length(Enabled) do begin
  3876. case Enabled[i] of
  3877. 'e': Options:=Options+[coShowErrors];
  3878. 'w': Options:=Options+[coShowWarnings];
  3879. 'n': Options:=Options+[coShowNotes];
  3880. 'h': Options:=Options+[coShowHints];
  3881. 'i': Options:=Options+[coShowInfos];
  3882. 'l': Options:=Options+[coShowLineNumbers];
  3883. 'a': Options:=Options+coShowAll;
  3884. '0': Options:=Options-coShowAll+[coShowErrors];
  3885. 'b': ShowFullPaths:=true;
  3886. 'c': Options:=Options+[coShowConditionals,coShowInfos];
  3887. 't': ShowTriedUsedFiles:=true;
  3888. 'd': ShowDebug:=true;
  3889. 'q': Options:=Options+[coShowMessageNumbers];
  3890. 'x': Options:=Options+[coShowUsedTools];
  3891. 'v': Options:=Options+[coWriteDebugLog];
  3892. 'z': WriteMsgToStdErr:=true;
  3893. end;
  3894. end;
  3895. for i:=1 to length(Disabled) do begin
  3896. case Disabled[i] of
  3897. 'e': Options:=Options-[coShowErrors];
  3898. 'w': Options:=Options-[coShowWarnings];
  3899. 'n': Options:=Options-[coShowNotes];
  3900. 'h': Options:=Options-[coShowHints];
  3901. 'i': Options:=Options-[coShowInfos];
  3902. 'l': Options:=Options-[coShowLineNumbers];
  3903. 'a': ;
  3904. '0': ;
  3905. 'b': ShowFullPaths:=false;
  3906. 'c': Options:=Options-[coShowConditionals];
  3907. 't': ShowTriedUsedFiles:=false;
  3908. 'd': ShowDebug:=false;
  3909. 'q': Options:=Options-[coShowMessageNumbers];
  3910. 'x': Options:=Options-[coShowUsedTools];
  3911. 'v': Options:=Options+[coWriteDebugLog];
  3912. 'z': WriteMsgToStdErr:=false;
  3913. end;
  3914. end;
  3915. end;
  3916. function TPas2jsCompiler.CreateImportList: TJSSourceElements;
  3917. begin
  3918. Result:=TJSSourceElements.Create(0,0,'');
  3919. end;
  3920. function TPas2jsCompiler.CreateImportStatement: TJSImportStatement;
  3921. begin
  3922. Result:=TJSImportStatement.Create(0,0,'');
  3923. end;
  3924. procedure TPas2jsCompiler.SetAllJSIntoMainJS(AValue: Boolean);
  3925. begin
  3926. if FAllJSIntoMainJS=AValue then Exit;
  3927. if aValue then
  3928. FMainJSFileIsResolved:=False;
  3929. FAllJSIntoMainJS:=AValue;
  3930. end;
  3931. procedure TPas2jsCompiler.SetConverterGlobals(
  3932. const AValue: TPasToJSConverterGlobals);
  3933. begin
  3934. if AValue=FConverterGlobals then exit;
  3935. if (FConverterGlobals<>nil) and (FConverterGlobals.Owner=Self) then
  3936. FreeAndNil(FConverterGlobals);
  3937. FConverterGlobals:=AValue;
  3938. end;
  3939. function TPas2jsCompiler.FormatPath(const aPath: String): String;
  3940. begin
  3941. Result:=FS.FormatPath(aPath);
  3942. end;
  3943. function TPas2jsCompiler.FullFormatPath(const aPath: String): String;
  3944. begin
  3945. Result:=QuoteStr(FormatPath(aPath));
  3946. end;
  3947. function TPas2jsCompiler.CreateMacroEngine: TPas2jsMacroEngine;
  3948. begin
  3949. Result:=TPas2jsMacroEngine.Create;
  3950. end;
  3951. function TPas2jsCompiler.CreateLog: TPas2jsLogger;
  3952. begin
  3953. Result:=TPas2jsLogger.Create;
  3954. end;
  3955. constructor TPas2jsCompiler.Create;
  3956. begin
  3957. FOptions:=DefaultP2jsCompilerOptions;
  3958. FConverterGlobals:=TPasToJSConverterGlobals.Create(Self);
  3959. FResolverHub:=TPas2JSResolverHub.Create(Self);
  3960. FNamespaces:=TStringList.Create;
  3961. FDefines:=TStringList.Create;
  3962. FInsertFilenames:=TStringList.Create;
  3963. FAppendFileNames:=TStringList.Create;
  3964. FImports:=CreateImportList;
  3965. FLog:=CreateLog;
  3966. FLog.OnFormatPath:=@FormatPath;
  3967. FParamMacros:=CreateMacroEngine;
  3968. RegisterMessages;
  3969. FS:=CreateFS;
  3970. FOwnsFS:=true;
  3971. // Done by Reset: TStringList(FDefines).Sorted:=True;
  3972. // Done by Reset: TStringList(FDefines).Duplicates:=dupError;
  3973. //FConditionEval.OnEvalFunction:=@ConditionEvalFunction;
  3974. FFiles:=CreateSetOfCompilerFiles(kcFilename);
  3975. FUnits:=CreateSetOfCompilerFiles(kcUnitName);
  3976. FResourceMode:=DefaultResourceMode;
  3977. FResourceStrings:=TResourceStringsFile.Create;
  3978. FReadingModules:=TFPList.Create;
  3979. InitParamMacros;
  3980. Reset;
  3981. end;
  3982. destructor TPas2jsCompiler.Destroy;
  3983. procedure FreeStuff;
  3984. begin
  3985. FreeAndNil(FImports);
  3986. FreeAndNil(FResourceStrings);
  3987. FreeAndNil(FNamespaces);
  3988. FreeAndNil(FWPOAnalyzer);
  3989. FreeAndNil(FInsertFilenames);
  3990. FreeAndNil(FAppendFilenames);
  3991. FMainFile:=nil;
  3992. FreeAndNil(FUnits);
  3993. FreeAndNil(FReadingModules);
  3994. FFiles.FreeItems;
  3995. FreeAndNil(FFiles);
  3996. FreeAndNil(FPostProcessorSupport);
  3997. FreeAndNil(FConfigSupport);
  3998. ConverterGlobals:=nil;
  3999. FreeAndNil(FResolverHub);
  4000. ClearDefines;
  4001. FreeAndNil(FDefines);
  4002. FLog.OnFormatPath:=nil;
  4003. if FOwnsFS then
  4004. FreeAndNil(FFS)
  4005. else
  4006. FFS:=nil;
  4007. FreeAndNil(FParamMacros);
  4008. end;
  4009. begin
  4010. if ShowDebug then
  4011. try
  4012. FreeStuff;
  4013. except
  4014. on E: Exception do
  4015. begin
  4016. Log.LogExceptionBackTrace(E);
  4017. end
  4018. {$IFDEF Pas2js}
  4019. else HandleJSException('[20181031190818] TPas2jsCompiler.Destroy',JSExceptValue);
  4020. {$ENDIF}
  4021. end
  4022. else
  4023. FreeStuff;
  4024. FreeAndNil(FLog);
  4025. inherited Destroy;
  4026. end;
  4027. function TPas2jsCompiler.OnMacroCfgDir(Sender: TObject; var Params: string;
  4028. Lvl: integer): boolean;
  4029. begin
  4030. if Lvl=0 then ;
  4031. if Sender=nil then ;
  4032. Params:=ExtractFilePath(ConfigSupport.CurrentCfgFilename);
  4033. Result:=true;
  4034. end;
  4035. procedure TPas2jsCompiler.AddDefine(const aName: String);
  4036. begin
  4037. if FDefines.IndexOf(aName)>=0 then exit;
  4038. FDefines.Add(aName);
  4039. end;
  4040. procedure TPas2jsCompiler.AddDefine(const aName, Value: String);
  4041. var
  4042. Index: Integer;
  4043. M: TMacroDef;
  4044. begin
  4045. Index:=FDefines.IndexOf(aName);
  4046. If (Index<0) then
  4047. FDefines.AddObject(aName,TMacroDef.Create(aName,Value))
  4048. else begin
  4049. M:=TMacroDef(FDefines.Objects[Index]);
  4050. if M=nil then
  4051. FDefines.Objects[Index]:=TMacroDef.Create(aName,Value)
  4052. else
  4053. M.Value:=Value;
  4054. end;
  4055. end;
  4056. procedure TPas2jsCompiler.RemoveDefine(const aName: String);
  4057. var
  4058. i: Integer;
  4059. M: TMacroDef;
  4060. begin
  4061. i:=FDefines.IndexOf(aName);
  4062. if (i<>-1) then
  4063. begin
  4064. M:=TMacroDef(FDefines.Objects[i]);
  4065. M.Free;
  4066. FDefines.Delete(i);
  4067. end;
  4068. end;
  4069. function TPas2jsCompiler.IsDefined(const aName: String): boolean;
  4070. begin
  4071. Result:=FDefines.IndexOf(aName)>=0;
  4072. end;
  4073. class function TPas2jsCompiler.GetVersion(ShortVersion: boolean): string;
  4074. begin
  4075. Result:=IntToStr(VersionMajor)+'.'+IntToStr(VersionMinor)+'.'+IntToStr(VersionRelease);
  4076. if not ShortVersion then
  4077. Result+=VersionExtra;
  4078. end;
  4079. procedure TPas2jsCompiler.WritePrecompiledFormats;
  4080. begin
  4081. WriteHelpLine(' -JU: This pas2js does not support PCU files');
  4082. end;
  4083. procedure TPas2jsCompiler.AddNamespaces(const Paths: string;
  4084. FromCmdLine: boolean);
  4085. // cmd line paths are added in front of the cfg paths
  4086. // cmd line paths are added in order, cfg paths are added in reverse order
  4087. // multi paths separated by semicolon are added in order
  4088. // duplicates are removed
  4089. var
  4090. Added: Integer;
  4091. function Add(aPath: string): boolean;
  4092. var
  4093. Remove: Boolean;
  4094. i: Integer;
  4095. begin
  4096. Remove:=false;
  4097. // search duplicate
  4098. if aPath[length(aPath)]='-' then
  4099. begin
  4100. Delete(aPath,length(aPath),1);
  4101. Remove:=true;
  4102. end;
  4103. if not IsValidIdent(aPath,true,true) then
  4104. exit(False);
  4105. i:=Namespaces.Count-1;
  4106. while (i>=0) and (CompareText(aPath,NameSpaces[i])<>0) do dec(i);
  4107. if Remove then
  4108. begin
  4109. // remove
  4110. if i>=0 then
  4111. begin
  4112. NameSpaces.Delete(i);
  4113. if NamespacesFromCmdLine>i then dec(FNamespacesFromCmdLine);
  4114. end;
  4115. exit(true);
  4116. end;
  4117. if FromCmdLine then
  4118. begin
  4119. // from cmdline: append in order to the cmdline params, in front of cfg params
  4120. if i>=0 then
  4121. begin
  4122. if i<=NamespacesFromCmdLine then exit(true);
  4123. NameSpaces.Delete(i);
  4124. end;
  4125. NameSpaces.Insert(NamespacesFromCmdLine,aPath);
  4126. inc(FNamespacesFromCmdLine);
  4127. end else begin
  4128. // from cfg: append in reverse order to the cfg params, behind cmdline params
  4129. if i>=0 then
  4130. begin
  4131. if i<=FNamespacesFromCmdLine+Added then exit(true);
  4132. NameSpaces.Delete(i);
  4133. end;
  4134. NameSpaces.Insert(FNamespacesFromCmdLine+Added,aPath);
  4135. inc(Added);
  4136. end;
  4137. Result:=true;
  4138. end;
  4139. var
  4140. aPath: String;
  4141. p: integer;
  4142. begin
  4143. p:=1;
  4144. Added:=0;
  4145. while p<=length(Paths) do
  4146. begin
  4147. aPath:=GetNextDelimitedItem(Paths,';',p);
  4148. if aPath='' then
  4149. continue;
  4150. if not Add(aPath) then
  4151. exit;
  4152. end;
  4153. end;
  4154. procedure TPas2jsCompiler.Reset;
  4155. begin
  4156. FResolverHub.Reset;
  4157. FreeAndNil(FWPOAnalyzer);
  4158. FPrecompileGUID:=default(TGUID);
  4159. FNamespaces.Clear;
  4160. FNamespacesFromCmdLine:=0;
  4161. FMainFile:=nil;
  4162. FUnits.Clear;
  4163. FReadingModules.Clear;
  4164. FFiles.FreeItems;
  4165. FInsertFilenames.Clear;
  4166. FAppendFIleNames.Clear;
  4167. if Assigned(FPostProcessorSupport) then
  4168. FPostProcessorSupport.Clear;
  4169. FCompilerExe:='';
  4170. FSrcMapBaseDir:='';
  4171. FMainSrcFile:='';
  4172. FOptions:=DefaultP2jsCompilerOptions;
  4173. FRTLVersionCheck:=DefaultP2jsRTLVersionCheck;
  4174. FModeSwitches:=p2jsMode_SwitchSets[p2jmObjFPC];
  4175. FConverterGlobals.Reset;
  4176. FConverterGlobals.RTLVersion:=(VersionMajor*100+VersionMinor)*100+VersionRelease;
  4177. FConverterGlobals.TargetPlatform:=PlatformBrowser;
  4178. FConverterGlobals.TargetProcessor:=ProcessorECMAScript5;
  4179. FMainJSFileIsResolved:=False;
  4180. Log.Reset;
  4181. Log.ShowMsgTypes:=GetShownMsgTypes;
  4182. ClearDefines;
  4183. TStringList(FDefines).Sorted:=True;
  4184. {$IFDEF FPC}
  4185. TStringList(FDefines).Duplicates:=dupError;
  4186. {$ENDIF}
  4187. AddDefine('PAS2JS');
  4188. AddDefine('PAS2JS_FULLVERSION',IntToStr((VersionMajor*100+VersionMinor)*100+VersionRelease));
  4189. AddDefinesForTargetPlatform;
  4190. AddDefinesForTargetProcessor;
  4191. // add FPC compatibility flags
  4192. AddDefine('FPC_HAS_FEATURE_CLASSES');
  4193. AddDefine('FPC_HAS_FEATURE_INIT');
  4194. AddDefine('FPC_HAS_FEATURE_DYNARRAYS');
  4195. AddDefine('FPC_HAS_FEATURE_EXCEPTIONS');
  4196. AddDefine('FPC_HAS_FEATURE_EXITCODE');
  4197. AddDefine('FPC_HAS_FEATURE_INITFINAL');
  4198. AddDefine('FPC_HAS_FEATURE_RTTI');
  4199. AddDefine('FPC_HAS_FEATURE_SUPPORT');
  4200. AddDefine('FPC_HAS_FEATURE_UNICODESTRINGS');
  4201. AddDefine('FPC_HAS_FEATURE_WIDESTRINGS');
  4202. AddDefine('FPC_HAS_TYPE_DOUBLE');
  4203. AddDefine('FPC_HAS_UNICODESTRING');
  4204. AddDefine('FPC_UNICODESTRINGS');
  4205. AddDefine('FPC_WIDESTRING_EQUAL_UNICODESTRING');
  4206. AddDefine('STR_CONCAT_PROCS');
  4207. AddDefine('UNICODE');
  4208. FHasShownLogo:=false;
  4209. FHasShownEncoding:=false;
  4210. FFS.Reset;
  4211. end;
  4212. procedure TPas2jsCompiler.Run(aCompilerExe: string; aWorkingDir: string;
  4213. ParamList: TStrings; DoReset: boolean);
  4214. var
  4215. i: Integer;
  4216. StartTime: TDateTime;
  4217. begin
  4218. StartTime:=Now;
  4219. if DoReset then Reset;
  4220. if FileCount>0 then
  4221. RaiseInternalError(20170504161340,'internal error: TPas2jsCompiler.Run FileCount>0');
  4222. try
  4223. // set working directory, needed by all relative filenames
  4224. SetWorkingDir(aWorkingDir);
  4225. CompilerExe:=aCompilerExe; // maybe needed to find the default config
  4226. // quick check command line params
  4227. for i:=0 to ParamList.Count-1 do
  4228. ReadParam(ParamList[i],true,true);
  4229. if WriteDebugLog then
  4230. Log.OpenDebugLog;
  4231. if ShowLogo then
  4232. WriteLogo;
  4233. // read default config
  4234. if Assigned(ConfigSupport) and not SkipDefaultConfig then
  4235. ConfigSupport.LoadDefaultConfig;
  4236. // read env PAS2JS_OPTS
  4237. ReadEnvironment;
  4238. // read command line parameters
  4239. for i:=0 to ParamList.Count-1 do
  4240. ReadParam(ParamList[i],false,true);
  4241. // At this point we know what kind of resources we must use
  4242. CreateResourceSupport;
  4243. // now we know, if the logo can be displayed
  4244. if ShowLogo then
  4245. WriteLogo;
  4246. // show debug info
  4247. if ShowDebug then
  4248. begin
  4249. WriteOptions;
  4250. WriteDefines;
  4251. end;
  4252. if ShowDebug or ShowUsedTools then
  4253. WriteUsedTools;
  4254. if ShowDebug or ShowTriedUsedFiles then
  4255. WriteFoldersAndSearchPaths;
  4256. if MainSrcFile='' then
  4257. ParamFatal('No source file name in command line');
  4258. if not FS.FileExists(MainSrcFile) then
  4259. ParamFatal('Pascal file not found: "'+MainSrcFile+'"');
  4260. // compile
  4261. Compile(StartTime);
  4262. except
  4263. on E: ECompilerTerminate do
  4264. begin
  4265. end;
  4266. on E: Exception do begin
  4267. if ShowDebug then
  4268. Log.LogExceptionBackTrace(E);
  4269. Log.Log(mtFatal,E.Message);
  4270. raise; // reraise unexpected exception
  4271. end else begin
  4272. if ShowDebug then
  4273. Log.LogExceptionBackTrace(nil);
  4274. {$IFDEF Pas2js}
  4275. HandleJSException('[20181031190933] TPas2jsCompiler.Run',JSExceptValue,false);
  4276. {$ENDIF}
  4277. raise; // reraise unexpected exception
  4278. end;
  4279. end;
  4280. end;
  4281. procedure TPas2jsCompiler.WriteHelpLine(S: String);
  4282. const
  4283. MaxLineLen = 78;
  4284. Indent = 12;
  4285. var
  4286. l, p, LastCharStart, WordBreak: integer;
  4287. Len: integer;
  4288. CodePointCount: Integer;
  4289. procedure InitLine;
  4290. begin
  4291. l:=length(s);
  4292. p:=1;
  4293. LastCharStart:=p;
  4294. WordBreak:=0;
  4295. CodePointCount:=0;
  4296. end;
  4297. begin
  4298. if length(s)<=MaxLineLen then
  4299. begin
  4300. Log.LogRaw(s);
  4301. exit;
  4302. end;
  4303. InitLine;
  4304. while p<=l do
  4305. begin
  4306. case s[p] of
  4307. 'a'..'z','A'..'Z','0'..'9','_','-','.',',','"','''','`',
  4308. #128..high(char) :
  4309. begin
  4310. LastCharStart:=p;
  4311. {$IFDEF FPC_HAS_CPSTRING}
  4312. Len:=UTF8CharacterStrictLength(@s[p]);
  4313. if Len=0 then Len:=1;
  4314. inc(p,Len);
  4315. {$ELSE}
  4316. if (p<l) and (s[p] in [#$DC00..#$DFFF]) then
  4317. inc(p,2)
  4318. else
  4319. inc(p,1);
  4320. {$ENDIF}
  4321. end;
  4322. else
  4323. LastCharStart:=p;
  4324. WordBreak:=p;
  4325. inc(p);
  4326. end;
  4327. inc(CodePointCount);
  4328. if CodePointCount>=MaxLineLen then
  4329. begin
  4330. if (WordBreak=0)
  4331. or (WordBreak<MaxLineLen div {$IFDEF FPC_HAS_CPSTRING}3{$ELSE}2{$ENDIF}) then
  4332. WordBreak:=LastCharStart;
  4333. Len:=WordBreak-1;
  4334. Log.LogRaw(LeftStr(s,Len));
  4335. Delete(s,1,len);
  4336. s:=StringOfChar(' ',Indent)+Trim(s);
  4337. InitLine;
  4338. end;
  4339. end;
  4340. Log.LogRaw(s);
  4341. end;
  4342. function TPas2jsCompiler.LoadFile(Filename: string; Binary: boolean
  4343. ): TPas2jsFile;
  4344. begin
  4345. try
  4346. Result:=FS.LoadFile(Filename,Binary);
  4347. except
  4348. on E: Exception do
  4349. begin
  4350. Log.Log(mtError,E.Message);
  4351. Terminate(ExitCodeFileNotFound);
  4352. end
  4353. end;
  4354. end;
  4355. procedure TPas2jsCompiler.WriteHelp;
  4356. procedure w(s: string); inline;
  4357. begin
  4358. WriteHelpLine(S);
  4359. end;
  4360. var
  4361. i: Integer;
  4362. ParamMacro: TPas2jsMacro;
  4363. begin
  4364. WriteLogo;
  4365. Log.LogLn;
  4366. if CompilerExe<>'' then
  4367. begin
  4368. w('Usage: '+CompilerExe+' <your.pas>');
  4369. end else begin
  4370. w('Usage: pas2js <your.pas>');
  4371. end;
  4372. Log.LogLn;
  4373. w('Options:');
  4374. w('Put + after a boolean switch option to enable it, - to disable it');
  4375. w(' @<x> : Read compiler options from file <x> in addition to the default '+DefaultConfigFile);
  4376. w(' -B : Rebuild all');
  4377. w(' -d<x> : Defines the symbol <x>. Optional: -d<x>:=<value>');
  4378. w(' -i<x> : Write information and halt. <x> is a combination of the following:');
  4379. w(' -iD : Write compiler date');
  4380. w(' -iSO : Write compiler OS');
  4381. w(' -iSP : Write compiler host processor');
  4382. w(' -iTO : Write target platform');
  4383. w(' -iTP : Write target processor');
  4384. w(' -iV : Write short compiler version');
  4385. w(' -iW : Write full compiler version');
  4386. w(' -ic : Write list of supported JS processors usable by -P<x>');
  4387. w(' -im : Write list of supported modeswitches usable by -M<x>');
  4388. w(' -io : Write list of supported optimizations usable by -Oo<x>');
  4389. w(' -it : Write list of supported targets usable by -T<x>');
  4390. w(' -iJ : Write list of supported JavaScript identifiers -JoRTL-<x>');
  4391. w(' -C<x> : Code generation options. <x> is a combination of the following letters:');
  4392. // -C3 Turn on ieee error checking for constants
  4393. w(' o : Overflow checking of integer operations');
  4394. // -CO Check for possible overflow of integer operations
  4395. w(' r : Range checking');
  4396. w(' R : Object checks. Verify method calls and object type casts.');
  4397. w(' -F... Set file names and paths:');
  4398. w(' -Fe<x>: Redirect output to file <x>. UTF-8 encoded.');
  4399. w(' -FE<x>: Set main output path to <x>');
  4400. w(' -Fi<x>: Add <x> to include paths');
  4401. w(' -FN<x>: add <x> to namespaces. Namespaces with trailing - are removed.');
  4402. w(' Delphi calls this flag "unit scope names".');
  4403. //w(' -Fr<x>: Load error message file <x>');
  4404. w(' -Fu<x>: Add <x> to unit paths');
  4405. w(' -FU<x>: Set unit output path to <x>');
  4406. w(' -I<x> : Add <x> to include paths, same as -Fi');
  4407. w(' -J... Extra options of pas2js');
  4408. w(' -Ja<x>: Append JS file <x> to main JS file. E.g. -Jamap.js. Can be given multiple times. To remove a file name append a minus, e.g. -Jamap.js-.');
  4409. w(' -Jc : Write all JavaScript concatenated into the output file');
  4410. w(' -Je<x>: Encode messages as <x>.');
  4411. w(' -Jeconsole: Console codepage. This is the default.');
  4412. w(' -Jesystem : System codepage. On non Windows console and system are the same.');
  4413. w(' -Jeutf-8 : Unicode UTF-8. Default when using -Fe.');
  4414. w(' -JeJSON : Output compiler messages as JSON. Logo etc are outputted as-is.');
  4415. w(' -Ji<x>: Insert JS file <x> into main JS file. E.g. -Jirtl.js. Can be given multiple times. To remove a file name append a minus, e.g. -Jirtl.js-.');
  4416. w(' -Jl : lower case identifiers');
  4417. w(' -Jm : generate source maps');
  4418. w(' -Jmsourceroot=<x>: use x as "sourceRoot", prefix URL for source file names.');
  4419. w(' -Jmbasedir=<x>: write source file names relative to directory x, default is map file folder.');
  4420. w(' -Jminclude: include Pascal sources in source map.');
  4421. w(' -Jmabsolute: store absolute filenames, not relative.');
  4422. w(' -Jmxssiheader: start source map with XSSI protection )]}'', default.');
  4423. w(' -Jm-: disable generating source maps');
  4424. w(' -Jo<x>: Enable or disable extra option. The x is case insensitive:');
  4425. w(' -JoSearchLikeFPC: search source files like FPC, default: search case insensitive.');
  4426. w(' -JoUseStrict: add "use strict" to modules, default.');
  4427. w(' -JoCheckVersion-: do not add rtl version check, default.');
  4428. w(' -JoCheckVersion=main: insert rtl version check into main.');
  4429. w(' -JoCheckVersion=system: insert rtl version check into system unit init.');
  4430. w(' -JoCheckVersion=unit: insert rtl version check into every unit init.');
  4431. w(' -JoRTL-<y>=<z>: set RTL identifier y to value z. See -iJ.');
  4432. w(' -Jr<x> Control writing of resource string file');
  4433. w(' -Jrnone: Do not write resource string file');
  4434. w(' -Jrunit: Write resource string file per unit with all resource strings');
  4435. w(' -Jrprogram: Write resource string file per program with all used resource strings in program');
  4436. w(' -JR<x> Control writing of linked resources');
  4437. w(' -JRnone: Skip resource directives');
  4438. w(' -JRjs: Write resources in Javascript structure');
  4439. w(' -JRhtml[=filename] : Write resources as preload links in HTML file (default is projectfile-res.html)');
  4440. w(' -Jpcmd<command>: Run postprocessor. For each generated js execute command passing the js as stdin and read the new js from stdout. This option can be added multiple times to call several postprocessors in succession.');
  4441. w(' -Ju<x>: Add <x> to foreign unit paths. Foreign units are not compiled.');
  4442. WritePrecompiledFormats;
  4443. w(' -l : Write logo');
  4444. w(' -M<x> : Set language mode or enable/disable a modeswitch');
  4445. w(' -MDelphi: Delphi 7 compatibility mode');
  4446. w(' -MObjFPC: FPC''s Object Pascal compatibility mode (default)');
  4447. w(' -M<x> : enable or disable modeswitch, see option -im');
  4448. w(' Each mode (as listed above) enables its default set of modeswitches.');
  4449. w(' Other modeswitches are disabled and need to be enabled one by another.');
  4450. w(' -NS<x> : obsolete: add <x> to namespaces. Same as -FN<x>');
  4451. w(' -n : Do not read the default config files');
  4452. w(' -o<x> : Change main JavaScript file to <x>, "." means stdout');
  4453. w(' -O<x> : Optimizations:');
  4454. w(' -O- : Disable optimizations');
  4455. w(' -O1 : Level 1 optimizations (quick and debugger friendly)');
  4456. w(' -O2 : Level 2 optimizations (Level 1 + not debugger friendly)');
  4457. w(' -Oo<x>: Enable or disable optimization. The x is case insensitive:');
  4458. w(' -OoEnumNumbers[-]: write enum value as number instead of name. Default in -O1.');
  4459. w(' -OoRemoveNotUsedPrivates[-]: Default is enabled');
  4460. w(' -OoRemoveNotUsedDeclarations[-]: Default enabled for programs with -Jc');
  4461. w(' -OoRemoveNotUsedPublished[-] : Default is disabled');
  4462. w(' -OoShortRefGlobals[-]: Insert JS local var for types, modules and static functions. Default enabled in -O2');
  4463. {$IFDEF EnableObfuscateIdentifiers}
  4464. w(' -OoObfuscateLocalIdentifiers[-]: Use auto generated names for private and local Pascal identifiers. Default enabled in -O2');
  4465. {$ENDIF}
  4466. w(' -P<x> : Set target processor. Case insensitive:');
  4467. w(' -Pecmascript5: default');
  4468. w(' -Pecmascript6');
  4469. w(' -S<x> : Syntax options. <x> is a combination of the following letters:');
  4470. w(' 2 : Same as -Mobjfpc (default)');
  4471. w(' a : Turn on assertions');
  4472. w(' c : Support operators like C (*=,+=,/= and -=)');
  4473. w(' d : Same as -Mdelphi');
  4474. w(' j : Allows typed constants to be writeable (default)');
  4475. w(' m : Enables macro replacements');
  4476. w(' -SI<x> : Set interface style to <x>');
  4477. w(' -SIcom : COM, reference counted interface (default)');
  4478. w(' -SIcorba: CORBA interface');
  4479. w(' -T<x> : Set target platform');
  4480. w(' -Tbrowser: default');
  4481. w(' -Tnodejs : add pas.run(), includes -Jc');
  4482. w(' -Telectron: experimental');
  4483. w(' -Tmodule : add pas.run(), includes -Jc');
  4484. w(' -u<x> : Undefines the symbol <x>');
  4485. w(' -v<x> : Be verbose. <x> is a combination of the following letters:');
  4486. w(' e : Show errors (default)');
  4487. w(' w : Show warnings');
  4488. w(' n : Show notes');
  4489. w(' h : Show hints');
  4490. w(' i : Show info');
  4491. w(' l : Show line numbers, needs -vi');
  4492. w(' a : Show everything');
  4493. w(' 0 : Show nothing (except errors)');
  4494. w(' b : Show file names with full path');
  4495. w(' c : Show conditionals');
  4496. w(' t : Show tried/used files');
  4497. w(' d : Show debug notes and info, enables -vni');
  4498. w(' q : Show message numbers');
  4499. w(' x : Show used tools');
  4500. w(' v : Write pas2jsdebug.log with lots of debugging info');
  4501. w(' z : Write messages to stderr, -o. still uses stdout.');
  4502. w(' -vm<x>,<y>: Do not show messages numbered <x> and <y>.');
  4503. w(' -? : Show this help');
  4504. w(' -h : Show this help');
  4505. Log.LogLn;
  4506. w('Environment variable PAS2JS_OPTS is parsed after default config and before command line parameters.');
  4507. Log.LogLn;
  4508. w('Macros: Format is $Name, $Name$ or $Name()');
  4509. for i:=0 to ParamMacros.Count-1 do begin
  4510. ParamMacro:=ParamMacros[i];
  4511. Log.LogRaw([' $',ParamMacro.Name,BoolToStr(ParamMacro.CanHaveParams,'()',''),': ',ParamMacro.Description]);
  4512. end;
  4513. end;
  4514. procedure TPas2jsCompiler.WriteLogo;
  4515. begin
  4516. if FHasShownLogo then exit;
  4517. FHasShownLogo:=true;
  4518. WriteVersionLine;
  4519. Log.LogPlain('Copyright (c) 2021 Free Pascal team.');
  4520. if coShowInfos in Options then
  4521. WriteEncoding;
  4522. end;
  4523. procedure TPas2jsCompiler.WriteEncoding;
  4524. begin
  4525. if FHasShownEncoding then exit;
  4526. FHasShownEncoding:=true;
  4527. Log.LogMsgIgnoreFilter(nMessageEncodingIs,[Log.GetEncodingCaption]);
  4528. end;
  4529. procedure TPas2jsCompiler.WriteVersionLine;
  4530. var
  4531. s: String;
  4532. begin
  4533. s:='Pas2JS Compiler version '+GetVersion(false);
  4534. s:=s+' ['+{$i %Date%}+'] for '+{$i %FPCTargetOS%}+' '+{$i %FPCTargetCPU%};
  4535. Log.LogPlain(s);
  4536. if coShowInfos in Options then
  4537. WriteEncoding;
  4538. end;
  4539. procedure TPas2jsCompiler.WriteOptions;
  4540. var
  4541. co: TP2jsCompilerOption;
  4542. fco: TP2jsFSOption;
  4543. ms: TModeSwitch;
  4544. begin
  4545. // message encoding
  4546. WriteEncoding;
  4547. // target platform
  4548. Log.LogMsgIgnoreFilter(nTargetPlatformIs,[PasToJsPlatformNames[TargetPlatform]]);
  4549. Log.LogMsgIgnoreFilter(nTargetProcessorIs,[PasToJsProcessorNames[TargetProcessor]]);
  4550. // syntax mode
  4551. for ms in msAllPas2jsModeSwitches do
  4552. case ms of
  4553. msObjfpc:
  4554. if ms in ModeSwitches then
  4555. Log.LogMsgIgnoreFilter(nSyntaxModeIs,[p2jscModeNames[p2jmObjFPC]]);
  4556. msDelphi:
  4557. if ms in ModeSwitches then
  4558. Log.LogMsgIgnoreFilter(nSyntaxModeIs,[p2jscModeNames[p2jmDelphi]]);
  4559. else
  4560. Log.LogMsgIgnoreFilter(nModeswitchXisY,[SModeSwitchNames[ms],BoolToStr(ms in ModeSwitches,'on','off')]);
  4561. end;
  4562. Log.LogMsgIgnoreFilter(nClassInterfaceStyleIs,[InterfaceTypeNames[InterfaceType]]);
  4563. // boolean options
  4564. for co in TP2jsCompilerOption do
  4565. Log.LogMsgIgnoreFilter(nOptionIsEnabled,
  4566. [p2jscoCaption[co],BoolToStr(co in Options,'enabled','disabled')]);
  4567. for fco in TP2jsFSOption do
  4568. Log.LogMsgIgnoreFilter(nOptionIsEnabled,
  4569. [p2jsfcoCaption[fco],BoolToStr(fco in FS.Options,'enabled','disabled')]);
  4570. // source map options
  4571. if SrcMapEnable then
  4572. begin
  4573. Log.LogMsgIgnoreFilter(nSrcMapSourceRootIs,[QuoteStr(SrcMapSourceRoot)]);
  4574. Log.LogMsgIgnoreFilter(nSrcMapBaseDirIs,[QuoteStr(SrcMapBaseDir)]);
  4575. end;
  4576. end;
  4577. procedure TPas2jsCompiler.WriteDefines;
  4578. var
  4579. i: Integer;
  4580. S: String;
  4581. M: TMacroDef;
  4582. pbi: TPas2JSBuiltInName;
  4583. begin
  4584. for i:=0 to Defines.Count-1 do
  4585. begin
  4586. S:=Defines[i];
  4587. M:=TMacroDef(Defines.Objects[i]);
  4588. if M<>nil then
  4589. Log.Log(mtInfo,SafeFormat(SLogMacroXSetToY,[S,QuoteStr(M.Value)]),nLogMacroXSetToY,'',0,0,false)
  4590. else
  4591. Log.Log(mtInfo,SafeFormat(SLogMacroDefined,[S]),nLogMacroDefined,'',0,0,false)
  4592. end;
  4593. for pbi in TPas2JSBuiltInName do
  4594. if Pas2JSBuiltInNames[pbi]<>ConverterGlobals.BuiltInNames[pbi] then
  4595. begin
  4596. WriteStr(S,pbi);
  4597. S:=copy(S,4,255);
  4598. Log.LogMsgIgnoreFilter(nRTLIdentifierChanged,[QuoteStr(S),
  4599. QuoteStr(Pas2JSBuiltInNames[pbi]),QuoteStr(ConverterGlobals.BuiltInNames[pbi])]);
  4600. end;
  4601. end;
  4602. procedure TPas2jsCompiler.WriteUsedTools;
  4603. begin
  4604. if Assigned(FPostProcessorSupport) then
  4605. FPostProcessorSupport.WriteUsedTools;
  4606. end;
  4607. procedure TPas2jsCompiler.WriteFoldersAndSearchPaths;
  4608. var
  4609. I: integer;
  4610. begin
  4611. Log.LogMsgIgnoreFilter(nNameValue,['Compiler exe',QuoteStr(CompilerExe)]);
  4612. FS.WriteFoldersAndSearchPaths;
  4613. for i:=0 to Namespaces.Count-1 do
  4614. Log.LogMsgIgnoreFilter(nUsingPath,['Unit scope',Namespaces[i]]);
  4615. Log.LogMsgIgnoreFilter(nNameValue,['Output file',QuoteStr(MainJSFile)]);
  4616. end;
  4617. procedure TPas2jsCompiler.WriteInfo;
  4618. var
  4619. Flags: string;
  4620. procedure AppendFlag(const s: string);
  4621. begin
  4622. if s='' then exit;
  4623. if Flags='' then
  4624. Flags:=StringOfChar(' ',Log.Indent)
  4625. else
  4626. Flags:=Flags+',';
  4627. if length(Flags)+length(s)>Log.LineLen then
  4628. begin
  4629. Log.LogPlain(Flags);
  4630. Flags:=StringOfChar(' ',Log.Indent);
  4631. end;
  4632. Flags:=Flags+s;
  4633. end;
  4634. procedure FlushFlags;
  4635. begin
  4636. if Flags='' then exit;
  4637. Log.LogPlain(Flags);
  4638. Flags:='';
  4639. end;
  4640. var
  4641. ms: TModeSwitch;
  4642. begin
  4643. WriteVersionLine;
  4644. Log.LogLn;
  4645. Log.LogPlain('Compiler date : '+GetCompiledDate);
  4646. Log.LogPlain('Compiler CPU target: '+GetCompiledTargetCPU);
  4647. Log.LogLn;
  4648. Log.LogPlain('Supported targets (targets marked with ''{*}'' are under development):');
  4649. Log.LogPlain([' ',PasToJsPlatformNames[PlatformBrowser],': webbrowser']);
  4650. Log.LogPlain([' ',PasToJsPlatformNames[PlatformNodeJS],': Node.js']);
  4651. Log.LogPlain([' ',PasToJsPlatformNames[PlatformElectron],': Electron app']);
  4652. Log.LogLn;
  4653. Log.LogPlain('Supported CPU instruction sets:');
  4654. Log.LogPlain(' ECMAScript5, ECMAScript6');
  4655. Log.LogLn;
  4656. Log.LogPlain('Recognized compiler and RTL features:');
  4657. Flags:='';
  4658. AppendFlag('INITFINAL');
  4659. AppendFlag('RTTI');
  4660. AppendFlag('CLASSES');
  4661. AppendFlag('EXCEPTIONS');
  4662. AppendFlag('EXITCODE');
  4663. AppendFlag('WIDESTRINGS');
  4664. AppendFlag('RANDOM');
  4665. AppendFlag('DYNARRAYS');
  4666. AppendFlag('COMMANDARGS');
  4667. AppendFlag('RESOURCES');
  4668. AppendFlag('UNICODESTRINGS');
  4669. FlushFlags;
  4670. Log.LogLn;
  4671. Log.LogPlain('Recognized modeswitches:');
  4672. Flags:='';
  4673. for ms in (msAllPas2jsModeSwitches-AllLanguageModes) do
  4674. AppendFlag(SModeSwitchNames[ms]);
  4675. FlushFlags;
  4676. Log.LogLn;
  4677. Log.LogPlain('Supported Optimizations:');
  4678. Log.LogPlain(' EnumNumbers');
  4679. Log.LogPlain(' RemoveNotUsedPrivates');
  4680. Log.LogPlain(' ShortRefGlobals');
  4681. Log.LogLn;
  4682. Log.LogPlain('Supported Whole Program Optimizations:');
  4683. Log.LogPlain(' RemoveNotUsedDeclarations');
  4684. Log.LogLn;
  4685. Log.LogPlain('This program comes under the Library GNU General Public License');
  4686. Log.LogPlain('For more information read COPYING.FPC, included in this distribution');
  4687. Log.LogLn;
  4688. Log.LogPlain('Please report bugs in our bug tracker on:');
  4689. Log.LogPlain(' http://bugs.freepascal.org');
  4690. Log.LogLn;
  4691. Log.LogPlain('More information may be found on our WWW pages (including directions');
  4692. Log.LogPlain('for mailing lists useful for asking questions or discussing potential');
  4693. Log.LogPlain('new features, etc.):');
  4694. Log.LogPlain(' http://www.freepascal.org');
  4695. end;
  4696. function TPas2jsCompiler.GetShownMsgTypes: TMessageTypes;
  4697. begin
  4698. Result:=[mtFatal];
  4699. if coShowErrors in FOptions then Include(Result,mtError);
  4700. if coShowWarnings in FOptions then Include(Result,mtWarning);
  4701. if coShowNotes in FOptions then Include(Result,mtNote);
  4702. if coShowHints in FOptions then Include(Result,mtHint);
  4703. if coShowInfos in FOptions then Include(Result,mtInfo);
  4704. if coShowDebug in FOptions then Include(Result,mtDebug);
  4705. end;
  4706. procedure TPas2jsCompiler.SetOption(Flag: TP2jsCompilerOption; Enable: boolean);
  4707. begin
  4708. if Enable then
  4709. Options:=Options+[Flag]
  4710. else
  4711. Options:=Options-[Flag];
  4712. end;
  4713. function TPas2jsCompiler.FindFileWithUnitFilename(UnitFilename: string): TPas2jsCompilerFile;
  4714. begin
  4715. if UnitFilename='' then exit(nil);
  4716. Result:=TPas2jsCompilerFile(FFiles.FindKey(Pointer(UnitFilename)));
  4717. end;
  4718. function TPas2jsCompiler.CreateCompilerFile(const PasFileName,
  4719. PCUFilename: String): TPas2jsCompilerFile;
  4720. begin
  4721. Result:=TPas2jsCompilerFile.Create(Self,PasFileName,PCUFilename);
  4722. end;
  4723. procedure TPas2jsCompiler.LoadModuleFile(UnitFilename, UseUnitName: string; out
  4724. aFile: TPas2jsCompilerFile; isPCU: Boolean);
  4725. // Creates aFile and opens the file, ready for parsing
  4726. // Note: aFile must be an out parameter and not a function result, so it is
  4727. // already set while running
  4728. var
  4729. aPasTree: TPas2jsCompilerResolver;
  4730. ExpUnitFilename: String;
  4731. begin
  4732. aFile:=nil;
  4733. Log.LogMsg(nParsingFile,[FormatPath(UnitFilename)],'',0,0,not (coShowLineNumbers in Options));
  4734. ExpUnitFilename:=UnitFilename;
  4735. if ExpUnitFilename<>'' then
  4736. ExpUnitFilename:=ExpandFileName(ExpUnitFilename);
  4737. aFile:=FindFileWithUnitFilename(ExpUnitFilename);
  4738. if aFile<>nil then exit;
  4739. if (ExpUnitFilename='') or not FS.FileExists(ExpUnitFilename) then
  4740. begin
  4741. if isPCU then
  4742. Log.LogMsg(nUnitFileNotFound,[QuoteStr(UnitFilename)])
  4743. else
  4744. Log.LogMsg(nSourceFileNotFound,[QuoteStr(UnitFilename)]);
  4745. Terminate(ExitCodeFileNotFound);
  4746. end;
  4747. if FS.DirectoryExists(ExpUnitFilename) then
  4748. begin
  4749. Log.LogMsg(nFileIsFolder,[QuoteStr(UnitFilename)]);
  4750. Terminate(ExitCodeFileNotFound);
  4751. end;
  4752. if isPCU then
  4753. aFile:=CreateCompilerFile('',ExpUnitFilename)
  4754. else
  4755. aFile:=CreateCompilerFile(ExpUnitFilename,'');
  4756. if UseUnitName<>'' then
  4757. begin
  4758. {$IFDEF VerboseSetPasUnitName}
  4759. writeln('TPas2jsCompiler.LoadModuleFile File="',aFile.UnitFilename,'" UseUnit="',UseUnitName,'"');
  4760. {$ENDIF}
  4761. if CompareText(ExtractFilenameOnly(UnitFilename),UseUnitName)=0 then
  4762. aFile.PasUnitName:=UseUnitName // e.g. when searching Unit1, found UNIT1.pas, use Unit1
  4763. else
  4764. aFile.PasUnitName:=ExtractFilenameOnly(UnitFilename);
  4765. end;
  4766. FFiles.Add(aFile);
  4767. // do not add here aFile to FUnits
  4768. aFile.ShowDebug:=ShowDebug;
  4769. if aFile.IsMainFile then
  4770. aFile.JSFilename:=GetResolvedMainJSFile;
  4771. // pastree (engine)
  4772. aPasTree:=aFile.PascalResolver;
  4773. if coShowLineNumbers in Options then
  4774. aPasTree.ScannerLogEvents:=aPasTree.ScannerLogEvents+[sleLineNumber];
  4775. if coShowConditionals in Options then
  4776. aPasTree.ScannerLogEvents:=aPasTree.ScannerLogEvents+[sleConditionals];
  4777. if [coShowLineNumbers,coShowInfos,coShowDebug]*Options<>[] then
  4778. aPasTree.ParserLogEvents:=aPasTree.ParserLogEvents+[pleInterface,pleImplementation];
  4779. // scanner
  4780. aFile.ResourceHandler:=FResources;;
  4781. aFile.CreateScannerAndParser(FS.CreateResolver);
  4782. aFile.Scanner.OnLinkLib:=@HandleLinkLibStatement;
  4783. if ShowDebug then
  4784. Log.LogPlain(['Debug: Opening file "',UnitFilename,'"...']);
  4785. if IsPCU then
  4786. begin
  4787. aFile.FileResolver.BaseDirectory:=ExtractFilePath(UnitFilename);
  4788. aFile.PCUSupport.CreatePCUReader;
  4789. end
  4790. else
  4791. begin
  4792. // open file (beware: this changes FileResolver.BaseDirectory)
  4793. aFile.OpenFile(UnitFilename);
  4794. end;
  4795. end;
  4796. function TPas2jsCompiler.FindUnitJSFileName(aFileName: String): String;
  4797. begin
  4798. if AllJSIntoMainJS then
  4799. Result:=GetResolvedMainJSFile
  4800. else
  4801. Result:=FS.FindUnitJSFileName(aFilename);
  4802. end;
  4803. function TPas2jsCompiler.FindLoadedUnit(const TheUnitName: string
  4804. ): TPas2jsCompilerFile;
  4805. begin
  4806. if not IsValidIdent(TheUnitName,true) then exit(nil);
  4807. Result:=TPas2jsCompilerFile(FUnits.FindKey(Pointer(TheUnitName)));
  4808. end;
  4809. procedure TPas2jsCompiler.AddUsedUnit(aFile: TPas2jsCompilerFile);
  4810. var
  4811. OldFile: TPas2jsCompilerFile;
  4812. begin
  4813. if aFile.PasUnitName='' then
  4814. RaiseInternalError(20170504161347,'missing PasUnitName "'+aFile.UnitFilename+'"');
  4815. OldFile:=FindLoadedUnit(aFile.PasUnitName);
  4816. if OldFile<>nil then
  4817. begin
  4818. if OldFile<>aFile then
  4819. RaiseInternalError(20170504161354,'duplicate unit "'+OldFile.PasUnitName+'" "'+aFile.UnitFilename+'" "'+OldFile.UnitFilename+'"');
  4820. end else begin
  4821. FUnits.Add(aFile);
  4822. end;
  4823. end;
  4824. function TPas2jsCompiler.ExpandFileName(const Filename: string): string;
  4825. begin
  4826. Result:=FS.ExpandFileName(Filename);
  4827. end;
  4828. procedure TPas2jsCompiler.InsertCustomJSFiles(aWriter: TPas2JSMapper);
  4829. var
  4830. i: Integer;
  4831. Filename: String;
  4832. FileResolver: TPas2jsFSResolver;
  4833. aFile: TPas2jsFile;
  4834. begin
  4835. if InsertFilenames.Count=0 then exit;
  4836. FileResolver:=FS.CreateResolver;
  4837. try
  4838. for i:=0 to InsertFilenames.Count-1 do begin
  4839. Filename:=FS.FindCustomJSFileName(InsertFilenames[i]);
  4840. if Filename='' then
  4841. begin
  4842. Log.LogMsg(nCustomJSFileNotFound,[InsertFilenames[i]]);
  4843. Terminate(ExitCodeFileNotFound);
  4844. end;
  4845. aFile:=LoadFile(Filename);
  4846. if aFile.Source='' then continue;
  4847. aWriter.WriteFile(aFile.Source,Filename);
  4848. end
  4849. finally
  4850. FileResolver.Free;
  4851. end;
  4852. end;
  4853. procedure TPas2jsCompiler.AppendCustomJSFiles(aWriter: TPas2JSMapper);
  4854. var
  4855. i: Integer;
  4856. Filename: String;
  4857. FileResolver: TPas2jsFSResolver;
  4858. aFile: TPas2jsFile;
  4859. begin
  4860. if AppendFilenames.Count=0 then exit;
  4861. FileResolver:=FS.CreateResolver;
  4862. try
  4863. for i:=0 to AppendFilenames.Count-1 do begin
  4864. Filename:=FS.FindCustomJSFileName(AppendFilenames[i]);
  4865. if Filename='' then
  4866. begin
  4867. Log.LogMsg(nCustomJSFileNotFound,[AppendFilenames[i]]);
  4868. Terminate(ExitCodeFileNotFound);
  4869. end;
  4870. aFile:=LoadFile(Filename);
  4871. if aFile.Source='' then continue;
  4872. aWriter.WriteFile(aFile.Source,Filename);
  4873. end
  4874. finally
  4875. FileResolver.Free;
  4876. end;
  4877. end;
  4878. function TPas2jsCompiler.IndexOfInsertJSFilename(const aFilename: string
  4879. ): integer;
  4880. var
  4881. i: Integer;
  4882. begin
  4883. for i:=0 to FInsertFilenames.Count-1 do
  4884. if FS.SameFileName(aFilename,InsertFilenames[i]) then
  4885. exit(i);
  4886. Result:=-1;
  4887. end;
  4888. procedure TPas2jsCompiler.AddInsertJSFilename(const aFilename: string);
  4889. begin
  4890. if IndexOfInsertJSFilename(aFilename)<0 then
  4891. InsertFilenames.Add(aFilename);
  4892. end;
  4893. procedure TPas2jsCompiler.RemoveInsertJSFilename(const aFilename: string);
  4894. var
  4895. i: Integer;
  4896. begin
  4897. i:=IndexOfInsertJSFilename(aFilename);
  4898. if i>=0 then
  4899. InsertFilenames.Delete(i);
  4900. end;
  4901. function TPas2jsCompiler.IndexOfAppendJSFilename(const aFilename: string
  4902. ): integer;
  4903. var
  4904. i: Integer;
  4905. begin
  4906. for i:=0 to AppendFilenames.Count-1 do
  4907. if FS.SameFileName(aFilename,AppendFilenames[i]) then
  4908. exit(i);
  4909. Result:=-1;
  4910. end;
  4911. procedure TPas2jsCompiler.RemoveAppendJSFilename(const aFilename: string);
  4912. var
  4913. i: Integer;
  4914. begin
  4915. i:=IndexOfAppendJSFilename(aFilename);
  4916. if i>=0 then
  4917. AppendFilenames.Delete(i);
  4918. end;
  4919. procedure TPas2jsCompiler.AddAppendJSFilename(const aFilename: string);
  4920. begin
  4921. if IndexOfAppendJSFilename(aFilename)<0 then
  4922. AppendFilenames.Add(aFilename);
  4923. end;
  4924. function TPas2jsCompiler.GetResolvedMainJSFile: string;
  4925. begin
  4926. if not FMainJSFileIsResolved then
  4927. begin
  4928. FMainJSFileResolved:=ResolvedMainJSFile;
  4929. FMainJSFileIsResolved:=True;
  4930. end;
  4931. Result:=FMainJSFileResolved;
  4932. end;
  4933. function TPas2jsCompiler.GetUnitInfo(UseUnitName, InFileName,
  4934. ModuleDir: String; PCUSupport: TPCUSupport): TFindUnitInfo;
  4935. var
  4936. FoundPasFilename, FoundPasUnitName: string;
  4937. FoundPasIsForeign: Boolean;
  4938. FoundPCUFilename, FoundPCUUnitName: string;
  4939. function TryUnitName(const TestUnitName: string): boolean;
  4940. var
  4941. aFile: TPas2jsCompilerFile;
  4942. begin
  4943. if FoundPasFilename='' then
  4944. begin
  4945. // search loaded units
  4946. aFile:=FindLoadedUnit(TestUnitName);
  4947. if aFile<>nil then
  4948. begin
  4949. if aFile.PasFilename<>'' then
  4950. begin
  4951. FoundPasFilename:=aFile.PasFilename;
  4952. FoundPasUnitName:=TestUnitName;
  4953. end else if Assigned(PCUSupport) and (aFile.PCUFilename<>'')
  4954. and (FoundPCUFilename='') then
  4955. begin
  4956. FoundPCUFilename:=aFile.PCUFilename;
  4957. FoundPCUUnitName:=TestUnitName;
  4958. end;
  4959. end else begin
  4960. // search pas in unit path
  4961. FoundPasFilename:=FS.FindUnitFileName(TestUnitName,'',ModuleDir,FoundPasIsForeign);
  4962. if FoundPasFilename<>'' then
  4963. FoundPasUnitName:=TestUnitName;
  4964. end;
  4965. end;
  4966. if Assigned(PCUSupport) and (FoundPCUFilename='')
  4967. and (FoundPasFilename='') // for now: search pcu only if there is no pas
  4968. then
  4969. begin
  4970. FoundPCUFilename:=PCUSupport.FindPCU(TestUnitName);
  4971. if FoundPCUFilename<>'' then
  4972. FoundPCUUnitName:=TestUnitName;
  4973. end;
  4974. Result:=(FoundPasFilename<>'')
  4975. and (not Assigned(PCUSupport) or (FoundPCUFilename<>''));
  4976. end;
  4977. var
  4978. aNameSpace, DefNameSpace: String;
  4979. i: Integer;
  4980. begin
  4981. //writeln('TPas2jsCompiler.GetUnitInfo ',UseUnitName,' in=',InFileName,' ',GetObjName(PCUSupport));
  4982. Result:=Default(TFindUnitInfo);
  4983. FoundPasFilename:='';
  4984. FoundPasIsForeign:=false;
  4985. FoundPasUnitName:='';
  4986. FoundPCUFilename:='';
  4987. FoundPCUUnitName:='';
  4988. if InFilename='' then
  4989. begin
  4990. CheckUnitAlias(UseUnitName);
  4991. // first search with name as written in module
  4992. if not TryUnitName(UseUnitname) then
  4993. begin
  4994. if Pos('.',UseUnitname)<1 then
  4995. begin
  4996. // generic unit name -> search with namespaces
  4997. // first the cmdline namespaces
  4998. for i:=0 to Namespaces.Count-1 do
  4999. begin
  5000. aNameSpace:=Namespaces[i];
  5001. if aNameSpace='' then continue;
  5002. if TryUnitName(aNameSpace+'.'+UseUnitname) then break;
  5003. end;
  5004. if (FoundPasFilename='') or (FoundPCUFilename='') then
  5005. begin
  5006. // then the default program namespace
  5007. DefNameSpace:=GetDefaultNamespace;
  5008. if DefNameSpace<>'' then
  5009. begin
  5010. i:=Namespaces.Count-1;
  5011. while (i>=0) and not SameText(Namespaces[i],DefNameSpace) do dec(i);
  5012. if i<0 then
  5013. TryUnitName(DefNameSpace+'.'+UseUnitname);
  5014. end;
  5015. end;
  5016. end;
  5017. end
  5018. end else begin
  5019. // search Pascal file with InFilename
  5020. FoundPasFilename:=FS.FindUnitFileName(UseUnitname,InFilename,ModuleDir,FoundPasIsForeign);
  5021. if FoundPasFilename<>'' then
  5022. FoundPasUnitName:=ExtractFilenameOnly(InFilename);
  5023. // Note: at the moment if there is a source do not search for pcu
  5024. // Eventually search for both, load pcu and if that fails unload pcu and load source
  5025. if (FoundPasFilename='') and Assigned(PCUSupport) and (FoundPCUFilename='') then
  5026. begin
  5027. // no pas file -> search pcu
  5028. FoundPCUFilename:=PCUSupport.FindPCU(UseUnitName);
  5029. if FoundPCUFilename<>'' then
  5030. begin
  5031. FoundPCUUnitName:=UseUnitName;
  5032. end;
  5033. end;
  5034. end;
  5035. if (FoundPasFilename='') and (FoundPCUFilename<>'') then
  5036. begin
  5037. Result.FileName:=FoundPCUFilename;
  5038. Result.UnitName:=FoundPCUUnitName;
  5039. Result.isPCU:=True;
  5040. Result.isForeign:=False;
  5041. end else if (FoundPasFileName<>'') then
  5042. begin
  5043. Result.FileName:=FoundPasFilename;
  5044. Result.UnitName:=FoundPasUnitName;
  5045. Result.isPCU:=False;
  5046. Result.isForeign:=FoundPasIsForeign;
  5047. end;
  5048. end;
  5049. procedure TPas2jsCompiler.CheckUnitAlias(var UseUnitName: string);
  5050. begin
  5051. if UseUnitName='' then ;
  5052. end;
  5053. function TPas2jsCompiler.LoadUsedUnit(Info: TLoadUnitInfo;
  5054. Context: TPas2jsCompilerFile): TPas2jsCompilerFile;
  5055. function FindCycle(aFile, SearchFor: TPas2jsCompilerFile;
  5056. var Cycle: TFPList): boolean;
  5057. // Note: when traversing, add every search file to Cycle, to avoid running in circles.
  5058. // When a cycle is detected, clear the Cycle list and build the cycle path
  5059. var
  5060. i: Integer;
  5061. aParent: TPas2jsCompilerFile;
  5062. begin
  5063. Cycle.Add(aFile);
  5064. for i:=0 to aFile.UsedByCount[ubMainSection]-1 do begin
  5065. aParent:=aFile.UsedBy[ubMainSection,i];
  5066. if aParent=SearchFor then
  5067. begin
  5068. // unit cycle found
  5069. Cycle.Clear;
  5070. Cycle.Add(aParent);
  5071. Cycle.Add(aFile);
  5072. exit(true);
  5073. end;
  5074. if Cycle.IndexOf(aParent)>=0 then
  5075. continue;// already searched
  5076. if FindCycle(aParent,SearchFor,Cycle) then
  5077. begin
  5078. Cycle.Add(aFile);
  5079. exit(true);
  5080. end;
  5081. end;
  5082. Result:=false;
  5083. end;
  5084. var
  5085. aFile: TPas2jsCompilerFile;
  5086. procedure CheckCycle;
  5087. var
  5088. i: Integer;
  5089. Cycle: TFPList;
  5090. CyclePath: String;
  5091. begin
  5092. if Context.PasModule.ImplementationSection=nil then
  5093. begin
  5094. // main uses section (e.g. interface or program, not implementation)
  5095. // -> check for cycles
  5096. aFile.FUsedBy[ubMainSection].Add(Context);
  5097. Cycle:=TFPList.Create;
  5098. try
  5099. if FindCycle(aFile,aFile,Cycle) then
  5100. begin
  5101. CyclePath:='';
  5102. for i:=0 to Cycle.Count-1 do begin
  5103. if i>0 then CyclePath+=',';
  5104. CyclePath+=TPas2jsCompilerFile(Cycle[i]).GetModuleName;
  5105. end;
  5106. Context.PascalResolver.RaiseMsg(20180223141537,nUnitCycle,sUnitCycle,[CyclePath],Info.NameExpr);
  5107. end;
  5108. finally
  5109. Cycle.Free;
  5110. end;
  5111. end else begin
  5112. // implementation uses section
  5113. aFile.FUsedBy[ubImplSection].Add(Context);
  5114. end;
  5115. end;
  5116. var
  5117. UseJSFilename: String;
  5118. OtherFile: TPas2jsCompilerFile;
  5119. begin
  5120. Result:=nil;
  5121. aFile:=FindFileWithUnitFilename(Info.UseFilename);
  5122. if aFile<>nil then
  5123. begin
  5124. // known unit
  5125. if (aFile.PasUnitName<>'') and (CompareText(aFile.PasUnitName,Info.UseUnitname)<>0) then
  5126. begin
  5127. Log.LogPlain(['Debug: TPas2jsPasTree.FindUnit unitname MISMATCH aFile.PasUnitname="',aFile.PasUnitName,'"',
  5128. ' Self=',Context.FileResolver.FS.FormatPath(Context.UnitFilename),
  5129. ' Uses=',Info.UseUnitname,
  5130. ' IsForeign=',Context.IsForeign]);
  5131. RaiseInternalError(20170504161412,'TPas2jsPasTree.FindUnit unit name mismatch');
  5132. end;
  5133. CheckCycle;
  5134. end else begin
  5135. // new unit
  5136. if Info.InFilename<>'' then
  5137. begin
  5138. aFile:=FindLoadedUnit(Info.UseUnitname);
  5139. if aFile<>nil then
  5140. begin
  5141. {$IF defined(VerbosePasResolver) or defined(VerbosePas2JS)}
  5142. writeln('TPas2jsCompilerFile.FindUnit in-file unit name duplicate: New=',Info.UseFilename,' Old=',aFile.UnitFilename);
  5143. {$ENDIF}
  5144. Context.PascalResolver.RaiseMsg(20180223141323,nDuplicateFileFound,sDuplicateFileFound,
  5145. [Info.UseFilename,aFile.UnitFilename],Info.InFileExpr);
  5146. end;
  5147. end;
  5148. UseJSFilename:='';
  5149. if (not Context.IsForeign) then
  5150. UseJSFilename:=FindUnitJSFileName(Info.UseFilename);
  5151. // Log.LogPlain(['Debug: TPas2jsPasTree.FindUnit Self=',FileResolver.Cache.FormatPath(UnitFilename),
  5152. // ' Uses=',ActualUnitname,' Found="',FileResolver.Cache.FormatPath(UseFilename),'"',
  5153. // ' IsForeign=',IsForeign,' JSFile="',FileResolver.Cache.FormatPath(useJSFilename),'"']);
  5154. // load Pascal or PCU file
  5155. LoadModuleFile(Info.UseFilename,Info.UseUnitname,aFile,Info.IsPCU);
  5156. // consistency checks
  5157. if aFile.PasUnitName<>Info.UseUnitname then
  5158. RaiseInternalError(20170922143329,'aFile.PasUnitName='+aFile.PasUnitName+' UseUnitname='+Info.UseUnitname);
  5159. if Info.isPCU then
  5160. begin
  5161. if Not FS.SameFileName(aFile.PCUFilename,Info.UseFilename) then
  5162. RaiseInternalError(20180312122331,'aFile.PCUFilename='+aFile.PCUFilename+' UseFilename='+Info.UseFilename);
  5163. end else
  5164. begin
  5165. if Not FS.SameFileName(aFile.UnitFilename,Info.UseFilename) then
  5166. RaiseInternalError(20170922143330,'aFile.UnitFilename='+aFile.UnitFilename+' UseFilename='+Info.UseFilename);
  5167. end;
  5168. if aFile=Context then
  5169. begin
  5170. // unit uses itself -> cycle
  5171. Context.Parser.RaiseParserError(nUnitCycle,[Info.UseUnitname]);
  5172. end;
  5173. // add file to trees
  5174. AddUsedUnit(aFile);
  5175. // consistency checks
  5176. OtherFile:=FindLoadedUnit(Info.UseUnitname);
  5177. if aFile<>OtherFile then
  5178. begin
  5179. if OtherFile=nil then
  5180. RaiseInternalError(20170922143405,'UseUnitname='+Info.UseUnitname)
  5181. else
  5182. RaiseInternalError(20170922143511,'UseUnitname='+Info.UseUnitname+' Found='+OtherFile.PasUnitName);
  5183. end;
  5184. OtherFile:=FindFileWithUnitFilename(Info.UseFilename);
  5185. if aFile<>OtherFile then
  5186. begin
  5187. if OtherFile=nil then
  5188. RaiseInternalError(20180224094625,'UseFilename='+Info.UseFilename)
  5189. else
  5190. RaiseInternalError(20180224094627,'UseFilename='+Info.UseFilename+' Found='+OtherFile.UnitFilename);
  5191. end;
  5192. CheckCycle;
  5193. aFile.JSFilename:=UseJSFilename;
  5194. aFile.IsForeign:=Info.UseIsForeign;
  5195. // read
  5196. aFile.ReadUnit;
  5197. // beware: the parser may not yet have finished
  5198. end;
  5199. Result:=aFile;
  5200. end;
  5201. function TPas2jsCompiler.ResolvedMainJSFile: string;
  5202. Var
  5203. OP,UP: String;
  5204. begin
  5205. OP:=FS.MainOutputPath;
  5206. UP:=FS.UnitOutputPath;
  5207. if MainJSFile='.' then
  5208. Result:=''
  5209. else begin
  5210. Result:=MainJSFile;
  5211. if Result<>'' then
  5212. begin
  5213. // has option -o
  5214. if ExtractFilePath(Result)='' then
  5215. begin
  5216. // -o<FileWithoutPath>
  5217. if OP<>'' then
  5218. Result:=OP+Result
  5219. else if UP<>'' then
  5220. Result:=UP+Result;
  5221. end;
  5222. end else begin
  5223. // no option -o
  5224. Result:=ChangeFileExt(MainSrcFile,'.js');
  5225. if OP<>'' then
  5226. begin
  5227. // option -FE and no -o => put into MainOutputPath
  5228. Result:=OP+ExtractFilename(Result)
  5229. end else if UP<>'' then
  5230. begin
  5231. // option -FU and no -o and no -FE => put into UnitOutputPath
  5232. Result:=UP+ExtractFilename(Result)
  5233. end else begin
  5234. // no -FU, no -FE and no -o => put into source directory
  5235. end;
  5236. end;
  5237. end;
  5238. end;
  5239. end.