Ver Fonte

* synchronised with trunk till r40466

git-svn-id: branches/debug_eh@40467 -
Jonas Maebe há 6 anos atrás
pai
commit
9630eb7ce9
47 ficheiros alterados com 2055 adições e 1038 exclusões
  1. 7 0
      .gitattributes
  2. 4 1
      compiler/aoptobj.pas
  3. 3 1
      compiler/arm/aoptcpu.pas
  4. 3 1
      compiler/avr/aoptcpu.pas
  5. 1 0
      compiler/compinnr.pas
  6. 1 1
      compiler/globtype.pas
  7. 3 2
      compiler/llvm/nllvmmat.pas
  8. 3 1
      compiler/m68k/aoptcpu.pas
  9. 15 1
      compiler/m68k/n68kinl.pas
  10. 18 4
      compiler/ncginl.pas
  11. 8 1
      compiler/ninl.pas
  12. 1 0
      compiler/nutils.pas
  13. 2 1
      compiler/pexpr.pas
  14. 1 0
      compiler/psystem.pas
  15. 2 2
      compiler/raatt.pas
  16. 7 3
      compiler/x86/aoptx86.pas
  17. 13 1
      packages/pastojs/fpmake.pp
  18. 0 37
      packages/pastojs/src/fppas2js.pp
  19. 5 0
      packages/pastojs/src/pas2js_defines.inc
  20. 205 471
      packages/pastojs/src/pas2jscompiler.pp
  21. 95 0
      packages/pastojs/src/pas2jscompilercfg.pp
  22. 262 0
      packages/pastojs/src/pas2jscompilerpp.pp
  23. 156 264
      packages/pastojs/src/pas2jsfilecache.pp
  24. 0 88
      packages/pastojs/src/pas2jsfileutils.pp
  25. 427 0
      packages/pastojs/src/pas2jsfs.pp
  26. 164 0
      packages/pastojs/src/pas2jsfscompiler.pp
  27. 6 4
      packages/pastojs/src/pas2jslibcompiler.pp
  28. 60 9
      packages/pastojs/src/pas2jslogger.pp
  29. 59 34
      packages/pastojs/src/pas2jspcucompiler.pp
  30. 430 0
      packages/pastojs/src/pas2jsutils.pp
  31. 0 25
      packages/pastojs/tests/tcmodules.pas
  32. 3 3
      packages/pastojs/tests/tcunitsearch.pas
  33. 4 8
      packages/pastojs/tests/testpas2js.lpi
  34. 1 1
      rtl/inc/generic.inc
  35. 2 2
      rtl/inc/innr.inc
  36. 32 0
      rtl/linux/arm/abitag.inc
  37. 0 15
      rtl/linux/arm/cprt0.as
  38. 0 15
      rtl/linux/arm/gprt0.as
  39. 0 15
      rtl/linux/arm/prt0.as
  40. 0 15
      rtl/linux/arm/ucprt0.as
  41. 32 0
      rtl/linux/i386/abitag.inc
  42. 8 0
      rtl/linux/system.pp
  43. 1 1
      tests/test/tmt1.pp
  44. 1 1
      utils/pas2jni/writer.pas
  45. 0 2
      utils/pas2js/docs/translation.html
  46. 4 4
      utils/pas2js/nodepas2js.pp
  47. 6 4
      utils/pas2js/pas2js.pp

+ 7 - 0
.gitattributes

@@ -6994,16 +6994,21 @@ packages/pastojs/src/fppas2js.pp svneol=native#text/plain
 packages/pastojs/src/fppjssrcmap.pp svneol=native#text/plain
 packages/pastojs/src/fppjssrcmap.pp svneol=native#text/plain
 packages/pastojs/src/pas2js_defines.inc svneol=native#text/plain
 packages/pastojs/src/pas2js_defines.inc svneol=native#text/plain
 packages/pastojs/src/pas2jscompiler.pp svneol=native#text/plain
 packages/pastojs/src/pas2jscompiler.pp svneol=native#text/plain
+packages/pastojs/src/pas2jscompilercfg.pp svneol=native#text/plain
+packages/pastojs/src/pas2jscompilerpp.pp svneol=native#text/plain
 packages/pastojs/src/pas2jsfilecache.pp svneol=native#text/plain
 packages/pastojs/src/pas2jsfilecache.pp svneol=native#text/plain
 packages/pastojs/src/pas2jsfiler.pp svneol=native#text/plain
 packages/pastojs/src/pas2jsfiler.pp svneol=native#text/plain
 packages/pastojs/src/pas2jsfileutils.pp svneol=native#text/plain
 packages/pastojs/src/pas2jsfileutils.pp svneol=native#text/plain
 packages/pastojs/src/pas2jsfileutilsnodejs.inc svneol=native#text/plain
 packages/pastojs/src/pas2jsfileutilsnodejs.inc svneol=native#text/plain
 packages/pastojs/src/pas2jsfileutilsunix.inc svneol=native#text/plain
 packages/pastojs/src/pas2jsfileutilsunix.inc svneol=native#text/plain
 packages/pastojs/src/pas2jsfileutilswin.inc svneol=native#text/plain
 packages/pastojs/src/pas2jsfileutilswin.inc svneol=native#text/plain
+packages/pastojs/src/pas2jsfs.pp svneol=native#text/plain
+packages/pastojs/src/pas2jsfscompiler.pp svneol=native#text/plain
 packages/pastojs/src/pas2jslibcompiler.pp svneol=native#text/plain
 packages/pastojs/src/pas2jslibcompiler.pp svneol=native#text/plain
 packages/pastojs/src/pas2jslogger.pp svneol=native#text/plain
 packages/pastojs/src/pas2jslogger.pp svneol=native#text/plain
 packages/pastojs/src/pas2jspcucompiler.pp svneol=native#text/plain
 packages/pastojs/src/pas2jspcucompiler.pp svneol=native#text/plain
 packages/pastojs/src/pas2jspparser.pp svneol=native#text/plain
 packages/pastojs/src/pas2jspparser.pp svneol=native#text/plain
+packages/pastojs/src/pas2jsutils.pp svneol=native#text/plain
 packages/pastojs/tests/tcconverter.pp svneol=native#text/plain
 packages/pastojs/tests/tcconverter.pp svneol=native#text/plain
 packages/pastojs/tests/tcfiler.pas svneol=native#text/plain
 packages/pastojs/tests/tcfiler.pas svneol=native#text/plain
 packages/pastojs/tests/tcmodules.pas svneol=native#text/plain
 packages/pastojs/tests/tcmodules.pas svneol=native#text/plain
@@ -9605,6 +9610,7 @@ rtl/linux/aarch64/stat.inc svneol=native#text/plain
 rtl/linux/aarch64/syscall.inc svneol=native#text/plain
 rtl/linux/aarch64/syscall.inc svneol=native#text/plain
 rtl/linux/aarch64/syscallh.inc svneol=native#text/plain
 rtl/linux/aarch64/syscallh.inc svneol=native#text/plain
 rtl/linux/aarch64/sysnr.inc svneol=native#text/plain
 rtl/linux/aarch64/sysnr.inc svneol=native#text/plain
+rtl/linux/arm/abitag.inc svneol=native#text/plain
 rtl/linux/arm/bsyscall.inc svneol=native#text/plain
 rtl/linux/arm/bsyscall.inc svneol=native#text/plain
 rtl/linux/arm/cprt0.as svneol=native#text/plain
 rtl/linux/arm/cprt0.as svneol=native#text/plain
 rtl/linux/arm/dllprt0.as svneol=native#text/plain
 rtl/linux/arm/dllprt0.as svneol=native#text/plain
@@ -9626,6 +9632,7 @@ rtl/linux/errno.inc svneol=native#text/plain
 rtl/linux/errnostr.inc svneol=native#text/plain
 rtl/linux/errnostr.inc svneol=native#text/plain
 rtl/linux/fpcylix.pp svneol=native#text/plain
 rtl/linux/fpcylix.pp svneol=native#text/plain
 rtl/linux/fpmake.inc svneol=native#text/plain
 rtl/linux/fpmake.inc svneol=native#text/plain
+rtl/linux/i386/abitag.inc svneol=native#text/plain
 rtl/linux/i386/bsyscall.inc svneol=native#text/plain
 rtl/linux/i386/bsyscall.inc svneol=native#text/plain
 rtl/linux/i386/si_c.inc svneol=native#text/plain
 rtl/linux/i386/si_c.inc svneol=native#text/plain
 rtl/linux/i386/si_c21.inc svneol=native#text/plain
 rtl/linux/i386/si_c21.inc svneol=native#text/plain

+ 4 - 1
compiler/aoptobj.pas

@@ -1059,7 +1059,10 @@ Unit AoptObj;
             Top_Reg :
             Top_Reg :
               OpsEqual:=o1.reg=o2.reg;
               OpsEqual:=o1.reg=o2.reg;
             Top_Ref :
             Top_Ref :
-              OpsEqual := references_equal(o1.ref^, o2.ref^);
+              OpsEqual:=
+                references_equal(o1.ref^, o2.ref^) and
+                (o1.ref^.volatility=[]) and
+                (o2.ref^.volatility=[]);
             Top_Const :
             Top_Const :
               OpsEqual:=o1.val=o2.val;
               OpsEqual:=o1.val=o2.val;
             Top_None :
             Top_None :

+ 3 - 1
compiler/arm/aoptcpu.pas

@@ -117,7 +117,9 @@ Implementation
         (r1.signindex = r2.signindex) and
         (r1.signindex = r2.signindex) and
         (r1.shiftimm = r2.shiftimm) and
         (r1.shiftimm = r2.shiftimm) and
         (r1.addressmode = r2.addressmode) and
         (r1.addressmode = r2.addressmode) and
-        (r1.shiftmode = r2.shiftmode);
+        (r1.shiftmode = r2.shiftmode) and
+        (r1.volatility=[]) and
+        (r2.volatility=[]);
     end;
     end;
 
 
   function MatchInstruction(const instr: tai; const op: TCommonAsmOps; const cond: TAsmConds; const postfix: TOpPostfixes): boolean;
   function MatchInstruction(const instr: tai; const op: TCommonAsmOps; const cond: TAsmConds; const postfix: TOpPostfixes): boolean;

+ 3 - 1
compiler/avr/aoptcpu.pas

@@ -75,7 +75,9 @@ Implementation
         (r1.index = r2.index) and (r1.scalefactor = r2.scalefactor) and
         (r1.index = r2.index) and (r1.scalefactor = r2.scalefactor) and
         (r1.symbol=r2.symbol) and (r1.refaddr = r2.refaddr) and
         (r1.symbol=r2.symbol) and (r1.refaddr = r2.refaddr) and
         (r1.relsymbol = r2.relsymbol) and
         (r1.relsymbol = r2.relsymbol) and
-        (r1.addressmode = r2.addressmode);
+        (r1.addressmode = r2.addressmode) and
+        (r1.volatility=[]) and
+        (r2.volatility=[]);
     end;
     end;
 
 
 
 

+ 1 - 0
compiler/compinnr.pas

@@ -117,6 +117,7 @@ type
      in_not_assign_x      = 95,
      in_not_assign_x      = 95,
      in_gettypekind_x     = 96,
      in_gettypekind_x     = 96,
      in_faraddr_x         = 97,
      in_faraddr_x         = 97,
+     in_volatile_x        = 98,
 
 
 { Internal constant functions }
 { Internal constant functions }
      in_const_sqr        = 100,
      in_const_sqr        = 100,

+ 1 - 1
compiler/globtype.pas

@@ -392,7 +392,7 @@ interface
        { switches being applied to all CPUs at the given level }
        { switches being applied to all CPUs at the given level }
        genericlevel1optimizerswitches = [cs_opt_level1,cs_opt_peephole];
        genericlevel1optimizerswitches = [cs_opt_level1,cs_opt_peephole];
        genericlevel2optimizerswitches = [cs_opt_level2,cs_opt_remove_emtpy_proc];
        genericlevel2optimizerswitches = [cs_opt_level2,cs_opt_remove_emtpy_proc];
-       genericlevel3optimizerswitches = [cs_opt_level3,cs_opt_constant_propagate,cs_opt_nodedfa,cs_opt_use_load_modify_store,cs_opt_loopunroll];
+       genericlevel3optimizerswitches = [cs_opt_level3,cs_opt_constant_propagate,cs_opt_nodedfa{$ifndef llvm},cs_opt_use_load_modify_store{$endif},cs_opt_loopunroll];
        genericlevel4optimizerswitches = [cs_opt_level4,cs_opt_reorder_fields,cs_opt_dead_values,cs_opt_fastmath];
        genericlevel4optimizerswitches = [cs_opt_level4,cs_opt_reorder_fields,cs_opt_dead_values,cs_opt_fastmath];
 
 
        { whole program optimizations whose information generation requires
        { whole program optimizations whose information generation requires

+ 3 - 2
compiler/llvm/nllvmmat.pas

@@ -34,6 +34,9 @@ type
     procedure pass_generate_code; override;
     procedure pass_generate_code; override;
   end;
   end;
 
 
+  tllvmshlshrnode = class(tcgshlshrnode)
+  end;
+
   Tllvmunaryminusnode = class(tcgunaryminusnode)
   Tllvmunaryminusnode = class(tcgunaryminusnode)
     procedure emit_float_sign_change(r: tregister; _size : tdef);override;
     procedure emit_float_sign_change(r: tregister; _size : tdef);override;
   end;
   end;
@@ -154,9 +157,7 @@ end;
 
 
 begin
 begin
   cmoddivnode := tllvmmoddivnode;
   cmoddivnode := tllvmmoddivnode;
-(*
   cshlshrnode := tllvmshlshrnode;
   cshlshrnode := tllvmshlshrnode;
-*)
   cnotnode    := tllvmnotnode;
   cnotnode    := tllvmnotnode;
   cunaryminusnode := Tllvmunaryminusnode;
   cunaryminusnode := Tllvmunaryminusnode;
 end.
 end.

+ 3 - 1
compiler/m68k/aoptcpu.pas

@@ -65,7 +65,9 @@ unit aoptcpu;
           (r1.base = r2.base) and
           (r1.base = r2.base) and
           (r1.index = r2.index) and (r1.scalefactor = r2.scalefactor) and
           (r1.index = r2.index) and (r1.scalefactor = r2.scalefactor) and
           (r1.symbol=r2.symbol) and (r1.refaddr = r2.refaddr) and
           (r1.symbol=r2.symbol) and (r1.refaddr = r2.refaddr) and
-          (r1.relsymbol = r2.relsymbol);
+          (r1.relsymbol = r2.relsymbol) and
+          (r1.volatility=[]) and
+          (r2.volatility=[]);
       end;
       end;
 
 
     function MatchOperand(const oper1: TOper; const oper2: TOper): boolean;
     function MatchOperand(const oper1: TOper; const oper2: TOper): boolean;

+ 15 - 1
compiler/m68k/n68kinl.pas

@@ -26,7 +26,7 @@ unit n68kinl;
 interface
 interface
 
 
     uses
     uses
-      node,ninl,ncginl,cpubase;
+      node,ninl,ncginl,symtype,cpubase;
 
 
     type
     type
       t68kinlinenode = class(tcgInlineNode)
       t68kinlinenode = class(tcgInlineNode)
@@ -51,6 +51,8 @@ interface
         procedure second_frac_real; override;
         procedure second_frac_real; override;
         {procedure second_prefetch; override;
         {procedure second_prefetch; override;
         procedure second_abs_long; override;}
         procedure second_abs_long; override;}
+      protected 
+        function second_incdec_tempregdef: tdef; override;
       private
       private
         procedure second_do_operation(op: TAsmOp);
         procedure second_do_operation(op: TAsmOp);
       end;
       end;
@@ -342,6 +344,18 @@ implementation
         eor.l   d1,d2
         eor.l   d1,d2
         sub.l   d1,d2
         sub.l   d1,d2
       }
       }
+
+      function t68kinlinenode.second_incdec_tempregdef: tdef;
+        begin
+          { this kludge results in the increment/decrement value of inc/dec to be loaded
+            always in a datareg, regardless of the target type. This results in significantly
+            better code on m68k, where if the inc/decrement is loaded to an address register
+            for pointers, the compiler will generate a bunch of useless data<->address register
+            shuffling, as it cannot do some operations on address registers (like shifting
+            or multiplication) (KB) }
+          second_incdec_tempregdef:=cgsize_orddef(def_cgsize(left.resultdef));
+        end;
+
 begin
 begin
   cinlinenode:=t68kinlinenode;
   cinlinenode:=t68kinlinenode;
 end.
 end.

+ 18 - 4
compiler/ncginl.pas

@@ -26,7 +26,7 @@ unit ncginl;
 interface
 interface
 
 
     uses
     uses
-       node,ninl;
+       node,ninl,symtype;
 
 
     type
     type
        tcginlinenode = class(tinlinenode)
        tcginlinenode = class(tinlinenode)
@@ -66,6 +66,8 @@ interface
           procedure second_seg; virtual; abstract;
           procedure second_seg; virtual; abstract;
           procedure second_fma; virtual;
           procedure second_fma; virtual;
           procedure second_frac_real; virtual;
           procedure second_frac_real; virtual;
+       protected
+          function  second_incdec_tempregdef: tdef;virtual;
        end;
        end;
 
 
 implementation
 implementation
@@ -73,7 +75,7 @@ implementation
     uses
     uses
       globtype,constexp,
       globtype,constexp,
       verbose,globals,compinnr,
       verbose,globals,compinnr,
-      symconst,symtype,symdef,defutil,
+      symconst,symdef,defutil,
       aasmbase,aasmdata,
       aasmbase,aasmdata,
       cgbase,pass_2,
       cgbase,pass_2,
       cpubase,procinfo,
       cpubase,procinfo,
@@ -162,6 +164,13 @@ implementation
                 if location.loc in [LOC_CREFERENCE,LOC_REFERENCE] then
                 if location.loc in [LOC_CREFERENCE,LOC_REFERENCE] then
                   location.reference.alignment:=resultdef.alignment;
                   location.reference.alignment:=resultdef.alignment;
               end;
               end;
+            in_volatile_x:
+              begin
+                secondpass(tcallparanode(left).left);
+                location:=tcallparanode(left).left.location;
+                if location.loc in [LOC_CREFERENCE,LOC_REFERENCE,LOC_SUBSETREF,LOC_CSUBSETREF] then
+                  location.reference.volatility:=[vol_read,vol_write];
+              end;
 {$ifdef SUPPORT_MMX}
 {$ifdef SUPPORT_MMX}
             in_mmx_pcmpeqb..in_mmx_pcmpgtw:
             in_mmx_pcmpeqb..in_mmx_pcmpgtw:
               begin
               begin
@@ -332,6 +341,11 @@ implementation
 {*****************************************************************************
 {*****************************************************************************
                          INC/DEC GENERIC HANDLING
                          INC/DEC GENERIC HANDLING
 *****************************************************************************}
 *****************************************************************************}
+      function tcginlinenode.second_incdec_tempregdef: tdef;
+        begin
+          second_incdec_tempregdef:=left.resultdef;
+        end;
+
       procedure tcginlinenode.second_IncDec;
       procedure tcginlinenode.second_IncDec;
        const
        const
          addsubop:array[in_inc_x..in_dec_x] of TOpCG=(OP_ADD,OP_SUB);
          addsubop:array[in_inc_x..in_dec_x] of TOpCG=(OP_ADD,OP_SUB);
@@ -382,7 +396,7 @@ implementation
                  addvalue:=addvalue*tpointerconstnode(tcallparanode(tcallparanode(left).right).left).value
                  addvalue:=addvalue*tpointerconstnode(tcallparanode(tcallparanode(left).right).left).value
               else
               else
                 begin
                 begin
-                  hlcg.location_force_reg(current_asmdata.CurrAsmList,tcallparanode(tcallparanode(left).right).left.location,tcallparanode(tcallparanode(left).right).left.resultdef,left.resultdef,addvalue<=1);
+                  hlcg.location_force_reg(current_asmdata.CurrAsmList,tcallparanode(tcallparanode(left).right).left.location,tcallparanode(tcallparanode(left).right).left.resultdef,second_incdec_tempregdef,addvalue<=1);
                   hregister:=tcallparanode(tcallparanode(left).right).left.location.register;
                   hregister:=tcallparanode(tcallparanode(left).right).left.location.register;
 {$ifndef cpu64bitalu}
 {$ifndef cpu64bitalu}
                   hregisterhi:=tcallparanode(tcallparanode(left).right).left.location.register64.reghi;
                   hregisterhi:=tcallparanode(tcallparanode(left).right).left.location.register64.reghi;
@@ -684,7 +698,7 @@ implementation
 
 
         tempreg1:=hlcg.getintregister(current_asmdata.CurrAsmList,left.resultdef);
         tempreg1:=hlcg.getintregister(current_asmdata.CurrAsmList,left.resultdef);
         tempreg2:=hlcg.getintregister(current_asmdata.CurrAsmList,left.resultdef);
         tempreg2:=hlcg.getintregister(current_asmdata.CurrAsmList,left.resultdef);
-	
+
         hlcg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_SAR,left.resultdef,left.resultdef.size*8-1,left.location.register,tempreg1);
         hlcg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_SAR,left.resultdef,left.resultdef.size*8-1,left.location.register,tempreg1);
         hlcg.a_op_reg_reg_reg(current_asmdata.CurrAsmList,OP_XOR,left.resultdef,left.location.register,tempreg1,tempreg2);
         hlcg.a_op_reg_reg_reg(current_asmdata.CurrAsmList,OP_XOR,left.resultdef,left.location.register,tempreg1,tempreg2);
         hlcg.a_op_reg_reg_reg(current_asmdata.CurrAsmlist,OP_SUB,left.resultdef,tempreg1,tempreg2,location.register);
         hlcg.a_op_reg_reg_reg(current_asmdata.CurrAsmlist,OP_SUB,left.resultdef,tempreg1,tempreg2,location.register);

