pas2jscompiler.pp 178 KB

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