+ 8 - 1
compiler/ninl.pas

@@ -3555,6 +3555,12 @@ implementation
                 begin
                 begin
                   resultdef:=left.resultdef;
                   resultdef:=left.resultdef;
                 end;
                 end;
+              in_volatile_x:
+                begin
+                  resultdef:=left.resultdef;
+                  { volatile only makes sense if the value is in memory }
+                  make_not_regable(left,[ra_addr_regable]);
+                end;
               in_assert_x_y :
               in_assert_x_y :
                 begin
                 begin
                   resultdef:=voidtype;
                   resultdef:=voidtype;
@@ -4044,7 +4050,8 @@ implementation
              expectloc:=LOC_VOID;
              expectloc:=LOC_VOID;
            end;
            end;
          in_aligned_x,
          in_aligned_x,
-         in_unaligned_x:
+         in_unaligned_x,
+         in_volatile_x:
            begin
            begin
              expectloc:=tcallparanode(left).left.expectloc;
              expectloc:=tcallparanode(left).left.expectloc;
            end;
            end;

+ 1 - 0
compiler/nutils.pas

@@ -891,6 +891,7 @@ implementation
                     in_abs_real,
                     in_abs_real,
                     in_aligned_x,
                     in_aligned_x,
                     in_unaligned_x,
                     in_unaligned_x,
+                    in_volatile_x,
                     in_prefetch_var:
                     in_prefetch_var:
                       begin
                       begin
                         inc(result);
                         inc(result);

+ 2 - 1
compiler/pexpr.pas

@@ -515,7 +515,8 @@ implementation
             end;
             end;
 
 
           in_aligned_x,
           in_aligned_x,
-          in_unaligned_x :
+          in_unaligned_x,
+          in_volatile_x:
             begin
             begin
               err:=false;
               err:=false;
               consume(_LKLAMMER);
               consume(_LKLAMMER);

+ 1 - 0
compiler/psystem.pas

@@ -103,6 +103,7 @@ implementation
 {$endif SUPPORT_GET_FRAME}
 {$endif SUPPORT_GET_FRAME}
         systemunit.insert(csyssym.create('Unaligned',in_unaligned_x));
         systemunit.insert(csyssym.create('Unaligned',in_unaligned_x));
         systemunit.insert(csyssym.create('Aligned',in_aligned_x));
         systemunit.insert(csyssym.create('Aligned',in_aligned_x));
+        systemunit.insert(csyssym.create('Volatile',in_volatile_x));
         systemunit.insert(csyssym.create('ObjCSelector',in_objc_selector_x)); { objc only }
         systemunit.insert(csyssym.create('ObjCSelector',in_objc_selector_x)); { objc only }
         systemunit.insert(csyssym.create('ObjCEncode',in_objc_encode_x)); { objc only }
         systemunit.insert(csyssym.create('ObjCEncode',in_objc_encode_x)); { objc only }
         systemunit.insert(csyssym.create('Default',in_default_x));
         systemunit.insert(csyssym.create('Default',in_default_x));

+ 2 - 2
compiler/raatt.pas

@@ -1340,9 +1340,9 @@ unit raatt;
                        if actasmtoken=AS_COMMA then
                        if actasmtoken=AS_COMMA then
                          begin
                          begin
                            Consume(AS_COMMA);
                            Consume(AS_COMMA);
-                           if actasmtoken=AS_MOD then
+                           if (actasmtoken=AS_MOD) or (actasmtoken=AS_AT) then
                              begin
                              begin
-                               Consume(AS_MOD);
+                               Consume(actasmtoken);
                                if actasmtoken=AS_ID then
                                if actasmtoken=AS_ID then
                                  begin
                                  begin
                                    case actasmpattern of
                                    case actasmpattern of

+ 7 - 3
compiler/x86/aoptx86.pas

@@ -218,7 +218,9 @@ unit aoptx86;
           (r1.segment = r2.segment) and (r1.base = r2.base) and
           (r1.segment = r2.segment) and (r1.base = r2.base) and
           (r1.index = r2.index) and (r1.scalefactor = r2.scalefactor) and
           (r1.index = r2.index) and (r1.scalefactor = r2.scalefactor) and
           (r1.symbol=r2.symbol) and (r1.refaddr = r2.refaddr) and
           (r1.symbol=r2.symbol) and (r1.refaddr = r2.refaddr) and
-          (r1.relsymbol = r2.relsymbol);
+          (r1.relsymbol = r2.relsymbol) and
+          (r1.volatility=[]) and
+          (r2.volatility=[]);
       end;
       end;
 
 
 
 
@@ -232,7 +234,8 @@ unit aoptx86;
          ((base=NR_INVALID) or
          ((base=NR_INVALID) or
           (ref.base=base)) and
           (ref.base=base)) and
          ((index=NR_INVALID) or
          ((index=NR_INVALID) or
-          (ref.index=index));
+          (ref.index=index)) and
+         (ref.volatility=[]);
       end;
       end;
 
 
 
 
@@ -245,7 +248,8 @@ unit aoptx86;
          ((base=NR_INVALID) or
          ((base=NR_INVALID) or
           (ref.base=base)) and
           (ref.base=base)) and
          ((index=NR_INVALID) or
          ((index=NR_INVALID) or
-          (ref.index=index));
+          (ref.index=index)) and
+         (ref.volatility=[]);
       end;
       end;
 
 
 
 

+ 13 - 1
packages/pastojs/fpmake.pp

@@ -44,7 +44,11 @@ begin
     T:=P.Targets.AddUnit('fppas2js.pp');
     T:=P.Targets.AddUnit('fppas2js.pp');
       T.ResourceStrings:=true;
       T.ResourceStrings:=true;
     T:=P.Targets.AddUnit('fppjssrcmap.pp');
     T:=P.Targets.AddUnit('fppjssrcmap.pp');
+    T:=P.Targets.AddUnit('pas2jsfs.pp');
+    T:=P.Targets.AddUnit('pas2jsutils.pp');
     T:=P.Targets.AddUnit('pas2jsfilecache.pp');
     T:=P.Targets.AddUnit('pas2jsfilecache.pp');
+      T.Dependencies.AddUnit('pas2jsfs');
+      T.Dependencies.AddUnit('pas2jsutils');
     T:=P.Targets.AddUnit('pas2jsfileutils.pp');
     T:=P.Targets.AddUnit('pas2jsfileutils.pp');
       T.Dependencies.AddInclude('pas2js_defines.inc');
       T.Dependencies.AddInclude('pas2js_defines.inc');
       T.Dependencies.AddInclude('pas2jsfileutilsunix.inc',AllUnixOSes);
       T.Dependencies.AddInclude('pas2jsfileutilsunix.inc',AllUnixOSes);
@@ -52,10 +56,18 @@ begin
     T:=P.Targets.AddUnit('pas2jslogger.pp');
     T:=P.Targets.AddUnit('pas2jslogger.pp');
     T:=P.Targets.AddUnit('pas2jspparser.pp');
     T:=P.Targets.AddUnit('pas2jspparser.pp');
     T:=P.Targets.AddUnit('pas2jscompiler.pp');
     T:=P.Targets.AddUnit('pas2jscompiler.pp');
+    T:=P.Targets.AddUnit('pas2jsfscompiler.pp');
+      T.Dependencies.AddUnit('pas2jscompiler');
     T:=P.Targets.AddUnit('pas2jspcucompiler.pp');
     T:=P.Targets.AddUnit('pas2jspcucompiler.pp');
+      T.Dependencies.AddUnit('pas2jsfscompiler');
+    T:=P.Targets.AddUnit('pas2jscompilercfg.pp');
       T.Dependencies.AddUnit('pas2jscompiler');
       T.Dependencies.AddUnit('pas2jscompiler');
-    T:=P.Targets.AddUnit('pas2jslibcompiler.pp');
+    T:=P.Targets.AddUnit('pas2jscompilerpp.pp');
       T.Dependencies.AddUnit('pas2jscompiler');
       T.Dependencies.AddUnit('pas2jscompiler');
+    T:=P.Targets.AddUnit('pas2jslibcompiler.pp');
+      T.Dependencies.AddUnit('pas2jspcucompiler');
+      T.Dependencies.AddUnit('pas2jscompilercfg');
+      T.Dependencies.AddUnit('pas2jscompilerpp');
 {$ifndef ALLPACKAGES}
 {$ifndef ALLPACKAGES}
     Run;
     Run;
     end;
     end;

+ 0 - 37
packages/pastojs/src/fppas2js.pp

@@ -354,7 +354,6 @@ Works:
 - typecast byte(longword) -> value & $ff
 - typecast byte(longword) -> value & $ff
 - typecast TJSFunction(func)
 - typecast TJSFunction(func)
 - modeswitch OmitRTTI
 - modeswitch OmitRTTI
-- debugger;
 
 
 ToDos:
 ToDos:
 - do not rename property Date
 - do not rename property Date
@@ -1263,11 +1262,8 @@ type
     procedure ComputeBinaryExprRes(Bin: TBinaryExpr; out
     procedure ComputeBinaryExprRes(Bin: TBinaryExpr; out
       ResolvedEl: TPasResolverResult; Flags: TPasResolverComputeFlags;
       ResolvedEl: TPasResolverResult; Flags: TPasResolverComputeFlags;
       var LeftResolved, RightResolved: TPasResolverResult); override;
       var LeftResolved, RightResolved: TPasResolverResult); override;
-    // built-in functions
     procedure BI_TypeInfo_OnGetCallResult(Proc: TResElDataBuiltInProc;
     procedure BI_TypeInfo_OnGetCallResult(Proc: TResElDataBuiltInProc;
       Params: TParamsExpr; out ResolvedEl: TPasResolverResult); override;
       Params: TParamsExpr; out ResolvedEl: TPasResolverResult); override;
-    function BI_Debugger_OnGetCallCompatibility(Proc: TResElDataBuiltInProc;
-      Expr: TPasExpr; RaiseOnError: boolean): integer; virtual;
   public
   public
     constructor Create; reintroduce;
     constructor Create; reintroduce;
     destructor Destroy; override;
     destructor Destroy; override;
@@ -1752,7 +1748,6 @@ type
     Function ConvertBuiltIn_New(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
     Function ConvertBuiltIn_New(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
     Function ConvertBuiltIn_Dispose(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
     Function ConvertBuiltIn_Dispose(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
     Function ConvertBuiltIn_Default(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
     Function ConvertBuiltIn_Default(El: TParamsExpr; AContext: TConvertContext): TJSElement; virtual;
-    Function ConvertBuiltIn_Debugger(El: TPasExpr; AContext: TConvertContext): TJSElement; virtual;
     Function ConvertRecordValues(El: TRecordValues; AContext: TConvertContext): TJSElement; virtual;
     Function ConvertRecordValues(El: TRecordValues; AContext: TConvertContext): TJSElement; virtual;
     Function ConvertSelfExpression(El: TSelfExpr; AContext: TConvertContext): TJSElement; virtual;
     Function ConvertSelfExpression(El: TSelfExpr; AContext: TConvertContext): TJSElement; virtual;
     Function ConvertBinaryExpression(El: TBinaryExpr; AContext: TConvertContext): TJSElement; virtual;
     Function ConvertBinaryExpression(El: TBinaryExpr; AContext: TConvertContext): TJSElement; virtual;
@@ -4236,16 +4231,6 @@ begin
   if Proc=nil then ;
   if Proc=nil then ;
 end;
 end;
 
 
-function TPas2JSResolver.BI_Debugger_OnGetCallCompatibility(
-  Proc: TResElDataBuiltInProc; Expr: TPasExpr; RaiseOnError: boolean): integer;
-// debugger;
-begin
-  if Expr is TParamsExpr then
-    Result:=CheckBuiltInMaxParamCount(Proc,TParamsExpr(Expr),0,RaiseOnError)
-  else
-    Result:=cExact;
-end;
-
 constructor TPas2JSResolver.Create;
 constructor TPas2JSResolver.Create;
 var
 var
   bt: TPas2jsBaseType;
   bt: TPas2jsBaseType;
@@ -4336,9 +4321,6 @@ begin
     AddBaseType(Pas2JSBuiltInNames[pbitnUIntDouble],btUIntDouble);
     AddBaseType(Pas2JSBuiltInNames[pbitnUIntDouble],btUIntDouble);
   if btIntDouble in TheBaseTypes then
   if btIntDouble in TheBaseTypes then
     AddBaseType(Pas2JSBuiltInNames[pbitnIntDouble],btIntDouble);
     AddBaseType(Pas2JSBuiltInNames[pbitnIntDouble],btIntDouble);
-  AddBuiltInProc('Debugger','procedure Debugger',
-      @BI_Debugger_OnGetCallCompatibility,nil,
-      nil,nil,bfCustom,[bipfCanBeStatement]);
 end;
 end;
 
 
 function TPas2JSResolver.CheckTypeCastRes(const FromResolved,
 function TPas2JSResolver.CheckTypeCastRes(const FromResolved,
@@ -7302,12 +7284,6 @@ begin
       bfBreak: Result:=ConvertBuiltInBreak(El,AContext);
       bfBreak: Result:=ConvertBuiltInBreak(El,AContext);
       bfContinue: Result:=ConvertBuiltInContinue(El,AContext);
       bfContinue: Result:=ConvertBuiltInContinue(El,AContext);
       bfExit: Result:=ConvertBuiltIn_Exit(El,AContext);
       bfExit: Result:=ConvertBuiltIn_Exit(El,AContext);
-      bfCustom:
-        case BuiltInProc.Element.Name of
-        'Debugger': Result:=ConvertBuiltIn_Debugger(El,AContext);
-        else
-          RaiseNotSupported(El,AContext,20181126102554,'built in custom proc '+BuiltInProc.Element.Name);
-        end
     else
     else
       RaiseNotSupported(El,AContext,20161130164955,'built in proc '+ResolverBuiltInProcNames[BuiltInProc.BuiltIn]);
       RaiseNotSupported(El,AContext,20161130164955,'built in proc '+ResolverBuiltInProcNames[BuiltInProc.BuiltIn]);
     end;
     end;
@@ -8407,12 +8383,6 @@ begin
             if Result=nil then exit;
             if Result=nil then exit;
             end;
             end;
           bfDefault: Result:=ConvertBuiltIn_Default(El,AContext);
           bfDefault: Result:=ConvertBuiltIn_Default(El,AContext);
-          bfCustom:
-            case BuiltInProc.Element.Name of
-            'Debugger': Result:=ConvertBuiltIn_Debugger(El,AContext);
-            else
-              RaiseNotSupported(El,AContext,20181126101801,'built in custom proc '+BuiltInProc.Element.Name);
-            end;
         else
         else
           RaiseNotSupported(El,AContext,20161130164955,'built in proc '+ResolverBuiltInProcNames[BuiltInProc.BuiltIn]);
           RaiseNotSupported(El,AContext,20161130164955,'built in proc '+ResolverBuiltInProcNames[BuiltInProc.BuiltIn]);
         end;
         end;
@@ -11003,13 +10973,6 @@ begin
     AContext.Resolver.GetResolverResultDescription(ResolvedEl)],Param);
     AContext.Resolver.GetResolverResultDescription(ResolvedEl)],Param);
 end;
 end;
 
 
-function TPasToJSConverter.ConvertBuiltIn_Debugger(El: TPasExpr;
-  AContext: TConvertContext): TJSElement;
-begin
-  Result:=CreateLiteralCustomValue(El,'debugger');
-  if AContext=nil then ;
-end;
-
 function TPasToJSConverter.ConvertRecordValues(El: TRecordValues;
 function TPasToJSConverter.ConvertRecordValues(El: TRecordValues;
   AContext: TConvertContext): TJSElement;
   AContext: TConvertContext): TJSElement;
 var
 var

+ 5 - 0
packages/pastojs/src/pas2js_defines.inc

@@ -19,6 +19,11 @@
   {$DEFINE UTF8_RTL}
   {$DEFINE UTF8_RTL}
   {$DEFINE HasStdErr}
   {$DEFINE HasStdErr}
   {$DEFINE HasPas2jsFiler}
   {$DEFINE HasPas2jsFiler}
+  {$DEFINE HASFILESYSTEM}
+{$ENDIF}
+
+{$IFDEF NODEJS}
+{$DEFINE HASFILESYSTEM}
 {$ENDIF}
 {$ENDIF}
 
 
 
 

Diff do ficheiro suprimidas por serem muito extensas
+ 205 - 471
packages/pastojs/src/pas2jscompiler.pp


+ 95 - 0
packages/pastojs/src/pas2jscompilercfg.pp

@@ -0,0 +1,95 @@
+{
+    This file is part of the Free Component Library (FCL)
+    Copyright (c) 2018  Michael Van Canneyt
+
+    Pascal to Javascript converter class.
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ **********************************************************************
+
+  Abstract:
+    Config file handling for compiler, depends on filesystem.
+}
+unit pas2jscompilercfg;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, pas2JSCompiler, pas2jsfs;
+
+Type
+  TPas2JSFileConfigSupport = Class(TPas2JSConfigSupport)
+    function FindDefaultConfig: String; override;
+    function GetReader(aFileName: string): TSourceLineReader; override;
+  end;
+
+implementation
+
+uses pas2jsfileutils;
+
+function TPas2JSFileConfigSupport.GetReader(aFileName: string): TSourceLineReader;
+
+Var
+  CacheFile: TPas2jsFile;
+
+begin
+  CacheFile:=Compiler.FS.LoadFile(aFilename);
+  Result:=CacheFile.CreateLineReader(true);
+end;
+
+Function TPas2JSFileConfigSupport.FindDefaultConfig : String;
+
+
+  function TryConfig(aFilename: string): boolean;
+  begin
+    Result:=false;
+    if aFilename='' then exit;
+    aFilename:=ExpandFileName(aFilename);
+    if Compiler.ShowDebug or Compiler.ShowTriedUsedFiles then
+      Compiler.Log.LogMsgIgnoreFilter(nConfigFileSearch,[aFilename]);
+    if not Compiler.FS.FileExists(aFilename) then exit;
+    Result:=true;
+  end;
+
+var
+  aFilename: String;
+
+begin
+  // first try HOME directory
+  aFilename:=ChompPathDelim(GetEnvironmentVariablePJ('HOME'));
+  if aFilename<>'' then
+    begin
+    aFilename:=aFilename+PathDelim{$IFDEF UNIX}+'.'{$ENDIF}+DefaultConfigFile;
+    if TryConfig(aFileName) then
+      exit(aFileName);
+    end;
+
+  // then try compiler directory
+  if (Compiler.CompilerExe<>'') then
+  begin
+    aFilename:=ExtractFilePath(Compiler.CompilerExe);
+    if aFilename<>'' then
+    begin
+      aFilename:=IncludeTrailingPathDelimiter(aFilename)+DefaultConfigFile;
+      if TryConfig(aFilename) then
+        exit(aFileName);
+    end;
+  end;
+
+  // finally try global directory
+  {$IFDEF Unix}
+  if TryConfig('/etc/'+DefaultConfigFile) then
+    exit(aFileName);
+  {$ENDIF}
+end;
+
+end.
+

+ 262 - 0
packages/pastojs/src/pas2jscompilerpp.pp

@@ -0,0 +1,262 @@
+{
+    This file is part of the Free Component Library (FCL)
+    Copyright (c) 2018  Michael Van Canneyt
+
+    Pascal to Javascript converter class.
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ **********************************************************************
+
+  Abstract:
+    Pas2JS compiler Preprocessor support. Can depend on filesystem.
+}
+unit pas2jscompilerpp;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, pas2jscompiler, jswriter, FPPJSSrcMap, contnrs;
+
+Type
+
+  { TPas2JSFSPostProcessorSupport }
+
+  TPas2JSFSPostProcessorSupport = Class(TPas2JSPostProcessorSupport)
+  Private
+    FPostProcs: TObjectList;
+    function CmdListAsStr(CmdList: TStrings): string;
+  Public
+    Constructor Create(aCompiler: TPas2JSCompiler); override;
+    Destructor Destroy; override;
+    Procedure Clear; override;
+    Procedure WriteUsedTools; override;
+    Procedure AddPostProcessor(const Cmd: String); override;
+    Procedure CallPostProcessors(const JSFileName: String; aWriter: TPas2JSMapper); override;
+    function Execute(const JSFilename: String; Cmd: TStringList; JS: TJSWriterString): TJSWriterString;
+  end;
+
+implementation
+
+uses process, pas2jslogger, pas2jsutils, pas2jsfileutils;
+
+function TPas2JSFSPostProcessorSupport.CmdListAsStr(CmdList: TStrings): string;
+var
+  i: Integer;
+begin
+  Result:='';
+  for i:=0 to CmdList.Count-1 do
+  begin
+    if Result<>'' then Result+=' ';
+    Result+=QuoteStr(CmdList[i]);
+  end;
+end;
+
+constructor TPas2JSFSPostProcessorSupport.Create(aCompiler: TPas2JSCompiler);
+begin
+  inherited Create(aCompiler);
+  FPostProcs:=TObjectList.Create; // Owns objects
+end;
+
+destructor TPas2JSFSPostProcessorSupport.Destroy;
+begin
+  FreeAndNil(FPostProcs);
+  inherited Destroy;
+end;
+
+procedure TPas2JSFSPostProcessorSupport.Clear;
+begin
+  FPostProcs.Clear;
+end;
+
+procedure TPas2JSFSPostProcessorSupport.WriteUsedTools;
+
+Var
+  I : integer;
+  PostProc : TStringList;
+
+begin
+  // post processors
+  for i:=0 to FPostProcs.Count-1 do
+  begin
+    PostProc:=TStringList(FPostProcs[i]);
+    Compiler.Log.LogMsgIgnoreFilter(nPostProcessorInfoX,[CmdListAsStr(PostProc)]);
+  end;
+end;
+
+procedure TPas2JSFSPostProcessorSupport.AddPostProcessor(const Cmd: String);
+
+Var
+  PostProc : TStringList;
+  S : String;
+
+begin
+  PostProc:=TStringList.Create;
+  FPostProcs.Add(PostProc);
+  SplitCmdLineParams(Cmd,PostProc);
+  if PostProc.Count<1 then
+    Compiler.ParamFatal('-Jpcmd executable missing');
+  // check executable
+  S:=Compiler.FS.ExpandExecutable(PostProc[0]);
+  if (S='') then
+    Compiler.ParamFatal('-Jpcmd executable "'+S+'" not found');
+  PostProc[0]:=S;
+end;
+
+procedure TPas2JSFSPostProcessorSupport.CallPostProcessors(const JSFileName: String; aWriter: TPas2JSMapper);
+
+var
+  i: Integer;
+  JS, OrigJS: TJSWriterString;
+
+begin
+  if FPostProcs.Count=0 then exit;
+  OrigJS:=aWriter.AsString;
+  JS:=OrigJS;
+  for i:=0 to FPostProcs.Count-1 do
+    JS:=Execute(JSFilename,TStringList(FPostProcs[i]),JS);
+  if JS<>OrigJS then
+  begin
+    aWriter.AsString:=JS;
+    if aWriter.SrcMap<>nil then
+      aWriter.SrcMap.Clear;
+  end;
+
+end;
+
+function TPas2JSFSPostProcessorSupport.Execute(const JSFilename: String; Cmd: TStringList; JS: TJSWriterString): TJSWriterString;
+
+const
+  BufSize = 65536;
+var
+  Exe: String;
+  TheProcess: TProcess;
+  WrittenBytes, ReadBytes: LongInt;
+  Buf, s, ErrBuf: string;
+  OutputChunks: TStringList;
+  CurExitCode, i, InPos: Integer;
+begin
+  Result:='';
+  Buf:='';
+  Exe:=Cmd[0];
+  if Compiler.ShowDebug or Compiler.ShowUsedTools then
+    Compiler.Log.LogMsgIgnoreFilter(nPostProcessorRunX,[QuoteStr(JSFilename)+' | '+CmdListAsStr(Cmd)]);
+  if Compiler.FS.DirectoryExists(Exe) then
+    raise EFOpenError.Create('post processor "'+Exe+'" is a directory');
+  if not FileIsExecutable(Exe) then
+    raise EFOpenError.Create('post processor "'+Exe+'" is a not executable');
+  try
+    TheProcess := TProcess.Create(nil);
+    OutputChunks:=TStringList.Create;
+    try
+      TheProcess.Executable := Exe;
+      for i:=1 to Cmd.Count-1 do
+        TheProcess.Parameters.Add(Cmd[i]);
+      TheProcess.Options:= [poUsePipes];
+      TheProcess.ShowWindow := swoHide;
+      //TheProcess.CurrentDirectory:=WorkingDirectory;
+      TheProcess.Execute;
+      ErrBuf:='';
+      SetLength(Buf,BufSize);
+      InPos:=1;
+      repeat
+        // read stderr and log immediately as warnings
+        repeat
+          if TheProcess.Stderr.NumBytesAvailable=0 then break;
+          ReadBytes:=TheProcess.Stderr.Read(Buf[1],BufSize);
+          if ReadBytes=0 then break;
+          ErrBuf+=LeftStr(Buf,ReadBytes);
+          repeat
+            i:=1;
+            while (i<=length(ErrBuf)) and (i<128) and not (ErrBuf[i] in [#10,#13]) do
+              inc(i);
+            if i>length(ErrBuf) then break;
+            Compiler.Log.LogMsg(nPostProcessorWarnX,[LeftStr(ErrBuf,i)]);
+            if (i<=length(ErrBuf)) and (ErrBuf[i] in [#10,#13]) then
+            begin
+              // skip linebreak
+              if (i<length(ErrBuf)) and (ErrBuf[i+1] in [#10,#13])
+                  and (ErrBuf[i]<>ErrBuf[i+1]) then
+                inc(i,2)
+              else
+                inc(i);
+            end;
+            Delete(ErrBuf,1,i-1);
+          until false;
+        until false;
+        // write to stdin
+        if InPos<length(JS) then
+        begin
+          i:=length(JS)-InPos+1;
+          if i>BufSize then i:=BufSize;
+          WrittenBytes:=TheProcess.Input.Write(JS[InPos],i);
+          inc(InPos,WrittenBytes);
+          if InPos>length(JS) then
+            TheProcess.CloseInput;
+        end else
+          WrittenBytes:=0;
+        // read stdout
+        if TheProcess.Output.NumBytesAvailable=0 then
+          ReadBytes:=0
+        else
+          ReadBytes:=TheProcess.Output.Read(Buf[1],BufSize);
+        if ReadBytes>0 then
+          OutputChunks.Add(LeftStr(Buf,ReadBytes));
+
+        if (WrittenBytes=0) and (ReadBytes=0) then
+        begin
+          if not TheProcess.Running then break;
+          Sleep(10); // give tool some time
+        end;
+      until false;
+      TheProcess.WaitOnExit;
+      CurExitCode:=TheProcess.ExitCode;
+
+      // concatenate output chunks
+      ReadBytes:=0;
+      for i:=0 to OutputChunks.Count-1 do
+        inc(ReadBytes,length(OutputChunks[i]));
+      SetLength(Result,ReadBytes);
+      ReadBytes:=0;
+      for i:=0 to OutputChunks.Count-1 do
+      begin
+        s:=OutputChunks[i];
+        if s='' then continue;
+        System.Move(s[1],Result[ReadBytes+1],length(s));
+        inc(ReadBytes,length(s));
+      end;
+    finally
+      OutputChunks.Free;
+      TheProcess.Free;
+    end;
+  except
+    on E: Exception do begin
+      if Compiler.ShowDebug then
+        Compiler.Log.LogExceptionBackTrace(E);
+      Compiler.Log.LogPlain('Error: '+E.Message);
+      Compiler.Log.LogMsg(nPostProcessorFailX,[CmdListAsStr(Cmd)]);
+      Compiler.Terminate(ExitCodeToolError);
+    end
+    {$IFDEF Pas2js}
+    else HandleJSException('[20181118170506] TPas2jsCompiler.CallPostProcessor Cmd: '+CmdListAsStr(Cmd),JSExceptValue,true);
+    {$ENDIF}
+  end;
+  if CurExitCode<>0 then
+  begin
+    Compiler.Log.LogMsg(nPostProcessorFailX,[CmdListAsStr(Cmd)]);
+    Compiler.Terminate(ExitCodeToolError);
+  end;
+  if Compiler.ShowDebug or Compiler.ShowUsedTools then
+    Compiler.Log.LogMsgIgnoreFilter(nPostProcessorFinished,[]);
+end;
+
+
+end.
+

+ 156 - 264
packages/pastojs/src/pas2jsfilecache.pp

@@ -32,20 +32,11 @@ uses
   {$ENDIF}
   {$ENDIF}
   Classes, SysUtils,
   Classes, SysUtils,
   fpjson,
   fpjson,
-  PScanner, PasUseAnalyzer, PasResolver, Pas2jsLogger, Pas2jsFileUtils;
-
-const // Messages
-  nIncludeSearch = 201; sIncludeSearch = 'Include file search: %s';
-  nUnitSearch = 202; sUnitSearch = 'Unitsearch: %s';
-  nSearchingFileFound = 203; sSearchingFileFound = 'Searching file: %s... found';
-  nSearchingFileNotFound = 204; sSearchingFileNotFound = 'Searching file: %s... not found';
-  nDuplicateFileFound = 205; sDuplicateFileFound = 'Duplicate file found: "%s" and "%s"';
-  nCustomJSFileNotFound = 206; sCustomJSFileNotFound = 'custom JS file not found: "%s"';
-  nUsingPath = 104; sUsingPath = 'Using %s: "%s"';
-  nFolderNotFound = 105; sFolderNotFound = '%s not found: %s';
+  PScanner, PasUseAnalyzer, PasResolver, Pas2jsLogger, Pas2jsFileUtils, pas2jsfs;
+
 
 
 type
 type
-  EPas2jsFileCache = class(Exception);
+  EPas2jsFileCache = class(EPas2JSFS);
 
 
 type
 type
   TPas2jsFileAgeTime = longint;
   TPas2jsFileAgeTime = longint;
@@ -87,7 +78,7 @@ type
     function Count: integer;
     function Count: integer;
     procedure Clear;
     procedure Clear;
     property ChangeStamp: TChangeStamp read FChangeStamp write FChangeStamp;// set on Update to Pool.ChangeStamp
     property ChangeStamp: TChangeStamp read FChangeStamp write FChangeStamp;// set on Update to Pool.ChangeStamp
-    function NeedsUpdate: boolean; inline;
+    function NeedsUpdate: boolean;
     procedure Update;
     procedure Update;
     procedure Reference;
     procedure Reference;
     procedure Release;
     procedure Release;
@@ -159,93 +150,58 @@ type
     property OnReadDirectory: TReadDirectoryEvent read FOnReadDirectory write FOnReadDirectory;
     property OnReadDirectory: TReadDirectoryEvent read FOnReadDirectory write FOnReadDirectory;
   end;
   end;
 
 
-type
-  TP2jsFileCacheOption = (
-    caoShowFullFilenames,
-    caoShowTriedUsedFiles,
-    caoSearchLikeFPC,
-    caoStrictFileCase
-    );
-  TP2jsFileCacheOptions = set of TP2jsFileCacheOption;
-
-const
-  DefaultPas2jsFileCacheOptions = [];
-
-  p2jsfcoCaption: array[TP2jsFileCacheOption] of string = (
-    // only used by experts, no need for resourcestrings
-    'Show full filenames',
-    'Show tried/used files',
-    'Search files like FPC',
-    'Strict file case'
-    );
-  // 'Combine all JavaScript into main file',
-
-  EncodingBinary = 'Binary';
 type
 type
   TPas2jsFilesCache = class;
   TPas2jsFilesCache = class;
   TPas2jsCachedFile = class;
   TPas2jsCachedFile = class;
 
 
   { TPas2jsFileResolver }
   { TPas2jsFileResolver }
 
 
-  TPas2jsFileResolver = class(TFileResolver)
+  TPas2jsFileResolver = class(TPas2JSFSResolver)
   private
   private
-    FCache: TPas2jsFilesCache;
+    function GetCache: TPas2jsFilesCache;
   public
   public
     constructor Create(aCache: TPas2jsFilesCache); reintroduce;
     constructor Create(aCache: TPas2jsFilesCache); reintroduce;
     // Redirect all calls to cache.
     // Redirect all calls to cache.
-    function FindIncludeFileName(const aFilename: string): String; override;
-    function FindIncludeFile(const aFilename: string): TLineReader; override;
-    function FindSourceFile(const aFilename: string): TLineReader; override;
-    property Cache: TPas2jsFilesCache read FCache;
+    property Cache: TPas2jsFilesCache read GetCache;
   end;
   end;
 
 
   { TPas2jsFileLineReader }
   { TPas2jsFileLineReader }
 
 
-  TPas2jsFileLineReader = class(TLineReader)
+  TPas2jsFileLineReader = class(TSourceLineReader)
   private
   private
     FCachedFile: TPas2jsCachedFile;
     FCachedFile: TPas2jsCachedFile;
-    FIsEOF: boolean;
-    FLineNumber: integer;
-    FSource: string;
-    FSrcPos: integer;
+  Protected
+    Procedure IncLineNumber; override;
+    property CachedFile: TPas2jsCachedFile read FCachedFile;
   public
   public
     constructor Create(const AFilename: string); override;
     constructor Create(const AFilename: string); override;
     constructor Create(aFile: TPas2jsCachedFile); reintroduce;
     constructor Create(aFile: TPas2jsCachedFile); reintroduce;
-    function IsEOF: Boolean; override;
-    function ReadLine: string; override;
-    property LineNumber: integer read FLineNumber;
-    property CachedFile: TPas2jsCachedFile read FCachedFile;
-    property Source: string read FSource;
-    property SrcPos: integer read FSrcPos;
   end;
   end;
 
 
   { TPas2jsCachedFile }
   { TPas2jsCachedFile }
 
 
-  TPas2jsCachedFile = class
+  TPas2jsCachedFile = class(TPas2JSFile)
   private
   private
-    FCache: TPas2jsFilesCache;
     FChangeStamp: TChangeStamp;
     FChangeStamp: TChangeStamp;
     FFileEncoding: string;
     FFileEncoding: string;
-    FFilename: string;
     FLastErrorMsg: string;
     FLastErrorMsg: string;
     FLoaded: boolean;
     FLoaded: boolean;
     FLoadedFileAge: longint;
     FLoadedFileAge: longint;
-    FSource: string;
     FCacheStamp: TChangeStamp; // Cache.ResetStamp when file was loaded
     FCacheStamp: TChangeStamp; // Cache.ResetStamp when file was loaded
+    function GetCache: TPas2jsFilesCache;
     function GetIsBinary: boolean; inline;
     function GetIsBinary: boolean; inline;
-  public
-    constructor Create(aCache: TPas2jsFilesCache; const aFilename: string); reintroduce;
-    function Load(RaiseOnError: boolean; Binary: boolean = false): boolean;
-    function CreateLineReader(RaiseOnError: boolean): TPas2jsFileLineReader;
+  Protected
     property IsBinary: boolean read GetIsBinary;
     property IsBinary: boolean read GetIsBinary;
     property FileEncoding: string read FFileEncoding;
     property FileEncoding: string read FFileEncoding;
-    property Filename: string read FFilename;
-    property Source: string read FSource; // UTF-8 without BOM or Binary
-    property Cache: TPas2jsFilesCache read FCache;
+    property Cache: TPas2jsFilesCache read GetCache;
     property ChangeStamp: TChangeStamp read FChangeStamp;// changed when Source changed
     property ChangeStamp: TChangeStamp read FChangeStamp;// changed when Source changed
     property Loaded: boolean read FLoaded; // Source valid, but may contain an old version
     property Loaded: boolean read FLoaded; // Source valid, but may contain an old version
     property LastErrorMsg: string read FLastErrorMsg;
     property LastErrorMsg: string read FLastErrorMsg;
     property LoadedFileAge: longint read FLoadedFileAge;// only valid if Loaded=true
     property LoadedFileAge: longint read FLoadedFileAge;// only valid if Loaded=true
+  public
+    constructor Create(aCache: TPas2jsFilesCache; const aFilename: string); reintroduce;
+    function Load(RaiseOnError: boolean; Binary: boolean = false): boolean; override;
+    function CreateLineReader(RaiseOnError: boolean): TSourceLineReader; override;
   end;
   end;
 
 
   TPas2jsReadFileEvent = function(aFilename: string; var aSource: string): boolean of object;
   TPas2jsReadFileEvent = function(aFilename: string; var aSource: string): boolean of object;
@@ -258,10 +214,9 @@ type
 
 
   { TPas2jsFilesCache }
   { TPas2jsFilesCache }
 
 
-  TPas2jsFilesCache = class
+  TPas2jsFilesCache = class (TPas2JSFS)
   private
   private
     FBaseDirectory: string;
     FBaseDirectory: string;
-    FDefaultOutputPath: string;
     FDirectoryCache: TPas2jsCachedDirectories;
     FDirectoryCache: TPas2jsCachedDirectories;
     FFiles: TPasAnalyzerKeySet; // set of TPas2jsCachedFile, key is Filename
     FFiles: TPasAnalyzerKeySet; // set of TPas2jsCachedFile, key is Filename
     FForeignUnitPaths: TStringList;
     FForeignUnitPaths: TStringList;
@@ -269,19 +224,14 @@ type
     FIncludePaths: TStringList;
     FIncludePaths: TStringList;
     FIncludePathsFromCmdLine: integer;
     FIncludePathsFromCmdLine: integer;
     FLog: TPas2jsLogger;
     FLog: TPas2jsLogger;
-    FNamespaces: TStringList;
-    FNamespacesFromCmdLine: integer;
     FOnReadFile: TPas2jsReadFileEvent;
     FOnReadFile: TPas2jsReadFileEvent;
     FOnWriteFile: TPas2jsWriteFileEvent;
     FOnWriteFile: TPas2jsWriteFileEvent;
-    FOptions: TP2jsFileCacheOptions;
-    FReadLineCounter: SizeInt;
     FResetStamp: TChangeStamp;
     FResetStamp: TChangeStamp;
-    FUnitOutputPath: string;
     FUnitPaths: TStringList;
     FUnitPaths: TStringList;
     FUnitPathsFromCmdLine: integer;
     FUnitPathsFromCmdLine: integer;
     function FileExistsILogged(var Filename: string): integer;
     function FileExistsILogged(var Filename: string): integer;
     function FileExistsLogged(const Filename: string): boolean;
     function FileExistsLogged(const Filename: string): boolean;
-    function FindSourceFileName(const aFilename: string): String;
+    function GetOnReadDirectory: TReadDirectoryEvent;
     function GetSearchLikeFPC: boolean;
     function GetSearchLikeFPC: boolean;
     function GetShowFullFilenames: boolean;
     function GetShowFullFilenames: boolean;
     function GetShowTriedUsedFiles: boolean;
     function GetShowTriedUsedFiles: boolean;
@@ -290,70 +240,66 @@ type
     procedure SetBaseDirectory(AValue: string);
     procedure SetBaseDirectory(AValue: string);
     function AddSearchPaths(const Paths: string; Kind: TPas2jsSearchPathKind;
     function AddSearchPaths(const Paths: string; Kind: TPas2jsSearchPathKind;
       FromCmdLine: boolean; var List: TStringList; var CmdLineCount: integer): string;
       FromCmdLine: boolean; var List: TStringList; var CmdLineCount: integer): string;
-    procedure SetDefaultOutputPath(AValue: string);
-    procedure SetOptions(AValue: TP2jsFileCacheOptions);
+    procedure SetOnReadDirectory(AValue: TReadDirectoryEvent);
     procedure SetSearchLikeFPC(const AValue: boolean);
     procedure SetSearchLikeFPC(const AValue: boolean);
     procedure SetShowFullFilenames(const AValue: boolean);
     procedure SetShowFullFilenames(const AValue: boolean);
     procedure SetShowTriedUsedFiles(const AValue: boolean);
     procedure SetShowTriedUsedFiles(const AValue: boolean);
     procedure SetStrictFileCase(AValue: Boolean);
     procedure SetStrictFileCase(AValue: Boolean);
-    procedure SetUnitOutputPath(AValue: string);
-    procedure SetOption(Flag: TP2jsFileCacheOption; Enable: boolean);
   protected
   protected
+    function FindSourceFileName(const aFilename: string): String; override;
     function GetHasPCUSupport: Boolean; virtual;
     function GetHasPCUSupport: Boolean; virtual;
     function ReadFile(Filename: string; var Source: string): boolean; virtual;
     function ReadFile(Filename: string; var Source: string): boolean; virtual;
     procedure FindMatchingFiles(Mask: string; MaxCount: integer; Files: TStrings);// find files, matching * and ?
     procedure FindMatchingFiles(Mask: string; MaxCount: integer; Files: TStrings);// find files, matching * and ?
   public
   public
-    constructor Create(aLog: TPas2jsLogger);
+    constructor Create(aLog: TPas2jsLogger); overload;
     destructor Destroy; override;
     destructor Destroy; override;
-    procedure Reset; virtual;
-    procedure WriteFoldersAndSearchPaths; virtual;
+    procedure Reset; override;
+    procedure WriteFoldersAndSearchPaths; override;
+    procedure GetPCUDirs(aList: TStrings; const aBaseDir: String); override;
+    Function SameFileName(Const File1,File2 : String) : Boolean;  override;
+    Function File1IsNewer(const File1, File2: String): Boolean; override;
     function SearchLowUpCase(var Filename: string): boolean;
     function SearchLowUpCase(var Filename: string): boolean;
-    function FindCustomJSFileName(const aFilename: string): String;
-    function FindUnitJSFileName(const aUnitFilename: string): String;
-    function FindUnitFileName(const aUnitname, InFilename: string; out IsForeign: boolean): String; virtual;
-    function FindIncludeFileName(const aFilename: string): String; virtual;
+    function FindCustomJSFileName(const aFilename: string): String; override;
+    function FindUnitJSFileName(const aUnitFilename: string): String; override;
+    function FindUnitFileName(const aUnitname, InFilename: string; out IsForeign: boolean): String; override;
+    function FindIncludeFileName(const aFilename: string): String; override;
     function AddIncludePaths(const Paths: string; FromCmdLine: boolean; out ErrorMsg: string): boolean;
     function AddIncludePaths(const Paths: string; FromCmdLine: boolean; out ErrorMsg: string): boolean;
-    function AddNamespaces(const Paths: string; FromCmdLine: boolean; out ErrorMsg: string): boolean;
     function AddUnitPaths(const Paths: string; FromCmdLine: boolean; out ErrorMsg: string): boolean;
     function AddUnitPaths(const Paths: string; FromCmdLine: boolean; out ErrorMsg: string): boolean;
     function AddSrcUnitPaths(const Paths: string; FromCmdLine: boolean; out ErrorMsg: string): boolean;
     function AddSrcUnitPaths(const Paths: string; FromCmdLine: boolean; out ErrorMsg: string): boolean;
-    function CreateResolver: TPas2jsFileResolver;
-    function FormatPath(const aPath: string): string;
-    Function DirectoryExists(Filename: string): boolean; virtual;
-    function FileExists(Filename: string): boolean; virtual;
+    function CreateResolver: TPas2jsFSResolver; override;
+    function FormatPath(const aPath: string): string; override;
+    Function DirectoryExists(Const Filename: string): boolean; override;
+    function FileExists(const Filename: string): boolean; override;
     function FileExistsI(var Filename: string): integer; // returns number of found files
     function FileExistsI(var Filename: string): integer; // returns number of found files
     function FileAge(const Filename: string): TPas2jsFileAgeTime; virtual;
     function FileAge(const Filename: string): TPas2jsFileAgeTime; virtual;
     function FindFile(Filename: string): TPas2jsCachedFile;
     function FindFile(Filename: string): TPas2jsCachedFile;
-    function LoadFile(Filename: string; Binary: boolean = false): TPas2jsCachedFile;
+    function LoadFile(Filename: string; Binary: boolean = false): TPas2jsFile; override;
     function NormalizeFilename(const Filename: string; RaiseOnError: boolean): string;
     function NormalizeFilename(const Filename: string; RaiseOnError: boolean): string;
     procedure GetListing(const aDirectory: string; var Files: TStrings;
     procedure GetListing(const aDirectory: string; var Files: TStrings;
                          FullPaths: boolean = true);
                          FullPaths: boolean = true);
     procedure RaiseDuplicateFile(aFilename: string);
     procedure RaiseDuplicateFile(aFilename: string);
-    procedure SaveToFile(ms: TFPJSStream; Filename: string);
-    function ExpandDirectory(const Filename, BaseDir: string): string;
-    function ExpandExecutable(const Filename, BaseDir: string): string;
+    procedure SaveToFile(ms: TFPJSStream; Filename: string); override;
+    function ExpandDirectory(const Filename: string): string; override;
+    function ExpandFileName(const Filename: string): string; override;
+    function ExpandExecutable(const Filename: string): string; override;
+    function HandleOptionPaths(C: Char; aValue: String; FromCmdLine: Boolean): String; override;
+    Function AddForeignUnitPath(const aValue: String; FromCmdLine: Boolean): String; override;
+    function TryCreateRelativePath(const Filename, BaseDirectory: String; UsePointDirectory: boolean; out RelPath: String): Boolean; override;
+  Protected
+    property DirectoryCache: TPas2jsCachedDirectories read FDirectoryCache;
   public
   public
     property BaseDirectory: string read FBaseDirectory write SetBaseDirectory; // includes trailing pathdelim
     property BaseDirectory: string read FBaseDirectory write SetBaseDirectory; // includes trailing pathdelim
-    property MainOutputPath: string read FDefaultOutputPath write SetDefaultOutputPath; // includes trailing pathdelim
-    property DirectoryCache: TPas2jsCachedDirectories read FDirectoryCache;
     property ForeignUnitPaths: TStringList read FForeignUnitPaths;
     property ForeignUnitPaths: TStringList read FForeignUnitPaths;
     property ForeignUnitPathsFromCmdLine: integer read FForeignUnitPathsFromCmdLine;
     property ForeignUnitPathsFromCmdLine: integer read FForeignUnitPathsFromCmdLine;
     property IncludePaths: TStringList read FIncludePaths;
     property IncludePaths: TStringList read FIncludePaths;
     property IncludePathsFromCmdLine: integer read FIncludePathsFromCmdLine;
     property IncludePathsFromCmdLine: integer read FIncludePathsFromCmdLine;
     property Log: TPas2jsLogger read FLog;
     property Log: TPas2jsLogger read FLog;
-    property Namespaces: TStringList read FNamespaces;
-    property NamespacesFromCmdLine: integer read FNamespacesFromCmdLine;
-    property Options: TP2jsFileCacheOptions read FOptions write SetOptions default DefaultPas2jsFileCacheOptions;
-    property ReadLineCounter: SizeInt read FReadLineCounter write FReadLineCounter;
     property ResetStamp: TChangeStamp read FResetStamp;
     property ResetStamp: TChangeStamp read FResetStamp;
-    property SearchLikeFPC: boolean read GetSearchLikeFPC write SetSearchLikeFPC;
-    property ShowFullPaths: boolean read GetShowFullFilenames write SetShowFullFilenames;
-    property ShowTriedUsedFiles: boolean read GetShowTriedUsedFiles write SetShowTriedUsedFiles;
-    property UnitOutputPath: string read FUnitOutputPath write SetUnitOutputPath; // includes trailing pathdelim
     property UnitPaths: TStringList read FUnitPaths;
     property UnitPaths: TStringList read FUnitPaths;
     property UnitPathsFromCmdLine: integer read FUnitPathsFromCmdLine;
     property UnitPathsFromCmdLine: integer read FUnitPathsFromCmdLine;
+    property OnReadDirectory: TReadDirectoryEvent read GetOnReadDirectory write SetOnReadDirectory;
     property OnReadFile: TPas2jsReadFileEvent read FOnReadFile write FOnReadFile;
     property OnReadFile: TPas2jsReadFileEvent read FOnReadFile write FOnReadFile;
     property OnWriteFile: TPas2jsWriteFileEvent read FOnWriteFile write FOnWriteFile;
     property OnWriteFile: TPas2jsWriteFileEvent read FOnWriteFile write FOnWriteFile;
-    Property StrictFileCase : Boolean Read GetStrictFileCase Write SetStrictFileCase;
   end;
   end;
 
 
 
 
@@ -409,6 +355,7 @@ var
 begin
 begin
   Result:=FilenameToKey(Dir.Path);
   Result:=FilenameToKey(Dir.Path);
 end;
 end;
+
 {$ELSE}
 {$ELSE}
 function CompareFilenameWithCachedFile(Filename, CachedFile: Pointer): integer;
 function CompareFilenameWithCachedFile(Filename, CachedFile: Pointer): integer;
 var
 var
@@ -439,6 +386,7 @@ var
 begin
 begin
   Result:=CompareFilenames(AnsiString(Path),Directory.Path);
   Result:=CompareFilenames(AnsiString(Path),Directory.Path);
 end;
 end;
+
 {$ENDIF}
 {$ENDIF}
 
 
 function ComparePas2jsDirectoryEntries(Entry1, Entry2: {$IFDEF Pas2js}jsvalue{$ELSE}Pointer{$ENDIF}): integer;
 function ComparePas2jsDirectoryEntries(Entry1, Entry2: {$IFDEF Pas2js}jsvalue{$ELSE}Pointer{$ENDIF}): integer;
@@ -614,6 +562,7 @@ begin
   FPath:=IncludeTrailingPathDelimiter(aPath);
   FPath:=IncludeTrailingPathDelimiter(aPath);
   FEntries:=TFPList.Create;
   FEntries:=TFPList.Create;
   FPool:=aPool;
   FPool:=aPool;
+  FChangeStamp:=InvalidChangeStamp;
 end;
 end;
 
 
 destructor TPas2jsCachedDirectory.Destroy;
 destructor TPas2jsCachedDirectory.Destroy;
@@ -1105,6 +1054,13 @@ end;
 
 
 { TPas2jsFileLineReader }
 { TPas2jsFileLineReader }
 
 
+procedure TPas2jsFileLineReader.IncLineNumber;
+begin
+  if (CachedFile<>nil) and (CachedFile.Cache<>nil) then
+    CachedFile.Cache.IncReadLineCounter;
+  inherited IncLineNumber;
+end;
+
 constructor TPas2jsFileLineReader.Create(const AFilename: string);
 constructor TPas2jsFileLineReader.Create(const AFilename: string);
 begin
 begin
   raise Exception.Create('TPas2jsFileLineReader.Create [20180126090825] no cache "'+AFilename+'"');
   raise Exception.Create('TPas2jsFileLineReader.Create [20180126090825] no cache "'+AFilename+'"');
@@ -1112,60 +1068,10 @@ end;
 
 
 constructor TPas2jsFileLineReader.Create(aFile: TPas2jsCachedFile);
 constructor TPas2jsFileLineReader.Create(aFile: TPas2jsCachedFile);
 begin
 begin
-  inherited Create(aFile.Filename);
+  inherited Create(aFile.Filename,aFile.Source);
   FCachedFile:=aFile;
   FCachedFile:=aFile;
-  FSource:=aFile.Source;
-  FSrcPos:=1;
-  FIsEOF:=FSource='';
 end;
 end;
 
 
-function TPas2jsFileLineReader.IsEOF: Boolean;
-begin
-  Result:=FIsEOF;
-end;
-
-function TPas2jsFileLineReader.ReadLine: string;
-var
-  S: string;
-  p, SrcLen: integer;
-
-  procedure GetLine;
-  var
-    l: SizeInt;
-  begin
-    l:=p-FSrcPos;
-    Result:=copy(S,FSrcPos,l);
-    FSrcPos:=p;
-    inc(FLineNumber);
-    if (CachedFile<>nil) and (CachedFile.Cache<>nil) then
-      inc(CachedFile.Cache.FReadLineCounter);
-    //writeln('GetLine "',Result,'"');
-  end;
-
-begin
-  if FIsEOF then exit('');
-  S:=Source;
-  SrcLen:=length(S);
-  p:=FSrcPos;
-  while p<=SrcLen do
-    case S[p] of
-    #10,#13:
-      begin
-        GetLine;
-        inc(p);
-        if (p<=SrcLen) and (S[p] in [#10,#13]) and (S[p]<>S[p-1]) then
-          inc(p);
-        if p>SrcLen then
-          FIsEOF:=true;
-        FSrcPos:=p;
-        exit;
-      end;
-    else
-      inc(p);
-    end;
-  FIsEOF:=true;
-  GetLine;
-end;
 
 
 { TPas2jsCachedFile }
 { TPas2jsCachedFile }
 
 
@@ -1175,13 +1081,17 @@ begin
   Result:=FFileEncoding=EncodingBinary;
   Result:=FFileEncoding=EncodingBinary;
 end;
 end;
 
 
+function TPas2jsCachedFile.GetCache: TPas2jsFilesCache;
+begin
+  Result:=TPas2jsFilesCache(FS);
+end;
+
 constructor TPas2jsCachedFile.Create(aCache: TPas2jsFilesCache;
 constructor TPas2jsCachedFile.Create(aCache: TPas2jsFilesCache;
   const aFilename: string);
   const aFilename: string);
 begin
 begin
+  inHerited Create(aCache,aFileName);
   FChangeStamp:=InvalidChangeStamp;
   FChangeStamp:=InvalidChangeStamp;
-  FCache:=aCache;
   FCacheStamp:=Cache.ResetStamp;
   FCacheStamp:=Cache.ResetStamp;
-  FFilename:=aFilename;
 end;
 end;
 
 
 function TPas2jsCachedFile.Load(RaiseOnError: boolean; Binary: boolean
 function TPas2jsCachedFile.Load(RaiseOnError: boolean; Binary: boolean
@@ -1254,14 +1164,14 @@ begin
   {$ENDIF}
   {$ENDIF}
   if Binary then
   if Binary then
   begin
   begin
-    FSource:=NewSource;
+    SetSource(NewSource);
     FFileEncoding:=EncodingBinary;
     FFileEncoding:=EncodingBinary;
   end else
   end else
   begin
   begin
     {$IFDEF FPC_HAS_CPSTRING}
     {$IFDEF FPC_HAS_CPSTRING}
-    FSource:=ConvertTextToUTF8(NewSource,FFileEncoding);
+    SetSource(ConvertTextToUTF8(NewSource,FFileEncoding));
     {$ELSE}
     {$ELSE}
-    FSource:=NewSource;
+    SetSource(NewSource);
     {$ENDIF}
     {$ENDIF}
   end;
   end;
   FLoaded:=true;
   FLoaded:=true;
@@ -1273,7 +1183,7 @@ begin
 end;
 end;
 
 
 function TPas2jsCachedFile.CreateLineReader(RaiseOnError: boolean
 function TPas2jsCachedFile.CreateLineReader(RaiseOnError: boolean
-  ): TPas2jsFileLineReader;
+  ): TSourceLineReader;
 begin
 begin
   if not Load(RaiseOnError) then
   if not Load(RaiseOnError) then
     exit(nil);
     exit(nil);
@@ -1282,41 +1192,14 @@ end;
 
 
 { TPas2jsFileResolver }
 { TPas2jsFileResolver }
 
 
-constructor TPas2jsFileResolver.Create(aCache: TPas2jsFilesCache);
+function TPas2jsFileResolver.GetCache: TPas2jsFilesCache;
 begin
 begin
-  inherited Create;
-  FCache:=aCache;
-end;
-
-function TPas2jsFileResolver.FindIncludeFile(const aFilename: string): TLineReader;
-var
-  Filename: String;
-begin
-  Result:=nil;
-  Filename:=Cache.FindIncludeFileName(aFilename);
-  if Filename='' then exit;
-  try
-    Result:=FindSourceFile(Filename);
-  except
-    // error is shown in the scanner, which has the context information
-  end;
+  Result:=TPas2jsFilesCache(FS);
 end;
 end;
 
 
-function TPas2jsFileResolver.FindIncludeFileName(const aFilename: string): String;
-
-begin
-  Result:=Cache.FindIncludeFileName(aFilename);
-end;
-
-
-function TPas2jsFileResolver.FindSourceFile(const aFilename: string): TLineReader;
-
-var
-  CurFilename: String;
-
+constructor TPas2jsFileResolver.Create(aCache: TPas2jsFilesCache);
 begin
 begin
-  CurFilename:=Cache.FindSourceFileName(aFileName);
-  Result:=Cache.LoadFile(CurFilename).CreateLineReader(false);
+  inherited Create(aCache);
 end;
 end;
 
 
 
 
@@ -1340,22 +1223,22 @@ end;
 function TPas2jsFilesCache.GetStrictFileCase : Boolean;
 function TPas2jsFilesCache.GetStrictFileCase : Boolean;
 
 
 begin
 begin
-  Result:=caoStrictFileCase in FOptions;
+  Result:=caoStrictFileCase in Options;
 end;
 end;
 
 
 function TPas2jsFilesCache.GetSearchLikeFPC: boolean;
 function TPas2jsFilesCache.GetSearchLikeFPC: boolean;
 begin
 begin
-  Result:=caoSearchLikeFPC in FOptions;
+  Result:=caoSearchLikeFPC in Options;
 end;
 end;
 
 
 function TPas2jsFilesCache.GetShowFullFilenames: boolean;
 function TPas2jsFilesCache.GetShowFullFilenames: boolean;
 begin
 begin
-  Result:=caoShowFullFilenames in FOptions;
+  Result:=caoShowFullFilenames in Options;
 end;
 end;
 
 
 function TPas2jsFilesCache.GetShowTriedUsedFiles: boolean;
 function TPas2jsFilesCache.GetShowTriedUsedFiles: boolean;
 begin
 begin
-  Result:=caoShowTriedUsedFiles in FOptions;
+  Result:=caoShowTriedUsedFiles in Options;
 end;
 end;
 
 
 
 
@@ -1456,7 +1339,7 @@ begin
       if aPath='' then continue;
       if aPath='' then continue;
       if Kind=spkPath then
       if Kind=spkPath then
       begin
       begin
-        aPath:=ExpandDirectory(aPath,BaseDirectory);
+        aPath:=ExpandDirectory(aPath);
         if aPath='' then continue;
         if aPath='' then continue;
       end;
       end;
       aPaths.Clear;
       aPaths.Clear;
@@ -1474,18 +1357,9 @@ begin
   end;
   end;
 end;
 end;
 
 
-procedure TPas2jsFilesCache.SetDefaultOutputPath(AValue: string);
-begin
-  AValue:=ExpandDirectory(AValue,BaseDirectory);
-  if FDefaultOutputPath=AValue then Exit;
-  FDefaultOutputPath:=AValue;
-end;
-
-
-procedure TPas2jsFilesCache.SetOptions(AValue: TP2jsFileCacheOptions);
+procedure TPas2jsFilesCache.SetOnReadDirectory(AValue: TReadDirectoryEvent);
 begin
 begin
-  if FOptions=AValue then Exit;
-  FOptions:=AValue;
+  DirectoryCache.OnReadDirectory:=AValue;
 end;
 end;
 
 
 procedure TPas2jsFilesCache.SetSearchLikeFPC(const AValue: boolean);
 procedure TPas2jsFilesCache.SetSearchLikeFPC(const AValue: boolean);
@@ -1508,23 +1382,6 @@ begin
   SetOption(caoStrictFileCase,aValue)
   SetOption(caoStrictFileCase,aValue)
 end;
 end;
 
 
-
-procedure TPas2jsFilesCache.SetUnitOutputPath(AValue: string);
-begin
-  AValue:=ExpandDirectory(AValue,BaseDirectory);
-  if FUnitOutputPath=AValue then Exit;
-  FUnitOutputPath:=AValue;
-end;
-
-procedure TPas2jsFilesCache.SetOption(Flag: TP2jsFileCacheOption; Enable: boolean
-  );
-begin
-  if Enable then
-    Include(FOptions,Flag)
-  else
-    Exclude(FOptions,Flag);
-end;
-
 function TPas2jsFilesCache.ReadFile(Filename: string; var Source: string
 function TPas2jsFilesCache.ReadFile(Filename: string; var Source: string
   ): boolean;
   ): boolean;
 {$IFDEF Pas2js}
 {$IFDEF Pas2js}
@@ -1629,10 +1486,8 @@ begin
   inherited Create;
   inherited Create;
   FResetStamp:=InvalidChangeStamp;
   FResetStamp:=InvalidChangeStamp;
   FLog:=aLog;
   FLog:=aLog;
-  FOptions:=DefaultPas2jsFileCacheOptions;
   FIncludePaths:=TStringList.Create;
   FIncludePaths:=TStringList.Create;
   FForeignUnitPaths:=TStringList.Create;
   FForeignUnitPaths:=TStringList.Create;
-  FNamespaces:=TStringList.Create;
   FUnitPaths:=TStringList.Create;
   FUnitPaths:=TStringList.Create;
   FFiles:=TPasAnalyzerKeySet.Create(
   FFiles:=TPasAnalyzerKeySet.Create(
     {$IFDEF Pas2js}
     {$IFDEF Pas2js}
@@ -1652,28 +1507,23 @@ begin
   FreeAndNil(FFiles);
   FreeAndNil(FFiles);
   FreeAndNil(FIncludePaths);
   FreeAndNil(FIncludePaths);
   FreeAndNil(FForeignUnitPaths);
   FreeAndNil(FForeignUnitPaths);
-  FreeAndNil(FNamespaces);
   FreeAndNil(FUnitPaths);
   FreeAndNil(FUnitPaths);
   inherited Destroy;
   inherited Destroy;
 end;
 end;
 
 
 procedure TPas2jsFilesCache.Reset;
 procedure TPas2jsFilesCache.Reset;
 begin
 begin
+  Inherited;
   IncreaseChangeStamp(FResetStamp);
   IncreaseChangeStamp(FResetStamp);
   FDirectoryCache.Invalidate;
   FDirectoryCache.Invalidate;
   // FFiles: keep data, files are checked against LoadedFileAge
   // FFiles: keep data, files are checked against LoadedFileAge
-  FOptions:=DefaultPas2jsFileCacheOptions;
   FBaseDirectory:='';
   FBaseDirectory:='';
-  FUnitOutputPath:='';
-  FReadLineCounter:=0;
   FForeignUnitPaths.Clear;
   FForeignUnitPaths.Clear;
   FForeignUnitPathsFromCmdLine:=0;
   FForeignUnitPathsFromCmdLine:=0;
   FUnitPaths.Clear;
   FUnitPaths.Clear;
   FUnitPathsFromCmdLine:=0;
   FUnitPathsFromCmdLine:=0;
   FIncludePaths.Clear;
   FIncludePaths.Clear;
   FIncludePathsFromCmdLine:=0;
   FIncludePathsFromCmdLine:=0;
-  FNamespaces.Clear;
-  FNamespacesFromCmdLine:=0;
   // FOnReadFile: TPas2jsReadFileEvent; keep
   // FOnReadFile: TPas2jsReadFileEvent; keep
   // FOnWriteFile: TPas2jsWriteFileEvent; keep
   // FOnWriteFile: TPas2jsWriteFileEvent; keep
 end;
 end;
@@ -1695,28 +1545,36 @@ begin
     WriteFolder('foreign unit path',ForeignUnitPaths[i]);
     WriteFolder('foreign unit path',ForeignUnitPaths[i]);
   for i:=0 to UnitPaths.Count-1 do
   for i:=0 to UnitPaths.Count-1 do
     WriteFolder('unit path',UnitPaths[i]);
     WriteFolder('unit path',UnitPaths[i]);
-  for i:=0 to Namespaces.Count-1 do
-    Log.LogMsgIgnoreFilter(nUsingPath,['unit scope',Namespaces[i]]);
   for i:=0 to IncludePaths.Count-1 do
   for i:=0 to IncludePaths.Count-1 do
     WriteFolder('include path',IncludePaths[i]);
     WriteFolder('include path',IncludePaths[i]);
   WriteFolder('unit output path',UnitOutputPath);
   WriteFolder('unit output path',UnitOutputPath);
   WriteFolder('main output path',MainOutputPath);
   WriteFolder('main output path',MainOutputPath);
 end;
 end;
 
 
-function TPas2jsFilesCache.AddIncludePaths(const Paths: string;
-  FromCmdLine: boolean; out ErrorMsg: string): boolean;
+procedure TPas2jsFilesCache.GetPCUDirs(aList: TStrings; const aBaseDir: String);
 begin
 begin
-  ErrorMsg:=AddSearchPaths(Paths,spkPath,FromCmdLine,FIncludePaths,FIncludePathsFromCmdLine);
-  Result:=ErrorMsg='';
+  inherited GetPCUDirs(aList, aBaseDir);
+  aList.AddStrings(UnitPaths);
+end;
+
+function TPas2jsFilesCache.SameFileName(const File1, File2: String): Boolean;
+begin
+  Result:=Pas2jsFileUtils.CompareFilenames(File1,File2)=0;
 end;
 end;
 
 
-function TPas2jsFilesCache.AddNamespaces(const Paths: string;
+function TPas2jsFilesCache.File1IsNewer(const File1, File2: String): Boolean;
+begin
+  Result:=FileAge(File1)>FileAge(File2);
+end;
+
+function TPas2jsFilesCache.AddIncludePaths(const Paths: string;
   FromCmdLine: boolean; out ErrorMsg: string): boolean;
   FromCmdLine: boolean; out ErrorMsg: string): boolean;
 begin
 begin
-  ErrorMsg:=AddSearchPaths(Paths,spkIdentifier,FromCmdLine,FNamespaces,FNamespacesFromCmdLine);
+  ErrorMsg:=AddSearchPaths(Paths,spkPath,FromCmdLine,FIncludePaths,FIncludePathsFromCmdLine);
   Result:=ErrorMsg='';
   Result:=ErrorMsg='';
 end;
 end;
 
 
+
 function TPas2jsFilesCache.AddUnitPaths(const Paths: string;
 function TPas2jsFilesCache.AddUnitPaths(const Paths: string;
   FromCmdLine: boolean; out ErrorMsg: string): boolean;
   FromCmdLine: boolean; out ErrorMsg: string): boolean;
 begin
 begin
@@ -1731,7 +1589,8 @@ begin
   Result:=ErrorMsg='';
   Result:=ErrorMsg='';
 end;
 end;
 
 
-function TPas2jsFilesCache.CreateResolver: TPas2jsFileResolver;
+function TPas2jsFilesCache.CreateResolver: TPas2jsFSResolver;
+
 begin
 begin
   Result := TPas2jsFileResolver.Create(Self);
   Result := TPas2jsFileResolver.Create(Self);
   {$IFDEF HasStreams}
   {$IFDEF HasStreams}
@@ -1759,12 +1618,12 @@ end;
 
 
 
 
 
 
-function TPas2jsFilesCache.DirectoryExists(Filename: string): boolean;
+function TPas2jsFilesCache.DirectoryExists(Const Filename: string): boolean;
 begin
 begin
   Result:=DirectoryCache.DirectoryExists(FileName);
   Result:=DirectoryCache.DirectoryExists(FileName);
 end;
 end;
 
 
-function TPas2jsFilesCache.FileExists(Filename: string): boolean;
+function TPas2jsFilesCache.FileExists(const Filename: string): boolean;
 begin
 begin
   Result:=DirectoryCache.FileExists(FileName);
   Result:=DirectoryCache.FileExists(FileName);
 end;
 end;
@@ -1786,7 +1645,7 @@ begin
 end;
 end;
 
 
 function TPas2jsFilesCache.LoadFile(Filename: string; Binary: boolean
 function TPas2jsFilesCache.LoadFile(Filename: string; Binary: boolean
-  ): TPas2jsCachedFile;
+  ): TPas2jsFile;
 begin
 begin
   Result:=FindFile(FileName);
   Result:=FindFile(FileName);
   if Result=nil then
   if Result=nil then
@@ -1899,20 +1758,20 @@ begin
   end;
   end;
 end;
 end;
 
 
-function TPas2jsFilesCache.ExpandDirectory(const Filename, BaseDir: string
-  ): string;
+function TPas2jsFilesCache.ExpandDirectory(const Filename: string): string;
 begin
 begin
   if Filename='' then exit('');
   if Filename='' then exit('');
-  if BaseDir<>'' then
-    Result:=ExpandFileNamePJ(Filename,BaseDir)
-  else
-    Result:=ExpandFileNamePJ(Filename,BaseDirectory);
+  Result:=ExpandFileNamePJ(Filename,BaseDirectory);
   if Result='' then exit;
   if Result='' then exit;
   Result:=IncludeTrailingPathDelimiter(Result);
   Result:=IncludeTrailingPathDelimiter(Result);
 end;
 end;
 
 
-function TPas2jsFilesCache.ExpandExecutable(const Filename, BaseDir: string
-  ): string;
+function TPas2jsFilesCache.ExpandFileName(const Filename: string): string;
+begin
+  Result:=ExpandFileNamePJ(Filename,BaseDirectory);
+end;
+
+function TPas2jsFilesCache.ExpandExecutable(const Filename: string): string;
 
 
   function TryFile(CurFilename: string): boolean;
   function TryFile(CurFilename: string): boolean;
   begin
   begin
@@ -1933,10 +1792,7 @@ begin
     // no file path -> search
     // no file path -> search
     {$IFDEF Windows}
     {$IFDEF Windows}
     // search in BaseDir
     // search in BaseDir
-    if BaseDir<>'' then
-    begin
-      if TryFile(IncludeTrailingPathDelimiter(BaseDir)+Filename) then exit;
-    end else if BaseDirectory<>'' then
+    if BaseDirectory<>'' then
     begin
     begin
       if TryFile(IncludeTrailingPathDelimiter(BaseDirectory)+Filename) then exit;
       if TryFile(IncludeTrailingPathDelimiter(BaseDirectory)+Filename) then exit;
     end;
     end;
@@ -1955,10 +1811,38 @@ begin
       if CurPath='' then continue;
       if CurPath='' then continue;
       if TryFile(IncludeTrailingPathDelimiter(CurPath)+Filename) then exit;
       if TryFile(IncludeTrailingPathDelimiter(CurPath)+Filename) then exit;
     end;
     end;
-  end else if BaseDir<>'' then
-    Result:=ExpandFileNamePJ(Filename,BaseDir)
+  end else
+    Result:=ExpandFileName(Filename);
+end;
+
+function TPas2jsFilesCache.HandleOptionPaths(C: Char; aValue: String; FromCmdLine: Boolean): String;
+
+Var
+  ErrorMsg : String;
+
+begin
+  Result:='';
+  case C of
+    'E': MainOutputPath:=aValue;
+    'i': if not AddIncludePaths(aValue,FromCmdLine,ErrorMsg) then
+           Result:='invalid include path (-Fi) "'+ErrorMsg+'"';
+    'u': if not AddUnitPaths(aValue,FromCmdLine,ErrorMsg) then
+           Result:='invalid unit path (-Fu) "'+ErrorMsg+'"';
+    'U': UnitOutputPath:=aValue;
   else
   else
-    Result:=ExpandFileNamePJ(Filename,BaseDirectory);
+    Result:=inherited HandleOptionPaths(C, aValue, FromCmdLine);
+  end;
+end;
+
+function TPas2jsFilesCache.AddForeignUnitPath(const aValue: String; FromCmdLine: Boolean): String;
+begin
+  AddSrcUnitPaths(aValue,FromCmdLine,Result);
+end;
+
+function TPas2jsFilesCache.TryCreateRelativePath(const Filename, BaseDirectory: String; UsePointDirectory: boolean; out
+  RelPath: String): Boolean;
+begin
+  Result:=Pas2jsFileUtils.TryCreateRelativePath(Filename, BaseDirectory, UsePointDirectory, RelPath);
 end;
 end;
 
 
 function TPas2jsFilesCache.FindIncludeFileName(const aFilename: string): String;
 function TPas2jsFilesCache.FindIncludeFileName(const aFilename: string): String;
@@ -2112,12 +1996,15 @@ end;
 
 
 function TPas2jsFilesCache.FindCustomJSFileName(const aFilename: string): String;
 function TPas2jsFilesCache.FindCustomJSFileName(const aFilename: string): String;
 
 
+Var
+  FN : String;
+
   function SearchInDir(Dir: string): boolean;
   function SearchInDir(Dir: string): boolean;
   var
   var
     CurFilename: String;
     CurFilename: String;
   begin
   begin
     Dir:=IncludeTrailingPathDelimiter(Dir);
     Dir:=IncludeTrailingPathDelimiter(Dir);
-    CurFilename:=Dir+aFilename;
+    CurFilename:=Dir+FN;
     Result:=FileExistsLogged(CurFilename);
     Result:=FileExistsLogged(CurFilename);
     if Result then
     if Result then
       FindCustomJSFileName:=CurFilename;
       FindCustomJSFileName:=CurFilename;
@@ -2127,18 +2014,18 @@ var
   i: Integer;
   i: Integer;
 begin
 begin
   Result:='';
   Result:='';
-
-  if FilenameIsAbsolute(aFilename) then
+  FN:=ResolveDots(aFileName);
+  if FilenameIsAbsolute(FN) then
     begin
     begin
-    Result:=aFilename;
+    Result:=FN;
     if not FileExistsLogged(Result) then
     if not FileExistsLogged(Result) then
       Result:='';
       Result:='';
     exit;
     exit;
     end;
     end;
 
 
-  if ExtractFilePath(aFilename)<>'' then
+  if ExtractFilePath(FN)<>'' then
     begin
     begin
-    Result:=ExpandFileNamePJ(aFilename,BaseDirectory);
+    Result:=ExpandFileNamePJ(FN,BaseDirectory);
     if not FileExistsLogged(Result) then
     if not FileExistsLogged(Result) then
       Result:='';
       Result:='';
     exit;
     exit;
@@ -2169,6 +2056,11 @@ begin
       Log.LogMsgIgnoreFilter(nSearchingFileNotFound,[FormatPath(Filename)]);
       Log.LogMsgIgnoreFilter(nSearchingFileNotFound,[FormatPath(Filename)]);
 end;
 end;
 
 
+function TPas2jsFilesCache.GetOnReadDirectory: TReadDirectoryEvent;
+begin
+  Result:=DirectoryCache.OnReadDirectory;
+end;
+
 function TPas2jsFilesCache.FileExistsILogged(var Filename: string): integer;
 function TPas2jsFilesCache.FileExistsILogged(var Filename: string): integer;
 begin
 begin
   Result:=DirectoryCache.FileExistsI(Filename);
   Result:=DirectoryCache.FileExistsI(Filename);

+ 0 - 88
packages/pastojs/src/pas2jsfileutils.pp

@@ -66,8 +66,6 @@ function GetEnvironmentVariablePJ(const EnvVar: string): String;
 
 
 function GetNextDelimitedItem(const List: string; Delimiter: char;
 function GetNextDelimitedItem(const List: string; Delimiter: char;
                               var Position: integer): string;
                               var Position: integer): string;
-procedure SplitCmdLineParams(const Params: string; ParamList: TStrings;
-                             ReadBackslash: boolean = false);
 
 
 type TChangeStamp = SizeInt;
 type TChangeStamp = SizeInt;
 const InvalidChangeStamp = low(TChangeStamp);
 const InvalidChangeStamp = low(TChangeStamp);
@@ -732,92 +730,6 @@ begin
   if Position<=length(List) then inc(Position); // skip Delimiter
   if Position<=length(List) then inc(Position); // skip Delimiter
 end;
 end;
 
 
-procedure SplitCmdLineParams(const Params: string; ParamList: TStrings;
-                             ReadBackslash: boolean = false);
-// split spaces, quotes are parsed as single parameter
-// if ReadBackslash=true then \" is replaced to " and not treated as quote
-// #0 is always end
-type
-  TMode = (mNormal,mApostrophe,mQuote);
-var
-  p: Integer;
-  Mode: TMode;
-  Param: String;
-begin
-  p:=1;
-  while p<=length(Params) do
-  begin
-    // skip whitespace
-    while (p<=length(Params)) and (Params[p] in [' ',#9,#10,#13]) do inc(p);
-    if (p>length(Params)) or (Params[p]=#0) then
-      break;
-    // read param
-    Param:='';
-    Mode:=mNormal;
-    while p<=length(Params) do
-    begin
-      case Params[p] of
-      #0:
-        break;
-      '\':
-        begin
-          inc(p);
-          if ReadBackslash then
-            begin
-            // treat next character as normal character
-            if (p>length(Params)) or (Params[p]=#0) then
-              break;
-            if ord(Params[p])<128 then
-            begin
-              Param+=Params[p];
-              inc(p);
-            end else begin
-              // next character is already a normal character
-            end;
-          end else begin
-            // treat backslash as normal character
-            Param+='\';
-          end;
-        end;
-      '''':
-        begin
-          inc(p);
-          case Mode of
-          mNormal:
-            Mode:=mApostrophe;
-          mApostrophe:
-            Mode:=mNormal;
-          mQuote:
-            Param+='''';
-          end;
-        end;
-      '"':
-        begin
-          inc(p);
-          case Mode of
-          mNormal:
-            Mode:=mQuote;
-          mApostrophe:
-            Param+='"';
-          mQuote:
-            Mode:=mNormal;
-          end;
-        end;
-      ' ',#9,#10,#13:
-        begin
-          if Mode=mNormal then break;
-          Param+=Params[p];
-          inc(p);
-        end;
-      else
-        Param+=Params[p];
-        inc(p);
-      end;
-    end;
-    //writeln('SplitCmdLineParams Param=#'+Param+'#');
-    ParamList.Add(Param);
-  end;
-end;
 
 
 procedure IncreaseChangeStamp(var Stamp: TChangeStamp);
 procedure IncreaseChangeStamp(var Stamp: TChangeStamp);
 begin
 begin

+ 427 - 0
packages/pastojs/src/pas2jsfs.pp

@@ -0,0 +1,427 @@
+{
+    This file is part of the Free Component Library (FCL)
+    Copyright (c) 2018  Michael Van Canneyt
+
+    Pascal to Javascript converter class.
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ **********************************************************************
+
+  Abstract:
+    FileSystem abstraction layer for compiler.
+    Has only abstract classes with no actual implementation, so it does not actually
+    interacts with the filesystem.
+    See Pas2JSFileCache for an actual implementation.
+}
+unit pas2jsfs;
+
+{$mode objfpc}{$H+}
+{$I pas2js_defines.inc}
+
+interface
+
+uses
+  // No filesystem-dependent units here !
+  Classes, SysUtils, pscanner, fpjson;
+
+const // Messages
+  nIncludeSearch = 201; sIncludeSearch = 'Include file search: %s';
+  nUnitSearch = 202; sUnitSearch = 'Unitsearch: %s';
+  nSearchingFileFound = 203; sSearchingFileFound = 'Searching file: %s... found';
+  nSearchingFileNotFound = 204; sSearchingFileNotFound = 'Searching file: %s... not found';
+  nDuplicateFileFound = 205; sDuplicateFileFound = 'Duplicate file found: "%s" and "%s"';
+  nCustomJSFileNotFound = 206; sCustomJSFileNotFound = 'custom JS file not found: "%s"';
+  nUsingPath = 104; sUsingPath = 'Using %s: "%s"';
+  nFolderNotFound = 105; sFolderNotFound = '%s not found: %s';
+
+Type
+  // Forward definitions
+  EPas2jsFS = Class(Exception);
+  TPas2jsFile = class;
+  TSourceLineReader = class;
+  TPas2jsFSResolver = class;
+  TPas2JSFS = Class;
+
+  { TSourceLineReader }
+
+  TSourceLineReader = class(TLineReader)
+  private
+    FIsEOF: boolean;
+    FLineNumber: integer;
+    FSource: string;
+    FSrcPos: integer;
+  Protected
+    Procedure IncLineNumber; virtual;
+    property Source: string read FSource;
+    property SrcPos: integer read FSrcPos;
+  public
+    Constructor Create(Const aFileName, aSource : String); overload;
+    function IsEOF: Boolean; override;
+    function ReadLine: string; override;
+    property LineNumber: integer read FLineNumber;
+  end;
+
+  TP2jsFSOption = (
+    caoShowFullFilenames,
+    caoShowTriedUsedFiles,
+    caoSearchLikeFPC,
+    caoStrictFileCase
+    );
+  TP2jsFSOptions = set of TP2jsFSOption;
+  TKeyCompareType = (kcFilename,kcUnitName);
+
+  { TPas2JSFS }
+
+  TPas2JSFS = Class
+  Private
+    FOptions: TP2jsFSOptions;
+    FReadLineCounter: SizeInt;
+    FDefaultOutputPath: string;
+    FUnitOutputPath: string;
+    procedure SetOptionFromIndex(AIndex: Integer; AValue: boolean);
+    procedure SetDefaultOutputPath(AValue: string);
+    procedure SetUnitOutputPath(AValue: string);
+  Protected
+    // Not to be overridden
+    procedure SetOption(Flag: TP2jsFSOption; Enable: boolean);
+    Function OptionIsSet(Index : Integer) :  Boolean;
+  Protected
+    // Protected Abstract. Must be overridden
+    function FindSourceFileName(const aFilename: string): String; virtual; abstract;
+  Public
+    // Public Abstract. Must be overridden
+    function FindIncludeFileName(const aFilename: string): String; virtual; abstract;
+    function LoadFile(Filename: string; Binary: boolean = false): TPas2jsFile; virtual; abstract;
+    Function FileExists(Const aFileName : String) : Boolean; virtual; abstract;
+    function FindUnitJSFileName(const aUnitFilename: string): String; virtual; abstract;
+    function FindCustomJSFileName(const aFilename: string): String; virtual; abstract;
+    function FindUnitFileName(const aUnitname, InFilename: string; out IsForeign: boolean): String; virtual; abstract;
+    procedure SaveToFile(ms: TFPJSStream; Filename: string); virtual; abstract;
+    Function PCUExists(var aFileName : string) : Boolean; virtual;
+    procedure GetPCUDirs(aList: TStrings; const aBaseDir: String); virtual;
+  Public
+    // Public, may be overridden
+    Function SameFileName(Const File1,File2 : String) : Boolean; virtual;
+    Function File1IsNewer(Const File1,File2 : String) : Boolean; virtual;
+    function ExpandDirectory(const Filename: string): string; virtual;
+    function ExpandFileName(const Filename: string): string; virtual;
+    function ExpandExecutable(const Filename: string): string; virtual;
+    Function FormatPath(Const aFileName : string) : String; virtual;
+    Function DirectoryExists(Const aDirectory : string) : boolean; virtual;
+    function TryCreateRelativePath(const Filename, BaseDirectory: String; UsePointDirectory: boolean; out RelPath: String): Boolean; virtual;
+    Procedure WriteFoldersAndSearchPaths; virtual;
+    function CreateResolver: TPas2jsFSResolver; virtual;
+    // On success, return '', On error, return error message.
+    Function AddForeignUnitPath(Const aValue : String; FromCmdLine : Boolean) : String; virtual;
+    Function HandleOptionPaths(C : Char; aValue : String; FromCmdLine : Boolean) : String; virtual;
+  Public
+    Constructor Create; virtual;
+    Procedure Reset; virtual;
+    Procedure IncReadLineCounter;
+    property ReadLineCounter: SizeInt read FReadLineCounter write FReadLineCounter;
+    property Options: TP2jsFSOptions read FOptions write FOptions;
+    property ShowFullPaths: boolean Index 0 Read OptionIsSet Write SetOptionFromIndex;
+    property ShowTriedUsedFiles: boolean Index 1 read OptionIsSet Write SetOptionFromIndex;
+    property SearchLikeFPC: boolean index 2 read OptionIsSet Write SetOptionFromIndex;
+    Property StrictFileCase : Boolean Index 3 Read OptionIsSet Write SetOptionFromIndex;
+    property MainOutputPath: string read FDefaultOutputPath write SetDefaultOutputPath; // includes trailing pathdelim
+    property UnitOutputPath: string read FUnitOutputPath write SetUnitOutputPath; // includes trailing pathdelim
+  end;
+
+  { TPas2jsFile }
+
+  TPas2jsFile = class
+  private
+    FFilename: string;
+    FFS: TPas2JSFS;
+    FSource: string;
+  Protected
+    Procedure SetSource(aSource : String);
+  public
+    constructor Create(aFS: TPas2jsFS; const aFilename: string);
+    function CreateLineReader(RaiseOnError: boolean): TSourceLineReader; virtual; abstract;
+    function Load(RaiseOnError: boolean; Binary: boolean): boolean; virtual; abstract;
+    property Source: string read FSource; // UTF-8 without BOM or Binary
+    Property FS : TPas2JSFS Read FFS;
+    property Filename: string read FFilename;
+  end;
+
+  { TPas2jsFSResolver }
+
+  TPas2jsFSResolver = class({$IFDEF HASFILESYSTEM}TFileResolver{$ELSE}TBaseFileResolver{$ENDIF})
+  private
+    FFS: TPas2jsFS;
+  public
+    constructor Create(aFS : TPas2jsFS); reintroduce;
+    // Redirect all calls to FS.
+    function FindIncludeFileName(const aFilename: string): String; override;
+    function FindIncludeFile(const aFilename: string): TLineReader; override;
+    function FindSourceFile(const aFilename: string): TLineReader; override;
+    property FS: TPas2jsFS read FFS;
+  end;
+
+
+Const
+  p2jsfcoCaption: array[TP2jsFSOption] of string = (
+      // only used by experts, no need for resourcestrings
+      'Show full filenames',
+      'Show tried/used files',
+      'Search files like FPC',
+      'Strict file case'
+      );
+    // 'Combine all JavaScript into main file',
+    EncodingBinary = 'Binary';
+
+  DefaultPas2jsFSOptions = [];
+
+implementation
+
+// No filesystem-dependent units here !
+
+{ TPas2JSFS }
+
+procedure TPas2JSFS.SetOptionFromIndex(AIndex: Integer; AValue: boolean);
+begin
+  SetOption(TP2jsFSOption(aIndex),aValue);
+end;
+
+procedure TPas2JSFS.SetOption(Flag: TP2jsFSOption; Enable: boolean);
+begin
+  if Enable then
+    Include(FOptions,Flag)
+  else
+    Exclude(FOptions,Flag);
+end;
+
+function TPas2JSFS.OPtionIsSet(Index: Integer): Boolean;
+begin
+  Result:=TP2jsFSOption(Index) in FOptions;
+end;
+
+function TPas2JSFS.PCUExists(var aFileName: string): Boolean;
+begin
+  Result:=Self.FileExists(aFileName);
+end;
+
+procedure TPas2JSFS.GetPCUDirs(aList: TStrings; Const aBaseDir : String);
+begin
+  if UnitOutputPath<>'' then
+    Alist.Add(UnitOutputPath);
+  Alist.Add(aBaseDir);
+end;
+
+function TPas2JSFS.SameFileName(const File1, File2: String): Boolean;
+begin
+  Result:=CompareText(File1,File2)=0;
+end;
+
+function TPas2JSFS.File1IsNewer(const File1, File2: String): Boolean;
+begin
+  Result:=False;
+end;
+
+function TPas2JSFS.ExpandDirectory(const Filename : String): string;
+begin
+  Result:=FileName;
+end;
+
+function TPas2JSFS.ExpandFileName(const Filename: string): string;
+begin
+  Result:=FileName;
+end;
+
+function TPas2JSFS.ExpandExecutable(const Filename : string): string;
+begin
+  Result:=FileName
+end;
+
+function TPas2JSFS.FormatPath(const aFileName: string): String;
+begin
+  Result:=aFileName;
+end;
+
+function TPas2JSFS.DirectoryExists(const aDirectory: string): boolean;
+begin
+  Result:=False;
+end;
+
+function TPas2JSFS.TryCreateRelativePath(const Filename, BaseDirectory: String; UsePointDirectory: boolean; out RelPath: String
+  ): Boolean;
+begin
+  Result:=True;
+  RelPath:=FileName;
+end;
+
+procedure TPas2JSFS.WriteFoldersAndSearchPaths;
+begin
+  // Do nothing
+end;
+
+function TPas2JSFS.CreateResolver: TPas2jsFSResolver;
+begin
+  Result:=TPas2jsFSResolver.Create(Self);
+end;
+
+function TPas2JSFS.AddForeignUnitPath(const aValue: String; FromCmdLine: Boolean): String;
+begin
+  Result:='';
+end;
+
+function TPas2JSFS.HandleOptionPaths(C: Char; aValue: String; FromCmdLine: Boolean): String;
+begin
+  Result:='Invalid parameter : -F'+C+aValue;
+end;
+
+constructor TPas2JSFS.Create;
+begin
+  FOptions:=DefaultPas2jsFSOptions;
+end;
+
+procedure TPas2JSFS.Reset;
+begin
+  FReadLineCounter:=0;
+  FUnitOutputPath:='';
+  FDefaultOutputPath:='';
+end;
+
+procedure TPas2JSFS.IncReadLineCounter;
+begin
+  Inc(FReadLineCounter);
+end;
+
+procedure TPas2jsFS.SetDefaultOutputPath(AValue: string);
+begin
+  AValue:=ExpandDirectory(AValue);
+  if FDefaultOutputPath=AValue then Exit;
+  FDefaultOutputPath:=AValue;
+end;
+
+procedure TPas2jsFS.SetUnitOutputPath(AValue: string);
+
+begin
+  AValue:=ExpandDirectory(AValue);
+  if FUnitOutputPath=AValue then Exit;
+  FUnitOutputPath:=AValue;
+end;
+
+
+{ TPas2jsFile }
+
+procedure TPas2jsFile.SetSource(aSource: String);
+begin
+  FSource:=ASource;
+end;
+
+constructor TPas2jsFile.Create(aFS: TPas2jsFS; const aFilename: string);
+begin
+  FFS:=aFS;
+  FFileName:=aFileName;
+end;
+
+procedure TSourceLineReader.IncLineNumber;
+begin
+  inc(FLineNumber);
+end;
+
+Constructor TSourceLineReader.Create(Const aFileName, aSource : String);
+
+begin
+  Inherited Create(aFileName);
+  FSource:=aSource;
+  FSrcPos:=1;
+  FIsEOF:=FSource='';
+end;
+
+function TSourceLineReader.IsEOF: Boolean;
+begin
+  Result:=FIsEOF;
+end;
+
+function TSourceLineReader.ReadLine: string;
+var
+  S: string;
+  p, SrcLen: integer;
+
+  procedure GetLine;
+  var
+    l: SizeInt;
+  begin
+    l:=p-FSrcPos;
+    Result:=copy(S,FSrcPos,l);
+    FSrcPos:=p;
+    IncLineNumber;
+    //writeln('GetLine "',Result,'"');
+  end;
+
+begin
+  if FIsEOF then exit('');
+  S:=Source;
+  SrcLen:=length(S);
+  p:=FSrcPos;
+  while p<=SrcLen do
+    case S[p] of
+    #10,#13:
+      begin
+        GetLine;
+        inc(p);
+        if (p<=SrcLen) and (S[p] in [#10,#13]) and (S[p]<>S[p-1]) then
+          inc(p);
+        if p>SrcLen then
+          FIsEOF:=true;
+        FSrcPos:=p;
+        exit;
+      end;
+    else
+      inc(p);
+    end;
+  FIsEOF:=true;
+  GetLine;
+end;
+
+
+function TPas2jsFSResolver.FindIncludeFile(const aFilename: string): TLineReader;
+var
+  Filename: String;
+begin
+  Result:=nil;
+  Filename:=FS.FindIncludeFileName(aFilename);
+  if Filename='' then exit;
+  try
+    Result:=FindSourceFile(Filename);
+  except
+    // error is shown in the scanner, which has the context information
+  end;
+end;
+
+constructor TPas2jsFSResolver.Create(aFS: TPas2jsFS);
+begin
+  FFS:=aFS;
+end;
+
+function TPas2jsFSResolver.FindIncludeFileName(const aFilename: string): String;
+
+begin
+  Result:=FS.FindIncludeFileName(aFilename);
+end;
+
+
+function TPas2jsFSResolver.FindSourceFile(const aFilename: string): TLineReader;
+
+var
+  CurFilename: String;
+
+begin
+  CurFilename:=FS.FindSourceFileName(aFileName);
+  Result:=FS.LoadFile(CurFilename).CreateLineReader(false);
+end;
+
+
+
+end.
+

+ 164 - 0
packages/pastojs/src/pas2jsfscompiler.pp

@@ -0,0 +1,164 @@
+{
+    This file is part of the Free Component Library (FCL)
+    Copyright (c) 2018  Michael Van Canneyt
+
+    Pascal to Javascript converter class.
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ **********************************************************************
+
+  Abstract:
+    FileSystem aware compiler descendent. No support for PCU.
+}
+unit pas2jsfscompiler;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, pastree, pas2jscompiler,
+  pas2jsfs, pas2jsfilecache, pasuseanalyzer;
+
+Type
+  TPas2jsFSCompiler = Class(TPas2JSCompiler)
+  private
+    function GetFileCache: TPas2jsFilesCache;
+    function OnMacroEnv(Sender: TObject; var Params: string; Lvl: integer): boolean;
+  Public
+    Procedure SetWorkingDir(const aDir: String); override;
+    function CreateSetOfCompilerFiles(keyType: TKeyCompareType): TPasAnalyzerKeySet; override;
+    Function CreateFS : TPas2JSFS; override;
+    Procedure InitParamMacros; override;
+    Property FileCache : TPas2jsFilesCache Read GetFileCache;
+  end;
+
+implementation
+
+uses fppas2js, pscanner, pas2jsfileutils;
+
+{$IFDEF PAS2JS}
+function Pas2jsCompilerFile_FilenameToKeyName(Item: Pointer): String;
+var
+  aFile: TPas2jsCompilerFile absolute Item;
+begin
+  Result:=FilenameToKey(aFile.PasFilename);
+end;
+
+function PtrUnitnameToKeyName(Item: Pointer): String;
+var
+  aUnitName: string absolute Item;
+begin
+  Result:=LowerCase(aUnitName);
+end;
+
+function Pas2jsCompilerFile_UnitnameToKeyName(Item: Pointer): String;
+var
+  aFile: TPas2jsCompilerFile absolute Item;
+begin
+  Result:=LowerCase(aFile.PasUnitName);
+end;
+{$ELSE}
+function CompareCompilerFilesPasFile(Item1, Item2: Pointer): integer;
+var
+  File1: TPas2JSCompilerFile absolute Item1;
+  File2: TPas2JSCompilerFile absolute Item2;
+begin
+  Result:=CompareFilenames(File1.PasFilename,File2.PasFilename);
+end;
+
+function CompareFileAndCompilerFilePasFile(Filename, Item: Pointer): integer;
+var
+  aFile: TPas2JSCompilerFile absolute Item;
+  aFilename: String;
+begin
+  aFilename:=AnsiString(Filename);
+  Result:=CompareFilenames(aFilename,aFile.PasFilename);
+end;
+
+function CompareCompilerFilesPasUnitname(Item1, Item2: Pointer): integer;
+var
+  File1: TPas2JSCompilerFile absolute Item1;
+  File2: TPas2JSCompilerFile absolute Item2;
+begin
+  Result:=CompareText(File1.PasUnitName,File2.PasUnitName);
+end;
+
+function CompareUnitnameAndCompilerFile(TheUnitname, Item: Pointer): integer;
+var
+  aFile: TPas2JSCompilerFile absolute Item;
+  anUnitname: String;
+begin
+  anUnitname:=AnsiString(TheUnitname);
+  Result:=CompareText(anUnitname,aFile.PasUnitName);
+end;
+{$ENDIF}
+
+function TPas2jsFSCompiler.CreateFS: TPas2JSFS;
+
+Var
+  C :  TPas2jsFilesCache;
+
+begin
+  C:=TPas2jsFilesCache.Create(Log);
+  C.BaseDirectory:=GetCurrentDirPJ;
+  Result:=C;
+end;
+
+function TPas2jsFSCompiler.GetFileCache: TPas2jsFilesCache;
+begin
+  Result:=FS as TPas2jsFilesCache;
+end;
+
+function TPas2jsFSCompiler.OnMacroEnv(Sender: TObject; var Params: string; Lvl: integer): boolean;
+
+begin
+  if Lvl=0 then ;
+  Params:=GetEnvironmentVariablePJ(Params);
+  Result:=true;
+end;
+
+procedure TPas2jsFSCompiler.SetWorkingDir(const aDir: String);
+begin
+  inherited SetWorkingDir(aDir);
+  FileCache.BaseDirectory:=aDir;
+end;
+
+function TPas2jsFSCompiler.CreateSetOfCompilerFiles(keyType: TKeyCompareType): TPasAnalyzerKeySet;
+begin
+  Case keyType of
+    kcFileName:
+      Result:=TPasAnalyzerKeySet.Create(
+          {$IFDEF Pas2js}
+          @Pas2jsCompilerFile_FilenameToKeyName,@PtrFilenameToKeyName
+          {$ELSE}
+          @CompareCompilerFilesPasFile,@CompareFileAndCompilerFilePasFile
+          {$ENDIF});
+    kcUnitName:
+      Result:=TPasAnalyzerKeySet.Create(
+        {$IFDEF Pas2js}
+        @Pas2jsCompilerFile_UnitnameToKeyName,@PtrUnitnameToKeyName
+        {$ELSE}
+        @CompareCompilerFilesPasUnitname,@CompareUnitnameAndCompilerFile
+        {$ENDIF});
+  else
+    Raise EPas2jsFileCache.CreateFmt('Internal Unknown key type: %d',[Ord(KeyType)]);
+  end;
+end;
+
+procedure TPas2jsFSCompiler.InitParamMacros;
+begin
+  inherited InitParamMacros;
+  ParamMacros.AddFunction('Env','environment variable, e.g. $Env(HOME)',@OnMacroEnv,true);
+end;
+
+
+
+end.
+

+ 6 - 4
packages/pastojs/src/pas2jslibcompiler.pp

@@ -2,7 +2,7 @@
     This file is part of the Free Component Library (FCL)
     This file is part of the Free Component Library (FCL)
     Copyright (c) 2018  Michael Van Canneyt
     Copyright (c) 2018  Michael Van Canneyt
 
 
-    Pascal to Javascript converter class.
+    Pascal to Javascript converter class. Library version
 
 
     See the file COPYING.FPC, included in this distribution,
     See the file COPYING.FPC, included in this distribution,
     for details about the copyright.
     for details about the copyright.
@@ -21,7 +21,7 @@ unit pas2jslibcompiler;
 interface
 interface
 
 
 uses
 uses
-  SysUtils, Classes, FPPJsSrcMap, Pas2jsFileCache, Pas2jsCompiler;
+  SysUtils, Classes, FPPJsSrcMap, Pas2jsFileCache, Pas2JSCompiler, Pas2jsPCUCompiler, pas2jscompilercfg, pas2jscompilerpp;
 
 
 { ---------------------------------------------------------------------
 { ---------------------------------------------------------------------
   Compiler descendant, usable in library
   Compiler descendant, usable in library
@@ -44,7 +44,7 @@ Type
 
 
   { TLibraryPas2JSCompiler }
   { TLibraryPas2JSCompiler }
 
 
-  TLibraryPas2JSCompiler = Class(TPas2JSCompiler)
+  TLibraryPas2JSCompiler = Class(TPas2JSPCUCompiler)
   private
   private
     FLastError: String;
     FLastError: String;
     FLastErrorClass: String;
     FLastErrorClass: String;
@@ -181,7 +181,9 @@ begin
   Log.OnLog:=@DoLibraryLog;
   Log.OnLog:=@DoLibraryLog;
   FileCache.OnReadFile:=@ReadFile;
   FileCache.OnReadFile:=@ReadFile;
   FReadBufferLen:=DefaultReadBufferSize;
   FReadBufferLen:=DefaultReadBufferSize;
-  FileCache.DirectoryCache.OnReadDirectory:=@ReadDirectory;
+  FileCache.OnReadDirectory:=@ReadDirectory;
+  ConfigSupport:=TPas2JSFileConfigSupport.Create(Self);
+  PostProcessorSupport:=TPas2JSFSPostProcessorSupport.Create(Self);
 end;
 end;
 
 
 procedure TLibraryPas2JSCompiler.DoLibraryLog(Sender: TObject; const Msg: String);
 procedure TLibraryPas2JSCompiler.DoLibraryLog(Sender: TObject; const Msg: String);

+ 60 - 9
packages/pastojs/src/pas2jslogger.pp

@@ -28,10 +28,13 @@ interface
 
 
 uses
 uses
   {$IFDEF Pas2JS}
   {$IFDEF Pas2JS}
-  JS, NodeJSFS,
+  JS,
   {$ENDIF}
   {$ENDIF}
-  Classes, SysUtils, PasTree, PScanner, jstree, jsbase, jswriter, fpjson,
-  Pas2jsFileUtils;
+  pas2jsutils,
+  {$IFDEF HASFILESYSTEM}
+  pas2jsfileutils,
+  {$ENDIF}
+  Classes, SysUtils, PasTree, PScanner, jstree, jsbase, jswriter, fpjson;
 
 
 const
 const
   ExitCodeErrorInternal = 1; // internal error
   ExitCodeErrorInternal = 1; // internal error
@@ -95,6 +98,16 @@ type
 
 
   TPas2jsLogEvent = Procedure (Sender : TObject; Const Msg : String) Of Object;
   TPas2jsLogEvent = Procedure (Sender : TObject; Const Msg : String) Of Object;
 
 
+
+  { TConsoleFileWriter }
+
+  TConsoleFileWriter = Class(TTextWriter)
+  Public
+    Constructor Create(aFileName : String); reintroduce;
+    Function DoWrite(Const S : TJSWriterString) : Integer; override;
+    Procedure Flush;
+  end;
+
   { TPas2jsLogger }
   { TPas2jsLogger }
 
 
   TPas2jsLogger = class
   TPas2jsLogger = class
@@ -111,7 +124,7 @@ type
     FMsg: TFPList; // list of TPas2jsMessage
     FMsg: TFPList; // list of TPas2jsMessage
     FOnFormatPath: TPScannerFormatPathEvent;
     FOnFormatPath: TPScannerFormatPathEvent;
     FOnLog: TPas2jsLogEvent;
     FOnLog: TPas2jsLogEvent;
-    FOutputFile: TFileWriter;
+    FOutputFile: TTextWriter; // TFileWriter;
     FOutputFilename: string;
     FOutputFilename: string;
     FShowMsgNumbers: boolean;
     FShowMsgNumbers: boolean;
     FShowMsgTypes: TMessageTypes;
     FShowMsgTypes: TMessageTypes;
@@ -129,6 +142,9 @@ type
     procedure SetSorted(AValue: boolean);
     procedure SetSorted(AValue: boolean);
     procedure DoLogRaw(const Msg: string; SkipEncoding : Boolean);
     procedure DoLogRaw(const Msg: string; SkipEncoding : Boolean);
     function Concatenate(Args: array of {$IFDEF Pas2JS}jsvalue{$ELSE}const{$ENDIF}): string;
     function Concatenate(Args: array of {$IFDEF Pas2JS}jsvalue{$ELSE}const{$ENDIF}): string;
+  Protected
+    // so it can be overridden
+    function CreateTextWriter(const aFileName: string): TTextWriter; virtual;
   public
   public
     constructor Create;
     constructor Create;
     destructor Destroy; override;
     destructor Destroy; override;
@@ -484,6 +500,27 @@ begin
   end;
   end;
 end;
 end;
 
 
+{ TConsoleFileWriter }
+
+constructor TConsoleFileWriter.Create(aFileName: String);
+begin
+  Inherited Create;
+  Write('Opening console log: '+aFileName);
+end;
+
+Function TConsoleFileWriter.DoWrite(Const S : TJSWriterString) : Integer;
+
+begin
+  Result:=Length(S);
+  Writeln(S);
+end;
+
+procedure TConsoleFileWriter.FLush;
+
+begin
+end;
+
+
 {$IFDEF Pas2JS}
 {$IFDEF Pas2JS}
 { TPas2jsFileStream }
 { TPas2jsFileStream }
 
 
@@ -1017,14 +1054,26 @@ begin
   end;
   end;
 end;
 end;
 
 
+Function TPas2jsLogger.CreateTextWriter(const aFileName : string) : TTextWriter;
+
+begin
+{$IFDEF HASFILESYSTEM}
+  Result:=TFileWriter.Create(aFilename);
+{$ELSE}
+  Result:=TConsoleFileWriter.Create(aFileName);
+{$ENDIF}
+end;
+
 procedure TPas2jsLogger.OpenOutputFile;
 procedure TPas2jsLogger.OpenOutputFile;
 begin
 begin
+{$IFDEF HASFILESYSTEM}
   if FOutputFile<>nil then exit;
   if FOutputFile<>nil then exit;
   if OutputFilename='' then
   if OutputFilename='' then
     raise Exception.Create('Log has empty OutputFilename');
     raise Exception.Create('Log has empty OutputFilename');
-  if DirectoryExists(OutputFilename) then
+   if DirectoryExists(OutputFilename) then
     raise Exception.Create('Log is directory: "'+OutputFilename+'"');
     raise Exception.Create('Log is directory: "'+OutputFilename+'"');
-  FOutputFile:=TFileWriter.Create(OutputFilename);
+{$ENDIF}
+  FOutputFile:=CreateTextWriter(OutputFileName);
   {$IFDEF FPC_HAS_CPSTRING}
   {$IFDEF FPC_HAS_CPSTRING}
   if (Encoding='') or (Encoding='utf8') then
   if (Encoding='') or (Encoding='utf8') then
     FOutputFile.Write(UTF8BOM);
     FOutputFile.Write(UTF8BOM);
@@ -1033,14 +1082,16 @@ end;
 
 
 procedure TPas2jsLogger.Flush;
 procedure TPas2jsLogger.Flush;
 begin
 begin
-  if FOutputFile<>nil then
-    FOutputFile.Flush;
+{$IFDEF HASFILESYSTEM}
+  if Assigned(FOutputFile) and (FoutputFile is TFileWriter) then
+    TFileWriter(FOutputFile).Flush;
+{$ENDIF}
 end;
 end;
 
 
 procedure TPas2jsLogger.CloseOutputFile;
 procedure TPas2jsLogger.CloseOutputFile;
 begin
 begin
   if FOutputFile=nil then exit;
   if FOutputFile=nil then exit;
-  FOutputFile.Flush;
+  Flush;
   FreeAndNil(FOutputFile);
   FreeAndNil(FOutputFile);
 end;
 end;
 
 

+ 59 - 34
packages/pastojs/src/pas2jspcucompiler.pp

@@ -1,3 +1,21 @@
+{
+    This file is part of the Free Component Library (FCL)
+    Copyright (c) 2018  Michael Van Canneyt
+
+    Pascal to Javascript converter class.
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ **********************************************************************
+
+  Abstract:
+    FileSystem aware compiler descendent with support for PCU files.
+}
 unit pas2jspcucompiler;
 unit pas2jspcucompiler;
 
 
 {$mode objfpc}{$H+}
 {$mode objfpc}{$H+}
@@ -11,11 +29,11 @@ unit pas2jspcucompiler;
 interface
 interface
 
 
 uses
 uses
-  Classes, SysUtils, pastree, pas2jscompiler, Pas2JsFiler;
+  SysUtils,Classes,
+  pastree,
+  pas2jscompiler, pas2jsfs, pas2jsfscompiler, Pas2JsFiler;
 
 
 Type
 Type
-  { TFilerPCUSupport }
-
   TFilerPCUSupport = Class(TPCUSupport)
   TFilerPCUSupport = Class(TPCUSupport)
   Private
   Private
     // This is the format that will be written.
     // This is the format that will be written.
@@ -46,15 +64,17 @@ Type
     property PrecompileInitialFlags: TPCUInitialFlags read FPrecompileInitialFlags;
     property PrecompileInitialFlags: TPCUInitialFlags read FPrecompileInitialFlags;
   end;
   end;
 
 
-  { TPas2jsPCUCompiler }
-
   { TPas2jsPCUCompilerFile }
   { TPas2jsPCUCompilerFile }
 
 
   TPas2jsPCUCompilerFile = Class(TPas2jsCompilerFile)
   TPas2jsPCUCompilerFile = Class(TPas2jsCompilerFile)
     Function CreatePCUSupport: TPCUSupport; override;
     Function CreatePCUSupport: TPCUSupport; override;
   end;
   end;
 
 
-  TPas2jsPCUCompiler = Class(TPas2JSCompiler)
+
+  { TPas2jsPCUCompiler }
+
+  TPas2jsPCUCompiler = Class(TPas2JSFSCompiler)
+  Private
     FPrecompileFormat : TPas2JSPrecompileFormat;
     FPrecompileFormat : TPas2JSPrecompileFormat;
   Protected
   Protected
     procedure WritePrecompiledFormats; override;
     procedure WritePrecompiledFormats; override;
@@ -64,7 +84,11 @@ Type
 
 
 implementation
 implementation
 
 
-uses fppas2js, pscanner, pas2jslogger, pas2jsfilecache, pasresolveeval, jstree, pas2jsfileutils;
+uses fppas2js, pscanner, pas2jslogger, pasresolveeval, jstree, pas2jsfileutils;
+
+
+
+{$IFDEF HASPAS2JSFILER}
 
 
 { ---------------------------------------------------------------------
 { ---------------------------------------------------------------------
   TFilerPCUSupport
   TFilerPCUSupport
@@ -148,7 +172,7 @@ end;
 
 
 procedure TFilerPCUSupport.CreatePCUReader;
 procedure TFilerPCUSupport.CreatePCUReader;
 var
 var
-  aFile: TPas2jsCachedFile;
+  aFile: TPas2jsFile;
   s: String;
   s: String;
 begin
 begin
   if MyFile.PCUFilename='' then
   if MyFile.PCUFilename='' then
@@ -162,7 +186,7 @@ begin
 
 
   if MyFile.ShowDebug then
   if MyFile.ShowDebug then
     MyFile.Log.LogMsg(nParsingFile,[QuoteStr(MyFile.PCUFilename)]);
     MyFile.Log.LogMsg(nParsingFile,[QuoteStr(MyFile.PCUFilename)]);
-  aFile:=Compiler.FileCache.LoadFile(MyFile.PCUFilename,true);
+  aFile:=Compiler.FS.LoadFile(MyFile.PCUFilename,true);
   if aFile=nil then
   if aFile=nil then
     RaiseInternalError(20180312145941,MyFile.PCUFilename);
     RaiseInternalError(20180312145941,MyFile.PCUFilename);
   FPCUReaderStream:=TMemoryStream.Create;
   FPCUReaderStream:=TMemoryStream.Create;
@@ -199,7 +223,7 @@ function TFilerPCUSupport.FindPCU(const UseUnitName: string; out  aFormat: TPas2
       CurFormat:=PrecompileFormats[i];
       CurFormat:=PrecompileFormats[i];
       if not CurFormat.Enabled then continue;
       if not CurFormat.Enabled then continue;
       Filename:=DirPath+UseUnitName+'.'+CurFormat.Ext;
       Filename:=DirPath+UseUnitName+'.'+CurFormat.Ext;
-      if Compiler.FileCache.SearchLowUpCase(Filename) then
+      if Compiler.FS.PCUExists(Filename) then
       begin
       begin
         FindPCU:=Filename;
         FindPCU:=Filename;
         aFormat:=CurFormat;
         aFormat:=CurFormat;
@@ -210,23 +234,20 @@ function TFilerPCUSupport.FindPCU(const UseUnitName: string; out  aFormat: TPas2
   end;
   end;
 
 
 var
 var
-  Cache: TPas2jsFilesCache;
+  L : TstringList;
   i: Integer;
   i: Integer;
+
 begin
 begin
   Result:='';
   Result:='';
   aFormat:=nil;
   aFormat:=nil;
-  Cache:=Compiler.FileCache;
-
-  // search in output directory
-  if Cache.UnitOutputPath<>'' then
-    if SearchInDir(Cache.UnitOutputPath) then exit;
-
-  // then in BaseDirectory
-  if SearchInDir(MyFile.FileResolver.BaseDirectory) then exit;
-
-  // finally search in unit paths
-  for i:=0 to Cache.UnitPaths.Count-1 do
-    if SearchInDir(Cache.UnitPaths[i]) then exit;
+  L:=TstringList.Create;
+  try
+    Compiler.FS.GetPCUDirs(L,MyFile.FileResolver.BaseDirectory);
+    for i:=0 to L.Count-1 do
+      if SearchInDir(L[i]) then exit;
+  finally
+    L.Free;
+  end;
 end;
 end;
 
 
 function TFilerPCUSupport.OnWriterIsElementUsed(Sender: TObject;
 function TFilerPCUSupport.OnWriterIsElementUsed(Sender: TObject;
@@ -269,8 +290,8 @@ begin
 
 
   // Determine output filename
   // Determine output filename
   FN:=ExtractFilenameOnly(MyFile.PasFilename)+'.'+FPCUFormat.Ext;
   FN:=ExtractFilenameOnly(MyFile.PasFilename)+'.'+FPCUFormat.Ext;
-  if Compiler.FileCache.UnitOutputPath<>'' then
-    FN:=Compiler.FileCache.UnitOutputPath+FN
+  if Compiler.FS.UnitOutputPath<>'' then
+    FN:=Compiler.FS.UnitOutputPath+FN
   else
   else
     FN:=ExtractFilePath(MyFile.PasFilename)+FN;
     FN:=ExtractFilePath(MyFile.PasFilename)+FN;
   // Set as our filename
   // Set as our filename
@@ -302,30 +323,30 @@ begin
     writeln('TPas2jsCompilerFile.WritePCU precompiled ',MyFile.PCUFilename);
     writeln('TPas2jsCompilerFile.WritePCU precompiled ',MyFile.PCUFilename);
     {$ENDIF}
     {$ENDIF}
 
 
-    MyFile.Log.LogMsg(nWritingFile,[QuoteStr(Compiler.FileCache.FormatPath(MyFile.PCUFilename))],'',0,0,
+    MyFile.Log.LogMsg(nWritingFile,[QuoteStr(Compiler.FS.FormatPath(MyFile.PCUFilename))],'',0,0,
                not (coShowLineNumbers in Compiler.Options));
                not (coShowLineNumbers in Compiler.Options));
 
 
     // check output directory
     // check output directory
     DestDir:=ChompPathDelim(ExtractFilePath(MyFile.PCUFilename));
     DestDir:=ChompPathDelim(ExtractFilePath(MyFile.PCUFilename));
-    if (DestDir<>'') and not Compiler.FileCache.DirectoryExists(DestDir) then
+    if (DestDir<>'') and not Compiler.FS.DirectoryExists(DestDir) then
     begin
     begin
       {$IFDEF REALLYVERBOSE}
       {$IFDEF REALLYVERBOSE}
       writeln('TPas2jsCompilerFile.WritePCU output dir not found "',DestDir,'"');
       writeln('TPas2jsCompilerFile.WritePCU output dir not found "',DestDir,'"');
       {$ENDIF}
       {$ENDIF}
-      MyFile.Log.LogMsg(nOutputDirectoryNotFound,[QuoteStr(Compiler.FileCache.FormatPath(DestDir))]);
+      MyFile.Log.LogMsg(nOutputDirectoryNotFound,[QuoteStr(Compiler.FS.FormatPath(DestDir))]);
       Compiler.Terminate(ExitCodeFileNotFound);
       Compiler.Terminate(ExitCodeFileNotFound);
     end;
     end;
-    if Compiler.FileCache.DirectoryExists(MyFile.PCUFilename) then
+    if Compiler.FS.DirectoryExists(MyFile.PCUFilename) then
     begin
     begin
       {$IFDEF REALLYVERBOSE}
       {$IFDEF REALLYVERBOSE}
       writeln('TPas2jsCompilerFile.WritePCU file is folder "',DestDir,'"');
       writeln('TPas2jsCompilerFile.WritePCU file is folder "',DestDir,'"');
       {$ENDIF}
       {$ENDIF}
-      MyFile.Log.LogMsg(nFileIsFolder,[QuoteStr(Compiler.FileCache.FormatPath(MyFile.PCUFilename))]);
+      MyFile.Log.LogMsg(nFileIsFolder,[QuoteStr(Compiler.FS.FormatPath(MyFile.PCUFilename))]);
       Compiler.Terminate(ExitCodeWriteError);
       Compiler.Terminate(ExitCodeWriteError);
     end;
     end;
 
 
     ms.Position:=0;
     ms.Position:=0;
-    Compiler.FileCache.SaveToFile(ms,MyFile.PCUFilename);
+    Compiler.FS.SaveToFile(ms,MyFile.PCUFilename);
     {$IFDEF REALLYVERBOSE}
     {$IFDEF REALLYVERBOSE}
     writeln('TPas2jsCompilerFile.WritePCU written ',MyFile.PCUFilename);
     writeln('TPas2jsCompilerFile.WritePCU written ',MyFile.PCUFilename);
     {$ENDIF}
     {$ENDIF}
@@ -339,11 +360,11 @@ end;
 procedure TFilerPCUSupport.OnFilerGetSrc(Sender: TObject; aFilename: string;
 procedure TFilerPCUSupport.OnFilerGetSrc(Sender: TObject; aFilename: string;
   out p: PChar; out Count: integer);
   out p: PChar; out Count: integer);
 var
 var
-  SrcFile: TPas2jsCachedFile;
+  SrcFile: TPas2jsFile;
 begin
 begin
   if Sender=nil then
   if Sender=nil then
     RaiseInternalError(20180311135558,aFilename);
     RaiseInternalError(20180311135558,aFilename);
-  SrcFile:=MyFile.Compiler.FileCache.LoadFile(aFilename);
+  SrcFile:=MyFile.Compiler.FS.LoadFile(aFilename);
   if SrcFile=nil then
   if SrcFile=nil then
     RaiseInternalError(20180311135329,aFilename);
     RaiseInternalError(20180311135329,aFilename);
   p:=PChar(SrcFile.Source);
   p:=PChar(SrcFile.Source);
@@ -370,6 +391,8 @@ end;
 
 
 { TPas2jsPCUCompiler }
 { TPas2jsPCUCompiler }
 
 
+
+
 procedure TPas2jsPCUCompiler.WritePrecompiledFormats;
 procedure TPas2jsPCUCompiler.WritePrecompiledFormats;
 
 
 Var
 Var
@@ -410,6 +433,8 @@ begin
     ParamFatal('invalid precompile output format (-JU) "'+Value+'"');
     ParamFatal('invalid precompile output format (-JU) "'+Value+'"');
 end;
 end;
 
 
+
+
 { TPas2jsPCUCompilerFile }
 { TPas2jsPCUCompilerFile }
 
 
 function TPas2jsPCUCompilerFile.CreatePCUSupport: TPCUSupport;
 function TPas2jsPCUCompilerFile.CreatePCUSupport: TPCUSupport;
@@ -425,7 +450,7 @@ begin
   else
   else
     Result:=Nil;
     Result:=Nil;
 end;
 end;
-
+{$ENDIF}
 
 
 end.
 end.
 
 

+ 430 - 0
packages/pastojs/src/pas2jsutils.pp

@@ -0,0 +1,430 @@
+unit pas2jsutils;
+{
+    This file is part of the Free Component Library (FCL)
+    Copyright (c) 2018  Mattias Gaertner  [email protected]
+
+    Pascal to Javascript converter class.
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ **********************************************************************
+
+  Abstract:
+    Utility routines that do not need a filesystem or OS functionality.
+    Filesystem-specific things should go to pas2jsfileutils instead.
+}
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils;
+
+function ChompPathDelim(const Path: string): string;
+function GetNextDelimitedItem(const List: string; Delimiter: char;
+                              var Position: integer): string;
+type
+   TChangeStamp = SizeInt;
+
+const
+  InvalidChangeStamp = low(TChangeStamp);
+
+Function IncreaseChangeStamp(Stamp: TChangeStamp) : TChangeStamp;
+const
+  EncodingUTF8 = 'UTF-8';
+  EncodingSystem = 'System';
+
+function NormalizeEncoding(const Encoding: string): string;
+function IsASCII(const s: string): boolean; inline;
+{$IFDEF FPC_HAS_CPSTRING}
+const
+  UTF8BOM = #$EF#$BB#$BF;
+function UTF8CharacterStrictLength(P: PChar): integer;
+
+function UTF8ToUTF16(const s: string): UnicodeString;
+function UTF16ToUTF8(const s: UnicodeString): string;
+
+{$ENDIF FPC_HAS_CPSTRING}
+
+function IsNonUTF8System: boolean;// true if system encoding is not UTF-8
+{$IFDEF Windows}
+// AConsole - If false, it is the general system encoding,
+//            if true, it is the console encoding
+function GetWindowsEncoding(AConsole: Boolean = False): string;
+{$ENDIF}
+{$IF defined(Unix) and not defined(Darwin)}
+function GetUnixEncoding: string;
+{$ENDIF}
+
+Function NonUTF8System: boolean;
+function GetDefaultTextEncoding: string;
+
+procedure SplitCmdLineParams(const Params: string; ParamList: TStrings;
+                             ReadBackslash: boolean = false);
+
+implementation
+
+{$IFDEF Windows}
+uses Windows;
+{$ENDIF}
+
+Var
+  {$IFDEF Unix}
+  {$IFNDEF Darwin}
+  Lang: string = '';
+  {$ENDIF}
+  {$ENDIF}
+  EncodingValid: boolean = false;
+  DefaultTextEncoding: string = EncodingSystem;
+  gNonUTF8System : Boolean = {$IFDEF FPC_HAS_CPSTRING}false{$ELSE}true{$ENDIF};
+
+Function NonUTF8System: boolean;
+
+begin
+  Result:=gNonUTF8System;
+end;
+
+function GetNextDelimitedItem(const List: string; Delimiter: char;
+  var Position: integer): string;
+var
+  StartPos: Integer;
+begin
+  StartPos:=Position;
+  while (Position<=length(List)) and (List[Position]<>Delimiter) do
+    inc(Position);
+  Result:=copy(List,StartPos,Position-StartPos);
+  if Position<=length(List) then inc(Position); // skip Delimiter
+end;
+
+function IncreaseChangeStamp(Stamp: TChangeStamp): TChangeStamp;
+begin
+  if Stamp<High(TChangeStamp) then
+    Result:=Stamp+1
+  else
+    Result:=InvalidChangeStamp+1;
+end;
+
+function ChompPathDelim(const Path: string): string;
+var
+  Len, MinLen: Integer;
+begin
+  Result:=Path;
+  if Path = '' then
+    exit;
+  Len:=length(Result);
+  if (Result[1] in AllowDirectorySeparators) then
+  begin
+    MinLen := 1;
+    {$IFDEF HasUNCPaths}
+    if (Len >= 2) and (Result[2] in AllowDirectorySeparators) then
+      MinLen := 2; // keep UNC '\\', chomp 'a\' to 'a'
+    {$ENDIF}
+    {$IFDEF Pas2js}
+    if (Len >= 2) and (Result[2]=Result[1]) and (PathDelim='\') then
+      MinLen := 2; // keep UNC '\\', chomp 'a\' to 'a'
+    {$ENDIF}
+  end
+  else begin
+    MinLen := 0;
+    {$IFdef MSWindows}
+    if (Len >= 3) and (Result[1] in ['a'..'z', 'A'..'Z'])  and
+       (Result[2] = ':') and (Result[3] in AllowDirectorySeparators)
+    then
+      MinLen := 3;
+    {$ENDIF}
+    {$IFdef Pas2js}
+    if (PathDelim='\')
+        and (Len >= 3) and (Result[1] in ['a'..'z', 'A'..'Z'])
+        and (Result[2] = ':') and (Result[3] in AllowDirectorySeparators)
+    then
+      MinLen := 3;
+    {$ENDIF}
+  end;
+
+  while (Len > MinLen) and (Result[Len] in AllowDirectorySeparators) do dec(Len);
+  if Len<length(Result) then
+    SetLength(Result,Len);
+end;
+
+function NormalizeEncoding(const Encoding: string): string;
+var
+  i: Integer;
+begin
+  Result:=LowerCase(Encoding);
+  for i:=length(Result) downto 1 do
+    if Result[i]='-' then Delete(Result,i,1);
+end;
+
+{$IFDEF WINDOWS}
+function GetWindowsEncoding(AConsole: Boolean = False): string;
+var
+  cp : UINT;
+{$IFDEF WinCE}
+// CP_UTF8 is missing in the windows unit of the Windows CE RTL
+const
+  CP_UTF8 = 65001;
+{$ENDIF}
+begin
+  if AConsole then cp := GetOEMCP
+  else cp := GetACP;
+
+  case cp of
+    CP_UTF8: Result := EncodingUTF8;
+  else
+    Result:='cp'+IntToStr(cp);
+  end;
+end;
+{$ENDIF}
+
+function IsASCII(const s: string): boolean; inline;
+{$IFDEF Pas2js}
+var
+  i: Integer;
+begin
+  for i:=1 to length(s) do
+    if s[i]>#127 then exit(false);
+  Result:=true;
+end;
+{$ELSE}
+var
+  p: PChar;
+begin
+  if s='' then exit(true);
+  p:=PChar(s);
+  repeat
+    case p^ of
+    #0: if p-PChar(s)=length(s) then exit(true);
+    #128..#255: exit(false);
+    end;
+    inc(p);
+  until false;
+end;
+{$ENDIF}
+
+{$IFDEF FPC_HAS_CPSTRING}
+function UTF8CharacterStrictLength(P: PChar): integer;
+begin
+  if p=nil then exit(0);
+  if ord(p^)<%10000000 then
+  begin
+    // regular single byte character
+    exit(1);
+  end
+  else if ord(p^)<%11000000 then
+  begin
+    // invalid single byte character
+    exit(0);
+  end
+  else if ((ord(p^) and %11100000) = %11000000) then
+  begin
+    // should be 2 byte character
+    if (ord(p[1]) and %11000000) = %10000000 then
+      exit(2)
+    else
+      exit(0);
+  end
+  else if ((ord(p^) and %11110000) = %11100000) then
+  begin
+    // should be 3 byte character
+    if ((ord(p[1]) and %11000000) = %10000000)
+    and ((ord(p[2]) and %11000000) = %10000000) then
+      exit(3)
+    else
+      exit(0);
+  end
+  else if ((ord(p^) and %11111000) = %11110000) then
+  begin
+    // should be 4 byte character
+    if ((ord(p[1]) and %11000000) = %10000000)
+    and ((ord(p[2]) and %11000000) = %10000000)
+    and ((ord(p[3]) and %11000000) = %10000000) then
+      exit(4)
+    else
+      exit(0);
+  end else
+    exit(0);
+end;
+
+function UTF8ToUTF16(const s: string): UnicodeString;
+begin
+  Result:=UTF8Decode(s);
+end;
+
+function UTF16ToUTF8(const s: UnicodeString): string;
+begin
+  if s='' then exit('');
+  Result:=UTF8Encode(s);
+  // prevent UTF8 codepage appear in the strings - we don't need codepage
+  // conversion magic
+  SetCodePage(RawByteString(Result), CP_ACP, False);
+end;
+{$ENDIF}
+
+function IsNonUTF8System: boolean;
+begin
+  Result:=NonUTF8System;
+end;
+
+{$IFDEF UNIX}
+{$IFNDEF Darwin}
+function GetUnixEncoding: string;
+var
+  i: integer;
+begin
+  Result:=EncodingSystem;
+  i:=pos('.',Lang);
+  if (i>0) and (i<=length(Lang)) then
+    Result:=copy(Lang,i+1,length(Lang)-i);
+end;
+{$ENDIF}
+{$ENDIF}
+
+function GetDefaultTextEncoding: string;
+
+
+begin
+  if EncodingValid then
+  begin
+    Result:=DefaultTextEncoding;
+    exit;
+  end;
+
+  {$IFDEF Pas2js}
+  Result:=EncodingUTF8;
+  {$ELSE}
+    {$IFDEF Windows}
+    Result:=GetWindowsEncoding;
+    {$ELSE}
+      {$IFDEF Darwin}
+      Result:=EncodingUTF8;
+      {$ELSE}
+      // unix
+      Lang := GetEnvironmentVariable('LC_ALL');
+      if Lang='' then
+      begin
+        Lang := GetEnvironmentVariable('LC_MESSAGES');
+        if Lang='' then
+          Lang := GetEnvironmentVariable('LANG');
+      end;
+      Result:=GetUnixEncoding;
+      {$ENDIF}
+    {$ENDIF}
+  {$ENDIF}
+  Result:=NormalizeEncoding(Result);
+
+  DefaultTextEncoding:=Result;
+  EncodingValid:=true;
+end;
+
+procedure InternalInit;
+begin
+  {$IFDEF FPC_HAS_CPSTRING}
+  SetMultiByteConversionCodePage(CP_UTF8);
+  // SetMultiByteFileSystemCodePage(CP_UTF8); not needed, this is the default under Windows
+  SetMultiByteRTLFileSystemCodePage(CP_UTF8);
+
+  GetDefaultTextEncoding;
+  {$IFDEF Windows}
+  gNonUTF8System:=true;
+  {$ELSE}
+  gNonUTF8System:=SysUtils.CompareText(DefaultTextEncoding,'UTF8')<>0;
+  {$ENDIF}
+  {$ENDIF}
+end;
+procedure SplitCmdLineParams(const Params: string; ParamList: TStrings;
+                             ReadBackslash: boolean = false);
+// split spaces, quotes are parsed as single parameter
+// if ReadBackslash=true then \" is replaced to " and not treated as quote
+// #0 is always end
+type
+  TMode = (mNormal,mApostrophe,mQuote);
+var
+  p: Integer;
+  Mode: TMode;
+  Param: String;
+begin
+  p:=1;
+  while p<=length(Params) do
+  begin
+    // skip whitespace
+    while (p<=length(Params)) and (Params[p] in [' ',#9,#10,#13]) do inc(p);
+    if (p>length(Params)) or (Params[p]=#0) then
+      break;
+    // read param
+    Param:='';
+    Mode:=mNormal;
+    while p<=length(Params) do
+    begin
+      case Params[p] of
+      #0:
+        break;
+      '\':
+        begin
+          inc(p);
+          if ReadBackslash then
+            begin
+            // treat next character as normal character
+            if (p>length(Params)) or (Params[p]=#0) then
+              break;
+            if ord(Params[p])<128 then
+            begin
+              Param+=Params[p];
+              inc(p);
+            end else begin
+              // next character is already a normal character
+            end;
+          end else begin
+            // treat backslash as normal character
+            Param+='\';
+          end;
+        end;
+      '''':
+        begin
+          inc(p);
+          case Mode of
+          mNormal:
+            Mode:=mApostrophe;
+          mApostrophe:
+            Mode:=mNormal;
+          mQuote:
+            Param+='''';
+          end;
+        end;
+      '"':
+        begin
+          inc(p);
+          case Mode of
+          mNormal:
+            Mode:=mQuote;
+          mApostrophe:
+            Param+='"';
+          mQuote:
+            Mode:=mNormal;
+          end;
+        end;
+      ' ',#9,#10,#13:
+        begin
+          if Mode=mNormal then break;
+          Param+=Params[p];
+          inc(p);
+        end;
+      else
+        Param+=Params[p];
+        inc(p);
+      end;
+    end;
+    //writeln('SplitCmdLineParams Param=#'+Param+'#');
+    ParamList.Add(Param);
+  end;
+end;
+
+
+initialization
+  InternalInit;
+end.
+

+ 0 - 25
packages/pastojs/tests/tcmodules.pas

@@ -381,7 +381,6 @@ type
     Procedure TestCaseOfRange;
     Procedure TestCaseOfRange;
     Procedure TestCaseOfString;
     Procedure TestCaseOfString;
     Procedure TestCaseOfExternalClassConst;
     Procedure TestCaseOfExternalClassConst;
-    Procedure TestDebugger;
 
 
     // arrays
     // arrays
     Procedure TestArray_Dynamic;
     Procedure TestArray_Dynamic;
@@ -7082,30 +7081,6 @@ begin
     ]));
     ]));
 end;
 end;
 
 
-procedure TTestModule.TestDebugger;
-begin
-  StartProgram(false);
-  Add([
-  'procedure DoIt;',
-  'begin',
-  '  deBugger;',
-  '  DeBugger();',
-  'end;',
-  'begin',
-  '  Debugger;']);
-  ConvertProgram;
-  CheckSource('TestDebugger',
-    LinesToStr([ // statements
-    'this.DoIt = function () {',
-    '  debugger;',
-    '  debugger;',
-    '};',
-    '']),
-    LinesToStr([ // $mod.$main
-    'debugger;',
-    '']));
-end;
-
 procedure TTestModule.TestArray_Dynamic;
 procedure TTestModule.TestArray_Dynamic;
 begin
 begin
   StartProgram(false);
   StartProgram(false);

+ 3 - 3
packages/pastojs/tests/tcunitsearch.pas

@@ -29,14 +29,14 @@ uses
   fpcunit, testregistry,
   fpcunit, testregistry,
   PScanner, PasTree,
   PScanner, PasTree,
   {$IFDEF CheckPasTreeRefCount}PasResolveEval,{$ENDIF}
   {$IFDEF CheckPasTreeRefCount}PasResolveEval,{$ENDIF}
-  Pas2jsFileUtils, Pas2jsCompiler, Pas2jsFileCache, Pas2jsLogger,
+  Pas2jsFileUtils, Pas2jsCompiler, Pas2jsfsCompiler, Pas2jsFileCache, Pas2jsLogger,
   tcmodules;
   tcmodules;
 
 
 type
 type
 
 
   { TTestCompiler }
   { TTestCompiler }
 
 
-  TTestCompiler = class(TPas2jsCompiler)
+  TTestCompiler = class(TPas2jsFSCompiler)
   private
   private
     FExitCode: longint;
     FExitCode: longint;
   protected
   protected
@@ -229,7 +229,7 @@ begin
   {$ENDIF}
   {$ENDIF}
   FCompiler:=TTestCompiler.Create;
   FCompiler:=TTestCompiler.Create;
   Compiler.Log.OnLog:=@DoLog;
   Compiler.Log.OnLog:=@DoLog;
-  Compiler.FileCache.DirectoryCache.OnReadDirectory:=@OnReadDirectory;
+  Compiler.FileCache.OnReadDirectory:=@OnReadDirectory;
   Compiler.FileCache.OnReadFile:=@OnReadFile;
   Compiler.FileCache.OnReadFile:=@OnReadFile;
   Compiler.FileCache.OnWriteFile:=@OnWriteFile;
   Compiler.FileCache.OnWriteFile:=@OnWriteFile;
 end;
 end;

+ 4 - 8
packages/pastojs/tests/testpas2js.lpi

@@ -19,16 +19,9 @@
       <Version Value="2"/>
       <Version Value="2"/>
     </PublishOptions>
     </PublishOptions>
     <RunParams>
     <RunParams>
-      <local>
-        <CommandLineParams Value="--suite=TTestCLI_UnitSearch"/>
-      </local>
       <FormatVersion Value="2"/>
       <FormatVersion Value="2"/>
       <Modes Count="1">
       <Modes Count="1">
-        <Mode0 Name="default">
-          <local>
-            <CommandLineParams Value="--suite=TTestCLI_UnitSearch"/>
-          </local>
-        </Mode0>
+        <Mode0 Name="default"/>
       </Modes>
       </Modes>
     </RunParams>
     </RunParams>
     <RequiredPackages Count="2">
     <RequiredPackages Count="2">
@@ -110,6 +103,9 @@
     </CodeGeneration>
     </CodeGeneration>
     <Other>
     <Other>
       <CustomOptions Value="-dVerbosePas2JS"/>
       <CustomOptions Value="-dVerbosePas2JS"/>
+      <OtherDefines Count="1">
+        <Define0 Value="VerbosePas2JS"/>
+      </OtherDefines>
     </Other>
     </Other>
   </CompilerOptions>
   </CompilerOptions>
   <Debugging>
   <Debugging>

+ 1 - 1
rtl/inc/generic.inc

@@ -76,7 +76,7 @@ begin
         then
         then
         begin
         begin
           { Align on native pointer size }
           { Align on native pointer size }
-          aligncount:=(PtrUInt(pdest) and (sizeof(PtrUInt)-1));
+          aligncount:=(sizeof(PtrUInt)-PtrInt(pdest)) and (sizeof(PtrUInt)-1);
           dec(count,aligncount);
           dec(count,aligncount);
           pend:=psrc+aligncount;
           pend:=psrc+aligncount;
           while psrc<pend do
           while psrc<pend do

+ 2 - 2
rtl/inc/innr.inc

@@ -62,8 +62,7 @@ const
    fpc_in_leave             = 51; {macpas}
    fpc_in_leave             = 51; {macpas}
    fpc_in_cycle             = 52; {macpas}
    fpc_in_cycle             = 52; {macpas}
    fpc_in_slice             = 53;
    fpc_in_slice             = 53;
-   fpc_in_move_x            = 54;
-   fpc_in_fillchar_x        = 55;
+   fpc_in_unaligned_x       = 54;
    fpc_in_get_frame         = 56;
    fpc_in_get_frame         = 56;
    fpc_in_get_caller_addr   = 57;
    fpc_in_get_caller_addr   = 57;
    fpc_in_get_caller_frame  = 58;
    fpc_in_get_caller_frame  = 58;
@@ -105,6 +104,7 @@ const
    fpc_in_neg_assign_x      = 94;
    fpc_in_neg_assign_x      = 94;
    fpc_in_not_assign_x      = 95;
    fpc_in_not_assign_x      = 95;
    fpc_in_faraddr_x         = 97;
    fpc_in_faraddr_x         = 97;
+   fpc_in_volatile_x        = 98;
 
 
 { Internal constant functions }
 { Internal constant functions }
    fpc_in_const_sqr        = 100;
    fpc_in_const_sqr        = 100;

+ 32 - 0
rtl/linux/arm/abitag.inc

@@ -0,0 +1,32 @@
+{
+   This file is part of the Free Pascal run time library.
+   Copyright (c) 2002,2018 by Florian Klaempfl
+   members of the Free Pascal development team.
+
+   See the file COPYING.FPC, included in this distribution,
+   for details about the copyright.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY;without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+**********************************************************************}
+
+procedure ABITag;nostackframe;assembler;
+asm
+  .section ".note.ABI-tag", "a"
+  .align 4
+  .long 4
+  .long 16
+  .long  1
+  .asciz "GNU"
+  .align 4
+  .long 0
+  // oldest supported kernel version, just a guess for now (FK)
+  .long 2,6,0
+  .align 4
+
+  .section ".note.GNU-stack","",@progbits
+  .text
+end;
+

+ 0 - 15
rtl/linux/arm/cprt0.as

@@ -131,18 +131,3 @@ __data_start:
         .byte 0
         .byte 0
         .ascii "generated by FPC http://www.freepascal.org\0"
         .ascii "generated by FPC http://www.freepascal.org\0"
 
 
-/* We need this stuff to make gdb behave itself, otherwise
-   gdb will chokes with SIGILL when trying to debug apps.
-*/
-        .section ".note.ABI-tag", "a"
-        .align 4
-        .long 1f - 0f
-        .long 3f - 2f
-        .long  1
-0:      .asciz "GNU"
-1:      .align 4
-2:      .long 0
-        .long 2,0,0
-3:      .align 4
-
-.section .note.GNU-stack,"",%progbits

+ 0 - 15
rtl/linux/arm/gprt0.as

@@ -143,18 +143,3 @@ __data_start:
         .byte 0
         .byte 0
         .ascii "generated by FPC http://www.freepascal.org\0"
         .ascii "generated by FPC http://www.freepascal.org\0"
 
 
-/* We need this stuff to make gdb behave itself, otherwise
-   gdb will chokes with SIGILL when trying to debug apps.
-*/
-        .section ".note.ABI-tag", "a"
-        .align 4
-        .long 1f - 0f
-        .long 3f - 2f
-        .long  1
-0:      .asciz "GNU"
-1:      .align 4
-2:      .long 0
-        .long 2,0,0
-3:      .align 4
-
-.section .note.GNU-stack,"",%progbits

+ 0 - 15
rtl/linux/arm/prt0.as

@@ -173,18 +173,3 @@ __data_start:
 	.byte 0
 	.byte 0
 	.ascii "generated by FPC http://www.freepascal.org\0"
 	.ascii "generated by FPC http://www.freepascal.org\0"
 
 
-/* We need this stuff to make gdb behave itself, otherwise
-   gdb will chokes with SIGILL when trying to debug apps.
-*/
-        .section ".note.ABI-tag", "a"
-        .align 4
-        .long 1f - 0f
-        .long 3f - 2f
-        .long  1
-0:      .asciz "GNU"
-1:      .align 4
-2:      .long 0
-        .long 2,0,0
-3:      .align 4
-
-.section .note.GNU-stack,"",%progbits

+ 0 - 15
rtl/linux/arm/ucprt0.as

@@ -168,18 +168,3 @@ __data_start:
         .comm operatingsystem_parameter_argc,4
         .comm operatingsystem_parameter_argc,4
         .comm operatingsystem_parameter_argv,4
         .comm operatingsystem_parameter_argv,4
 
 
-/* We need this stuff to make gdb behave itself, otherwise
-   gdb will chokes with SIGILL when trying to debug apps.
-*/
-        .section ".note.ABI-tag", "a"
-        .align 4
-        .long 1f - 0f
-        .long 3f - 2f
-        .long  1
-0:      .asciz "GNU"
-1:      .align 4
-2:      .long 0
-        .long 2,0,0
-3:      .align 4
-
-.section .note.GNU-stack,"",%progbits

+ 32 - 0
rtl/linux/i386/abitag.inc

@@ -0,0 +1,32 @@
+{
+   This file is part of the Free Pascal run time library.
+   Copyright (c) 2002,2018 by Florian Klaempfl
+   members of the Free Pascal development team.
+
+   See the file COPYING.FPC, included in this distribution,
+   for details about the copyright.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY;without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+**********************************************************************}
+
+procedure ABITag;nostackframe;assembler;
+asm
+  .section ".note.ABI-tag", "a"
+  .align 4
+  .long 4
+  .long 16
+  .long  1
+  .asciz "GNU"
+  .align 4
+  .long 0
+  // oldest supported kernel version, just a guess for now (FK)
+  .long 2,6,0
+  .align 4
+
+  .section ".note.GNU-stack","",@progbits
+  .text
+end;
+

+ 8 - 0
rtl/linux/system.pp

@@ -525,6 +525,8 @@ procedure InitTLS; [public,alias:'FPC_INITTLS'];
     while assigned(auxp^) do
     while assigned(auxp^) do
       inc(auxp);
       inc(auxp);
     inc(auxp);
     inc(auxp);
+    phdr:=nil;
+    phnum:=0;
     { now we are at the auxillary vector }
     { now we are at the auxillary vector }
     while assigned(auxp^) do
     while assigned(auxp^) do
       begin
       begin
@@ -573,6 +575,12 @@ procedure InitTLS; [public,alias:'FPC_INITTLS'];
 {$endif CPUARM}
 {$endif CPUARM}
 
 
 
 
+{$if FPC_FULLVERSION>30200}
+{$if defined(CPUI386) or defined(CPUARM)}
+{$I abitag.inc}
+{$endif defined(CPUI386) or defined(CPUARM)}
+{$endif FPC_FULLVERSION>30200}
+
 begin
 begin
 {$if defined(i386) and not defined(FPC_USE_LIBC)}
 {$if defined(i386) and not defined(FPC_USE_LIBC)}
   InitSyscallIntf;
   InitSyscallIntf;

+ 1 - 1
tests/test/tmt1.pp

@@ -55,7 +55,7 @@ begin
      if BeginThread({$ifdef fpc}@{$endif}f,pointer(i)) <> tthreadid(0) then
      if BeginThread({$ifdef fpc}@{$endif}f,pointer(i)) <> tthreadid(0) then
        inc(started);
        inc(started);
 
 
-   while finished<started do
+   while volatile(finished)<started do
      {$ifdef wince}sleep(10){$endif};
      {$ifdef wince}sleep(10){$endif};
    writeln(finished);
    writeln(finished);
 end.
 end.

+ 1 - 1
utils/pas2jni/writer.pas

@@ -2075,7 +2075,7 @@ begin
     end;
     end;
 
 
     // Class ref helpers
     // Class ref helpers
-    if FClasses.IndexOf('system.TClass', nil) >= 0 then begin
+    if (u.Name = 'system') and (FClasses.IndexOf('system.TClass', nil) >= 0) then begin
       Fjs.WriteLn('native static long GetClassRef(int index);');
       Fjs.WriteLn('native static long GetClassRef(int index);');
       AddNativeMethod(u, '_GetClassRef', 'GetClassRef', '(I)J');
       AddNativeMethod(u, '_GetClassRef', 'GetClassRef', '(I)J');
       Fjs.WriteLn('static TClass GetTClass(int index) { TClass c = new TClass(null); c._pasobj=GetClassRef(index); return c; }');
       Fjs.WriteLn('static TClass GetTClass(int index) { TClass c = new TClass(null); c._pasobj=GetClassRef(index); return c; }');

+ 0 - 2
utils/pas2js/docs/translation.html

@@ -2923,8 +2923,6 @@ End.
     Width and precision is supported. str(i:10) will add spaces to the left to fill up to 10 characters.</b>
     Width and precision is supported. str(i:10) will add spaces to the left to fill up to 10 characters.</b>
     str(aDouble:1:5) returns a string in decimal format with 5 digits for the fraction.</li>
     str(aDouble:1:5) returns a string in decimal format with 5 digits for the fraction.</li>
     <li>Intrinsic procedure WriteStr(out s: string; params...)</li>
     <li>Intrinsic procedure WriteStr(out s: string; params...)</li>
-    <li><i>Debugger;</i> converts to <i>debugger;</i>. If a debugger is running
-      it will break on this line just like a break point.</li>
     </ul>
     </ul>
     </div>
     </div>
 
 

+ 4 - 4
utils/pas2js/nodepas2js.pp

@@ -6,7 +6,7 @@ program nodepas2js;
 uses
 uses
   JS, NodeJSApp,
   JS, NodeJSApp,
   Classes, SysUtils,
   Classes, SysUtils,
-  Pas2jsFileUtils, Pas2jsLogger, Pas2jsCompiler;
+  Pas2jsFileUtils, Pas2jsLogger, pas2jscompiler, Pas2jsfscompiler;
 
 
 type
 type
 
 
@@ -14,13 +14,13 @@ type
 
 
   TPas2jsCLI = class(TNodeJSApplication)
   TPas2jsCLI = class(TNodeJSApplication)
   private
   private
-    FCompiler: TPas2jsCompiler;
+    FCompiler: TPas2jsFSCompiler;
   protected
   protected
     procedure DoRun; override;
     procedure DoRun; override;
   public
   public
     constructor Create(TheOwner: TComponent); override;
     constructor Create(TheOwner: TComponent); override;
     destructor Destroy; override;
     destructor Destroy; override;
-    property Compiler: TPas2jsCompiler read FCompiler;
+    property Compiler: TPas2jsFsCompiler read FCompiler;
   end;
   end;
 
 
 procedure TPas2jsCLI.DoRun;
 procedure TPas2jsCLI.DoRun;
@@ -65,7 +65,7 @@ constructor TPas2jsCLI.Create(TheOwner: TComponent);
 begin
 begin
   inherited Create(TheOwner);
   inherited Create(TheOwner);
   StopOnException:=True;
   StopOnException:=True;
-  FCompiler:=TPas2jsCompiler.Create;
+  FCompiler:=TPas2jsFSCompiler.Create;
 end;
 end;
 
 
 destructor TPas2jsCLI.Destroy;
 destructor TPas2jsCLI.Destroy;

+ 6 - 4
utils/pas2js/pas2js.pp

@@ -12,7 +12,7 @@ uses
   cthreads, cwstring,
   cthreads, cwstring,
   {$ENDIF}
   {$ENDIF}
   Classes, SysUtils, CustApp,
   Classes, SysUtils, CustApp,
-  Pas2jsFileUtils, Pas2jsLogger, Pas2jsCompiler;
+  Pas2jsFileUtils, Pas2jsLogger, Pas2jsCompiler, pas2jspcucompiler, pas2jscompilerpp, pas2JScompilercfg;
 
 
 Type
 Type
 
 
@@ -20,14 +20,14 @@ Type
 
 
   TPas2jsCLI = class(TCustomApplication)
   TPas2jsCLI = class(TCustomApplication)
   private
   private
-    FCompiler: TPas2jsCompiler;
+    FCompiler: TPas2jsPCUCompiler;
     FWriteOutputToStdErr: Boolean;
     FWriteOutputToStdErr: Boolean;
   protected
   protected
     procedure DoRun; override;
     procedure DoRun; override;
   public
   public
     constructor Create(TheOwner: TComponent); override;
     constructor Create(TheOwner: TComponent); override;
     destructor Destroy; override;
     destructor Destroy; override;
-    property Compiler: TPas2jsCompiler read FCompiler;
+    property Compiler: TPas2jsPCUCompiler read FCompiler;
     property WriteOutputToStdErr: Boolean read FWriteOutputToStdErr write FWriteOutputToStdErr;
     property WriteOutputToStdErr: Boolean read FWriteOutputToStdErr write FWriteOutputToStdErr;
   end;
   end;
 
 
@@ -66,7 +66,9 @@ constructor TPas2jsCLI.Create(TheOwner: TComponent);
 begin
 begin
   inherited Create(TheOwner);
   inherited Create(TheOwner);
   StopOnException:=True;
   StopOnException:=True;
-  FCompiler:=TPas2jsCompiler.Create;
+  FCompiler:=TPas2jsPCUCompiler.Create;
+  FCompiler.ConfigSupport:=TPas2JSFileConfigSupport.Create(FCompiler);
+  FCompiler.PostProcessorSupport:=TPas2JSFSPostProcessorSupport.Create(FCompiler);
 end;
 end;
 
 
 destructor TPas2jsCLI.Destroy;
 destructor TPas2jsCLI.Destroy;

Alguns ficheiros não foram mostrados porque muitos ficheiros mudaram neste diff