Browse Source

* synchronized with trunk

git-svn-id: branches/unicodekvm@49282 -
nickysn 4 years ago
parent
commit
23000ed570
100 changed files with 9305 additions and 295 deletions
  1. 37 0
      .gitattributes
  2. 0 0
      compiler/MPWMake
  3. 1 1
      compiler/Makefile
  4. 1 1
      compiler/Makefile.fpc
  5. 41 3
      compiler/aarch64/agcpugas.pas
  6. 15 7
      compiler/aarch64/aoptcpu.pas
  7. 2 1
      compiler/aarch64/hlcgcpu.pas
  8. 57 11
      compiler/aarch64/ncpuinl.pas
  9. 2 1
      compiler/aasmtai.pas
  10. 4 0
      compiler/arm/aasmcpu.pas
  11. 3 3
      compiler/arm/cpubase.pas
  12. 13 5
      compiler/arm/narmset.pas
  13. 6 0
      compiler/arm/raarmgas.pas
  14. 5 4
      compiler/arm/rgcpu.pas
  15. 9 1
      compiler/assemble.pas
  16. 1 0
      compiler/globals.pas
  17. 1 2
      compiler/m68k/ag68kvasm.pas
  18. 8 0
      compiler/m68k/cpubase.pas
  19. 8 8
      compiler/m68k/r68kgri.inc
  20. 18 18
      compiler/m68k/r68ksri.inc
  21. 6 1
      compiler/m68k/ra68kmot.pas
  22. 34 14
      compiler/ncnv.pas
  23. 4 0
      compiler/ogcoff.pas
  24. 4 1
      compiler/ogelf.pas
  25. 8 0
      compiler/options.pas
  26. 1 0
      compiler/pass_1.pas
  27. 2 1
      compiler/pdecsub.pas
  28. 3 0
      compiler/pgenutil.pas
  29. 8 0
      compiler/pmodules.pas
  30. 14 5
      compiler/scanner.pas
  31. 4 2
      compiler/systems/t_bsd.pas
  32. 17 2
      compiler/systems/t_freertos.pas
  33. 1 1
      compiler/systems/t_nds.pas
  34. 16 3
      compiler/systems/t_sinclairql.pas
  35. 2 2
      compiler/utils/mk68kreg.pp
  36. 35 27
      compiler/wasm32/agllvmmc.pas
  37. 5 2
      compiler/wasm32/agwat.pas
  38. 70 2
      compiler/wasm32/nwasmflw.pas
  39. 10 0
      compiler/x86/aasmcpu.pas
  40. 0 5
      compiler/x86/nx86cnv.pas
  41. 7 1
      packages/fcl-db/src/base/fields.inc
  42. 3265 0
      packages/fcl-mustache/Makefile
  43. 128 0
      packages/fcl-mustache/Makefile.fpc
  44. 27 0
      packages/fcl-mustache/examples/README.txt
  45. 57 0
      packages/fcl-mustache/examples/demo1.lpi
  46. 42 0
      packages/fcl-mustache/examples/demo1.lpr
  47. 57 0
      packages/fcl-mustache/examples/demo2.lpi
  48. 48 0
      packages/fcl-mustache/examples/demo2.lpr
  49. 7 0
      packages/fcl-mustache/examples/family.csv
  50. 10 0
      packages/fcl-mustache/examples/family.json
  51. 22 0
      packages/fcl-mustache/examples/family.tmpl
  52. 57 0
      packages/fcl-mustache/examples/mustache.lpi
  53. 207 0
      packages/fcl-mustache/examples/mustache.lpr
  54. 49 0
      packages/fcl-mustache/fpmake.pp
  55. 268 0
      packages/fcl-mustache/src/fpdbmustache.pp
  56. 399 0
      packages/fcl-mustache/src/fpexmustache.pp
  57. 1340 0
      packages/fcl-mustache/src/fpmustache.pp
  58. 0 0
      packages/fcl-mustache/tests/spec/comments.json
  59. 0 0
      packages/fcl-mustache/tests/spec/delimiters.json
  60. 0 0
      packages/fcl-mustache/tests/spec/interpolation.json
  61. 0 0
      packages/fcl-mustache/tests/spec/inverted.json
  62. 0 0
      packages/fcl-mustache/tests/spec/partials.json
  63. 0 0
      packages/fcl-mustache/tests/spec/sections.json
  64. 290 0
      packages/fcl-mustache/tests/tcbasemustache.pas
  65. 149 0
      packages/fcl-mustache/tests/tcdbmustache.pas
  66. 199 0
      packages/fcl-mustache/tests/tcexmustache.pas
  67. 728 0
      packages/fcl-mustache/tests/tcmustache.pas
  68. 188 0
      packages/fcl-mustache/tests/tcspecs.pas
  69. 88 0
      packages/fcl-mustache/tests/testmustache.lpi
  70. 29 0
      packages/fcl-mustache/tests/testmustache.lpr
  71. 50 9
      packages/fcl-passrc/src/pasresolver.pp
  72. 1 0
      packages/fcl-passrc/src/pasuseanalyzer.pas
  73. 5 2
      packages/fcl-passrc/src/pparser.pp
  74. 27 0
      packages/fcl-passrc/tests/tcresolvegenerics.pas
  75. 13 3
      packages/fcl-web/src/base/custhttpapp.pp
  76. 1 0
      packages/fpmake_add.inc
  77. 6 0
      packages/fpmake_proc.inc
  78. 85 30
      packages/fpmkunit/src/fpmkunit.pp
  79. 1 1
      packages/openssl/src/openssl.pas
  80. 76 39
      packages/pastojs/src/fppas2js.pp
  81. 140 10
      packages/pastojs/tests/tcgenerics.pas
  82. 38 37
      packages/pastojs/tests/tcmodules.pas
  83. 5 2
      packages/winunits-base/src/comserv.pp
  84. 13 2
      rtl/aarch64/math.inc
  85. 8 8
      rtl/aarch64/mathu.inc
  86. 1 1
      rtl/darwin/Makefile
  87. 1 1
      rtl/darwin/Makefile.fpc
  88. 7 5
      rtl/objpas/sysutils/dati.inc
  89. 1 1
      rtl/objpas/sysutils/filutilh.inc
  90. 1 1
      rtl/objpas/sysutils/osutil.inc
  91. 4 3
      rtl/sinclairql/buildrtl.pp
  92. 50 0
      rtl/sinclairql/classes.pp
  93. 1 1
      rtl/sinclairql/si_prc.pp
  94. 501 0
      rtl/sinclairql/sysutils.pp
  95. 9 4
      rtl/win/sysutils.pp
  96. 8 0
      tests/tbf/tb0274.pp
  97. 22 0
      tests/webtbf/tw38771.pp
  98. 42 0
      tests/webtbs/tw38353.pp
  99. 23 0
      tests/webtbs/tw38631.pp
  100. 28 0
      tests/webtbs/tw38766.pp

+ 37 - 0
.gitattributes

@@ -3837,6 +3837,35 @@ packages/fcl-json/tests/testjsondata.pp svneol=native#text/plain
 packages/fcl-json/tests/testjsonparser.pp svneol=native#text/plain
 packages/fcl-json/tests/testjsonparser.pp svneol=native#text/plain
 packages/fcl-json/tests/testjsonreader.pp svneol=native#text/plain
 packages/fcl-json/tests/testjsonreader.pp svneol=native#text/plain
 packages/fcl-json/tests/testjsonrtti.pp svneol=native#text/plain
 packages/fcl-json/tests/testjsonrtti.pp svneol=native#text/plain
+packages/fcl-mustache/Makefile svneol=native#text/plain
+packages/fcl-mustache/Makefile.fpc svneol=native#text/plain
+packages/fcl-mustache/examples/README.txt svneol=native#text/plain
+packages/fcl-mustache/examples/demo1.lpi svneol=native#text/plain
+packages/fcl-mustache/examples/demo1.lpr svneol=native#text/plain
+packages/fcl-mustache/examples/demo2.lpi svneol=native#text/plain
+packages/fcl-mustache/examples/demo2.lpr svneol=native#text/plain
+packages/fcl-mustache/examples/family.csv svneol=native#text/plain
+packages/fcl-mustache/examples/family.json svneol=native#text/plain
+packages/fcl-mustache/examples/family.tmpl svneol=native#text/plain
+packages/fcl-mustache/examples/mustache.lpi svneol=native#text/plain
+packages/fcl-mustache/examples/mustache.lpr svneol=native#text/plain
+packages/fcl-mustache/fpmake.pp svneol=native#text/plain
+packages/fcl-mustache/src/fpdbmustache.pp svneol=native#text/plain
+packages/fcl-mustache/src/fpexmustache.pp svneol=native#text/plain
+packages/fcl-mustache/src/fpmustache.pp svneol=native#text/plain
+packages/fcl-mustache/tests/spec/comments.json svneol=native#text/plain
+packages/fcl-mustache/tests/spec/delimiters.json svneol=native#text/plain
+packages/fcl-mustache/tests/spec/interpolation.json svneol=native#text/plain
+packages/fcl-mustache/tests/spec/inverted.json svneol=native#text/plain
+packages/fcl-mustache/tests/spec/partials.json svneol=native#text/plain
+packages/fcl-mustache/tests/spec/sections.json svneol=native#text/plain
+packages/fcl-mustache/tests/tcbasemustache.pas svneol=native#text/plain
+packages/fcl-mustache/tests/tcdbmustache.pas svneol=native#text/plain
+packages/fcl-mustache/tests/tcexmustache.pas svneol=native#text/plain
+packages/fcl-mustache/tests/tcmustache.pas svneol=native#text/plain
+packages/fcl-mustache/tests/tcspecs.pas svneol=native#text/plain
+packages/fcl-mustache/tests/testmustache.lpi svneol=native#text/plain
+packages/fcl-mustache/tests/testmustache.lpr svneol=native#text/plain
 packages/fcl-net/Makefile svneol=native#text/plain
 packages/fcl-net/Makefile svneol=native#text/plain
 packages/fcl-net/Makefile.fpc svneol=native#text/plain
 packages/fcl-net/Makefile.fpc svneol=native#text/plain
 packages/fcl-net/Makefile.fpc.fpcmake svneol=native#text/plain
 packages/fcl-net/Makefile.fpc.fpcmake svneol=native#text/plain
@@ -12093,6 +12122,7 @@ rtl/riscv64/stringss.inc svneol=native#text/plain
 rtl/sinclairql/Makefile svneol=native#text/plain
 rtl/sinclairql/Makefile svneol=native#text/plain
 rtl/sinclairql/Makefile.fpc svneol=native#text/plain
 rtl/sinclairql/Makefile.fpc svneol=native#text/plain
 rtl/sinclairql/buildrtl.pp svneol=native#text/plain
 rtl/sinclairql/buildrtl.pp svneol=native#text/plain
+rtl/sinclairql/classes.pp svneol=native#text/plain
 rtl/sinclairql/qdos.inc svneol=native#text/plain
 rtl/sinclairql/qdos.inc svneol=native#text/plain
 rtl/sinclairql/qdosfuncs.inc svneol=native#text/plain
 rtl/sinclairql/qdosfuncs.inc svneol=native#text/plain
 rtl/sinclairql/qdosh.inc svneol=native#text/plain
 rtl/sinclairql/qdosh.inc svneol=native#text/plain
@@ -12107,6 +12137,7 @@ rtl/sinclairql/sysheap.inc svneol=native#text/plain
 rtl/sinclairql/sysos.inc svneol=native#text/plain
 rtl/sinclairql/sysos.inc svneol=native#text/plain
 rtl/sinclairql/sysosh.inc svneol=native#text/plain
 rtl/sinclairql/sysosh.inc svneol=native#text/plain
 rtl/sinclairql/system.pp svneol=native#text/plain
 rtl/sinclairql/system.pp svneol=native#text/plain
+rtl/sinclairql/sysutils.pp svneol=native#text/plain
 rtl/sinclairql/tthread.inc svneol=native#text/plain
 rtl/sinclairql/tthread.inc svneol=native#text/plain
 rtl/solaris/Makefile svneol=native#text/plain
 rtl/solaris/Makefile svneol=native#text/plain
 rtl/solaris/Makefile.fpc svneol=native#text/plain
 rtl/solaris/Makefile.fpc svneol=native#text/plain
@@ -12895,6 +12926,7 @@ tests/tbf/tb0270.pp svneol=native#text/pascal
 tests/tbf/tb0271.pp svneol=native#text/pascal
 tests/tbf/tb0271.pp svneol=native#text/pascal
 tests/tbf/tb0272.pp svneol=native#text/plain
 tests/tbf/tb0272.pp svneol=native#text/plain
 tests/tbf/tb0273.pp svneol=native#text/pascal
 tests/tbf/tb0273.pp svneol=native#text/pascal
+tests/tbf/tb0274.pp svneol=native#text/pascal
 tests/tbf/tb0588.pp svneol=native#text/pascal
 tests/tbf/tb0588.pp svneol=native#text/pascal
 tests/tbf/ub0115.pp svneol=native#text/plain
 tests/tbf/ub0115.pp svneol=native#text/plain
 tests/tbf/ub0149.pp svneol=native#text/plain
 tests/tbf/ub0149.pp svneol=native#text/plain
@@ -16890,6 +16922,7 @@ tests/webtbf/tw38289b.pp svneol=native#text/pascal
 tests/webtbf/tw38439.pp svneol=native#text/pascal
 tests/webtbf/tw38439.pp svneol=native#text/pascal
 tests/webtbf/tw38504.pp svneol=native#text/pascal
 tests/webtbf/tw38504.pp svneol=native#text/pascal
 tests/webtbf/tw38504b.pp svneol=native#text/pascal
 tests/webtbf/tw38504b.pp svneol=native#text/pascal
+tests/webtbf/tw38771.pp svneol=native#text/pascal
 tests/webtbf/tw3930a.pp svneol=native#text/plain
 tests/webtbf/tw3930a.pp svneol=native#text/plain
 tests/webtbf/tw3931b.pp svneol=native#text/plain
 tests/webtbf/tw3931b.pp svneol=native#text/plain
 tests/webtbf/tw3969.pp svneol=native#text/plain
 tests/webtbf/tw3969.pp svneol=native#text/plain
@@ -18839,6 +18872,7 @@ tests/webtbs/tw3833.pp svneol=native#text/plain
 tests/webtbs/tw38337.pp svneol=native#text/plain
 tests/webtbs/tw38337.pp svneol=native#text/plain
 tests/webtbs/tw38339.pp svneol=native#text/plain
 tests/webtbs/tw38339.pp svneol=native#text/plain
 tests/webtbs/tw38351.pp -text svneol=native#text/pascal
 tests/webtbs/tw38351.pp -text svneol=native#text/pascal
+tests/webtbs/tw38353.pp svneol=native#text/pascal
 tests/webtbs/tw38385.pp svneol=native#text/pascal
 tests/webtbs/tw38385.pp svneol=native#text/pascal
 tests/webtbs/tw38390.pp svneol=native#text/pascal
 tests/webtbs/tw38390.pp svneol=native#text/pascal
 tests/webtbs/tw3840.pp svneol=native#text/plain
 tests/webtbs/tw3840.pp svneol=native#text/plain
@@ -18856,6 +18890,7 @@ tests/webtbs/tw38549c.pp svneol=native#text/plain
 tests/webtbs/tw38549d.pp svneol=native#text/plain
 tests/webtbs/tw38549d.pp svneol=native#text/plain
 tests/webtbs/tw38557.pp svneol=native#text/pascal
 tests/webtbs/tw38557.pp svneol=native#text/pascal
 tests/webtbs/tw3863.pp svneol=native#text/plain
 tests/webtbs/tw3863.pp svneol=native#text/plain
+tests/webtbs/tw38631.pp svneol=native#text/pascal
 tests/webtbs/tw38636.pp svneol=native#text/plain
 tests/webtbs/tw38636.pp svneol=native#text/plain
 tests/webtbs/tw3864.pp svneol=native#text/plain
 tests/webtbs/tw3864.pp svneol=native#text/plain
 tests/webtbs/tw38642.pp svneol=native#text/pascal
 tests/webtbs/tw38642.pp svneol=native#text/pascal
@@ -18865,6 +18900,8 @@ tests/webtbs/tw3870.pp svneol=native#text/plain
 tests/webtbs/tw38703.pp svneol=native#text/pascal
 tests/webtbs/tw38703.pp svneol=native#text/pascal
 tests/webtbs/tw38718.pp svneol=native#text/pascal
 tests/webtbs/tw38718.pp svneol=native#text/pascal
 tests/webtbs/tw38733.pp svneol=native#text/pascal
 tests/webtbs/tw38733.pp svneol=native#text/pascal
+tests/webtbs/tw38766.pp svneol=native#text/plain
+tests/webtbs/tw38802.pp svneol=native#text/pascal
 tests/webtbs/tw3893.pp svneol=native#text/plain
 tests/webtbs/tw3893.pp svneol=native#text/plain
 tests/webtbs/tw3898.pp svneol=native#text/plain
 tests/webtbs/tw3898.pp svneol=native#text/plain
 tests/webtbs/tw3899.pp svneol=native#text/plain
 tests/webtbs/tw3899.pp svneol=native#text/plain

File diff suppressed because it is too large
+ 0 - 0
compiler/MPWMake


+ 1 - 1
compiler/Makefile

@@ -581,7 +581,7 @@ endif
 endif
 endif
 endif
 endif
 endif
 endif
-override LOCALOPT+=-d$(CPC_TARGET) -dGDB -dBROWSERLOG
+override LOCALOPT+=-d$(CPC_TARGET) -dGDB
 ifdef LLVM
 ifdef LLVM
 ifeq ($(findstring $(PPC_TARGET),x86_64 aarch64 arm),)
 ifeq ($(findstring $(PPC_TARGET),x86_64 aarch64 arm),)
 $(error The $(PPC_TARGET) architecture is not (yet) supported by the FPC/LLVM code generator)
 $(error The $(PPC_TARGET) architecture is not (yet) supported by the FPC/LLVM code generator)

+ 1 - 1
compiler/Makefile.fpc

@@ -323,7 +323,7 @@ endif
 endif
 endif
 
 
 # set correct defines (-d$(CPU_TARGET) is automatically added in makefile.fpc)
 # set correct defines (-d$(CPU_TARGET) is automatically added in makefile.fpc)
-override LOCALOPT+=-d$(CPC_TARGET) -dGDB -dBROWSERLOG
+override LOCALOPT+=-d$(CPC_TARGET) -dGDB
 
 
 #include LLVM define/directory if requested
 #include LLVM define/directory if requested
 ifdef LLVM
 ifdef LLVM

+ 41 - 3
compiler/aarch64/agcpugas.pas

@@ -41,10 +41,12 @@ unit agcpugas;
 
 
       TAArch64Assembler=class(TGNUassembler)
       TAArch64Assembler=class(TGNUassembler)
         constructor CreateWithWriter(info: pasminfo; wr: TExternalAssemblerOutputFile; freewriter, smart: boolean); override;
         constructor CreateWithWriter(info: pasminfo; wr: TExternalAssemblerOutputFile; freewriter, smart: boolean); override;
+        function MakeCmdLine: TCmdStr; override;
       end;
       end;
 
 
       TAArch64AppleAssembler=class(TAppleGNUassembler)
       TAArch64AppleAssembler=class(TAppleGNUassembler)
         constructor CreateWithWriter(info: pasminfo; wr: TExternalAssemblerOutputFile; freewriter, smart: boolean); override;
         constructor CreateWithWriter(info: pasminfo; wr: TExternalAssemblerOutputFile; freewriter, smart: boolean); override;
+        function MakeCmdLine: TCmdStr; override;
       end;
       end;
 
 
       TAArch64ClangGASAssembler=class(TAArch64Assembler)
       TAArch64ClangGASAssembler=class(TAArch64Assembler)
@@ -53,6 +55,7 @@ unit agcpugas;
       protected
       protected
         function sectionflags(secflags:TSectionFlags):string;override;
         function sectionflags(secflags:TSectionFlags):string;override;
       public
       public
+        function MakeCmdLine: TCmdStr; override;
         procedure WriteAsmList; override;
         procedure WriteAsmList; override;
       end;
       end;
 
 
@@ -64,6 +67,18 @@ unit agcpugas;
 
 
     const
     const
       cputype_to_gas_march : array[tcputype] of string = (
       cputype_to_gas_march : array[tcputype] of string = (
+        '', // cpu_none
+        '', // armv8 is not accepted by GNU assembler
+        'armv8-a',
+        'armv8.1-a',
+        'armv8.2-a',
+        'armv8.3-a',
+        'armv8.4-a',
+        'armv8.5-a',
+        'armv8.6-a'
+      );
+
+      cputype_to_clang_march : array[tcputype] of string = (
         '', // cpu_none
         '', // cpu_none
         'armv8',
         'armv8',
         'armv8-a',
         'armv8-a',
@@ -94,6 +109,15 @@ unit agcpugas;
         InstrWriter := TAArch64InstrWriter.create(self);
         InstrWriter := TAArch64InstrWriter.create(self);
       end;
       end;
 
 
+    function TAArch64Assembler.MakeCmdLine: TCmdStr;
+      begin
+        result:=inherited MakeCmdLine;
+        if cputype_to_gas_march[current_settings.cputype] <> '' then
+	  Replace(result,'$MARCHOPT','-march='+cputype_to_gas_march[current_settings.cputype])
+        else
+          Replace(result,'$MARCHOPT','');
+      end;
+
 {****************************************************************************}
 {****************************************************************************}
 {                      Apple AArch64 Assembler writer                        }
 {                      Apple AArch64 Assembler writer                        }
 {****************************************************************************}
 {****************************************************************************}
@@ -105,10 +129,24 @@ unit agcpugas;
       end;
       end;
 
 
 
 
+    function TAArch64AppleAssembler.MakeCmdLine: TCmdStr;
+      begin
+        result:=inherited MakeCmdLine;
+        if cputype_to_gas_march[current_settings.cputype] <> '' then
+	  Replace(result,'$MARCHOPT','-march='+cputype_to_gas_march[current_settings.cputype])
+        else
+          Replace(result,'$MARCHOPT','');
+      end;
+
 {****************************************************************************}
 {****************************************************************************}
 {                      CLang AArch64 Assembler writer                        }
 {                      CLang AArch64 Assembler writer                        }
 {****************************************************************************}
 {****************************************************************************}
 
 
+    function TAArch64ClangGASAssembler.MakeCmdLine: TCmdStr;
+      begin
+        result:=inherited MakeCmdLine;
+      end;
+
     procedure TAArch64ClangGASAssembler.TransformSEHDirectives(list:TAsmList);
     procedure TAArch64ClangGASAssembler.TransformSEHDirectives(list:TAsmList);
 
 
       function convert_unwinddata(list:tasmlist):tdynamicarray;
       function convert_unwinddata(list:tasmlist):tdynamicarray;
@@ -773,7 +811,7 @@ unit agcpugas;
             id     : as_gas;
             id     : as_gas;
             idtxt  : 'AS';
             idtxt  : 'AS';
             asmbin : 'as';
             asmbin : 'as';
-            asmcmd : '-o $OBJ $EXTRAOPT $ASM';
+            asmcmd : '-o $OBJ $MARCHOPT $EXTRAOPT $ASM';
             supported_targets : [system_aarch64_freebsd,system_aarch64_linux,system_aarch64_android];
             supported_targets : [system_aarch64_freebsd,system_aarch64_linux,system_aarch64_android];
             flags : [af_needar,af_smartlink_sections];
             flags : [af_needar,af_smartlink_sections];
             labelprefix : '.L';
             labelprefix : '.L';
@@ -787,7 +825,7 @@ unit agcpugas;
             id     : as_clang_asdarwin;
             id     : as_clang_asdarwin;
             idtxt  : 'CLANG';
             idtxt  : 'CLANG';
             asmbin : 'clang';
             asmbin : 'clang';
-            asmcmd : '-x assembler -c -target $TRIPLET -o $OBJ $EXTRAOPT -x assembler $ASM';
+            asmcmd : '-x assembler -c -target $TRIPLET -o $OBJ $MARCHOPT $EXTRAOPT -x assembler $ASM';
             supported_targets : [system_aarch64_ios,system_aarch64_darwin];
             supported_targets : [system_aarch64_ios,system_aarch64_darwin];
             flags : [af_needar,af_smartlink_sections,af_supports_dwarf,af_llvm,af_supports_hlcfi];
             flags : [af_needar,af_smartlink_sections,af_supports_dwarf,af_llvm,af_supports_hlcfi];
             labelprefix : 'L';
             labelprefix : 'L';
@@ -801,7 +839,7 @@ unit agcpugas;
             id     : as_clang_gas;
             id     : as_clang_gas;
             idtxt  : 'CLANG';
             idtxt  : 'CLANG';
             asmbin : 'clang';
             asmbin : 'clang';
-            asmcmd : '-x assembler -c -target $TRIPLET -o $OBJ $EXTRAOPT -x assembler $ASM';
+            asmcmd : '-x assembler -c -target $TRIPLET -o $OBJ $MARCHOPT $EXTRAOPT -x assembler $ASM';
             supported_targets : [system_aarch64_win64];
             supported_targets : [system_aarch64_win64];
             flags : [af_needar,af_smartlink_sections,af_supports_dwarf,af_llvm,af_supports_hlcfi];
             flags : [af_needar,af_smartlink_sections,af_supports_dwarf,af_llvm,af_supports_hlcfi];
             labelprefix : '.L';
             labelprefix : '.L';

+ 15 - 7
compiler/aarch64/aoptcpu.pas

@@ -379,15 +379,23 @@ Implementation
                          taicpu(hp1).oper[0]^.reg, taicpu(p).oper[1]^.reg,
                          taicpu(hp1).oper[0]^.reg, taicpu(p).oper[1]^.reg,
                          shifterop);
                          shifterop);
 
 
+                { Make sure the register used in the shifting is tracked all
+                  the way through, otherwise it may become deallocated while
+                  it's still live and cause incorrect optimisations later }
+                if (taicpu(hp1).oper[0]^.reg <> taicpu(p).oper[1]^.reg) then
+                  begin
+                    TransferUsedRegs(TmpUsedRegs);
+                    UpdateUsedRegs(TmpUsedRegs, tai(p.Next));
+                    ALlocRegBetween(taicpu(p).oper[1]^.reg, p, hp1, TmpUsedRegs);
+                  end;
+
                 taicpu(hp2).fileinfo:=taicpu(hp1).fileinfo;
                 taicpu(hp2).fileinfo:=taicpu(hp1).fileinfo;
                 asml.insertbefore(hp2, hp1);
                 asml.insertbefore(hp2, hp1);
-                GetNextInstruction(p, hp2);
-                asml.remove(p);
-                asml.remove(hp1);
-                p.free;
-                hp1.free;
-                p:=hp2;
-                DebugMsg('Peephole FoldShiftProcess done', p);
+
+                RemoveInstruction(hp1);
+                RemoveCurrentp(p);
+
+                DebugMsg('Peephole FoldShiftProcess done', hp2);
                 Result:=true;
                 Result:=true;
                 break;
                 break;
               end;
               end;

+ 2 - 1
compiler/aarch64/hlcgcpu.pas

@@ -210,7 +210,8 @@ implementation
       if slopt in [SL_SETZERO,SL_SETMAX] then
       if slopt in [SL_SETZERO,SL_SETMAX] then
         inherited
         inherited
       else if not(sreg.bitlen in [32,64]) or
       else if not(sreg.bitlen in [32,64]) or
-              (sreg.startbit<>0) then
+              (sreg.startbit<>0) or
+              (getsubreg(fromreg)<getsubreg(sreg.subsetreg)) then
         begin
         begin
           makeregssamesize(list,def_cgsize(fromsize),sreg.subsetregsize,fromreg,sreg.subsetreg,fromreg,toreg);
           makeregssamesize(list,def_cgsize(fromsize),sreg.subsetregsize,fromreg,sreg.subsetreg,fromreg,toreg);
           list.concat(taicpu.op_reg_reg_const_const(A_BFI,toreg,fromreg,sreg.startbit,sreg.bitlen))
           list.concat(taicpu.op_reg_reg_const_const(A_BFI,toreg,fromreg,sreg.startbit,sreg.bitlen))

+ 57 - 11
compiler/aarch64/ncpuinl.pas

@@ -1,7 +1,7 @@
 {
 {
     Copyright (c) 1998-2002 by Florian Klaempfl
     Copyright (c) 1998-2002 by Florian Klaempfl
 
 
-    Generates ARM inline nodes
+    Generates AAarch64 inline nodes
 
 
     This program is free software; you can redistribute it and/or modify
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
     it under the terms of the GNU General Public License as published by
@@ -35,6 +35,8 @@ interface
         function first_sqrt_real: tnode; override;
         function first_sqrt_real: tnode; override;
         function first_round_real: tnode; override;
         function first_round_real: tnode; override;
         function first_trunc_real: tnode; override;
         function first_trunc_real: tnode; override;
+        function first_int_real: tnode; override;
+        function first_frac_real: tnode; override;
         function first_fma : tnode; override;
         function first_fma : tnode; override;
         procedure second_abs_real; override;
         procedure second_abs_real; override;
         procedure second_sqr_real; override;
         procedure second_sqr_real; override;
@@ -42,6 +44,8 @@ interface
         procedure second_abs_long; override;
         procedure second_abs_long; override;
         procedure second_round_real; override;
         procedure second_round_real; override;
         procedure second_trunc_real; override;
         procedure second_trunc_real; override;
+        procedure second_int_real; override;
+        procedure second_frac_real; override;
         procedure second_get_frame; override;
         procedure second_get_frame; override;
         procedure second_fma; override;
         procedure second_fma; override;
         procedure second_prefetch; override;
         procedure second_prefetch; override;
@@ -108,16 +112,31 @@ implementation
       end;
       end;
 
 
 
 
-     function taarch64inlinenode.first_fma : tnode;
-       begin
-         if ((is_double(resultdef)) or (is_single(resultdef))) then
-           begin
-             expectloc:=LOC_MMREGISTER;
-             Result:=nil;
-           end
-         else
-           Result:=inherited first_fma;
-       end;
+    function taarch64inlinenode.first_int_real : tnode;
+      begin
+        expectloc:=LOC_MMREGISTER;
+        result:=nil;
+      end;
+
+
+    function taarch64inlinenode.first_frac_real : tnode;
+      begin
+        expectloc:=LOC_MMREGISTER;
+        result:=nil;
+      end;
+
+
+    function taarch64inlinenode.first_fma : tnode;
+      begin
+        if ((is_double(resultdef)) or (is_single(resultdef))) then
+          begin
+            expectloc:=LOC_MMREGISTER;
+            Result:=nil;
+          end
+        else
+          Result:=inherited first_fma;
+     end;
+
 
 
     procedure taarch64inlinenode.second_abs_real;
     procedure taarch64inlinenode.second_abs_real;
       begin
       begin
@@ -187,6 +206,33 @@ implementation
       end;
       end;
 
 
 
 
+    procedure taarch64inlinenode.second_int_real;
+      var
+        hreg: tregister;
+      begin
+        secondpass(left);
+        hlcg.location_force_mmregscalar(current_asmdata.CurrAsmList,left.location,left.resultdef,true);
+        location_reset(location,LOC_MMREGISTER,def_cgsize(resultdef));
+        location.register:=cg.getmmregister(current_asmdata.CurrAsmList,location.size);
+        current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_FRINTZ,location.register,left.location.register));
+        cg.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList);
+      end;
+
+
+    procedure taarch64inlinenode.second_frac_real;
+      var
+        hreg: tregister;
+      begin
+        secondpass(left);
+        hlcg.location_force_mmregscalar(current_asmdata.CurrAsmList,left.location,left.resultdef,true);
+        location_reset(location,LOC_MMREGISTER,def_cgsize(resultdef));
+        location.register:=cg.getmmregister(current_asmdata.CurrAsmList,location.size);
+        current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_FRINTZ,location.register,left.location.register));
+        current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_FSUB,location.register,left.location.register,location.register));
+        cg.maybe_check_for_fpu_exception(current_asmdata.CurrAsmList);
+      end;
+
+
     procedure taarch64inlinenode.second_get_frame;
     procedure taarch64inlinenode.second_get_frame;
       begin
       begin
         location_reset(location,LOC_CREGISTER,OS_ADDR);
         location_reset(location,LOC_CREGISTER,OS_ADDR);

+ 2 - 1
compiler/aasmtai.pas

@@ -402,7 +402,7 @@ interface
         { supported by recent clang-based assemblers for data-in-code  }
         { supported by recent clang-based assemblers for data-in-code  }
         asd_data_region, asd_end_data_region,
         asd_data_region, asd_end_data_region,
         { ARM }
         { ARM }
-        asd_thumb_func,asd_code,
+        asd_thumb_func,asd_code,asd_force_thumb,
         { restricts the assembler only to those instructions, which are
         { restricts the assembler only to those instructions, which are
           available on the specified CPU; this represents directives such as
           available on the specified CPU; this represents directives such as
           NASM's 'CPU 686' or MASM/TASM's '.686p'. Might not be supported by
           NASM's 'CPU 686' or MASM/TASM's '.686p'. Might not be supported by
@@ -452,6 +452,7 @@ interface
         { ARM }
         { ARM }
         'thumb_func',
         'thumb_func',
         'code',
         'code',
+	'force_thumb',
         'cpu',
         'cpu',
         { for the OMF object format }
         { for the OMF object format }
         'omf_line',
         'omf_line',

+ 4 - 0
compiler/arm/aasmcpu.pas

@@ -1621,6 +1621,9 @@ implementation
           end;
           end;
       end;
       end;
 
 
+{$push}
+{ Disable range and overflow checking here }
+{$R-}{$Q-}        
     procedure fix_invalid_imms(list: TAsmList);
     procedure fix_invalid_imms(list: TAsmList);
       var
       var
         curtai: tai;
         curtai: tai;
@@ -1669,6 +1672,7 @@ implementation
           end;
           end;
       end;
       end;
 
 
+{$pop}
 
 
     procedure gather_it_info(list: TAsmList);
     procedure gather_it_info(list: TAsmList);
       var
       var

+ 3 - 3
compiler/arm/cpubase.pas

@@ -605,6 +605,9 @@ unit cpubase;
       end;
       end;
 
 
 
 
+{$push}
+{ Disable range and overflow checking here }
+{$R-}{$Q-}        
     function is_thumb32_imm(d: aint): boolean;
     function is_thumb32_imm(d: aint): boolean;
       var
       var
         t : aint;
         t : aint;
@@ -639,9 +642,6 @@ unit cpubase;
           end;
           end;
       end;
       end;
     
     
-{$push}
-{ Disable range and overflow checking here }
-{$R-}{$Q-}        
     function is_continuous_mask(d : aword;var lsb, width: byte) : boolean;
     function is_continuous_mask(d : aword;var lsb, width: byte) : boolean;
       var
       var
         msb : byte;
         msb : byte;

+ 13 - 5
compiler/arm/narmset.pas

@@ -191,15 +191,23 @@ implementation
 
 
         procedure genitem_thumb2(list:TAsmList;t : pcaselabel);
         procedure genitem_thumb2(list:TAsmList;t : pcaselabel);
           var
           var
-            i : aint;
+            i : int64;
           begin
           begin
             if assigned(t^.less) then
             if assigned(t^.less) then
               genitem_thumb2(list,t^.less);
               genitem_thumb2(list,t^.less);
             { fill possible hole }
             { fill possible hole }
-            for i:=last.svalue+1 to t^._low.svalue-1 do
-              list.concat(Tai_const.Create_rel_sym(aitconst_half16bit,tablelabel,elselabel));
-            for i:=t^._low.svalue to t^._high.svalue do
-              list.concat(Tai_const.Create_rel_sym(aitconst_half16bit,tablelabel,blocklabel(t^.blockid)));
+            i:=last.svalue+1;
+            while i<=t^._low.svalue-1 do
+              begin
+                list.concat(Tai_const.Create_rel_sym(aitconst_half16bit,tablelabel,elselabel));
+                i:=i+1;
+              end;
+            i:=t^._low.svalue;
+            while i<=t^._high.svalue do
+              begin
+                list.concat(Tai_const.Create_rel_sym(aitconst_half16bit,tablelabel,blocklabel(t^.blockid)));
+                i:=i+1;
+              end;
             last:=t^._high.svalue;
             last:=t^._high.svalue;
             if assigned(t^.greater) then
             if assigned(t^.greater) then
               genitem_thumb2(list,t^.greater);
               genitem_thumb2(list,t^.greater);

+ 6 - 0
compiler/arm/raarmgas.pas

@@ -151,6 +151,7 @@ Unit raarmgas;
     function tarmattreader.is_targetdirective(const s: string): boolean;
     function tarmattreader.is_targetdirective(const s: string): boolean;
       begin
       begin
         case s of
         case s of
+          '.force_thumb',
           '.thumb_func',
           '.thumb_func',
           '.code',
           '.code',
           '.thumb_set':
           '.thumb_set':
@@ -1464,6 +1465,11 @@ Unit raarmgas;
             begin
             begin
               consume(AS_TARGET_DIRECTIVE);
               consume(AS_TARGET_DIRECTIVE);
               curList.concat(tai_directive.create(asd_thumb_func,''));
               curList.concat(tai_directive.create(asd_thumb_func,''));
+            end;
+          '.force_thumb':
+            begin
+              consume(AS_TARGET_DIRECTIVE);
+              curList.concat(tai_directive.create(asd_force_thumb,''));
             end
             end
           else
           else
             inherited HandleTargetDirective;
             inherited HandleTargetDirective;

+ 5 - 4
compiler/arm/rgcpu.pas

@@ -400,10 +400,11 @@ unit rgcpu;
         level := 0;
         level := 0;
         while assigned(hp) do
         while assigned(hp) do
           begin
           begin
-            if IsIT(taicpu(hp).opcode) then
-              break
-            else if hp.typ=ait_instruction then
-              inc(level);
+            if hp.typ=ait_instruction then
+              if IsIT(taicpu(hp).opcode) then
+                break
+              else
+                inc(level);
 
 
             hp:=tai(hp.Previous);
             hp:=tai(hp.Previous);
           end;
           end;

+ 9 - 1
compiler/assemble.pas

@@ -1403,8 +1403,8 @@ Implementation
                   len:=p-pstart;
                   len:=p-pstart;
                   if len>255 then
                   if len>255 then
                     internalerror(200509187);
                     internalerror(200509187);
-                  move(pstart^,hs[1],len);
                   hs[0]:=chr(len);
                   hs[0]:=chr(len);
+                  move(pstart^,hs[1],len);
                   sym:=objdata.symbolref(hs);
                   sym:=objdata.symbolref(hs);
                   { Second symbol? }
                   { Second symbol? }
                   if assigned(relocsym) then
                   if assigned(relocsym) then
@@ -1719,6 +1719,11 @@ Implementation
 {$ifdef ARM}
 {$ifdef ARM}
                    asd_thumb_func:
                    asd_thumb_func:
                      ObjData.ThumbFunc:=true;
                      ObjData.ThumbFunc:=true;
+                   asd_force_thumb:
+                     begin
+                       ObjData.ThumbFunc:=true;
+                       Code16:=true;
+                     end;
                    asd_code:
                    asd_code:
                      begin
                      begin
                        { ai_directive(hp).name can be only 16 or 32, this is checked by the reader }
                        { ai_directive(hp).name can be only 16 or 32, this is checked by the reader }
@@ -1924,6 +1929,9 @@ Implementation
                    asd_thumb_func:
                    asd_thumb_func:
                      { ignore for now, but should be added}
                      { ignore for now, but should be added}
                      ;
                      ;
+                   asd_force_thumb:
+                     { ignore for now, but should be added}
+                     ;
                    asd_code:
                    asd_code:
                      { ignore for now, but should be added}
                      { ignore for now, but should be added}
                      ;
                      ;

+ 1 - 0
compiler/globals.pas

@@ -416,6 +416,7 @@ interface
 {$if defined(m68k)}
 {$if defined(m68k)}
        { Sinclair QL specific }
        { Sinclair QL specific }
        sinclairql_metadata_format: string[4] = 'QHDR';
        sinclairql_metadata_format: string[4] = 'QHDR';
+       sinclairql_vlink_experimental: boolean = false; { temporary }
 {$endif defined(m68k)}
 {$endif defined(m68k)}
 
 
        { default name of the C-style "main" procedure of the library/program }
        { default name of the C-style "main" procedure of the library/program }

+ 1 - 2
compiler/m68k/ag68kvasm.pas

@@ -96,8 +96,7 @@ unit ag68kvasm;
         result:=asminfo^.asmcmd;
         result:=asminfo^.asmcmd;
 
 
         case target_info.system of
         case target_info.system of
-          { a.out doesn't support named sections, a.out is limited 
-            (no named sections) lets use ELF for interoperability }
+          { a.out doesn't support named sections, lets use ELF for interoperability }
           system_m68k_amiga,
           system_m68k_amiga,
           system_m68k_atari,
           system_m68k_atari,
           system_m68k_sinclairql: objtype:='-Felf';
           system_m68k_sinclairql: objtype:='-Felf';

+ 8 - 0
compiler/m68k/cpubase.pas

@@ -331,6 +331,10 @@ implementation
         {$i r68kstd.inc}
         {$i r68kstd.inc}
       );
       );
 
 
+      std_regfullname_table : TRegNameTable = (
+        {$i r68kstdf.inc}
+      );
+
       regnumber_index : array[tregisterindex] of tregisterindex = (
       regnumber_index : array[tregisterindex] of tregisterindex = (
         {$i r68krni.inc}
         {$i r68krni.inc}
       );
       );
@@ -484,6 +488,10 @@ implementation
     function std_regnum_search(const s:string):Tregister;
     function std_regnum_search(const s:string):Tregister;
       begin
       begin
         result:=regnumber_table[findreg_by_name_table(s,std_regname_table,std_regname_index)];
         result:=regnumber_table[findreg_by_name_table(s,std_regname_table,std_regname_index)];
+        if result=NR_NO then
+          begin
+            result:=regnumber_table[findreg_by_name_table(s,std_regfullname_table,std_regname_index)];
+          end;
       end;
       end;
 
 
 
 

+ 8 - 8
compiler/m68k/r68kgri.inc

@@ -16,30 +16,30 @@
 56,
 56,
 57,
 57,
 34,
 34,
+3,
 1,
 1,
 2,
 2,
-3,
+6,
 4,
 4,
 5,
 5,
-6,
+9,
 7,
 7,
 8,
 8,
-9,
 12,
 12,
-11,
 10,
 10,
+11,
+15,
 13,
 13,
 14,
 14,
-15,
+18,
 16,
 16,
 17,
 17,
-18,
+21,
 19,
 19,
 20,
 20,
-21,
 24,
 24,
-23,
 22,
 22,
+23,
 38,
 38,
 25,
 25,
 26,
 26,

+ 18 - 18
compiler/m68k/r68ksri.inc

@@ -1,46 +1,46 @@
 { don't edit, this file is generated from m68kreg.dat }
 { don't edit, this file is generated from m68kreg.dat }
 0,
 0,
-43,
 42,
 42,
-45,
+43,
 44,
 44,
-47,
+45,
 46,
 46,
-49,
+47,
 48,
 48,
-51,
+49,
 50,
 50,
-53,
+51,
 52,
 52,
-55,
+53,
 54,
 54,
-57,
+55,
 56,
 56,
+57,
 34,
 34,
-1,
 3,
 3,
+1,
 2,
 2,
-5,
-4,
 6,
 6,
-7,
+4,
+5,
 9,
 9,
+7,
 8,
 8,
-11,
 12,
 12,
 10,
 10,
-13,
+11,
 15,
 15,
+13,
 14,
 14,
-17,
-16,
 18,
 18,
-19,
+16,
+17,
 21,
 21,
+19,
 20,
 20,
-23,
 24,
 24,
 22,
 22,
+23,
 38,
 38,
 25,
 25,
 26,
 26,

+ 6 - 1
compiler/m68k/ra68kmot.pas

@@ -216,6 +216,11 @@ const
         actasmregister:=std_regnum_search(lower(s));
         actasmregister:=std_regnum_search(lower(s));
         if actasmregister<>NR_NO then
         if actasmregister<>NR_NO then
           begin
           begin
+            { this is a hack. if the reg is valid, and its string doesn't
+              contain a dot, we make sure it's a full size reg (KB) }
+            if (getregtype(actasmregister) in [R_ADDRESSREGISTER,R_INTREGISTER]) and
+               (Pos('.',s) = 0) then
+              setsubreg(actasmregister,R_SUBWHOLE);
             result:=true;
             result:=true;
             actasmtoken:=AS_REGISTER;
             actasmtoken:=AS_REGISTER;
           end;
           end;
@@ -1196,7 +1201,7 @@ const
                      while actasmtoken <> AS_SEPARATOR do
                      while actasmtoken <> AS_SEPARATOR do
                         Consume(actasmtoken);
                         Consume(actasmtoken);
                    end;
                    end;
-                   exit;
+                 exit;
                end;
                end;
               { // (reg,reg .. // }
               { // (reg,reg .. // }
               Consume(AS_COMMA);
               Consume(AS_COMMA);

+ 34 - 14
compiler/ncnv.pas

@@ -1630,6 +1630,10 @@ implementation
                    include(flags,nf_is_currency);
                    include(flags,nf_is_currency);
                    typecheckpass(left);
                    typecheckpass(left);
                  end;
                  end;
+             { comp is handled by the fpu but not a floating type point }
+             if is_fpucomp(resultdef) and not(is_fpucomp(left.resultdef)) and
+               not (nf_explicit in flags) then
+               Message(type_w_convert_real_2_comp);
            end
            end
          else
          else
            include(flags,nf_is_currency);
            include(flags,nf_is_currency);
@@ -2948,6 +2952,11 @@ implementation
                 gotsint:=true;
                 gotsint:=true;
                 result:=docheckremoveinttypeconvs(tunarynode(n).left);
                 result:=docheckremoveinttypeconvs(tunarynode(n).left);
               end;
               end;
+            shrn:
+              begin
+                result:=wasoriginallysmallerint(tbinarynode(n).left) and
+                  docheckremoveinttypeconvs(tbinarynode(n).right);
+              end;
             notn:
             notn:
               result:=docheckremoveinttypeconvs(tunarynode(n).left);
               result:=docheckremoveinttypeconvs(tunarynode(n).left);
             addn,muln,divn,modn,andn,shln:
             addn,muln,divn,modn,andn,shln:
@@ -2981,15 +2990,26 @@ implementation
 
 
 
 
     { remove int type conversions and set the result to the given type }
     { remove int type conversions and set the result to the given type }
-    procedure doremoveinttypeconvs(var n: tnode; todef: tdef; forceunsigned: boolean; signedtype,unsignedtype : tdef);
+    procedure doremoveinttypeconvs(level : dword;var n: tnode; todef: tdef; forceunsigned: boolean; signedtype,unsignedtype : tdef);
       var
       var
         newblock: tblocknode;
         newblock: tblocknode;
         newstatements: tstatementnode;
         newstatements: tstatementnode;
         originaldivtree: tnode;
         originaldivtree: tnode;
         tempnode: ttempcreatenode;
         tempnode: ttempcreatenode;
       begin
       begin
+        { we may not recurse into shr nodes:
+
+          dword1:=dword1+((dword2+dword3) shr 2);
+
+          while we can remove an extension on the addition, we cannot remove it from the shr
+        }
+        if (n.nodetype=shrn) and (level<>0) then
+          begin
+            inserttypeconv_internal(n,todef);
+            exit;
+          end;
         case n.nodetype of
         case n.nodetype of
-          subn,addn,muln,divn,modn,xorn,andn,orn,shln:
+          subn,addn,muln,divn,modn,xorn,andn,orn,shln,shrn:
             begin
             begin
               exclude(n.flags,nf_internal);
               exclude(n.flags,nf_internal);
               if not forceunsigned and
               if not forceunsigned and
@@ -2998,8 +3018,8 @@ implementation
                   originaldivtree:=nil;
                   originaldivtree:=nil;
                   if n.nodetype in [divn,modn] then
                   if n.nodetype in [divn,modn] then
                     originaldivtree:=n.getcopy;
                     originaldivtree:=n.getcopy;
-                  doremoveinttypeconvs(tbinarynode(n).left,signedtype,false,signedtype,unsignedtype);
-                  doremoveinttypeconvs(tbinarynode(n).right,signedtype,false,signedtype,unsignedtype);
+                  doremoveinttypeconvs(level+1,tbinarynode(n).left,signedtype,false,signedtype,unsignedtype);
+                  doremoveinttypeconvs(level+1,tbinarynode(n).right,signedtype,false,signedtype,unsignedtype);
                   n.resultdef:=signedtype;
                   n.resultdef:=signedtype;
                   if n.nodetype in [divn,modn] then
                   if n.nodetype in [divn,modn] then
                     begin
                     begin
@@ -3026,8 +3046,8 @@ implementation
                 end
                 end
               else
               else
                 begin
                 begin
-                  doremoveinttypeconvs(tbinarynode(n).left,unsignedtype,forceunsigned,signedtype,unsignedtype);
-                  doremoveinttypeconvs(tbinarynode(n).right,unsignedtype,forceunsigned,signedtype,unsignedtype);
+                  doremoveinttypeconvs(level+1,tbinarynode(n).left,unsignedtype,forceunsigned,signedtype,unsignedtype);
+                  doremoveinttypeconvs(level+1,tbinarynode(n).right,unsignedtype,forceunsigned,signedtype,unsignedtype);
                   n.resultdef:=unsignedtype;
                   n.resultdef:=unsignedtype;
                 end;
                 end;
               //if ((n.nodetype=andn) and (tbinarynode(n).left.nodetype=ordconstn) and
               //if ((n.nodetype=andn) and (tbinarynode(n).left.nodetype=ordconstn) and
@@ -3044,12 +3064,12 @@ implementation
               if not forceunsigned and
               if not forceunsigned and
                  is_signed(n.resultdef) then
                  is_signed(n.resultdef) then
                 begin
                 begin
-                  doremoveinttypeconvs(tunarynode(n).left,signedtype,false,signedtype,unsignedtype);
+                  doremoveinttypeconvs(level+1,tunarynode(n).left,signedtype,false,signedtype,unsignedtype);
                   n.resultdef:=signedtype;
                   n.resultdef:=signedtype;
                 end
                 end
               else
               else
                 begin
                 begin
-                  doremoveinttypeconvs(tunarynode(n).left,unsignedtype,forceunsigned,signedtype,unsignedtype);
+                  doremoveinttypeconvs(level+1,tunarynode(n).left,unsignedtype,forceunsigned,signedtype,unsignedtype);
                   n.resultdef:=unsignedtype;
                   n.resultdef:=unsignedtype;
                 end;
                 end;
             end;
             end;
@@ -3344,22 +3364,22 @@ implementation
                     to 64 bit                                               }
                     to 64 bit                                               }
                   if (resultdef.size <= 4) and
                   if (resultdef.size <= 4) and
                     is_64bitint(left.resultdef) and
                     is_64bitint(left.resultdef) and
-                    (left.nodetype in [subn,addn,muln,divn,modn,xorn,andn,orn,notn,unaryminusn,shln]) and
+                    (left.nodetype in [subn,addn,muln,divn,modn,xorn,andn,orn,notn,unaryminusn,shln,shrn]) and
                     checkremovebiginttypeconvs(left,foundsint,[s8bit,u8bit,s16bit,u16bit,s32bit,u32bit],int64(low(longint)),high(cardinal)) then
                     checkremovebiginttypeconvs(left,foundsint,[s8bit,u8bit,s16bit,u16bit,s32bit,u32bit],int64(low(longint)),high(cardinal)) then
-                    doremoveinttypeconvs(left,generrordef,not foundsint,s32inttype,u32inttype);
+                    doremoveinttypeconvs(0,left,generrordef,not foundsint,s32inttype,u32inttype);
 {$if defined(cpu16bitalu)}
 {$if defined(cpu16bitalu)}
                   if (resultdef.size <= 2) and
                   if (resultdef.size <= 2) and
                     (is_32bitint(left.resultdef) or is_64bitint(left.resultdef)) and
                     (is_32bitint(left.resultdef) or is_64bitint(left.resultdef)) and
-                    (left.nodetype in [subn,addn,muln,divn,modn,xorn,andn,orn,notn,unaryminusn,shln]) and
+                    (left.nodetype in [subn,addn,muln,divn,modn,xorn,andn,orn,notn,unaryminusn,shln,shrn]) and
                     checkremovebiginttypeconvs(left,foundsint,[s8bit,u8bit,s16bit,u16bit],int64(low(smallint)),high(word)) then
                     checkremovebiginttypeconvs(left,foundsint,[s8bit,u8bit,s16bit,u16bit],int64(low(smallint)),high(word)) then
-                    doremoveinttypeconvs(left,generrordef,not foundsint,s16inttype,u16inttype);
+                    doremoveinttypeconvs(0,left,generrordef,not foundsint,s16inttype,u16inttype);
 {$endif defined(cpu16bitalu)}
 {$endif defined(cpu16bitalu)}
 {$if defined(cpu8bitalu)}
 {$if defined(cpu8bitalu)}
                  if (resultdef.size<left.resultdef.size) and
                  if (resultdef.size<left.resultdef.size) and
                   is_integer(left.resultdef) and
                   is_integer(left.resultdef) and
-                  (left.nodetype in [subn,addn,muln,divn,modn,xorn,andn,orn,notn,unaryminusn,shln]) and
+                  (left.nodetype in [subn,addn,muln,divn,modn,xorn,andn,orn,notn,unaryminusn,shln,shrn]) and
                   checkremovebiginttypeconvs(left,foundsint,[s8bit,u8bit],int64(low(shortint)),high(byte)) then
                   checkremovebiginttypeconvs(left,foundsint,[s8bit,u8bit],int64(low(shortint)),high(byte)) then
-                    doremoveinttypeconvs(left,generrordef,not foundsint,s8inttype,u8inttype);
+                    doremoveinttypeconvs(0,left,generrordef,not foundsint,s8inttype,u8inttype);
 {$endif defined(cpu8bitalu)}
 {$endif defined(cpu8bitalu)}
                   { the above simplification may have left a redundant equal
                   { the above simplification may have left a redundant equal
                     typeconv (e.g. int32 to int32). If that's the case, we remove it }
                     typeconv (e.g. int32 to int32). If that's the case, we remove it }

+ 4 - 0
compiler/ogcoff.pas

@@ -2063,6 +2063,8 @@ const pemagic : array[0..3] of byte = (
                   FCoffSyms.Read(bosym,sizeof(bosym));
                   FCoffSyms.Read(bosym,sizeof(bosym));
                   if bosym.Name.Offset.Zeroes<>0 then
                   if bosym.Name.Offset.Zeroes<>0 then
                     begin
                     begin
+                      { Added for sake of global data analysis }
+                      strname[0]:=#0;
                       move(bosym.Name.ShortName,strname[1],8);
                       move(bosym.Name.ShortName,strname[1],8);
                       strname[9]:=#0;
                       strname[9]:=#0;
                       strname[0]:=chr(strlen(@strname[1]));
                       strname[0]:=chr(strlen(@strname[1]));
@@ -2081,6 +2083,8 @@ const pemagic : array[0..3] of byte = (
                   FCoffSyms.Read(sym,sizeof(sym));
                   FCoffSyms.Read(sym,sizeof(sym));
                   if plongint(@sym.name)^<>0 then
                   if plongint(@sym.name)^<>0 then
                     begin
                     begin
+                      { Added for sake of global data analysis }
+                      strname[0]:=#0;
                       move(sym.name,strname[1],8);
                       move(sym.name,strname[1],8);
                       strname[9]:=#0;
                       strname[9]:=#0;
                       strname[0]:=chr(strlen(@strname[1]));
                       strname[0]:=chr(strlen(@strname[1]));

+ 4 - 1
compiler/ogelf.pas

@@ -672,7 +672,10 @@ implementation
         if assigned(objreloc) then
         if assigned(objreloc) then
           begin
           begin
             objreloc.size:=len;
             objreloc.size:=len;
-            if reltype in [RELOC_RELATIVE{$ifdef x86},RELOC_PLT32{$endif}{$ifdef x86_64},RELOC_TLSGD,RELOC_GOTPCREL{$endif}] then
+            { RELOC_GOTPCREL, RELOC_REX_GOTPCRELX, RELOC_GOTPCRELX] need special handling
+              this is done in x86/aasmcpu unit }
+            if reltype in [RELOC_RELATIVE{$ifdef x86},RELOC_PLT32{$endif}
+               {$ifdef x86_64}, RELOC_GOTPCREL, RELOC_REX_GOTPCRELX, RELOC_GOTPCRELX,RELOC_TLSGD{$endif}] then
               dec(data,len);
               dec(data,len);
             if ElfTarget.relocs_use_addend then
             if ElfTarget.relocs_use_addend then
               begin
               begin

+ 8 - 0
compiler/options.pas

@@ -140,6 +140,7 @@ const
 
 
 
 
   suppported_targets_x_smallr = systems_linux + systems_solaris + systems_android
   suppported_targets_x_smallr = systems_linux + systems_solaris + systems_android
+                             + systems_openbsd
                              + [system_i386_haiku,system_x86_64_haiku]
                              + [system_i386_haiku,system_x86_64_haiku]
                              + [system_i386_beos]
                              + [system_i386_beos]
                              + [system_m68k_amiga];
                              + [system_m68k_amiga];
@@ -2760,6 +2761,13 @@ begin
                           IllegalPara(opt);
                           IllegalPara(opt);
                       end;
                       end;
 {$if defined(m68k)}
 {$if defined(m68k)}
+                    'L':
+                      begin
+                        if (target_info.system in [system_m68k_sinclairql]) then
+                          sinclairql_vlink_experimental:=true
+                        else
+                          IllegalPara(opt);
+                      end;
                     'Q':
                     'Q':
                       begin
                       begin
                         if (target_info.system in [system_m68k_sinclairql]) then
                         if (target_info.system in [system_m68k_sinclairql]) then

+ 1 - 0
compiler/pass_1.pas

@@ -189,6 +189,7 @@ implementation
                    { should the node be replaced? }
                    { should the node be replaced? }
                    if assigned(hp) then
                    if assigned(hp) then
                      begin
                      begin
+                       hp.flags := hp.flags + (p.flags * [nf_usercode_entry]);
                        p.free;
                        p.free;
                        { switch to new node }
                        { switch to new node }
                        p:=hp;
                        p:=hp;

+ 2 - 1
compiler/pdecsub.pas

@@ -1959,7 +1959,8 @@ var
   pt : tnode;
   pt : tnode;
 {$endif WITHDMT}
 {$endif WITHDMT}
 begin
 begin
-  if (not assigned(pd.owner.defowner) or
+  if assigned(pd.owner) and
+     (not assigned(pd.owner.defowner) or
       not is_java_class_or_interface(tdef(pd.owner.defowner))) and
       not is_java_class_or_interface(tdef(pd.owner.defowner))) and
      (po_external in pd.procoptions) then
      (po_external in pd.procoptions) then
     Message2(parser_e_proc_dir_conflict,'EXTERNAL','"VIRTUAL"');
     Message2(parser_e_proc_dir_conflict,'EXTERNAL','"VIRTUAL"');

+ 3 - 0
compiler/pgenutil.pas

@@ -813,6 +813,9 @@ uses
             st : TSymtable;
             st : TSymtable;
             i : longint;
             i : longint;
           begin
           begin
+            { since commit 48986 deflist might have NIL entries }
+            if not assigned(def) then
+              exit;
             case def.typ of
             case def.typ of
               procdef:
               procdef:
                 tprocdef(def).forwarddef:=false;
                 tprocdef(def).forwarddef:=false;

+ 8 - 0
compiler/pmodules.pas

@@ -614,10 +614,14 @@ implementation
         i: longint;
         i: longint;
         def: tdef;
         def: tdef;
         sym: tsym;
         sym: tsym;
+        tmpidx: Integer;
       begin
       begin
         for i:=current_module.localsymtable.deflist.count-1 downto 0 do
         for i:=current_module.localsymtable.deflist.count-1 downto 0 do
           begin
           begin
             def:=tdef(current_module.localsymtable.deflist[i]);
             def:=tdef(current_module.localsymtable.deflist[i]);
+            { since commit 48986 deflist might have NIL entries }
+            if not assigned(def) then
+              continue;
             { this also frees def, as the defs are owned by the symtable }
             { this also frees def, as the defs are owned by the symtable }
             if not def.is_registered and
             if not def.is_registered and
                not(df_not_registered_no_free in def.defoptions) then
                not(df_not_registered_no_free in def.defoptions) then
@@ -630,6 +634,10 @@ implementation
                    tprocdef(def).procsym.is_registered then
                    tprocdef(def).procsym.is_registered then
                  tprocsym(tprocdef(def).procsym).ProcdefList.Remove(def);
                  tprocsym(tprocdef(def).procsym).ProcdefList.Remove(def);
                 current_module.localsymtable.deletedef(def);
                 current_module.localsymtable.deletedef(def);
+                { this prevents a dangling pointer and use after free }
+                tmpidx:=current_module.deflist.IndexOfItem(def,FromEnd);
+                if tmpidx<>-1 then
+                  current_module.deflist[tmpidx]:=nil;
               end;
               end;
           end;
           end;
         { from high to low so we hopefully have moves of less data }
         { from high to low so we hopefully have moves of less data }

+ 14 - 5
compiler/scanner.pas

@@ -4883,12 +4883,21 @@ type
                        inc(yylexcount);
                        inc(yylexcount);
                        substitutemacro(pattern,mac.buftext,mac.buflen,
                        substitutemacro(pattern,mac.buftext,mac.buflen,
                          mac.fileinfo.line,mac.fileinfo.fileindex);
                          mac.fileinfo.line,mac.fileinfo.fileindex);
-                     { handle empty macros }
+                       { handle empty macros }
                        if c=#0 then
                        if c=#0 then
-                         reload;
-                       readtoken(false);
-                       { that's all folks }
-                       dec(yylexcount);
+                         begin
+                           reload;
+                           { avoid macro nesting error in case of
+                             a sequence of empty macros, see #38802 }
+                           dec(yylexcount);
+                           readtoken(false);
+                         end
+                       else
+                         begin
+                           readtoken(false);
+                           { that's all folks }
+                           dec(yylexcount);
+                         end;
                        exit;
                        exit;
                      end
                      end
                     else
                     else

+ 4 - 2
compiler/systems/t_bsd.pas

@@ -482,12 +482,14 @@ begin
      (tf_smartlink_sections in target_info.flags) then
      (tf_smartlink_sections in target_info.flags) then
     GCSectionsStr:='--gc-sections';
     GCSectionsStr:='--gc-sections';
 
 
-   if(cs_profile in current_settings.moduleswitches) or
+  if (cs_profile in current_settings.moduleswitches) or
      ((Info.DynamicLinker<>'') and
      ((Info.DynamicLinker<>'') and
       ((not SharedLibFiles.Empty) or
       ((not SharedLibFiles.Empty) or
        (target_info.system in systems_openbsd))) then
        (target_info.system in systems_openbsd))) then
-   DynLinkStr:='-dynamic-linker='+Info.DynamicLinker;
+    DynLinkStr:='-dynamic-linker='+Info.DynamicLinker;
 
 
+  if rlinkpath<>'' then
+    DynLinkStr:=DynLinkStr+' --rpath-link '+rlinkpath;
   if CShared Then
   if CShared Then
    begin
    begin
       DynLinKStr:=DynLinkStr+' --shared'
       DynLinKStr:=DynLinkStr+' --shared'

+ 17 - 2
compiler/systems/t_freertos.pas

@@ -955,6 +955,8 @@ var
   t: Text;
   t: Text;
   hp: TCmdStrListItem;
   hp: TCmdStrListItem;
   filepath: TCmdStr;
   filepath: TCmdStr;
+  i,j: integer;
+  lib: AnsiString;
 {$endif XTENSA}
 {$endif XTENSA}
 begin
 begin
 {$ifdef XTENSA}
 {$ifdef XTENSA}
@@ -1139,6 +1141,20 @@ begin
   if ioresult<>0 then
   if ioresult<>0 then
     exit;
     exit;
 
 
+  { extract libraries from linker options and add to static libraries list }
+  Info.ExtraOptions:=trim(Info.ExtraOptions);
+  i := pos('-l', Info.ExtraOptions);
+  while i > 0 do
+   begin
+     j:=pos(' ',Info.ExtraOptions);
+     if j=0 then
+       j:=length(Info.ExtraOptions)+1;
+     lib:=copy(Info.ExtraOptions,i+2,j-i-2);
+     AddStaticCLibrary(lib);
+     delete(Info.ExtraOptions,i,j);
+     trim(Info.ExtraOptions);
+     i := pos('-l', Info.ExtraOptions);
+   end;
   hp:=TCmdStrListItem(StaticLibFiles.First);
   hp:=TCmdStrListItem(StaticLibFiles.First);
   while assigned(hp) do
   while assigned(hp) do
     begin
     begin
@@ -1256,8 +1272,7 @@ begin
     Replace(cmdstr,'$GCSECTIONS',GCSectionsStr);
     Replace(cmdstr,'$GCSECTIONS',GCSectionsStr);
     Replace(cmdstr,'$DYNLINK',DynLinkStr);
     Replace(cmdstr,'$DYNLINK',DynLinkStr);
    end;
    end;
-  if success and not(cs_link_nolink in current_settings.globalswitches) then
-    success:=DoExec(FindUtil(utilsprefix+BinStr),cmdstr,true,false);
+   success:=DoExec(FindUtil(utilsprefix+BinStr),cmdstr,true,false);
 
 
 { Remove ReponseFile }
 { Remove ReponseFile }
   if success and not(cs_link_nolink in current_settings.globalswitches) then
   if success and not(cs_link_nolink in current_settings.globalswitches) then

+ 1 - 1
compiler/systems/t_nds.pas

@@ -57,7 +57,7 @@ begin
   SharedLibFiles.doubles:=true;
   SharedLibFiles.doubles:=true;
   StaticLibFiles.doubles:=true;
   StaticLibFiles.doubles:=true;
   // set arm9 as default apptype
   // set arm9 as default apptype
-  if (apptype <> app_arm9) or (apptype <> app_arm7) then
+  if (apptype <> app_arm9) and (apptype <> app_arm7) then
     apptype:=app_arm9;
     apptype:=app_arm9;
 end;
 end;
 
 

+ 16 - 3
compiler/systems/t_sinclairql.pas

@@ -115,7 +115,7 @@ begin
      end
      end
     else
     else
      begin
      begin
-      ExeCmd[1]:='vlink -b rawseg -q $FLAGS $GCSECTIONS $OPT $STRIP $MAP -o $EXE -T $RES';
+      ExeCmd[1]:='vlink $QLFLAGS $FLAGS $GCSECTIONS $OPT $STRIP $MAP -o $EXE -T $RES';
      end;
      end;
    end;
    end;
 end;
 end;
@@ -245,6 +245,7 @@ var
   DynLinkStr : string;
   DynLinkStr : string;
   GCSectionsStr : string;
   GCSectionsStr : string;
   FlagsStr : string;
   FlagsStr : string;
+  QLFlagsStr: string;
   MapStr : string;
   MapStr : string;
   ExeName: string;
   ExeName: string;
   fd,fs: file;
   fd,fs: file;
@@ -258,6 +259,7 @@ var
   QLHeader: TQLHeader;
   QLHeader: TQLHeader;
   XTccData: TXTccData;
   XTccData: TXTccData;
   BinSize: longint;
   BinSize: longint;
+  RelocSize: longint;
   DataSpace: DWord;
   DataSpace: DWord;
 begin
 begin
   StripStr:='';
   StripStr:='';
@@ -276,6 +278,10 @@ begin
     begin
     begin
       if create_smartlink_sections then
       if create_smartlink_sections then
         GCSectionsStr:='-gc-all';
         GCSectionsStr:='-gc-all';
+      if sinclairql_vlink_experimental then
+        QLFlagsStr:='-b sinclairql -q -'+lower(sinclairql_metadata_format)+' -stack='+tostr(StackSize)
+      else
+        QLFlagsStr:='-b rawseg -q';
     end;
     end;
 
 
   ExeName:=current_module.exefilename;
   ExeName:=current_module.exefilename;
@@ -292,18 +298,20 @@ begin
   Replace(cmdstr,'$STRIP',StripStr);
   Replace(cmdstr,'$STRIP',StripStr);
   Replace(cmdstr,'$GCSECTIONS',GCSectionsStr);
   Replace(cmdstr,'$GCSECTIONS',GCSectionsStr);
   Replace(cmdstr,'$DYNLINK',DynLinkStr);
   Replace(cmdstr,'$DYNLINK',DynLinkStr);
+  Replace(cmdstr,'$QLFLAGS',QLFlagsStr);
 
 
   MakeSinclairQLExe:=DoExec(BinStr,CmdStr,true,false);
   MakeSinclairQLExe:=DoExec(BinStr,CmdStr,true,false);
 
 
   { Kludge:
   { Kludge:
       With the above linker script, vlink will produce two files. The main binary 
       With the above linker script, vlink will produce two files. The main binary 
       and the relocation info. Here we copy the two together. (KB) }
       and the relocation info. Here we copy the two together. (KB) }
-  if MakeSinclairQLExe then
+  if MakeSinclairQLExe and not sinclairql_vlink_experimental then
     begin
     begin
       QLHeader:=DefaultQLHeader;
       QLHeader:=DefaultQLHeader;
       XTccData:=DefaultXTccData;
       XTccData:=DefaultXTccData;
 
 
       BinSize:=0;
       BinSize:=0;
+      RelocSize:=0;
       bufsize:=16384;
       bufsize:=16384;
 {$push}
 {$push}
 {$i-}
 {$i-}
@@ -321,13 +329,18 @@ begin
       assign(fd,ExeName);
       assign(fd,ExeName);
       rewrite(fd,1);
       rewrite(fd,1);
 
 
+      assign(fs,ExeName+'.'+ProgramHeaderName+'.rel'+ProgramHeaderName);
+      reset(fs,1);
+      RelocSize := FileSize(fs);
+      close(fs);
+
       assign(fs,ExeName+'.'+ProgramHeaderName);
       assign(fs,ExeName+'.'+ProgramHeaderName);
       reset(fs,1);
       reset(fs,1);
       BinSize := FileSize(fs);
       BinSize := FileSize(fs);
 
 
       { We assume .bss size is total size indicated by linker minus emmited binary.
       { We assume .bss size is total size indicated by linker minus emmited binary.
         DataSpace size is .bss + stack space }
         DataSpace size is .bss + stack space }
-      DataSpace := NToBE(DWord(HeaderSize - BinSize + StackSize));
+      DataSpace := NToBE(DWord(max((HeaderSize - BinSize) - RelocSize + StackSize,0)));
 
 
       { Option: prepend QEmuLator and QPC2 v5 compatible header to EXE }
       { Option: prepend QEmuLator and QPC2 v5 compatible header to EXE }
       if sinclairql_metadata_format='QHDR' then
       if sinclairql_metadata_format='QHDR' then

+ 2 - 2
compiler/utils/mk68kreg.pp

@@ -133,7 +133,7 @@ begin
         i:=h;
         i:=h;
         repeat
         repeat
           j:=i+p;
           j:=i+p;
-          if stdnames[std_regname_index[j]]>=stdnames[std_regname_index[i]] then
+          if stdfullnames[std_regname_index[j]]>=stdfullnames[std_regname_index[i]] then
             break;
             break;
           t:=std_regname_index[i];
           t:=std_regname_index[i];
           std_regname_index[i]:=std_regname_index[j];
           std_regname_index[i]:=std_regname_index[j];
@@ -164,7 +164,7 @@ begin
         i:=h;
         i:=h;
         repeat
         repeat
           j:=i+p;
           j:=i+p;
-          if gasnames[gas_regname_index[j]]>=gasnames[gas_regname_index[i]] then
+          if gasfullnames[gas_regname_index[j]]>=gasfullnames[gas_regname_index[i]] then
             break;
             break;
           t:=gas_regname_index[i];
           t:=gas_regname_index[i];
           gas_regname_index[i]:=gas_regname_index[j];
           gas_regname_index[i]:=gas_regname_index[j];

+ 35 - 27
compiler/wasm32/agllvmmc.pas

@@ -70,31 +70,36 @@ implementation
   procedure TLLVMMachineCodePlaygroundAssembler.WriteImports;
   procedure TLLVMMachineCodePlaygroundAssembler.WriteImports;
     var
     var
       i    : integer;
       i    : integer;
+      def  : tdef;
       proc : tprocdef;
       proc : tprocdef;
       list : TAsmList;
       list : TAsmList;
       cur_unit: tused_unit;
       cur_unit: tused_unit;
     begin
     begin
       for i:=0 to current_module.deflist.Count-1 do
       for i:=0 to current_module.deflist.Count-1 do
-        if assigned(current_module.deflist[i]) and (tdef(current_module.deflist[i]).typ=procdef) then
-          begin
-            proc := tprocdef(current_module.deflist[i]);
-            if (po_external in proc.procoptions) and assigned(proc.import_dll) then
-              begin
-                //WriteProcDef(proc);
-                list:=TAsmList.Create;
-                thlcgwasm(hlcg).g_procdef(list,proc);
-                WriteTree(list);
-                list.free;
-                writer.AsmWrite(#9'.import_module'#9);
-                writer.AsmWrite(proc.mangledname);
-                writer.AsmWrite(', ');
-                writer.AsmWriteLn(proc.import_dll^);
-                writer.AsmWrite(#9'.import_name'#9);
-                writer.AsmWrite(proc.mangledname);
-                writer.AsmWrite(', ');
-                writer.AsmWriteLn(proc.import_name^);
-              end;
-          end;
+        begin
+          def:=tdef(current_module.deflist[i]);
+          { since commit 48986 deflist might have NIL entries }
+          if assigned(def) and (def.typ=procdef) then
+            begin
+              proc := tprocdef(def);
+              if (po_external in proc.procoptions) and assigned(proc.import_dll) then
+                begin
+                  //WriteProcDef(proc);
+                  list:=TAsmList.Create;
+                  thlcgwasm(hlcg).g_procdef(list,proc);
+                  WriteTree(list);
+                  list.free;
+                  writer.AsmWrite(#9'.import_module'#9);
+                  writer.AsmWrite(proc.mangledname);
+                  writer.AsmWrite(', ');
+                  writer.AsmWriteLn(proc.import_dll^);
+                  writer.AsmWrite(#9'.import_name'#9);
+                  writer.AsmWrite(proc.mangledname);
+                  writer.AsmWrite(', ');
+                  writer.AsmWriteLn(proc.import_name^);
+                end;
+            end;
+         end;
       list:=TAsmList.Create;
       list:=TAsmList.Create;
       cur_unit:=tused_unit(usedunits.First);
       cur_unit:=tused_unit(usedunits.First);
       while assigned(cur_unit) do
       while assigned(cur_unit) do
@@ -107,13 +112,16 @@ implementation
                 list.Concat(tai_functype.create(make_mangledname('FINALIZE$',cur_unit.u.globalsymtable,''),TWasmFuncType.Create([],[])));
                 list.Concat(tai_functype.create(make_mangledname('FINALIZE$',cur_unit.u.globalsymtable,''),TWasmFuncType.Create([],[])));
             end;
             end;
           for i:=0 to cur_unit.u.deflist.Count-1 do
           for i:=0 to cur_unit.u.deflist.Count-1 do
-            if assigned(cur_unit.u.deflist[i]) and (tdef(cur_unit.u.deflist[i]).typ = procdef) then
-              begin
-                proc := tprocdef(cur_unit.u.deflist[i]);
-                if (not proc.owner.iscurrentunit or (po_external in proc.procoptions)) and
-                   ((proc.paras.Count=0) or (proc.has_paraloc_info in [callerside,callbothsides])) then
-                  thlcgwasm(hlcg).g_procdef(list,proc);
-              end;
+            begin
+              def:=tdef(cur_unit.u.deflist[i]);
+              if assigned(def) and (tdef(def).typ = procdef) then
+                begin
+                  proc := tprocdef(def);
+                  if (not proc.owner.iscurrentunit or (po_external in proc.procoptions)) and
+                     ((proc.paras.Count=0) or (proc.has_paraloc_info in [callerside,callbothsides])) then
+                    thlcgwasm(hlcg).g_procdef(list,proc);
+                end;
+            end;
           cur_unit:=tused_unit(cur_unit.Next);
           cur_unit:=tused_unit(cur_unit.Next);
         end;
         end;
       WriteTree(list);
       WriteTree(list);

+ 5 - 2
compiler/wasm32/agwat.pas

@@ -957,14 +957,17 @@ implementation
     procedure TWabtTextAssembler.WriteImports;
     procedure TWabtTextAssembler.WriteImports;
       var
       var
         i    : integer;
         i    : integer;
+        def  : tdef;
         proc : tprocdef;
         proc : tprocdef;
         sym  : tsym;
         sym  : tsym;
         j    : integer;
         j    : integer;
         psym : tprocsym;
         psym : tprocsym;
       begin
       begin
         for i:=0 to current_module.deflist.Count-1 do begin
         for i:=0 to current_module.deflist.Count-1 do begin
-          if tdef(current_module.deflist[i]).typ = procdef then begin
-            proc := tprocdef(current_module.deflist[i]);
+          def:=tdef(current_module.deflist[i]);
+          { since commit 48986 deflist might have NIL entries }
+          if assigned(def) and (def.typ=procdef) then begin
+            proc := tprocdef(def);
             if (po_external in proc.procoptions) and assigned(proc.import_dll) then begin
             if (po_external in proc.procoptions) and assigned(proc.import_dll) then begin
               writer.AsmWrite(#9'(import "');
               writer.AsmWrite(#9'(import "');
               writer.AsmWrite(proc.import_dll^);
               writer.AsmWrite(proc.import_dll^);

+ 70 - 2
compiler/wasm32/nwasmflw.pas

@@ -49,6 +49,13 @@ interface
         procedure pass_generate_code;override;
         procedure pass_generate_code;override;
       end;
       end;
 
 
+      { twasmraisenode }
+
+      twasmraisenode = class(tcgraisenode)
+      public
+        function pass_1 : tnode;override;
+      end;
+
       { twasmtryexceptnode }
       { twasmtryexceptnode }
 
 
       twasmtryexceptnode = class(tcgtryexceptnode)
       twasmtryexceptnode = class(tcgtryexceptnode)
@@ -68,9 +75,9 @@ implementation
     uses
     uses
       verbose,globals,systems,globtype,constexp,
       verbose,globals,systems,globtype,constexp,
       symconst,symdef,symsym,aasmtai,aasmdata,aasmcpu,defutil,defcmp,
       symconst,symdef,symsym,aasmtai,aasmdata,aasmcpu,defutil,defcmp,
-      procinfo,cgbase,pass_1,pass_2,parabase,
+      procinfo,cgbase,pass_1,pass_2,parabase,compinnr,
       cpubase,cpuinfo,
       cpubase,cpuinfo,
-      nbas,nld,ncon,ncnv,
+      nbas,nld,ncon,ncnv,ncal,ninl,nmem,nadd,
       tgobj,paramgr,
       tgobj,paramgr,
       cgutils,hlcgobj,hlcgcpu;
       cgutils,hlcgobj,hlcgcpu;
 
 
@@ -203,6 +210,66 @@ implementation
         flowcontrol := oldflowcontrol + (flowcontrol - [fc_inflowcontrol]);
         flowcontrol := oldflowcontrol + (flowcontrol - [fc_inflowcontrol]);
       end;
       end;
 
 
+{*****************************************************************************
+                             twasmraisenode
+*****************************************************************************}
+
+    function twasmraisenode.pass_1 : tnode;
+      var
+        statements : tstatementnode;
+        //current_addr : tlabelnode;
+        raisenode : tcallnode;
+      begin
+        result:=internalstatements(statements);
+
+        if assigned(left) then
+          begin
+            { first para must be a class }
+            firstpass(left);
+            { insert needed typeconvs for addr,frame }
+            if assigned(right) then
+              begin
+                { addr }
+                firstpass(right);
+                { frame }
+                if assigned(third) then
+                  firstpass(third)
+                else
+                  third:=cpointerconstnode.Create(0,voidpointertype);
+              end
+            else
+              begin
+                third:=cinlinenode.create(in_get_frame,false,nil);
+                //current_addr:=clabelnode.create(cnothingnode.create,clabelsym.create('$raiseaddr'));
+                //addstatement(statements,current_addr);
+                //right:=caddrnode.create(cloadnode.create(current_addr.labsym,current_addr.labsym.owner));
+                right:=cnilnode.create;
+
+                { raise address off by one so we are for sure inside the action area for the raise }
+                if tf_use_psabieh in target_info.flags then
+                  right:=caddnode.create_internal(addn,right,cordconstnode.create(1,sizesinttype,false));
+              end;
+
+            raisenode:=ccallnode.createintern('fpc_raiseexception',
+              ccallparanode.create(third,
+              ccallparanode.create(right,
+              ccallparanode.create(left,nil)))
+              );
+            include(raisenode.callnodeflags,cnf_call_never_returns);
+            addstatement(statements,raisenode);
+          end
+        else
+          begin
+            addstatement(statements,ccallnode.createintern('fpc_popaddrstack',nil));
+            raisenode:=ccallnode.createintern('fpc_reraise',nil);
+            include(raisenode.callnodeflags,cnf_call_never_returns);
+            addstatement(statements,raisenode);
+          end;
+        left:=nil;
+        right:=nil;
+        third:=nil;
+      end;
+
 {*****************************************************************************
 {*****************************************************************************
                              twasmtryexceptnode
                              twasmtryexceptnode
 *****************************************************************************}
 *****************************************************************************}
@@ -258,6 +325,7 @@ implementation
 initialization
 initialization
   cifnode:=twasmifnode;
   cifnode:=twasmifnode;
   cwhilerepeatnode:=twasmwhilerepeatnode;
   cwhilerepeatnode:=twasmwhilerepeatnode;
+  craisenode:=twasmraisenode;
   ctryexceptnode:=twasmtryexceptnode;
   ctryexceptnode:=twasmtryexceptnode;
   ctryfinallynode:=twasmtryfinallynode;
   ctryfinallynode:=twasmtryfinallynode;
 end.
 end.

+ 10 - 0
compiler/x86/aasmcpu.pas

@@ -3682,6 +3682,16 @@ implementation
              end;
              end;
 {$endif i386}
 {$endif i386}
            objdata.writereloc(data,len,p,Reloctype);
            objdata.writereloc(data,len,p,Reloctype);
+{$ifdef x86_64}
+	   { Computed offset is not yet correct for GOTPC relocation }
+           { RELOC_GOTPCREL, RELOC_REX_GOTPCRELX, RELOC_GOTPCRELX need special handling }
+           if assigned(p) and (RelocType in [RELOC_GOTPCREL, RELOC_REX_GOTPCRELX, RELOC_GOTPCRELX]) and
+              { These relocations seem to be used only for ELF
+                which always has relocs_use_addend set to true 
+                so that it is the orgsize of the last relocation which needs to be fixed PM  }
+              (insend<>objdata.CurrObjSec.size) then
+             dec(TObjRelocation(objdata.CurrObjSec.ObjRelocations.Last).orgsize,insend-objdata.CurrObjSec.size);
+{$endif}
          end;
          end;
 
 
 
 

+ 0 - 5
compiler/x86/nx86cnv.pas

@@ -72,11 +72,6 @@ implementation
     function tx86typeconvnode.first_real_to_real : tnode;
     function tx86typeconvnode.first_real_to_real : tnode;
       begin
       begin
          first_real_to_real:=nil;
          first_real_to_real:=nil;
-        { comp isn't a floating type }
-         if (tfloatdef(resultdef).floattype=s64comp) and
-            (tfloatdef(left.resultdef).floattype<>s64comp) and
-            not (nf_explicit in flags) then
-           CGMessage(type_w_convert_real_2_comp);
          if use_vectorfpu(resultdef) then
          if use_vectorfpu(resultdef) then
            expectloc:=LOC_MMREGISTER
            expectloc:=LOC_MMREGISTER
          else
          else

+ 7 - 1
packages/fcl-db/src/base/fields.inc

@@ -68,12 +68,13 @@ end;
 
 
 function TFieldDef.AddChild: TFieldDef;
 function TFieldDef.AddChild: TFieldDef;
 begin
 begin
+  // http://docwiki.embarcadero.com/Libraries/Sydney/en/Data.DB.TFieldDef.AddChild
   // Adds a new TFieldDef object to the ChildDefs array.
   // Adds a new TFieldDef object to the ChildDefs array.
 end;
 end;
 
 
 function TFieldDef.GetChildDefs: TFieldDefs;
 function TFieldDef.GetChildDefs: TFieldDefs;
 begin
 begin
-
+  Result:=nil;
 end;
 end;
 
 
 procedure TFieldDef.SetChildDefs(AValue: TFieldDefs);
 procedure TFieldDef.SetChildDefs(AValue: TFieldDefs);
@@ -84,11 +85,13 @@ end;
 function TFieldDef.HasChildDefs: Boolean;
 function TFieldDef.HasChildDefs: Boolean;
 begin
 begin
   // http://docwiki.embarcadero.com/Libraries/Sydney/en/Data.DB.TFieldDef.HasChildDefs
   // http://docwiki.embarcadero.com/Libraries/Sydney/en/Data.DB.TFieldDef.HasChildDefs
+  Result:=False;
 end;
 end;
 
 
 function TFieldDef.GetParentDef: TFieldDef;
 function TFieldDef.GetParentDef: TFieldDef;
 begin
 begin
   // http://docwiki.embarcadero.com/Libraries/Sydney/en/Data.DB.TFieldDef.ParentDef
   // http://docwiki.embarcadero.com/Libraries/Sydney/en/Data.DB.TFieldDef.ParentDef
+  Result:=nil;
 end;
 end;
 
 
 procedure TFieldDef.Assign(APersistent: TPersistent);
 procedure TFieldDef.Assign(APersistent: TPersistent);
@@ -3705,6 +3708,7 @@ end;
 function TObjectField.GetFieldCount: Integer;
 function TObjectField.GetFieldCount: Integer;
 begin
 begin
   // http://docwiki.embarcadero.com/Libraries/Sydney/en/Data.DB.TObjectField.GetFieldCount
   // http://docwiki.embarcadero.com/Libraries/Sydney/en/Data.DB.TObjectField.GetFieldCount
+  Result:=0;
 end;
 end;
 
 
 function TObjectField.GetFields: TFields;
 function TObjectField.GetFields: TFields;
@@ -3716,6 +3720,7 @@ end;
 function TObjectField.GetFieldValue(AIndex: Integer): Variant;
 function TObjectField.GetFieldValue(AIndex: Integer): Variant;
 begin
 begin
   // http://docwiki.embarcadero.com/Libraries/Sydney/en/Data.DB.TObjectField.GetFieldValue
   // http://docwiki.embarcadero.com/Libraries/Sydney/en/Data.DB.TObjectField.GetFieldValue
+  Result:=NULL;
 end;
 end;
 
 
 procedure TObjectField.SetFieldValue(AIndex: Integer; const AValue: Variant);
 procedure TObjectField.SetFieldValue(AIndex: Integer; const AValue: Variant);
@@ -3732,6 +3737,7 @@ end;
 function TObjectField.GetAsVariant: Variant;
 function TObjectField.GetAsVariant: Variant;
 begin
 begin
   // http://docwiki.embarcadero.com/Libraries/Sydney/en/Data.DB.TObjectField.GetAsVariant
   // http://docwiki.embarcadero.com/Libraries/Sydney/en/Data.DB.TObjectField.GetAsVariant
+  Result:=NULL;
 end;
 end;
 
 
 procedure TObjectField.SetVarValue(const AValue: Variant);
 procedure TObjectField.SetVarValue(const AValue: Variant);

+ 3265 - 0
packages/fcl-mustache/Makefile

@@ -0,0 +1,3265 @@
+#
+# Don't edit, this file is generated by FPCMake Version 2.0.0
+#
+default: all
+MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macosclassic m68k-embedded m68k-sinclairql powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macosclassic powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-haiku x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-android x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros arm-freertos arm-ios powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android mips64el-linux jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-freebsd aarch64-darwin aarch64-win64 aarch64-android aarch64-ios wasm32-embedded wasm32-wasi sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded xtensa-linux xtensa-embedded xtensa-freertos z80-embedded z80-zxspectrum z80-msxdos z80-amstradcpc
+BSDs = freebsd netbsd openbsd darwin dragonfly
+UNIXs = linux $(BSDs) solaris qnx haiku aix
+LIMIT83fs = go32v2 os2 emx watcom msdos win16 atari
+OSNeedsComspecToRunBatch = go32v2 watcom
+FORCE:
+.PHONY: FORCE
+override PATH:=$(patsubst %/,%,$(subst \,/,$(PATH)))
+ifneq ($(findstring darwin,$(OSTYPE)),)
+inUnix=1 #darwin
+SEARCHPATH:=$(filter-out .,$(subst :, ,$(PATH)))
+else
+ifeq ($(findstring ;,$(PATH)),)
+inUnix=1
+SEARCHPATH:=$(filter-out .,$(subst :, ,$(PATH)))
+else
+SEARCHPATH:=$(subst ;, ,$(PATH))
+endif
+endif
+SEARCHPATH+=$(patsubst %/,%,$(subst \,/,$(dir $(MAKE))))
+PWD:=$(strip $(wildcard $(addsuffix /pwd.exe,$(SEARCHPATH))))
+ifeq ($(PWD),)
+PWD:=$(strip $(wildcard $(addsuffix /pwd,$(SEARCHPATH))))
+ifeq ($(PWD),)
+$(error You need the GNU utils package to use this Makefile)
+else
+PWD:=$(firstword $(PWD))
+SRCEXEEXT=
+endif
+else
+PWD:=$(firstword $(PWD))
+SRCEXEEXT=.exe
+endif
+ifndef inUnix
+ifeq ($(OS),Windows_NT)
+inWinNT=1
+else
+ifdef OS2_SHELL
+inOS2=1
+endif
+endif
+else
+ifneq ($(findstring cygdrive,$(PATH)),)
+inCygWin=1
+endif
+endif
+ifdef inUnix
+SRCBATCHEXT=.sh
+else
+ifdef inOS2
+SRCBATCHEXT=.cmd
+else
+SRCBATCHEXT=.bat
+endif
+endif
+ifdef COMSPEC
+ifneq ($(findstring $(OS_SOURCE),$(OSNeedsComspecToRunBatch)),)
+ifndef RUNBATCH
+RUNBATCH=$(COMSPEC) /C
+endif
+endif
+endif
+ifdef inUnix
+PATHSEP=/
+else
+PATHSEP:=$(subst /,\,/)
+ifdef inCygWin
+PATHSEP=/
+endif
+endif
+ifdef PWD
+BASEDIR:=$(subst \,/,$(shell $(PWD)))
+ifdef inCygWin
+ifneq ($(findstring /cygdrive/,$(BASEDIR)),)
+BASENODIR:=$(patsubst /cygdrive%,%,$(BASEDIR))
+BASEDRIVE:=$(firstword $(subst /, ,$(BASENODIR)))
+BASEDIR:=$(subst /cygdrive/$(BASEDRIVE)/,$(BASEDRIVE):/,$(BASEDIR))
+endif
+endif
+else
+BASEDIR=.
+endif
+ifdef inOS2
+ifndef ECHO
+ECHO:=$(strip $(wildcard $(addsuffix /gecho$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(ECHO),)
+ECHO:=$(strip $(wildcard $(addsuffix /echo$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(ECHO),)
+ECHO=echo
+else
+ECHO:=$(firstword $(ECHO))
+endif
+else
+ECHO:=$(firstword $(ECHO))
+endif
+endif
+export ECHO
+endif
+override DEFAULT_FPCDIR=../..
+ifndef FPC
+ifdef PP
+FPC=$(PP)
+endif
+endif
+ifndef FPC
+FPCPROG:=$(strip $(wildcard $(addsuffix /fpc$(SRCEXEEXT),$(SEARCHPATH))))
+ifneq ($(FPCPROG),)
+FPCPROG:=$(firstword $(FPCPROG))
+ifneq ($(CPU_TARGET),)
+FPC:=$(shell $(FPCPROG) -P$(CPU_TARGET) -PB)
+else
+FPC:=$(shell $(FPCPROG) -PB)
+endif
+ifneq ($(findstring Error,$(FPC)),)
+override FPC=$(firstword $(strip $(wildcard $(addsuffix /ppc386$(SRCEXEEXT),$(SEARCHPATH)))))
+else
+ifeq ($(strip $(wildcard $(FPC))),)
+FPC:=$(firstword $(FPCPROG))
+endif
+endif
+else
+override FPC=$(firstword $(strip $(wildcard $(addsuffix /ppc386$(SRCEXEEXT),$(SEARCHPATH)))))
+endif
+endif
+override FPC:=$(subst $(SRCEXEEXT),,$(FPC))
+override FPC:=$(subst \,/,$(FPC))$(SRCEXEEXT)
+FOUNDFPC:=$(strip $(wildcard $(FPC)))
+ifeq ($(FOUNDFPC),)
+FOUNDFPC=$(strip $(wildcard $(addsuffix /$(FPC),$(SEARCHPATH))))
+ifeq ($(FOUNDFPC),)
+$(error Compiler $(FPC) not found)
+endif
+endif
+ifndef FPC_COMPILERINFO
+FPC_COMPILERINFO:=$(shell $(FPC) -iVSPTPSOTO)
+endif
+ifndef FPC_VERSION
+FPC_VERSION:=$(word 1,$(FPC_COMPILERINFO))
+endif
+export FPC FPC_VERSION FPC_COMPILERINFO
+unexport CHECKDEPEND ALLDEPENDENCIES
+ifndef CPU_TARGET
+ifdef CPU_TARGET_DEFAULT
+CPU_TARGET=$(CPU_TARGET_DEFAULT)
+endif
+endif
+ifndef OS_TARGET
+ifdef OS_TARGET_DEFAULT
+OS_TARGET=$(OS_TARGET_DEFAULT)
+endif
+endif
+ifndef CPU_SOURCE
+CPU_SOURCE:=$(word 2,$(FPC_COMPILERINFO))
+endif
+ifndef CPU_TARGET
+CPU_TARGET:=$(word 3,$(FPC_COMPILERINFO))
+endif
+ifndef OS_SOURCE
+OS_SOURCE:=$(word 4,$(FPC_COMPILERINFO))
+endif
+ifndef OS_TARGET
+OS_TARGET:=$(word 5,$(FPC_COMPILERINFO))
+endif
+FULL_TARGET=$(CPU_TARGET)-$(OS_TARGET)
+FULL_SOURCE=$(CPU_SOURCE)-$(OS_SOURCE)
+ifeq ($(CPU_TARGET),armeb)
+ARCH=arm
+override FPCOPT+=-Cb
+else
+ifeq ($(CPU_TARGET),armel)
+ARCH=arm
+override FPCOPT+=-CaEABI
+else
+ARCH=$(CPU_TARGET)
+endif
+endif
+ifeq ($(FULL_TARGET),arm-embedded)
+ifeq ($(SUBARCH),)
+$(error When compiling for arm-embedded, a sub-architecture (e.g. SUBARCH=armv4t or SUBARCH=armv7m) must be defined)
+endif
+override FPCOPT+=-Cp$(SUBARCH)
+endif
+ifeq ($(FULL_TARGET),avr-embedded)
+ifeq ($(SUBARCH),)
+$(error When compiling for avr-embedded, a sub-architecture (e.g. SUBARCH=avr25 or SUBARCH=avr35) must be defined)
+endif
+override FPCOPT+=-Cp$(SUBARCH)
+endif
+ifeq ($(FULL_TARGET),mipsel-embedded)
+ifeq ($(SUBARCH),)
+$(error When compiling for mipsel-embedded, a sub-architecture (e.g. SUBARCH=pic32mx) must be defined)
+endif
+override FPCOPT+=-Cp$(SUBARCH)
+endif
+ifeq ($(FULL_TARGET),xtensa-embedded)
+ifeq ($(SUBARCH),)
+$(error When compiling for xtensa-embedded, a sub-architecture (e.g. SUBARCH=lx106 or SUBARCH=lx6) must be defined)
+endif
+override FPCOPT+=-Cp$(SUBARCH)
+endif
+ifeq ($(FULL_TARGET),xtensa-freertos)
+ifeq ($(SUBARCH),)
+$(error When compiling for xtensa-freertos, a sub-architecture (e.g. SUBARCH=lx106 or SUBARCH=lx6) must be defined)
+endif
+override FPCOPT+=-Cp$(SUBARCH)
+endif
+ifeq ($(FULL_TARGET),arm-freertos)
+ifeq ($(SUBARCH),)
+$(error When compiling for arm-freertos, a sub-architecture (e.g. SUBARCH=armv6m or SUBARCH=armv7em) must be defined)
+endif
+override FPCOPT+=-Cp$(SUBARCH)
+endif
+ifneq ($(findstring $(OS_SOURCE),$(LIMIT83fs)),)
+TARGETSUFFIX=$(OS_TARGET)
+SOURCESUFFIX=$(OS_SOURCE)
+else
+ifneq ($(findstring $(OS_TARGET),$(LIMIT83fs)),)
+TARGETSUFFIX=$(OS_TARGET)
+else
+TARGETSUFFIX=$(FULL_TARGET)
+endif
+SOURCESUFFIX=$(FULL_SOURCE)
+endif
+ifneq ($(FULL_TARGET),$(FULL_SOURCE))
+CROSSCOMPILE=1
+endif
+ifeq ($(findstring makefile,$(MAKECMDGOALS)),)
+ifeq ($(findstring $(FULL_TARGET),$(MAKEFILETARGETS)),)
+$(error The Makefile doesn't support target $(FULL_TARGET), please run fpcmake first)
+endif
+endif
+ifneq ($(findstring $(OS_TARGET),$(BSDs)),)
+BSDhier=1
+endif
+ifeq ($(OS_TARGET),linux)
+linuxHier=1
+endif
+ifndef CROSSCOMPILE
+BUILDFULLNATIVE=1
+export BUILDFULLNATIVE
+endif
+ifdef BUILDFULLNATIVE
+BUILDNATIVE=1
+export BUILDNATIVE
+endif
+export OS_TARGET OS_SOURCE ARCH CPU_TARGET CPU_SOURCE FULL_TARGET FULL_SOURCE TARGETSUFFIX SOURCESUFFIX CROSSCOMPILE
+ifdef FPCDIR
+override FPCDIR:=$(subst \,/,$(FPCDIR))
+ifeq ($(wildcard $(addprefix $(FPCDIR)/,rtl)),)
+override FPCDIR=wrong
+endif
+else
+override FPCDIR=wrong
+endif
+ifdef DEFAULT_FPCDIR
+ifeq ($(FPCDIR),wrong)
+override FPCDIR:=$(subst \,/,$(DEFAULT_FPCDIR))
+ifeq ($(wildcard $(addprefix $(FPCDIR)/,rtl)),)
+override FPCDIR=wrong
+endif
+endif
+endif
+ifeq ($(FPCDIR),wrong)
+ifdef inUnix
+override FPCDIR=/usr/local/lib/fpc/$(FPC_VERSION)
+ifeq ($(wildcard $(FPCDIR)/units),)
+override FPCDIR=/usr/lib/fpc/$(FPC_VERSION)
+endif
+else
+override FPCDIR:=$(subst /$(FPC),,$(firstword $(strip $(wildcard $(addsuffix /$(FPC),$(SEARCHPATH))))))
+override FPCDIR:=$(FPCDIR)/..
+ifeq ($(wildcard $(addprefix $(FPCDIR)/,rtl)),)
+override FPCDIR:=$(FPCDIR)/..
+ifeq ($(wildcard $(addprefix $(FPCDIR)/,rtl)),)
+override FPCDIR:=$(BASEDIR)
+ifeq ($(wildcard $(addprefix $(FPCDIR)/,rtl)),)
+override FPCDIR=c:/pp
+endif
+endif
+endif
+endif
+endif
+ifndef CROSSBINDIR
+CROSSBINDIR:=$(wildcard $(FPCDIR)/bin/$(TARGETSUFFIX))
+endif
+ifneq ($(findstring $(OS_TARGET),darwin iphonesim ios),)
+ifneq ($(findstring $(OS_SOURCE),darwin ios),)
+DARWIN2DARWIN=1
+endif
+endif
+ifndef BINUTILSPREFIX
+ifndef CROSSBINDIR
+ifdef CROSSCOMPILE
+ifneq ($(OS_TARGET),msdos)
+ifndef DARWIN2DARWIN
+ifneq ($(CPU_TARGET),jvm)
+BINUTILSPREFIX=$(CPU_TARGET)-$(OS_TARGET)-
+ifeq ($(OS_TARGET),android)
+ifeq ($(CPU_TARGET),arm)
+BINUTILSPREFIX=arm-linux-androideabi-
+else
+ifeq ($(CPU_TARGET),i386)
+BINUTILSPREFIX=i686-linux-android-
+else
+BINUTILSPREFIX=$(CPU_TARGET)-linux-android-
+endif
+endif
+endif
+endif
+endif
+else
+BINUTILSPREFIX=$(OS_TARGET)-
+endif
+endif
+endif
+endif
+UNITSDIR:=$(wildcard $(FPCDIR)/units/$(TARGETSUFFIX))
+ifeq ($(UNITSDIR),)
+UNITSDIR:=$(wildcard $(FPCDIR)/units/$(OS_TARGET))
+endif
+PACKAGESDIR:=$(wildcard $(FPCDIR) $(FPCDIR)/packages)
+ifndef FPCFPMAKE
+ifdef CROSSCOMPILE
+ifeq ($(strip $(wildcard $(addsuffix /compiler/ppc$(SRCEXEEXT),$(FPCDIR)))),)
+FPCPROG:=$(strip $(wildcard $(addsuffix /fpc$(SRCEXEEXT),$(SEARCHPATH))))
+ifneq ($(FPCPROG),)
+FPCPROG:=$(firstword $(FPCPROG))
+FPCFPMAKE:=$(shell $(FPCPROG) -PB)
+ifeq ($(strip $(wildcard $(FPCFPMAKE))),)
+FPCFPMAKE:=$(firstword $(FPCPROG))
+endif
+else
+override FPCFPMAKE=$(firstword $(strip $(wildcard $(addsuffix /ppc386$(SRCEXEEXT),$(SEARCHPATH)))))
+endif
+else
+FPCFPMAKE=$(strip $(wildcard $(addsuffix /compiler/ppc$(SRCEXEEXT),$(FPCDIR))))
+FPMAKE_SKIP_CONFIG=-n
+export FPCFPMAKE
+export FPMAKE_SKIP_CONFIG
+endif
+else
+FPMAKE_SKIP_CONFIG=-n
+FPCFPMAKE=$(FPC)
+endif
+endif
+override PACKAGE_NAME=fcl-mustache
+override PACKAGE_VERSION=3.3.1
+FPMAKE_BIN_CLEAN=$(wildcard ./fpmake$(SRCEXEEXT))
+ifdef OS_TARGET
+FPC_TARGETOPT+=--os=$(OS_TARGET)
+endif
+ifdef CPU_TARGET
+FPC_TARGETOPT+=--cpu=$(CPU_TARGET)
+endif
+LOCALFPMAKE=./fpmake$(SRCEXEEXT)
+PACKAGEDIR_FPMKUNIT:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /fpmkunit/Makefile.fpc,$(PACKAGESDIR))))))
+ifneq ($(PACKAGEDIR_FPMKUNIT),)
+ifneq ($(wildcard $(PACKAGEDIR_FPMKUNIT)/units_bs/$(SOURCESUFFIX)),)
+UNITDIR_FPMAKE_FPMKUNIT=$(PACKAGEDIR_FPMKUNIT)/units_bs/$(SOURCESUFFIX)
+else
+UNITDIR_FPMAKE_FPMKUNIT=$(PACKAGEDIR_FPMKUNIT)
+endif
+ifdef CHECKDEPEND
+$(PACKAGEDIR_FPMKUNIT)/$(FPCMADE):
+	$(MAKE) -C $(PACKAGEDIR_FPMKUNIT) $(FPCMADE)
+override ALLDEPENDENCIES+=$(PACKAGEDIR_FPMKUNIT)/$(FPCMADE)
+endif
+else
+PACKAGEDIR_FPMKUNIT=
+UNITDIR_FPMKUNIT:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /fpmkunit/Package.fpc,$(UNITSDIR)))))
+ifneq ($(UNITDIR_FPMKUNIT),)
+UNITDIR_FPMKUNIT:=$(firstword $(UNITDIR_FPMKUNIT))
+else
+UNITDIR_FPMKUNIT=
+endif
+endif
+ifdef UNITDIR_FPMAKE_FPMKUNIT
+override COMPILER_FPMAKE_UNITDIR+=$(UNITDIR_FPMAKE_FPMKUNIT)
+endif
+override INSTALL_FPCPACKAGE=y
+ifdef REQUIRE_UNITSDIR
+override UNITSDIR+=$(REQUIRE_UNITSDIR)
+endif
+ifdef REQUIRE_PACKAGESDIR
+override PACKAGESDIR+=$(REQUIRE_PACKAGESDIR)
+endif
+ifdef ZIPINSTALL
+ifneq ($(findstring $(OS_TARGET),$(UNIXs)),)
+UNIXHier=1
+endif
+else
+ifneq ($(findstring $(OS_SOURCE),$(UNIXs)),)
+UNIXHier=1
+endif
+endif
+ifndef INSTALL_PREFIX
+ifdef PREFIX
+INSTALL_PREFIX=$(PREFIX)
+endif
+endif
+ifndef INSTALL_PREFIX
+ifdef UNIXHier
+INSTALL_PREFIX=/usr/local
+else
+ifdef INSTALL_FPCPACKAGE
+INSTALL_BASEDIR:=/pp
+else
+INSTALL_BASEDIR:=/$(PACKAGE_NAME)
+endif
+endif
+endif
+export INSTALL_PREFIX
+ifdef INSTALL_FPCSUBDIR
+export INSTALL_FPCSUBDIR
+endif
+ifndef DIST_DESTDIR
+DIST_DESTDIR:=$(BASEDIR)
+endif
+export DIST_DESTDIR
+ifndef COMPILER_UNITTARGETDIR
+ifdef PACKAGEDIR_MAIN
+COMPILER_UNITTARGETDIR=$(PACKAGEDIR_MAIN)/units/$(TARGETSUFFIX)
+else
+COMPILER_UNITTARGETDIR=units/$(TARGETSUFFIX)
+endif
+endif
+ifndef COMPILER_TARGETDIR
+COMPILER_TARGETDIR=.
+endif
+ifndef INSTALL_BASEDIR
+ifdef UNIXHier
+ifdef INSTALL_FPCPACKAGE
+INSTALL_BASEDIR:=$(INSTALL_PREFIX)/lib/fpc/$(FPC_VERSION)
+else
+INSTALL_BASEDIR:=$(INSTALL_PREFIX)/lib/$(PACKAGE_NAME)
+endif
+else
+INSTALL_BASEDIR:=$(INSTALL_PREFIX)
+endif
+endif
+ifndef INSTALL_BINDIR
+ifdef UNIXHier
+INSTALL_BINDIR:=$(INSTALL_PREFIX)/bin
+else
+INSTALL_BINDIR:=$(INSTALL_BASEDIR)/bin
+ifdef INSTALL_FPCPACKAGE
+ifdef CROSSCOMPILE
+ifdef CROSSINSTALL
+INSTALL_BINDIR:=$(INSTALL_BINDIR)/$(SOURCESUFFIX)
+else
+INSTALL_BINDIR:=$(INSTALL_BINDIR)/$(TARGETSUFFIX)
+endif
+else
+INSTALL_BINDIR:=$(INSTALL_BINDIR)/$(TARGETSUFFIX)
+endif
+endif
+endif
+endif
+ifndef INSTALL_UNITDIR
+INSTALL_UNITDIR:=$(INSTALL_BASEDIR)/units/$(TARGETSUFFIX)
+ifdef INSTALL_FPCPACKAGE
+ifdef PACKAGE_NAME
+INSTALL_UNITDIR:=$(INSTALL_UNITDIR)/$(PACKAGE_NAME)
+endif
+endif
+endif
+ifndef INSTALL_LIBDIR
+ifdef UNIXHier
+INSTALL_LIBDIR:=$(INSTALL_PREFIX)/lib
+else
+INSTALL_LIBDIR:=$(INSTALL_UNITDIR)
+endif
+endif
+ifndef INSTALL_SOURCEDIR
+ifdef UNIXHier
+ifdef BSDhier
+SRCPREFIXDIR=share/src
+else
+ifdef linuxHier
+SRCPREFIXDIR=share/src
+else
+SRCPREFIXDIR=src
+endif
+endif
+ifdef INSTALL_FPCPACKAGE
+ifdef INSTALL_FPCSUBDIR
+INSTALL_SOURCEDIR:=$(INSTALL_PREFIX)/$(SRCPREFIXDIR)/fpc-$(FPC_VERSION)/$(INSTALL_FPCSUBDIR)/$(PACKAGE_NAME)
+else
+INSTALL_SOURCEDIR:=$(INSTALL_PREFIX)/$(SRCPREFIXDIR)/fpc-$(FPC_VERSION)/$(PACKAGE_NAME)
+endif
+else
+INSTALL_SOURCEDIR:=$(INSTALL_PREFIX)/$(SRCPREFIXDIR)/$(PACKAGE_NAME)-$(PACKAGE_VERSION)
+endif
+else
+ifdef INSTALL_FPCPACKAGE
+ifdef INSTALL_FPCSUBDIR
+INSTALL_SOURCEDIR:=$(INSTALL_BASEDIR)/source/$(INSTALL_FPCSUBDIR)/$(PACKAGE_NAME)
+else
+INSTALL_SOURCEDIR:=$(INSTALL_BASEDIR)/source/$(PACKAGE_NAME)
+endif
+else
+INSTALL_SOURCEDIR:=$(INSTALL_BASEDIR)/source
+endif
+endif
+endif
+ifndef INSTALL_DOCDIR
+ifdef UNIXHier
+ifdef BSDhier
+DOCPREFIXDIR=share/doc
+else
+ifdef linuxHier
+DOCPREFIXDIR=share/doc
+else
+DOCPREFIXDIR=doc
+endif
+endif
+ifdef INSTALL_FPCPACKAGE
+INSTALL_DOCDIR:=$(INSTALL_PREFIX)/$(DOCPREFIXDIR)/fpc-$(FPC_VERSION)/$(PACKAGE_NAME)
+else
+INSTALL_DOCDIR:=$(INSTALL_PREFIX)/$(DOCPREFIXDIR)/$(PACKAGE_NAME)-$(PACKAGE_VERSION)
+endif
+else
+ifdef INSTALL_FPCPACKAGE
+INSTALL_DOCDIR:=$(INSTALL_BASEDIR)/doc/$(PACKAGE_NAME)
+else
+INSTALL_DOCDIR:=$(INSTALL_BASEDIR)/doc
+endif
+endif
+endif
+ifndef INSTALL_EXAMPLEDIR
+ifdef UNIXHier
+ifdef INSTALL_FPCPACKAGE
+ifdef BSDhier
+INSTALL_EXAMPLEDIR:=$(INSTALL_PREFIX)/share/examples/fpc-$(FPC_VERSION)/$(PACKAGE_NAME)
+else
+ifdef linuxHier
+INSTALL_EXAMPLEDIR:=$(INSTALL_DOCDIR)/examples
+else
+INSTALL_EXAMPLEDIR:=$(INSTALL_PREFIX)/doc/fpc-$(FPC_VERSION)/examples/$(PACKAGE_NAME)
+endif
+endif
+else
+ifdef BSDhier
+INSTALL_EXAMPLEDIR:=$(INSTALL_PREFIX)/share/examples/$(PACKAGE_NAME)-$(PACKAGE_VERSION)
+else
+ifdef linuxHier
+INSTALL_EXAMPLEDIR:=$(INSTALL_DOCDIR)/examples/$(PACKAGE_NAME)-$(PACKAGE_VERSION)
+else
+INSTALL_EXAMPLEDIR:=$(INSTALL_PREFIX)/doc/$(PACKAGE_NAME)-$(PACKAGE_VERSION)
+endif
+endif
+endif
+else
+ifdef INSTALL_FPCPACKAGE
+INSTALL_EXAMPLEDIR:=$(INSTALL_BASEDIR)/examples/$(PACKAGE_NAME)
+else
+INSTALL_EXAMPLEDIR:=$(INSTALL_BASEDIR)/examples
+endif
+endif
+endif
+ifndef INSTALL_DATADIR
+INSTALL_DATADIR=$(INSTALL_BASEDIR)
+endif
+ifndef INSTALL_SHAREDDIR
+INSTALL_SHAREDDIR=$(INSTALL_PREFIX)/lib
+endif
+ifdef CROSSCOMPILE
+ifndef CROSSBINDIR
+CROSSBINDIR:=$(wildcard $(CROSSTARGETDIR)/bin/$(SOURCESUFFIX))
+ifeq ($(CROSSBINDIR),)
+CROSSBINDIR:=$(wildcard $(INSTALL_BASEDIR)/cross/$(TARGETSUFFIX)/bin/$(FULL_SOURCE))
+endif
+endif
+else
+CROSSBINDIR=
+endif
+ifeq ($(OS_SOURCE),linux)
+ifndef GCCLIBDIR
+ifeq ($(CPU_TARGET),i386)
+ifneq ($(findstring x86_64,$(shell uname -a)),)
+ifeq ($(BINUTILSPREFIX),)
+GCCLIBDIR:=$(shell dirname `gcc -m32 -print-libgcc-file-name`)
+else
+CROSSGCCOPT=-m32
+endif
+endif
+endif
+ifeq ($(CPU_TARGET),powerpc)
+ifeq ($(BINUTILSPREFIX),)
+GCCLIBDIR:=$(shell dirname `gcc -m32 -print-libgcc-file-name`)
+else
+CROSSGCCOPT=-m32
+endif
+endif
+ifeq ($(CPU_TARGET),powerpc64)
+ifeq ($(BINUTILSPREFIX),)
+GCCLIBDIR:=$(shell dirname `gcc -m64 -print-libgcc-file-name`)
+else
+CROSSGCCOPT=-m64
+endif
+endif
+ifeq ($(CPU_TARGET),sparc)
+ifneq ($(findstring sparc64,$(shell uname -a)),)
+ifeq ($(BINUTILSPREFIX),)
+GCCLIBDIR:=$(shell dirname `gcc -m32 -print-libgcc-file-name`)
+else
+ifneq ($(findstring $(FPCFPMAKE_CPU_OPT),mips mipsel),)
+CROSSGCCOPT=-mabi=32
+else
+CROSSGCCOPT=-m32
+endif
+endif
+endif
+endif
+endif
+ifdef FPCFPMAKE
+FPCFPMAKE_CPU_TARGET=$(shell $(FPCFPMAKE) -iTP)
+ifeq ($(CPU_TARGET),$(FPCFPMAKE_CPU_TARGET))
+FPCMAKEGCCLIBDIR:=$(GCCLIBDIR)
+else
+ifneq ($(findstring $(FPCFPMAKE_CPU_TARGET),aarch64 powerpc64 riscv64 sparc64 x86_64),)
+FPCMAKE_CROSSGCCOPT=-m64
+else
+ifneq ($(findstring $(FPCFPMAKE_CPU_OPT),mips64 mips64el),)
+FPCMAKE_CROSSGCCOPT=-mabi=64
+else
+ifneq ($(findstring $(FPCFPMAKE_CPU_OPT),mips mipsel),)
+FPCMAKE_CROSSGCCOPT=-mabi=32
+else
+ifneq ($(findstring $(FPCFPMAKE_CPU_OPT),riscv64),)
+FPCMAKE_CROSSGCCOPT=-mabi=lp64
+else
+ifneq ($(findstring $(FPCFPMAKE_CPU_OPT),riscv32),)
+FPCMAKE_CROSSGCCOPT=-mabi=ilp32
+else
+FPCMAKE_CROSSGCCOPT=-m32
+endif
+endif
+endif
+endif
+endif
+FPCMAKEGCCLIBDIR:=$(shell dirname `gcc $(FPCMAKE_CROSSGCCOPT) -print-libgcc-file-name`)
+endif
+endif
+ifndef FPCMAKEGCCLIBDIR
+FPCMAKEGCCLIBDIR:=$(shell dirname `gcc -print-libgcc-file-name`)
+endif
+ifndef GCCLIBDIR
+CROSSGCC=$(strip $(wildcard $(addsuffix /$(BINUTILSPREFIX)gcc$(SRCEXEEXT),$(SEARCHPATH))))
+ifneq ($(CROSSGCC),)
+GCCLIBDIR:=$(shell dirname `$(CROSSGCC) $(CROSSGCCOPT) -print-libgcc-file-name`)
+endif
+endif
+endif
+ifdef inUnix
+ifeq ($(OS_SOURCE),netbsd)
+OTHERLIBDIR:=/usr/pkg/lib
+endif
+export GCCLIBDIR FPCMAKEGCCLIBDIR OTHERLIBDIR
+endif
+BATCHEXT=.bat
+LOADEREXT=.as
+EXEEXT=.exe
+PPLEXT=.ppl
+PPUEXT=.ppu
+OEXT=.o
+LTOEXT=.bc
+ASMEXT=.s
+SMARTEXT=.sl
+STATICLIBEXT=.a
+SHAREDLIBEXT=.so
+SHAREDLIBPREFIX=libfp
+STATICLIBPREFIX=libp
+IMPORTLIBPREFIX=libimp
+RSTEXT=.rst
+EXEDBGEXT=.dbg
+ifeq ($(OS_TARGET),go32v1)
+STATICLIBPREFIX=
+SHORTSUFFIX=v1
+endif
+ifeq ($(OS_TARGET),go32v2)
+STATICLIBPREFIX=
+SHORTSUFFIX=dos
+IMPORTLIBPREFIX=
+endif
+ifeq ($(OS_TARGET),watcom)
+STATICLIBPREFIX=
+OEXT=.obj
+ASMEXT=.asm
+SHAREDLIBEXT=.dll
+SHORTSUFFIX=wat
+IMPORTLIBPREFIX=
+endif
+ifneq ($(CPU_TARGET),jvm)
+ifeq ($(OS_TARGET),android)
+BATCHEXT=.sh
+EXEEXT=
+HASSHAREDLIB=1
+SHORTSUFFIX=lnx
+endif
+endif
+ifeq ($(OS_TARGET),linux)
+BATCHEXT=.sh
+EXEEXT=
+HASSHAREDLIB=1
+SHORTSUFFIX=lnx
+endif
+ifeq ($(OS_TARGET),dragonfly)
+BATCHEXT=.sh
+EXEEXT=
+HASSHAREDLIB=1
+SHORTSUFFIX=df
+endif
+ifeq ($(OS_TARGET),freebsd)
+BATCHEXT=.sh
+EXEEXT=
+HASSHAREDLIB=1
+SHORTSUFFIX=fbs
+endif
+ifeq ($(OS_TARGET),netbsd)
+BATCHEXT=.sh
+EXEEXT=
+HASSHAREDLIB=1
+SHORTSUFFIX=nbs
+endif
+ifeq ($(OS_TARGET),openbsd)
+BATCHEXT=.sh
+EXEEXT=
+HASSHAREDLIB=1
+SHORTSUFFIX=obs
+endif
+ifeq ($(OS_TARGET),win32)
+SHAREDLIBEXT=.dll
+SHORTSUFFIX=w32
+endif
+ifeq ($(OS_TARGET),os2)
+BATCHEXT=.cmd
+AOUTEXT=.out
+STATICLIBPREFIX=
+SHAREDLIBEXT=.dll
+SHORTSUFFIX=os2
+ECHO=echo
+IMPORTLIBPREFIX=
+endif
+ifeq ($(OS_TARGET),emx)
+BATCHEXT=.cmd
+AOUTEXT=.out
+STATICLIBPREFIX=
+SHAREDLIBEXT=.dll
+SHORTSUFFIX=emx
+ECHO=echo
+IMPORTLIBPREFIX=
+endif
+ifeq ($(OS_TARGET),amiga)
+EXEEXT=
+SHAREDLIBEXT=.library
+SHORTSUFFIX=amg
+endif
+ifeq ($(OS_TARGET),aros)
+EXEEXT=
+SHAREDLIBEXT=.library
+SHORTSUFFIX=aros
+endif
+ifeq ($(OS_TARGET),morphos)
+EXEEXT=
+SHAREDLIBEXT=.library
+SHORTSUFFIX=mos
+endif
+ifeq ($(OS_TARGET),atari)
+EXEEXT=.ttp
+SHORTSUFFIX=ata
+endif
+ifeq ($(OS_TARGET),beos)
+BATCHEXT=.sh
+EXEEXT=
+SHORTSUFFIX=be
+endif
+ifeq ($(OS_TARGET),haiku)
+BATCHEXT=.sh
+EXEEXT=
+SHORTSUFFIX=hai
+endif
+ifeq ($(OS_TARGET),solaris)
+BATCHEXT=.sh
+EXEEXT=
+SHORTSUFFIX=sun
+endif
+ifeq ($(OS_TARGET),qnx)
+BATCHEXT=.sh
+EXEEXT=
+SHORTSUFFIX=qnx
+endif
+ifeq ($(OS_TARGET),netware)
+EXEEXT=.nlm
+STATICLIBPREFIX=
+SHORTSUFFIX=nw
+IMPORTLIBPREFIX=imp
+endif
+ifeq ($(OS_TARGET),netwlibc)
+EXEEXT=.nlm
+STATICLIBPREFIX=
+SHORTSUFFIX=nwl
+IMPORTLIBPREFIX=imp
+endif
+ifeq ($(OS_TARGET),macosclassic)
+BATCHEXT=
+EXEEXT=
+DEBUGSYMEXT=.xcoff
+SHORTSUFFIX=mac
+IMPORTLIBPREFIX=imp
+endif
+ifneq ($(findstring $(OS_TARGET),darwin iphonesim ios),)
+BATCHEXT=.sh
+EXEEXT=
+HASSHAREDLIB=1
+SHORTSUFFIX=dwn
+EXEDBGEXT=.dSYM
+endif
+ifeq ($(OS_TARGET),gba)
+EXEEXT=.gba
+SHAREDLIBEXT=.so
+SHORTSUFFIX=gba
+endif
+ifeq ($(OS_TARGET),symbian)
+SHAREDLIBEXT=.dll
+SHORTSUFFIX=symbian
+endif
+ifeq ($(OS_TARGET),NativeNT)
+SHAREDLIBEXT=.dll
+SHORTSUFFIX=nativent
+endif
+ifeq ($(OS_TARGET),wii)
+EXEEXT=.dol
+SHAREDLIBEXT=.so
+SHORTSUFFIX=wii
+endif
+ifeq ($(OS_TARGET),aix)
+BATCHEXT=.sh
+EXEEXT=
+SHAREDLIBEXT=.a
+SHORTSUFFIX=aix
+endif
+ifeq ($(OS_TARGET),java)
+OEXT=.class
+ASMEXT=.j
+SHAREDLIBEXT=.jar
+SHORTSUFFIX=java
+endif
+ifeq ($(CPU_TARGET),jvm)
+ifeq ($(OS_TARGET),android)
+OEXT=.class
+ASMEXT=.j
+SHAREDLIBEXT=.jar
+SHORTSUFFIX=android
+endif
+endif
+ifeq ($(OS_TARGET),msdos)
+STATICLIBPREFIX=
+STATICLIBEXT=.a
+SHORTSUFFIX=d16
+endif
+ifeq ($(OS_TARGET),msxdos)
+STATICLIBPREFIX=
+STATICLIBEXT=.a
+SHORTSUFFIX=msd
+endif
+ifeq ($(OS_TARGET),embedded)
+ifeq ($(CPU_TARGET),i8086)
+STATICLIBPREFIX=
+STATICLIBEXT=.a
+else
+EXEEXT=.bin
+endif
+ifeq ($(CPU_TARGET),z80)
+OEXT=.rel
+endif
+SHORTSUFFIX=emb
+endif
+ifeq ($(OS_TARGET),win16)
+STATICLIBPREFIX=
+STATICLIBEXT=.a
+SHAREDLIBEXT=.dll
+SHORTSUFFIX=w16
+endif
+ifeq ($(OS_TARGET),zxspectrum)
+OEXT=.rel
+endif
+ifneq ($(findstring $(OS_SOURCE),$(LIMIT83fs)),)
+FPCMADE=fpcmade.$(SHORTSUFFIX)
+ZIPSUFFIX=$(SHORTSUFFIX)
+ZIPCROSSPREFIX=
+ZIPSOURCESUFFIX=src
+ZIPEXAMPLESUFFIX=exm
+else
+FPCMADE=fpcmade.$(TARGETSUFFIX)
+ZIPSOURCESUFFIX=.source
+ZIPEXAMPLESUFFIX=.examples
+ifdef CROSSCOMPILE
+ZIPSUFFIX=.$(SOURCESUFFIX)
+ZIPCROSSPREFIX=$(TARGETSUFFIX)-
+else
+ZIPSUFFIX=.$(TARGETSUFFIX)
+ZIPCROSSPREFIX=
+endif
+endif
+ifndef ECHO
+ECHO:=$(strip $(wildcard $(addsuffix /gecho$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(ECHO),)
+ECHO:=$(strip $(wildcard $(addsuffix /echo$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(ECHO),)
+ECHO= __missing_command_ECHO
+else
+ECHO:=$(firstword $(ECHO))
+endif
+else
+ECHO:=$(firstword $(ECHO))
+endif
+endif
+export ECHO
+ifndef DATE
+DATE:=$(strip $(wildcard $(addsuffix /gdate$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(DATE),)
+DATE:=$(strip $(wildcard $(addsuffix /date$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(DATE),)
+DATE= __missing_command_DATE
+else
+DATE:=$(firstword $(DATE))
+endif
+else
+DATE:=$(firstword $(DATE))
+endif
+endif
+export DATE
+ifndef GINSTALL
+GINSTALL:=$(strip $(wildcard $(addsuffix /ginstall$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(GINSTALL),)
+GINSTALL:=$(strip $(wildcard $(addsuffix /install$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(GINSTALL),)
+GINSTALL= __missing_command_GINSTALL
+else
+GINSTALL:=$(firstword $(GINSTALL))
+endif
+else
+GINSTALL:=$(firstword $(GINSTALL))
+endif
+endif
+export GINSTALL
+ifndef CPPROG
+CPPROG:=$(strip $(wildcard $(addsuffix /cp$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(CPPROG),)
+CPPROG= __missing_command_CPPROG
+else
+CPPROG:=$(firstword $(CPPROG))
+endif
+endif
+export CPPROG
+ifndef RMPROG
+RMPROG:=$(strip $(wildcard $(addsuffix /rm$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(RMPROG),)
+RMPROG= __missing_command_RMPROG
+else
+RMPROG:=$(firstword $(RMPROG))
+endif
+endif
+export RMPROG
+ifndef MVPROG
+MVPROG:=$(strip $(wildcard $(addsuffix /mv$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(MVPROG),)
+MVPROG= __missing_command_MVPROG
+else
+MVPROG:=$(firstword $(MVPROG))
+endif
+endif
+export MVPROG
+ifndef MKDIRPROG
+MKDIRPROG:=$(strip $(wildcard $(addsuffix /gmkdir$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(MKDIRPROG),)
+MKDIRPROG:=$(strip $(wildcard $(addsuffix /mkdir$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(MKDIRPROG),)
+MKDIRPROG= __missing_command_MKDIRPROG
+else
+MKDIRPROG:=$(firstword $(MKDIRPROG))
+endif
+else
+MKDIRPROG:=$(firstword $(MKDIRPROG))
+endif
+endif
+export MKDIRPROG
+ifndef ECHOREDIR
+ifndef inUnix
+ECHOREDIR=echo
+else
+ECHOREDIR=$(ECHO)
+endif
+endif
+ifndef COPY
+COPY:=$(CPPROG) -fp
+endif
+ifndef COPYTREE
+COPYTREE:=$(CPPROG) -Rfp
+endif
+ifndef MKDIRTREE
+MKDIRTREE:=$(MKDIRPROG) -p
+endif
+ifndef MOVE
+MOVE:=$(MVPROG) -f
+endif
+ifndef DEL
+DEL:=$(RMPROG) -f
+endif
+ifndef DELTREE
+DELTREE:=$(RMPROG) -rf
+endif
+ifndef INSTALL
+ifdef inUnix
+INSTALL:=$(GINSTALL) -c -m 644
+else
+INSTALL:=$(COPY)
+endif
+endif
+ifndef INSTALLEXE
+ifdef inUnix
+INSTALLEXE:=$(GINSTALL) -c -m 755
+else
+INSTALLEXE:=$(COPY)
+endif
+endif
+ifndef MKDIR
+MKDIR:=$(GINSTALL) -m 755 -d
+endif
+export ECHOREDIR COPY COPYTREE MOVE DEL DELTREE INSTALL INSTALLEXE MKDIR
+ifndef PPUMOVE
+PPUMOVE:=$(strip $(wildcard $(addsuffix /ppumove$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(PPUMOVE),)
+PPUMOVE= __missing_command_PPUMOVE
+else
+PPUMOVE:=$(firstword $(PPUMOVE))
+endif
+endif
+export PPUMOVE
+ifndef FPCMAKE
+FPCMAKE:=$(strip $(wildcard $(addsuffix /fpcmake$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(FPCMAKE),)
+FPCMAKE= __missing_command_FPCMAKE
+else
+FPCMAKE:=$(firstword $(FPCMAKE))
+endif
+endif
+export FPCMAKE
+ifndef ZIPPROG
+ZIPPROG:=$(strip $(wildcard $(addsuffix /zip$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(ZIPPROG),)
+ZIPPROG= __missing_command_ZIPPROG
+else
+ZIPPROG:=$(firstword $(ZIPPROG))
+endif
+endif
+export ZIPPROG
+ifndef TARPROG
+TARPROG:=$(strip $(wildcard $(addsuffix /gtar$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(TARPROG),)
+TARPROG:=$(strip $(wildcard $(addsuffix /tar$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(TARPROG),)
+TARPROG= __missing_command_TARPROG
+else
+TARPROG:=$(firstword $(TARPROG))
+endif
+else
+TARPROG:=$(firstword $(TARPROG))
+endif
+endif
+export TARPROG
+ASNAME=$(BINUTILSPREFIX)as
+LDNAME=$(BINUTILSPREFIX)ld
+ARNAME=$(BINUTILSPREFIX)ar
+RCNAME=$(BINUTILSPREFIX)rc
+NASMNAME=$(BINUTILSPREFIX)nasm
+ifndef ASPROG
+ifdef CROSSBINDIR
+ASPROG=$(CROSSBINDIR)/$(ASNAME)$(SRCEXEEXT)
+else
+ASPROG=$(ASNAME)
+endif
+endif
+ifndef LDPROG
+ifdef CROSSBINDIR
+LDPROG=$(CROSSBINDIR)/$(LDNAME)$(SRCEXEEXT)
+else
+LDPROG=$(LDNAME)
+endif
+endif
+ifndef RCPROG
+ifdef CROSSBINDIR
+RCPROG=$(CROSSBINDIR)/$(RCNAME)$(SRCEXEEXT)
+else
+RCPROG=$(RCNAME)
+endif
+endif
+ifndef ARPROG
+ifdef CROSSBINDIR
+ARPROG=$(CROSSBINDIR)/$(ARNAME)$(SRCEXEEXT)
+else
+ARPROG=$(ARNAME)
+endif
+endif
+ifndef NASMPROG
+ifdef CROSSBINDIR
+NASMPROG=$(CROSSBINDIR)/$(NASMNAME)$(SRCEXEEXT)
+else
+NASMPROG=$(NASMNAME)
+endif
+endif
+AS=$(ASPROG)
+LD=$(LDPROG)
+RC=$(RCPROG)
+AR=$(ARPROG)
+NASM=$(NASMPROG)
+ifdef inUnix
+PPAS=./ppas$(SRCBATCHEXT)
+else
+PPAS=ppas$(SRCBATCHEXT)
+endif
+ifdef inUnix
+LDCONFIG=ldconfig
+else
+LDCONFIG=
+endif
+ifdef DATE
+DATESTR:=$(shell $(DATE) +%Y%m%d)
+else
+DATESTR=
+endif
+ZIPOPT=-9
+ZIPEXT=.zip
+ifeq ($(USETAR),bz2)
+TAROPT=vj
+TAREXT=.tar.bz2
+else
+TAROPT=vz
+TAREXT=.tar.gz
+endif
+override REQUIRE_PACKAGES=rtl fcl-base fcl-db fcl-json
+ifeq ($(FULL_TARGET),i386-linux)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),i386-go32v2)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),i386-win32)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),i386-os2)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),i386-freebsd)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),i386-beos)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),i386-haiku)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),i386-netbsd)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),i386-solaris)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),i386-netware)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),i386-openbsd)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),i386-wdosx)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),i386-darwin)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),i386-emx)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),i386-watcom)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),i386-netwlibc)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),i386-wince)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),i386-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),i386-symbian)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),i386-nativent)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),i386-iphonesim)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),i386-android)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),i386-aros)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),m68k-linux)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),m68k-netbsd)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),m68k-amiga)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),m68k-atari)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),m68k-palmos)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),m68k-macosclassic)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),m68k-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),m68k-sinclairql)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),powerpc-linux)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),powerpc-netbsd)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),powerpc-amiga)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),powerpc-macosclassic)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),powerpc-darwin)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),powerpc-morphos)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),powerpc-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),powerpc-wii)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),powerpc-aix)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),sparc-linux)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),sparc-netbsd)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),sparc-solaris)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),sparc-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),x86_64-linux)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),x86_64-freebsd)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),x86_64-haiku)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),x86_64-netbsd)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),x86_64-solaris)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),x86_64-openbsd)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),x86_64-darwin)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),x86_64-win64)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),x86_64-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),x86_64-iphonesim)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),x86_64-android)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),x86_64-aros)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),x86_64-dragonfly)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),arm-linux)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),arm-netbsd)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),arm-palmos)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),arm-wince)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),arm-gba)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),arm-nds)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),arm-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),arm-symbian)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),arm-android)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),arm-aros)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),arm-freertos)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),arm-ios)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),powerpc64-linux)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),powerpc64-darwin)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),powerpc64-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),powerpc64-aix)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),avr-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),armeb-linux)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),armeb-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),mips-linux)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),mipsel-linux)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),mipsel-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),mipsel-android)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),mips64el-linux)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),jvm-java)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),jvm-android)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),i8086-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),i8086-msdos)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),i8086-win16)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),aarch64-linux)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),aarch64-freebsd)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),aarch64-darwin)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),aarch64-win64)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),aarch64-android)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),aarch64-ios)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),wasm32-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),wasm32-wasi)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),sparc64-linux)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),riscv32-linux)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),riscv32-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),riscv64-linux)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),riscv64-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),xtensa-linux)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),xtensa-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),xtensa-freertos)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),z80-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),z80-zxspectrum)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),z80-msxdos)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifeq ($(FULL_TARGET),z80-amstradcpc)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_FCL-BASE=1
+REQUIRE_PACKAGES_FCL-DB=1
+REQUIRE_PACKAGES_FCL-JSON=1
+endif
+ifdef REQUIRE_PACKAGES_RTL
+PACKAGEDIR_RTL:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /rtl/Makefile.fpc,$(PACKAGESDIR))))))
+ifneq ($(PACKAGEDIR_RTL),)
+ifneq ($(wildcard $(PACKAGEDIR_RTL)/units/$(TARGETSUFFIX)),)
+UNITDIR_RTL=$(PACKAGEDIR_RTL)/units/$(TARGETSUFFIX)
+else
+UNITDIR_RTL=$(PACKAGEDIR_RTL)
+endif
+ifneq ($(wildcard $(PACKAGEDIR_RTL)/units/$(SOURCESUFFIX)),)
+UNITDIR_FPMAKE_RTL=$(PACKAGEDIR_RTL)/units/$(SOURCESUFFIX)
+else
+ifneq ($(wildcard $(PACKAGEDIR_RTL)/units_bs/$(SOURCESUFFIX)),)
+UNITDIR_FPMAKE_RTL=$(PACKAGEDIR_RTL)/units_bs/$(SOURCESUFFIX)
+else
+UNITDIR_FPMAKE_RTL=$(PACKAGEDIR_RTL)
+endif
+endif
+ifdef CHECKDEPEND
+$(PACKAGEDIR_RTL)/$(OS_TARGET)/$(FPCMADE):
+	$(MAKE) -C $(PACKAGEDIR_RTL)/$(OS_TARGET) $(FPCMADE)
+override ALLDEPENDENCIES+=$(PACKAGEDIR_RTL)/$(OS_TARGET)/$(FPCMADE)
+endif
+else
+PACKAGEDIR_RTL=
+UNITDIR_RTL:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /rtl/Package.fpc,$(UNITSDIR)))))
+ifneq ($(UNITDIR_RTL),)
+UNITDIR_RTL:=$(firstword $(UNITDIR_RTL))
+else
+UNITDIR_RTL=
+endif
+endif
+ifdef UNITDIR_RTL
+override COMPILER_UNITDIR+=$(UNITDIR_RTL)
+endif
+ifdef UNITDIR_FPMAKE_RTL
+override COMPILER_FPMAKE_UNITDIR+=$(UNITDIR_FPMAKE_RTL)
+endif
+endif
+ifdef REQUIRE_PACKAGES_PASZLIB
+PACKAGEDIR_PASZLIB:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /paszlib/Makefile.fpc,$(PACKAGESDIR))))))
+ifneq ($(PACKAGEDIR_PASZLIB),)
+ifneq ($(wildcard $(PACKAGEDIR_PASZLIB)/units/$(TARGETSUFFIX)),)
+UNITDIR_PASZLIB=$(PACKAGEDIR_PASZLIB)/units/$(TARGETSUFFIX)
+else
+UNITDIR_PASZLIB=$(PACKAGEDIR_PASZLIB)
+endif
+ifneq ($(wildcard $(PACKAGEDIR_PASZLIB)/units/$(SOURCESUFFIX)),)
+UNITDIR_FPMAKE_PASZLIB=$(PACKAGEDIR_PASZLIB)/units/$(SOURCESUFFIX)
+else
+ifneq ($(wildcard $(PACKAGEDIR_PASZLIB)/units_bs/$(SOURCESUFFIX)),)
+UNITDIR_FPMAKE_PASZLIB=$(PACKAGEDIR_PASZLIB)/units_bs/$(SOURCESUFFIX)
+else
+UNITDIR_FPMAKE_PASZLIB=$(PACKAGEDIR_PASZLIB)
+endif
+endif
+ifdef CHECKDEPEND
+$(PACKAGEDIR_PASZLIB)/$(FPCMADE):
+	$(MAKE) -C $(PACKAGEDIR_PASZLIB) $(FPCMADE)
+override ALLDEPENDENCIES+=$(PACKAGEDIR_PASZLIB)/$(FPCMADE)
+endif
+else
+PACKAGEDIR_PASZLIB=
+UNITDIR_PASZLIB:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /paszlib/Package.fpc,$(UNITSDIR)))))
+ifneq ($(UNITDIR_PASZLIB),)
+UNITDIR_PASZLIB:=$(firstword $(UNITDIR_PASZLIB))
+else
+UNITDIR_PASZLIB=
+endif
+endif
+ifdef UNITDIR_PASZLIB
+override COMPILER_UNITDIR+=$(UNITDIR_PASZLIB)
+endif
+ifdef UNITDIR_FPMAKE_PASZLIB
+override COMPILER_FPMAKE_UNITDIR+=$(UNITDIR_FPMAKE_PASZLIB)
+endif
+endif
+ifdef REQUIRE_PACKAGES_FCL-PROCESS
+PACKAGEDIR_FCL-PROCESS:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /fcl-process/Makefile.fpc,$(PACKAGESDIR))))))
+ifneq ($(PACKAGEDIR_FCL-PROCESS),)
+ifneq ($(wildcard $(PACKAGEDIR_FCL-PROCESS)/units/$(TARGETSUFFIX)),)
+UNITDIR_FCL-PROCESS=$(PACKAGEDIR_FCL-PROCESS)/units/$(TARGETSUFFIX)
+else
+UNITDIR_FCL-PROCESS=$(PACKAGEDIR_FCL-PROCESS)
+endif
+ifneq ($(wildcard $(PACKAGEDIR_FCL-PROCESS)/units/$(SOURCESUFFIX)),)
+UNITDIR_FPMAKE_FCL-PROCESS=$(PACKAGEDIR_FCL-PROCESS)/units/$(SOURCESUFFIX)
+else
+ifneq ($(wildcard $(PACKAGEDIR_FCL-PROCESS)/units_bs/$(SOURCESUFFIX)),)
+UNITDIR_FPMAKE_FCL-PROCESS=$(PACKAGEDIR_FCL-PROCESS)/units_bs/$(SOURCESUFFIX)
+else
+UNITDIR_FPMAKE_FCL-PROCESS=$(PACKAGEDIR_FCL-PROCESS)
+endif
+endif
+ifdef CHECKDEPEND
+$(PACKAGEDIR_FCL-PROCESS)/$(FPCMADE):
+	$(MAKE) -C $(PACKAGEDIR_FCL-PROCESS) $(FPCMADE)
+override ALLDEPENDENCIES+=$(PACKAGEDIR_FCL-PROCESS)/$(FPCMADE)
+endif
+else
+PACKAGEDIR_FCL-PROCESS=
+UNITDIR_FCL-PROCESS:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /fcl-process/Package.fpc,$(UNITSDIR)))))
+ifneq ($(UNITDIR_FCL-PROCESS),)
+UNITDIR_FCL-PROCESS:=$(firstword $(UNITDIR_FCL-PROCESS))
+else
+UNITDIR_FCL-PROCESS=
+endif
+endif
+ifdef UNITDIR_FCL-PROCESS
+override COMPILER_UNITDIR+=$(UNITDIR_FCL-PROCESS)
+endif
+ifdef UNITDIR_FPMAKE_FCL-PROCESS
+override COMPILER_FPMAKE_UNITDIR+=$(UNITDIR_FPMAKE_FCL-PROCESS)
+endif
+endif
+ifdef REQUIRE_PACKAGES_HASH
+PACKAGEDIR_HASH:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /hash/Makefile.fpc,$(PACKAGESDIR))))))
+ifneq ($(PACKAGEDIR_HASH),)
+ifneq ($(wildcard $(PACKAGEDIR_HASH)/units/$(TARGETSUFFIX)),)
+UNITDIR_HASH=$(PACKAGEDIR_HASH)/units/$(TARGETSUFFIX)
+else
+UNITDIR_HASH=$(PACKAGEDIR_HASH)
+endif
+ifneq ($(wildcard $(PACKAGEDIR_HASH)/units/$(SOURCESUFFIX)),)
+UNITDIR_FPMAKE_HASH=$(PACKAGEDIR_HASH)/units/$(SOURCESUFFIX)
+else
+ifneq ($(wildcard $(PACKAGEDIR_HASH)/units_bs/$(SOURCESUFFIX)),)
+UNITDIR_FPMAKE_HASH=$(PACKAGEDIR_HASH)/units_bs/$(SOURCESUFFIX)
+else
+UNITDIR_FPMAKE_HASH=$(PACKAGEDIR_HASH)
+endif
+endif
+ifdef CHECKDEPEND
+$(PACKAGEDIR_HASH)/$(FPCMADE):
+	$(MAKE) -C $(PACKAGEDIR_HASH) $(FPCMADE)
+override ALLDEPENDENCIES+=$(PACKAGEDIR_HASH)/$(FPCMADE)
+endif
+else
+PACKAGEDIR_HASH=
+UNITDIR_HASH:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /hash/Package.fpc,$(UNITSDIR)))))
+ifneq ($(UNITDIR_HASH),)
+UNITDIR_HASH:=$(firstword $(UNITDIR_HASH))
+else
+UNITDIR_HASH=
+endif
+endif
+ifdef UNITDIR_HASH
+override COMPILER_UNITDIR+=$(UNITDIR_HASH)
+endif
+ifdef UNITDIR_FPMAKE_HASH
+override COMPILER_FPMAKE_UNITDIR+=$(UNITDIR_FPMAKE_HASH)
+endif
+endif
+ifdef REQUIRE_PACKAGES_LIBTAR
+PACKAGEDIR_LIBTAR:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /libtar/Makefile.fpc,$(PACKAGESDIR))))))
+ifneq ($(PACKAGEDIR_LIBTAR),)
+ifneq ($(wildcard $(PACKAGEDIR_LIBTAR)/units/$(TARGETSUFFIX)),)
+UNITDIR_LIBTAR=$(PACKAGEDIR_LIBTAR)/units/$(TARGETSUFFIX)
+else
+UNITDIR_LIBTAR=$(PACKAGEDIR_LIBTAR)
+endif
+ifneq ($(wildcard $(PACKAGEDIR_LIBTAR)/units/$(SOURCESUFFIX)),)
+UNITDIR_FPMAKE_LIBTAR=$(PACKAGEDIR_LIBTAR)/units/$(SOURCESUFFIX)
+else
+ifneq ($(wildcard $(PACKAGEDIR_LIBTAR)/units_bs/$(SOURCESUFFIX)),)
+UNITDIR_FPMAKE_LIBTAR=$(PACKAGEDIR_LIBTAR)/units_bs/$(SOURCESUFFIX)
+else
+UNITDIR_FPMAKE_LIBTAR=$(PACKAGEDIR_LIBTAR)
+endif
+endif
+ifdef CHECKDEPEND
+$(PACKAGEDIR_LIBTAR)/$(FPCMADE):
+	$(MAKE) -C $(PACKAGEDIR_LIBTAR) $(FPCMADE)
+override ALLDEPENDENCIES+=$(PACKAGEDIR_LIBTAR)/$(FPCMADE)
+endif
+else
+PACKAGEDIR_LIBTAR=
+UNITDIR_LIBTAR:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /libtar/Package.fpc,$(UNITSDIR)))))
+ifneq ($(UNITDIR_LIBTAR),)
+UNITDIR_LIBTAR:=$(firstword $(UNITDIR_LIBTAR))
+else
+UNITDIR_LIBTAR=
+endif
+endif
+ifdef UNITDIR_LIBTAR
+override COMPILER_UNITDIR+=$(UNITDIR_LIBTAR)
+endif
+ifdef UNITDIR_FPMAKE_LIBTAR
+override COMPILER_FPMAKE_UNITDIR+=$(UNITDIR_FPMAKE_LIBTAR)
+endif
+endif
+ifdef REQUIRE_PACKAGES_FPMKUNIT
+PACKAGEDIR_FPMKUNIT:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /fpmkunit/Makefile.fpc,$(PACKAGESDIR))))))
+ifneq ($(PACKAGEDIR_FPMKUNIT),)
+ifneq ($(wildcard $(PACKAGEDIR_FPMKUNIT)/units/$(TARGETSUFFIX)),)
+UNITDIR_FPMKUNIT=$(PACKAGEDIR_FPMKUNIT)/units/$(TARGETSUFFIX)
+else
+UNITDIR_FPMKUNIT=$(PACKAGEDIR_FPMKUNIT)
+endif
+ifneq ($(wildcard $(PACKAGEDIR_FPMKUNIT)/units/$(SOURCESUFFIX)),)
+UNITDIR_FPMAKE_FPMKUNIT=$(PACKAGEDIR_FPMKUNIT)/units/$(SOURCESUFFIX)
+else
+ifneq ($(wildcard $(PACKAGEDIR_FPMKUNIT)/units_bs/$(SOURCESUFFIX)),)
+UNITDIR_FPMAKE_FPMKUNIT=$(PACKAGEDIR_FPMKUNIT)/units_bs/$(SOURCESUFFIX)
+else
+UNITDIR_FPMAKE_FPMKUNIT=$(PACKAGEDIR_FPMKUNIT)
+endif
+endif
+ifdef CHECKDEPEND
+$(PACKAGEDIR_FPMKUNIT)/$(FPCMADE):
+	$(MAKE) -C $(PACKAGEDIR_FPMKUNIT) $(FPCMADE)
+override ALLDEPENDENCIES+=$(PACKAGEDIR_FPMKUNIT)/$(FPCMADE)
+endif
+else
+PACKAGEDIR_FPMKUNIT=
+UNITDIR_FPMKUNIT:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /fpmkunit/Package.fpc,$(UNITSDIR)))))
+ifneq ($(UNITDIR_FPMKUNIT),)
+UNITDIR_FPMKUNIT:=$(firstword $(UNITDIR_FPMKUNIT))
+else
+UNITDIR_FPMKUNIT=
+endif
+endif
+ifdef UNITDIR_FPMKUNIT
+override COMPILER_UNITDIR+=$(UNITDIR_FPMKUNIT)
+endif
+ifdef UNITDIR_FPMAKE_FPMKUNIT
+override COMPILER_FPMAKE_UNITDIR+=$(UNITDIR_FPMAKE_FPMKUNIT)
+endif
+endif
+ifdef REQUIRE_PACKAGES_FCL-BASE
+PACKAGEDIR_FCL-BASE:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /fcl-base/Makefile.fpc,$(PACKAGESDIR))))))
+ifneq ($(PACKAGEDIR_FCL-BASE),)
+ifneq ($(wildcard $(PACKAGEDIR_FCL-BASE)/units/$(TARGETSUFFIX)),)
+UNITDIR_FCL-BASE=$(PACKAGEDIR_FCL-BASE)/units/$(TARGETSUFFIX)
+else
+UNITDIR_FCL-BASE=$(PACKAGEDIR_FCL-BASE)
+endif
+ifneq ($(wildcard $(PACKAGEDIR_FCL-BASE)/units/$(SOURCESUFFIX)),)
+UNITDIR_FPMAKE_FCL-BASE=$(PACKAGEDIR_FCL-BASE)/units/$(SOURCESUFFIX)
+else
+ifneq ($(wildcard $(PACKAGEDIR_FCL-BASE)/units_bs/$(SOURCESUFFIX)),)
+UNITDIR_FPMAKE_FCL-BASE=$(PACKAGEDIR_FCL-BASE)/units_bs/$(SOURCESUFFIX)
+else
+UNITDIR_FPMAKE_FCL-BASE=$(PACKAGEDIR_FCL-BASE)
+endif
+endif
+ifdef CHECKDEPEND
+$(PACKAGEDIR_FCL-BASE)/$(FPCMADE):
+	$(MAKE) -C $(PACKAGEDIR_FCL-BASE) $(FPCMADE)
+override ALLDEPENDENCIES+=$(PACKAGEDIR_FCL-BASE)/$(FPCMADE)
+endif
+else
+PACKAGEDIR_FCL-BASE=
+UNITDIR_FCL-BASE:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /fcl-base/Package.fpc,$(UNITSDIR)))))
+ifneq ($(UNITDIR_FCL-BASE),)
+UNITDIR_FCL-BASE:=$(firstword $(UNITDIR_FCL-BASE))
+else
+UNITDIR_FCL-BASE=
+endif
+endif
+ifdef UNITDIR_FCL-BASE
+override COMPILER_UNITDIR+=$(UNITDIR_FCL-BASE)
+endif
+ifdef UNITDIR_FPMAKE_FCL-BASE
+override COMPILER_FPMAKE_UNITDIR+=$(UNITDIR_FPMAKE_FCL-BASE)
+endif
+endif
+ifdef REQUIRE_PACKAGES_FCL-DB
+PACKAGEDIR_FCL-DB:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /fcl-db/Makefile.fpc,$(PACKAGESDIR))))))
+ifneq ($(PACKAGEDIR_FCL-DB),)
+ifneq ($(wildcard $(PACKAGEDIR_FCL-DB)/units/$(TARGETSUFFIX)),)
+UNITDIR_FCL-DB=$(PACKAGEDIR_FCL-DB)/units/$(TARGETSUFFIX)
+else
+UNITDIR_FCL-DB=$(PACKAGEDIR_FCL-DB)
+endif
+ifneq ($(wildcard $(PACKAGEDIR_FCL-DB)/units/$(SOURCESUFFIX)),)
+UNITDIR_FPMAKE_FCL-DB=$(PACKAGEDIR_FCL-DB)/units/$(SOURCESUFFIX)
+else
+ifneq ($(wildcard $(PACKAGEDIR_FCL-DB)/units_bs/$(SOURCESUFFIX)),)
+UNITDIR_FPMAKE_FCL-DB=$(PACKAGEDIR_FCL-DB)/units_bs/$(SOURCESUFFIX)
+else
+UNITDIR_FPMAKE_FCL-DB=$(PACKAGEDIR_FCL-DB)
+endif
+endif
+ifdef CHECKDEPEND
+$(PACKAGEDIR_FCL-DB)/$(FPCMADE):
+	$(MAKE) -C $(PACKAGEDIR_FCL-DB) $(FPCMADE)
+override ALLDEPENDENCIES+=$(PACKAGEDIR_FCL-DB)/$(FPCMADE)
+endif
+else
+PACKAGEDIR_FCL-DB=
+UNITDIR_FCL-DB:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /fcl-db/Package.fpc,$(UNITSDIR)))))
+ifneq ($(UNITDIR_FCL-DB),)
+UNITDIR_FCL-DB:=$(firstword $(UNITDIR_FCL-DB))
+else
+UNITDIR_FCL-DB=
+endif
+endif
+ifdef UNITDIR_FCL-DB
+override COMPILER_UNITDIR+=$(UNITDIR_FCL-DB)
+endif
+ifdef UNITDIR_FPMAKE_FCL-DB
+override COMPILER_FPMAKE_UNITDIR+=$(UNITDIR_FPMAKE_FCL-DB)
+endif
+endif
+ifdef REQUIRE_PACKAGES_FCL-JSON
+PACKAGEDIR_FCL-JSON:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /fcl-json/Makefile.fpc,$(PACKAGESDIR))))))
+ifneq ($(PACKAGEDIR_FCL-JSON),)
+ifneq ($(wildcard $(PACKAGEDIR_FCL-JSON)/units/$(TARGETSUFFIX)),)
+UNITDIR_FCL-JSON=$(PACKAGEDIR_FCL-JSON)/units/$(TARGETSUFFIX)
+else
+UNITDIR_FCL-JSON=$(PACKAGEDIR_FCL-JSON)
+endif
+ifneq ($(wildcard $(PACKAGEDIR_FCL-JSON)/units/$(SOURCESUFFIX)),)
+UNITDIR_FPMAKE_FCL-JSON=$(PACKAGEDIR_FCL-JSON)/units/$(SOURCESUFFIX)
+else
+ifneq ($(wildcard $(PACKAGEDIR_FCL-JSON)/units_bs/$(SOURCESUFFIX)),)
+UNITDIR_FPMAKE_FCL-JSON=$(PACKAGEDIR_FCL-JSON)/units_bs/$(SOURCESUFFIX)
+else
+UNITDIR_FPMAKE_FCL-JSON=$(PACKAGEDIR_FCL-JSON)
+endif
+endif
+ifdef CHECKDEPEND
+$(PACKAGEDIR_FCL-JSON)/$(FPCMADE):
+	$(MAKE) -C $(PACKAGEDIR_FCL-JSON) $(FPCMADE)
+override ALLDEPENDENCIES+=$(PACKAGEDIR_FCL-JSON)/$(FPCMADE)
+endif
+else
+PACKAGEDIR_FCL-JSON=
+UNITDIR_FCL-JSON:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /fcl-json/Package.fpc,$(UNITSDIR)))))
+ifneq ($(UNITDIR_FCL-JSON),)
+UNITDIR_FCL-JSON:=$(firstword $(UNITDIR_FCL-JSON))
+else
+UNITDIR_FCL-JSON=
+endif
+endif
+ifdef UNITDIR_FCL-JSON
+override COMPILER_UNITDIR+=$(UNITDIR_FCL-JSON)
+endif
+ifdef UNITDIR_FPMAKE_FCL-JSON
+override COMPILER_FPMAKE_UNITDIR+=$(UNITDIR_FPMAKE_FCL-JSON)
+endif
+endif
+ifndef NOCPUDEF
+override FPCOPTDEF=$(ARCH)
+endif
+ifneq ($(OS_TARGET),$(OS_SOURCE))
+override FPCOPT+=-T$(OS_TARGET)
+endif
+ifneq ($(CPU_TARGET),$(CPU_SOURCE))
+override FPCOPT+=-P$(ARCH)
+endif
+ifeq ($(OS_SOURCE),openbsd)
+override FPCOPT+=-FD$(NEW_BINUTILS_PATH)
+override FPCMAKEOPT+=-FD$(NEW_BINUTILS_PATH)
+override FPMAKE_BUILD_OPT+=-FD$(NEW_BINUTILS_PATH)
+endif
+ifndef CROSSBOOTSTRAP
+ifneq ($(BINUTILSPREFIX),)
+override FPCOPT+=-XP$(BINUTILSPREFIX)
+ifneq ($(RLINKPATH),)
+override FPCOPT+=-Xr$(RLINKPATH)
+endif
+endif
+endif
+ifndef CROSSCOMPILE
+ifneq ($(BINUTILSPREFIX),)
+override FPCMAKEOPT+=-XP$(BINUTILSPREFIX)
+override FPMAKE_BUILD_OPT+=-XP$(BINUTILSPREFIX)
+endif
+endif
+ifdef UNITDIR
+override FPCOPT+=$(addprefix -Fu,$(UNITDIR))
+endif
+ifdef LIBDIR
+override FPCOPT+=$(addprefix -Fl,$(LIBDIR))
+endif
+ifdef OBJDIR
+override FPCOPT+=$(addprefix -Fo,$(OBJDIR))
+endif
+ifdef INCDIR
+override FPCOPT+=$(addprefix -Fi,$(INCDIR))
+endif
+ifdef LINKSMART
+override FPCOPT+=-XX
+endif
+ifdef CREATESMART
+override FPCOPT+=-CX
+endif
+ifdef DEBUG
+override FPCOPT+=-gl
+override FPCOPTDEF+=DEBUG
+endif
+ifdef RELEASE
+FPCCPUOPT:=-O2
+override FPCOPT+=-Ur -Xs $(FPCCPUOPT) -n
+override FPCOPTDEF+=RELEASE
+endif
+ifdef STRIP
+override FPCOPT+=-Xs
+endif
+ifdef OPTIMIZE
+override FPCOPT+=-O2
+endif
+ifdef VERBOSE
+override FPCOPT+=-vwni
+endif
+ifdef COMPILER_OPTIONS
+override FPCOPT+=$(COMPILER_OPTIONS)
+endif
+ifdef COMPILER_UNITDIR
+override FPCOPT+=$(addprefix -Fu,$(COMPILER_UNITDIR))
+endif
+ifdef COMPILER_LIBRARYDIR
+override FPCOPT+=$(addprefix -Fl,$(COMPILER_LIBRARYDIR))
+endif
+ifdef COMPILER_OBJECTDIR
+override FPCOPT+=$(addprefix -Fo,$(COMPILER_OBJECTDIR))
+endif
+ifdef COMPILER_INCLUDEDIR
+override FPCOPT+=$(addprefix -Fi,$(COMPILER_INCLUDEDIR))
+endif
+ifdef CROSSBINDIR
+override FPCOPT+=-FD$(CROSSBINDIR)
+endif
+ifdef COMPILER_TARGETDIR
+override FPCOPT+=-FE$(COMPILER_TARGETDIR)
+ifeq ($(COMPILER_TARGETDIR),.)
+override TARGETDIRPREFIX=
+else
+override TARGETDIRPREFIX=$(COMPILER_TARGETDIR)/
+endif
+endif
+ifdef COMPILER_UNITTARGETDIR
+override FPCOPT+=-FU$(COMPILER_UNITTARGETDIR)
+ifeq ($(COMPILER_UNITTARGETDIR),.)
+override UNITTARGETDIRPREFIX=
+else
+override UNITTARGETDIRPREFIX=$(COMPILER_UNITTARGETDIR)/
+endif
+else
+ifdef COMPILER_TARGETDIR
+override COMPILER_UNITTARGETDIR=$(COMPILER_TARGETDIR)
+override UNITTARGETDIRPREFIX=$(TARGETDIRPREFIX)
+endif
+endif
+ifdef SYSROOTPATH
+override FPCOPT+=-XR$(SYSROOTPATH)
+else
+ifeq ($(OS_TARGET),$(OS_SOURCE))
+ifneq ($(findstring $(OS_TARGET),darwin),)
+ifneq ($(findstring $(CPU_TARGET),aarch64),)
+ifneq ($(wildcard /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk),)
+override FPCOPT+=-XR/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk
+endif
+endif
+endif
+endif
+endif
+ifdef CREATESHARED
+override FPCOPT+=-Cg
+endif
+ifneq ($(findstring $(OS_TARGET),dragonfly freebsd openbsd netbsd linux solaris),)
+ifneq ($(findstring $(CPU_TARGET),x86_64 mips mipsel riscv64),)
+override FPCOPT+=-Cg
+endif
+endif
+ifdef LINKSHARED
+endif
+ifdef GCCLIBDIR
+override FPCOPT+=-Fl$(GCCLIBDIR)
+ifdef FPCMAKEGCCLIBDIR
+override FPCMAKEOPT+=-Fl$(FPCMAKEGCCLIBDIR)
+else
+override FPCMAKEOPT+=-Fl$(GCCLIBDIR)
+endif
+endif
+ifdef OTHERLIBDIR
+override FPCOPT+=$(addprefix -Fl,$(OTHERLIBDIR))
+endif
+ifdef OPT
+override FPCOPT+=$(OPT)
+endif
+ifdef FPMAKEBUILDOPT
+override FPMAKE_BUILD_OPT+=$(FPMAKEBUILDOPT)
+endif
+ifdef FPCOPTDEF
+override FPCOPT+=$(addprefix -d,$(FPCOPTDEF))
+endif
+ifdef CFGFILE
+override FPCOPT+=@$(CFGFILE)
+endif
+ifdef USEENV
+override FPCEXTCMD:=$(FPCOPT)
+override FPCOPT:=!FPCEXTCMD
+export FPCEXTCMD
+endif
+override AFULL_TARGET=$(CPU_TARGET)-$(OS_TARGET)
+override AFULL_SOURCE=$(CPU_SOURCE)-$(OS_SOURCE)
+ifneq ($(AFULL_TARGET),$(AFULL_SOURCE))
+override ACROSSCOMPILE=1
+endif
+ifdef ACROSSCOMPILE
+override FPCOPT+=$(CROSSOPT)
+endif
+override COMPILER:=$(strip $(FPC) $(FPCOPT))
+ifneq (,$(findstring -sh ,$(COMPILER)))
+UseEXECPPAS=1
+endif
+ifneq (,$(findstring -s ,$(COMPILER)))
+ifeq ($(FULL_SOURCE),$(FULL_TARGET))
+UseEXECPPAS=1
+endif
+endif
+ifneq ($(UseEXECPPAS),1)
+EXECPPAS=
+else
+ifdef RUNBATCH
+EXECPPAS:=@$(RUNBATCH) $(PPAS)
+else
+EXECPPAS:=@$(PPAS)
+endif
+endif
+ifdef TARGET_RSTS
+override RSTFILES=$(addsuffix $(RSTEXT),$(TARGET_RSTS))
+override CLEANRSTFILES+=$(RSTFILES)
+endif
+.PHONY: fpc_install fpc_sourceinstall fpc_exampleinstall
+ifdef INSTALL_UNITS
+override INSTALLPPUFILES+=$(addsuffix $(PPUEXT),$(INSTALL_UNITS))
+endif
+ifdef INSTALL_BUILDUNIT
+override INSTALLPPUFILES:=$(filter-out $(INSTALL_BUILDUNIT)$(PPUEXT),$(INSTALLPPUFILES))
+endif
+ifdef INSTALLPPUFILES
+ifneq ($(IMPORTLIBPREFIX)-$(STATICLIBEXT),$(STATICLIBPREFIX)-$(STATICLIBEXT))
+override INSTALLPPULINKFILES:=$(subst $(PPUEXT),$(OEXT),$(INSTALLPPUFILES)) $(subst $(PPUEXT),$(LTOEXT),$(INSTALLPPUFILES)) $(addprefix $(STATICLIBPREFIX),$(subst $(PPUEXT),$(STATICLIBEXT),$(INSTALLPPUFILES))) $(addprefix $(IMPORTLIBPREFIX),$(subst $(PPUEXT),$(STATICLIBEXT),$(INSTALLPPUFILES)))
+else
+override INSTALLPPULINKFILES:=$(subst $(PPUEXT),$(OEXT),$(INSTALLPPUFILES)) $(subst $(PPUEXT),$(LTOEXT),$(INSTALLPPUFILES)) $(addprefix $(STATICLIBPREFIX),$(subst $(PPUEXT),$(STATICLIBEXT),$(INSTALLPPUFILES)))
+endif
+ifneq ($(UNITTARGETDIRPREFIX),)
+override INSTALLPPUFILENAMES:=$(notdir $(INSTALLPPUFILES))
+override INSTALLPPULINKFILENAMES:=$(notdir $(INSTALLPPULINKFILES))
+override INSTALLPPUFILES=$(addprefix $(UNITTARGETDIRPREFIX),$(INSTALLPPUFILENAMES))
+override INSTALLPPULINKFILES=$(wildcard $(addprefix $(UNITTARGETDIRPREFIX),$(INSTALLPPULINKFILENAMES)))
+endif
+override INSTALL_CREATEPACKAGEFPC=1
+endif
+ifdef INSTALLEXEFILES
+ifneq ($(TARGETDIRPREFIX),)
+override INSTALLEXEFILES:=$(addprefix $(TARGETDIRPREFIX),$(notdir $(INSTALLEXEFILES)))
+endif
+endif
+fpc_install: all $(INSTALLTARGET)
+ifdef INSTALLEXEFILES
+	$(MKDIR) $(INSTALL_BINDIR)
+	$(INSTALLEXE) $(INSTALLEXEFILES) $(INSTALL_BINDIR)
+endif
+ifdef INSTALL_CREATEPACKAGEFPC
+ifdef FPCMAKE
+ifdef PACKAGE_VERSION
+ifneq ($(wildcard Makefile.fpc),)
+	$(FPCMAKE) -p -T$(CPU_TARGET)-$(OS_TARGET) Makefile.fpc
+	$(MKDIR) $(INSTALL_UNITDIR)
+	$(INSTALL) Package.fpc $(INSTALL_UNITDIR)
+endif
+endif
+endif
+endif
+ifdef INSTALLPPUFILES
+	$(MKDIR) $(INSTALL_UNITDIR)
+	$(INSTALL) $(INSTALLPPUFILES) $(INSTALL_UNITDIR)
+ifneq ($(INSTALLPPULINKFILES),)
+	$(INSTALL) $(INSTALLPPULINKFILES) $(INSTALL_UNITDIR)
+endif
+ifneq ($(wildcard $(LIB_FULLNAME)),)
+	$(MKDIR) $(INSTALL_LIBDIR)
+	$(INSTALL) $(LIB_FULLNAME) $(INSTALL_LIBDIR)
+ifdef inUnix
+	ln -sf $(LIB_FULLNAME) $(INSTALL_LIBDIR)/$(LIB_NAME)
+endif
+endif
+endif
+ifdef INSTALL_FILES
+	$(MKDIR) $(INSTALL_DATADIR)
+	$(INSTALL) $(INSTALL_FILES) $(INSTALL_DATADIR)
+endif
+fpc_sourceinstall: distclean
+	$(MKDIR) $(INSTALL_SOURCEDIR)
+	$(COPYTREE) $(BASEDIR)/* $(INSTALL_SOURCEDIR)
+fpc_exampleinstall: $(EXAMPLEINSTALLTARGET) $(addsuffix _distclean,$(TARGET_EXAMPLEDIRS))
+ifdef HASEXAMPLES
+	$(MKDIR) $(INSTALL_EXAMPLEDIR)
+endif
+ifdef EXAMPLESOURCEFILES
+	$(COPY) $(EXAMPLESOURCEFILES) $(INSTALL_EXAMPLEDIR)
+endif
+ifdef TARGET_EXAMPLEDIRS
+	$(COPYTREE) $(addsuffix /*,$(TARGET_EXAMPLEDIRS)) $(INSTALL_EXAMPLEDIR)
+endif
+.PHONY: fpc_distinstall
+fpc_distinstall: install exampleinstall
+.PHONY: fpc_zipinstall fpc_zipsourceinstall fpc_zipexampleinstall
+ifndef PACKDIR
+ifndef inUnix
+PACKDIR=$(BASEDIR)/../fpc-pack
+else
+PACKDIR=/tmp/fpc-pack
+endif
+endif
+ifndef ZIPNAME
+ifdef DIST_ZIPNAME
+ZIPNAME=$(DIST_ZIPNAME)
+else
+ZIPNAME=$(PACKAGE_NAME)
+endif
+endif
+ifndef FULLZIPNAME
+FULLZIPNAME=$(ZIPCROSSPREFIX)$(ZIPPREFIX)$(ZIPNAME)$(ZIPSUFFIX)
+endif
+ifndef ZIPTARGET
+ifdef DIST_ZIPTARGET
+ZIPTARGET=DIST_ZIPTARGET
+else
+ZIPTARGET=install
+endif
+endif
+ifndef USEZIP
+ifdef inUnix
+USETAR=1
+endif
+endif
+ifndef inUnix
+USEZIPWRAPPER=1
+endif
+ifdef USEZIPWRAPPER
+ZIPPATHSEP=$(PATHSEP)
+ZIPWRAPPER=$(subst /,$(PATHSEP),$(DIST_DESTDIR)/fpczip$(SRCBATCHEXT))
+else
+ZIPPATHSEP=/
+endif
+ZIPCMD_CDPACK:=cd $(subst /,$(ZIPPATHSEP),$(PACKDIR))
+ZIPCMD_CDBASE:=cd $(subst /,$(ZIPPATHSEP),$(BASEDIR))
+ifdef USETAR
+ZIPDESTFILE:=$(DIST_DESTDIR)/$(FULLZIPNAME)$(TAREXT)
+ZIPCMD_ZIP:=$(TARPROG) c$(TAROPT)f $(ZIPDESTFILE) *
+else
+ZIPDESTFILE:=$(DIST_DESTDIR)/$(FULLZIPNAME)$(ZIPEXT)
+ZIPCMD_ZIP:=$(subst /,$(ZIPPATHSEP),$(ZIPPROG)) -Dr $(ZIPOPT) $(ZIPDESTFILE) *
+endif
+fpc_zipinstall:
+	$(MAKE) $(ZIPTARGET) INSTALL_PREFIX=$(PACKDIR) ZIPINSTALL=1
+	$(MKDIR) $(DIST_DESTDIR)
+	$(DEL) $(ZIPDESTFILE)
+ifdef USEZIPWRAPPER
+ifneq ($(ECHOREDIR),echo)
+	$(ECHOREDIR) -e "$(subst \,\\,$(ZIPCMD_CDPACK))" > $(ZIPWRAPPER)
+	$(ECHOREDIR) -e "$(subst \,\\,$(ZIPCMD_ZIP))" >> $(ZIPWRAPPER)
+	$(ECHOREDIR) -e "$(subst \,\\,$(ZIPCMD_CDBASE))" >> $(ZIPWRAPPER)
+else
+	echo $(ZIPCMD_CDPACK) > $(ZIPWRAPPER)
+	echo $(ZIPCMD_ZIP) >> $(ZIPWRAPPER)
+	echo $(ZIPCMD_CDBASE) >> $(ZIPWRAPPER)
+endif
+ifdef inUnix
+	/bin/sh $(ZIPWRAPPER)
+else
+ifdef RUNBATCH
+	$(RUNBATCH) $(ZIPWRAPPER)
+else
+	$(ZIPWRAPPER)
+endif
+endif
+	$(DEL) $(ZIPWRAPPER)
+else
+	$(ZIPCMD_CDPACK) ; $(ZIPCMD_ZIP) ; $(ZIPCMD_CDBASE)
+endif
+	$(DELTREE) $(PACKDIR)
+fpc_zipsourceinstall:
+	$(MAKE) fpc_zipinstall ZIPTARGET=sourceinstall ZIPSUFFIX=$(ZIPSOURCESUFFIX)
+fpc_zipexampleinstall:
+ifdef HASEXAMPLES
+	$(MAKE) fpc_zipinstall ZIPTARGET=exampleinstall ZIPSUFFIX=$(ZIPEXAMPLESUFFIX)
+endif
+fpc_zipdistinstall:
+	$(MAKE) fpc_zipinstall ZIPTARGET=distinstall
+.PHONY: fpc_clean fpc_cleanall fpc_distclean
+ifdef EXEFILES
+override CLEANEXEFILES:=$(addprefix $(TARGETDIRPREFIX),$(CLEANEXEFILES))
+override CLEANEXEDBGFILES:=$(addprefix $(TARGETDIRPREFIX),$(CLEANEXEDBGFILES))
+endif
+ifdef CLEAN_PROGRAMS
+override CLEANEXEFILES+=$(addprefix $(TARGETDIRPREFIX),$(addsuffix $(EXEEXT), $(CLEAN_PROGRAMS)))
+override CLEANEXEDBGFILES+=$(addprefix $(TARGETDIRPREFIX),$(addsuffix $(EXEDBGEXT), $(CLEAN_PROGRAMS)))
+endif
+ifdef CLEAN_UNITS
+override CLEANPPUFILES+=$(addsuffix $(PPUEXT),$(CLEAN_UNITS))
+endif
+ifdef CLEANPPUFILES
+override CLEANPPULINKFILES:=$(subst $(PPUEXT),$(OEXT),$(CLEANPPUFILES)) $(subst $(PPUEXT),$(LTOEXT),$(CLEANPPUFILES)) $(addprefix $(STATICLIBPREFIX),$(subst $(PPUEXT),$(STATICLIBEXT),$(CLEANPPUFILES))) $(addprefix $(IMPORTLIBPREFIX),$(subst $(PPUEXT),$(STATICLIBEXT),$(CLEANPPUFILES)))
+ifdef DEBUGSYMEXT
+override CLEANPPULINKFILES+=$(subst $(PPUEXT),$(DEBUGSYMEXT),$(CLEANPPUFILES))
+endif
+override CLEANPPUFILENAMES:=$(CLEANPPUFILES)
+override CLEANPPUFILES=$(addprefix $(UNITTARGETDIRPREFIX),$(CLEANPPUFILENAMES))
+override CLEANPPULINKFILENAMES:=$(CLEANPPULINKFILES)
+override CLEANPPULINKFILES=$(wildcard $(addprefix $(UNITTARGETDIRPREFIX),$(CLEANPPULINKFILENAMES)))
+endif
+fpc_clean: $(CLEANTARGET)
+ifdef CLEANEXEFILES
+	-$(DEL) $(CLEANEXEFILES)
+endif
+ifdef CLEANEXEDBGFILES
+	-$(DELTREE) $(CLEANEXEDBGFILES)
+endif
+ifdef CLEANPPUFILES
+	-$(DEL) $(CLEANPPUFILES)
+endif
+ifneq ($(CLEANPPULINKFILES),)
+	-$(DEL) $(CLEANPPULINKFILES)
+endif
+ifdef CLEANRSTFILES
+	-$(DEL) $(addprefix $(UNITTARGETDIRPREFIX),$(CLEANRSTFILES))
+endif
+ifdef CLEAN_FILES
+	-$(DEL) $(CLEAN_FILES)
+endif
+ifdef LIB_NAME
+	-$(DEL) $(LIB_NAME) $(LIB_FULLNAME)
+endif
+	-$(DEL) $(FPCMADE) *$(FULL_TARGET).fpm Package.fpc *$(ASMEXT)
+	-$(DEL) $(FPCEXTFILE) $(REDIRFILE) script*.res link*.res *_script.res *_link.res
+	-$(DEL) $(PPAS) *_ppas$(BATCHEXT) ppas$(BATCHEXT) ppaslink$(BATCHEXT)
+fpc_cleanall: $(CLEANTARGET)
+ifdef CLEANEXEFILES
+	-$(DEL) $(CLEANEXEFILES)
+endif
+ifdef COMPILER_UNITTARGETDIR
+ifdef CLEANPPUFILES
+	-$(DEL) $(CLEANPPUFILES)
+endif
+ifneq ($(CLEANPPULINKFILES),)
+	-$(DEL) $(CLEANPPULINKFILES)
+endif
+ifdef CLEANRSTFILES
+	-$(DEL) $(addprefix $(UNITTARGETDIRPREFIX),$(CLEANRSTFILES))
+endif
+endif
+ifdef CLEAN_FILES
+	-$(DEL) $(CLEAN_FILES)
+endif
+	-$(DELTREE) units
+	-$(DELTREE) bin
+	-$(DEL) *$(OEXT) *$(LTOEXT) *$(PPUEXT) *$(RSTEXT) *$(ASMEXT) *$(STATICLIBEXT) *$(SHAREDLIBEXT) *$(PPLEXT)
+ifneq ($(PPUEXT),.ppu)
+	-$(DEL) *.o *.ppu *.a
+endif
+	-$(DELTREE) *$(SMARTEXT)
+	-$(DEL) fpcmade.* Package.fpc *.fpm
+	-$(DEL) $(FPCEXTFILE) $(REDIRFILE) script*.res link*.res *_script.res *_link.res
+	-$(DEL) $(PPAS) *_ppas$(BATCHEXT) ppas$(BATCHEXT) ppaslink$(BATCHEXT)
+ifdef AOUTEXT
+	-$(DEL) *$(AOUTEXT)
+endif
+ifdef DEBUGSYMEXT
+	-$(DEL) *$(DEBUGSYMEXT)
+endif
+ifdef LOCALFPMAKEBIN
+	-$(DEL) $(LOCALFPMAKEBIN)
+	-$(DEL) $(FPMAKEBINOBJ)
+endif
+fpc_distclean: cleanall
+.PHONY: fpc_baseinfo
+override INFORULES+=fpc_baseinfo
+fpc_baseinfo:
+	@$(ECHO)
+	@$(ECHO)  == Package info ==
+	@$(ECHO)  Package Name..... $(PACKAGE_NAME)
+	@$(ECHO)  Package Version.. $(PACKAGE_VERSION)
+	@$(ECHO)
+	@$(ECHO)  == Configuration info ==
+	@$(ECHO)
+	@$(ECHO)  FPC.......... $(FPC)
+	@$(ECHO)  FPC Version.. $(FPC_VERSION)
+	@$(ECHO)  Source CPU... $(CPU_SOURCE)
+	@$(ECHO)  Target CPU... $(CPU_TARGET)
+	@$(ECHO)  Source OS.... $(OS_SOURCE)
+	@$(ECHO)  Target OS.... $(OS_TARGET)
+	@$(ECHO)  Full Source.. $(FULL_SOURCE)
+	@$(ECHO)  Full Target.. $(FULL_TARGET)
+	@$(ECHO)  SourceSuffix. $(SOURCESUFFIX)
+	@$(ECHO)  TargetSuffix. $(TARGETSUFFIX)
+	@$(ECHO)  FPC fpmake... $(FPCFPMAKE)
+	@$(ECHO)
+	@$(ECHO)  == Directory info ==
+	@$(ECHO)
+	@$(ECHO)  Required pkgs... $(REQUIRE_PACKAGES)
+	@$(ECHO)
+	@$(ECHO)  Basedir......... $(BASEDIR)
+	@$(ECHO)  FPCDir.......... $(FPCDIR)
+	@$(ECHO)  CrossBinDir..... $(CROSSBINDIR)
+	@$(ECHO)  UnitsDir........ $(UNITSDIR)
+	@$(ECHO)  PackagesDir..... $(PACKAGESDIR)
+	@$(ECHO)
+	@$(ECHO)  GCC library..... $(GCCLIBDIR)
+	@$(ECHO)  Other library... $(OTHERLIBDIR)
+	@$(ECHO)
+	@$(ECHO)  == Tools info ==
+	@$(ECHO)
+	@$(ECHO)  As........ $(AS)
+	@$(ECHO)  Ld........ $(LD)
+	@$(ECHO)  Ar........ $(AR)
+	@$(ECHO)  Rc........ $(RC)
+	@$(ECHO)
+	@$(ECHO)  Mv........ $(MVPROG)
+	@$(ECHO)  Cp........ $(CPPROG)
+	@$(ECHO)  Rm........ $(RMPROG)
+	@$(ECHO)  GInstall.. $(GINSTALL)
+	@$(ECHO)  Echo...... $(ECHO)
+	@$(ECHO)  Shell..... $(SHELL)
+	@$(ECHO)  Date...... $(DATE)
+	@$(ECHO)  FPCMake... $(FPCMAKE)
+	@$(ECHO)  PPUMove... $(PPUMOVE)
+	@$(ECHO)  Zip....... $(ZIPPROG)
+	@$(ECHO)
+	@$(ECHO)  == Object info ==
+	@$(ECHO)
+	@$(ECHO)  Target Loaders........ $(TARGET_LOADERS)
+	@$(ECHO)  Target Units.......... $(TARGET_UNITS)
+	@$(ECHO)  Target Implicit Units. $(TARGET_IMPLICITUNITS)
+	@$(ECHO)  Target Programs....... $(TARGET_PROGRAMS)
+	@$(ECHO)  Target Dirs........... $(TARGET_DIRS)
+	@$(ECHO)  Target Examples....... $(TARGET_EXAMPLES)
+	@$(ECHO)  Target ExampleDirs.... $(TARGET_EXAMPLEDIRS)
+	@$(ECHO)
+	@$(ECHO)  Clean Units......... $(CLEAN_UNITS)
+	@$(ECHO)  Clean Files......... $(CLEAN_FILES)
+	@$(ECHO)
+	@$(ECHO)  Install Units....... $(INSTALL_UNITS)
+	@$(ECHO)  Install Files....... $(INSTALL_FILES)
+	@$(ECHO)
+	@$(ECHO)  == Install info ==
+	@$(ECHO)
+	@$(ECHO)  DateStr.............. $(DATESTR)
+	@$(ECHO)  ZipName.............. $(ZIPNAME)
+	@$(ECHO)  ZipPrefix............ $(ZIPPREFIX)
+	@$(ECHO)  ZipCrossPrefix....... $(ZIPCROSSPREFIX)
+	@$(ECHO)  ZipSuffix............ $(ZIPSUFFIX)
+	@$(ECHO)  FullZipName.......... $(FULLZIPNAME)
+	@$(ECHO)  Install FPC Package.. $(INSTALL_FPCPACKAGE)
+	@$(ECHO)
+	@$(ECHO)  Install base dir..... $(INSTALL_BASEDIR)
+	@$(ECHO)  Install binary dir... $(INSTALL_BINDIR)
+	@$(ECHO)  Install library dir.. $(INSTALL_LIBDIR)
+	@$(ECHO)  Install units dir.... $(INSTALL_UNITDIR)
+	@$(ECHO)  Install source dir... $(INSTALL_SOURCEDIR)
+	@$(ECHO)  Install doc dir...... $(INSTALL_DOCDIR)
+	@$(ECHO)  Install example dir.. $(INSTALL_EXAMPLEDIR)
+	@$(ECHO)  Install data dir..... $(INSTALL_DATADIR)
+	@$(ECHO)
+	@$(ECHO)  Dist destination dir. $(DIST_DESTDIR)
+	@$(ECHO)  Dist zip name........ $(DIST_ZIPNAME)
+	@$(ECHO)
+.PHONY: fpc_info
+fpc_info: $(INFORULES)
+.PHONY: fpc_makefile fpc_makefiles fpc_makefile_sub1 fpc_makefile_sub2 \
+	fpc_makefile_dirs
+fpc_makefile:
+	$(FPCMAKE) -w -T$(OS_TARGET) Makefile.fpc
+fpc_makefile_sub1:
+ifdef TARGET_DIRS
+	$(FPCMAKE) -w -T$(OS_TARGET) $(addsuffix /Makefile.fpc,$(TARGET_DIRS))
+endif
+ifdef TARGET_EXAMPLEDIRS
+	$(FPCMAKE) -w -T$(OS_TARGET) $(addsuffix /Makefile.fpc,$(TARGET_EXAMPLEDIRS))
+endif
+fpc_makefile_sub2: $(addsuffix _makefile_dirs,$(TARGET_DIRS) $(TARGET_EXAMPLEDIRS))
+fpc_makefile_dirs: fpc_makefile_sub1 fpc_makefile_sub2
+fpc_makefiles: fpc_makefile fpc_makefile_dirs
+units:
+examples:
+shared:
+sourceinstall: fpc_sourceinstall
+exampleinstall: fpc_exampleinstall
+zipexampleinstall: fpc_zipexampleinstall
+info: fpc_info
+makefiles: fpc_makefiles
+.PHONY: units examples shared sourceinstall exampleinstall zipexampleinstall info makefiles
+ifneq ($(wildcard fpcmake.loc),)
+include fpcmake.loc
+endif
+override FPCOPT:=$(filter-out -FU%,$(FPCOPT))
+override FPCOPT:=$(filter-out -FE%,$(FPCOPT))
+override FPCOPT:=$(filter-out $(addprefix -Fu,$(COMPILER_UNITDIR)),$(FPCOPT))# Compose general fpmake-parameters
+ifdef FPMAKEOPT
+FPMAKE_OPT+=$(FPMAKEOPT)
+endif
+FPMAKE_OPT+=--localunitdir=../..
+FPMAKE_OPT+=--globalunitdir=..
+FPMAKE_OPT+=$(FPC_TARGETOPT)
+FPMAKE_OPT+=$(addprefix -o ,$(FPCOPT))
+FPMAKE_OPT+=--compiler=$(FPC)
+FPMAKE_OPT+=-bu
+.NOTPARALLEL:
+fpmake$(SRCEXEEXT): fpmake.pp
+	$(FPCFPMAKE) fpmake.pp $(FPMAKE_SKIP_CONFIG) $(addprefix -Fu,$(COMPILER_FPMAKE_UNITDIR)) $(FPCMAKEOPT) $(OPT)
+all:	fpmake$(SRCEXEEXT)
+	$(LOCALFPMAKE) compile $(FPMAKE_OPT)
+smart:	fpmake$(SRCEXEEXT)
+	$(LOCALFPMAKE) compile $(FPMAKE_OPT) -o -XX -o -CX
+release:	fpmake$(SRCEXEEXT)
+	$(LOCALFPMAKE) compile $(FPMAKE_OPT) -o -dRELEASE
+debug:	fpmake$(SRCEXEEXT)
+	$(LOCALFPMAKE) compile $(FPMAKE_OPT) -o -dDEBUG
+ifeq ($(FPMAKE_BIN_CLEAN),)
+clean:
+else
+clean:
+	$(FPMAKE_BIN_CLEAN) clean $(FPMAKE_OPT)
+endif
+ifeq ($(FPMAKE_BIN_CLEAN),)
+distclean:	$(addsuffix _distclean,$(TARGET_DIRS)) fpc_cleanall
+else
+distclean:
+ifdef inUnix
+	{ $(FPMAKE_BIN_CLEAN) distclean $(FPMAKE_OPT); if [ $$? != "0" ]; then { echo Something wrong with fpmake exectable. Remove the executable and call make recursively to recover.; $(DEL) $(FPMAKE_BIN_CLEAN); $(MAKE) fpc_cleanall; }; fi;  }
+else
+	$(FPMAKE_BIN_CLEAN) distclean $(FPMAKE_OPT)
+endif
+	-$(DEL) $(LOCALFPMAKE)
+endif
+cleanall: distclean
+install:	fpmake$(SRCEXEEXT)
+ifdef UNIXHier
+	$(LOCALFPMAKE) install $(FPMAKE_OPT) --prefix=$(INSTALL_PREFIX) --baseinstalldir=$(INSTALL_LIBDIR)/fpc/$(FPC_VERSION) --unitinstalldir=$(INSTALL_UNITDIR)
+else
+	$(LOCALFPMAKE) install $(FPMAKE_OPT) --prefix=$(INSTALL_BASEDIR) --baseinstalldir=$(INSTALL_BASEDIR) --unitinstalldir=$(INSTALL_UNITDIR)
+endif
+distinstall:	fpmake$(SRCEXEEXT)
+ifdef UNIXHier
+	$(LOCALFPMAKE) install $(FPMAKE_OPT) --prefix=$(INSTALL_PREFIX) --baseinstalldir=$(INSTALL_LIBDIR)/fpc/$(FPC_VERSION) --unitinstalldir=$(INSTALL_UNITDIR) -ie -fsp 0
+else
+	$(LOCALFPMAKE) install $(FPMAKE_OPT) --prefix=$(INSTALL_BASEDIR) --baseinstalldir=$(INSTALL_BASEDIR) --unitinstalldir=$(INSTALL_UNITDIR) -ie -fsp 0
+endif
+zipinstall:	fpmake$(SRCEXEEXT)
+	$(LOCALFPMAKE) zipinstall $(FPMAKE_OPT) --zipprefix=$(DIST_DESTDIR)/$(ZIPPREFIX)
+zipdistinstall:	fpmake$(SRCEXEEXT)
+	$(LOCALFPMAKE) zipinstall $(FPMAKE_OPT) --zipprefix=$(DIST_DESTDIR)/$(ZIPPREFIX) -ie -fsp 0
+zipsourceinstall:	fpmake$(SRCEXEEXT)
+ifdef UNIXHier
+	$(LOCALFPMAKE) archive $(FPMAKE_OPT) --zipprefix=$(DIST_DESTDIR)/$(ZIPPREFIX) --prefix=share/src/fpc-\$$\(PACKAGEVERSION\)/$(INSTALL_FPCSUBDIR)/\$$\(PACKAGEDIRECTORY\)
+else
+	$(LOCALFPMAKE) archive $(FPMAKE_OPT) --zipprefix=$(DIST_DESTDIR)/$(ZIPPREFIX) --prefix=source\\$(INSTALL_FPCSUBDIR)\\\$$\(PACKAGEDIRECTORY\)
+endif

+ 128 - 0
packages/fcl-mustache/Makefile.fpc

@@ -0,0 +1,128 @@
+#
+#   Makefile.fpc for running fpmake
+#
+
+[package]
+name=fcl-mustache
+version=3.3.1
+
+[require]
+packages=rtl fcl-base fcl-db fcl-json
+
+[install]
+fpcpackage=y
+
+[default]
+fpcdir=../..
+
+[prerules]
+FPMAKE_BIN_CLEAN=$(wildcard ./fpmake$(SRCEXEEXT))
+ifdef OS_TARGET
+FPC_TARGETOPT+=--os=$(OS_TARGET)
+endif
+ifdef CPU_TARGET
+FPC_TARGETOPT+=--cpu=$(CPU_TARGET)
+endif
+LOCALFPMAKE=./fpmake$(SRCEXEEXT)
+# Adding a dependency on fpmkunit is not possbile due to an infinite loop. So
+# the fpmkunit-searchpath is added here:
+PACKAGEDIR_FPMKUNIT:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /fpmkunit/Makefile.fpc,$(PACKAGESDIR))))))
+ifneq ($(PACKAGEDIR_FPMKUNIT),)
+ifneq ($(wildcard $(PACKAGEDIR_FPMKUNIT)/units_bs/$(SOURCESUFFIX)),)
+UNITDIR_FPMAKE_FPMKUNIT=$(PACKAGEDIR_FPMKUNIT)/units_bs/$(SOURCESUFFIX)
+else
+UNITDIR_FPMAKE_FPMKUNIT=$(PACKAGEDIR_FPMKUNIT)
+endif
+ifdef CHECKDEPEND
+$(PACKAGEDIR_FPMKUNIT)/$(FPCMADE):
+        $(MAKE) -C $(PACKAGEDIR_FPMKUNIT) $(FPCMADE)
+override ALLDEPENDENCIES+=$(PACKAGEDIR_FPMKUNIT)/$(FPCMADE)
+endif
+else
+PACKAGEDIR_FPMKUNIT=
+UNITDIR_FPMKUNIT:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /fpmkunit/Package.fpc,$(UNITSDIR)))))
+ifneq ($(UNITDIR_FPMKUNIT),)
+UNITDIR_FPMKUNIT:=$(firstword $(UNITDIR_FPMKUNIT))
+else
+UNITDIR_FPMKUNIT=
+endif
+endif
+ifdef UNITDIR_FPMAKE_FPMKUNIT
+override COMPILER_FPMAKE_UNITDIR+=$(UNITDIR_FPMAKE_FPMKUNIT)
+endif
+
+[rules]
+# Do not pass the Makefile's unit and binary target locations. Fpmake uses it's own.
+override FPCOPT:=$(filter-out -FU%,$(FPCOPT))
+override FPCOPT:=$(filter-out -FE%,$(FPCOPT))
+# Do not pass the package-unitdirectories. Fpmake adds those and this way they don't apear in the .fpm
+override FPCOPT:=$(filter-out $(addprefix -Fu,$(COMPILER_UNITDIR)),$(FPCOPT))# Compose general fpmake-parameters
+# Compose general fpmake-parameters
+ifdef FPMAKEOPT
+FPMAKE_OPT+=$(FPMAKEOPT)
+endif
+FPMAKE_OPT+=--localunitdir=../..
+FPMAKE_OPT+=--globalunitdir=..
+FPMAKE_OPT+=$(FPC_TARGETOPT)
+FPMAKE_OPT+=$(addprefix -o ,$(FPCOPT))
+FPMAKE_OPT+=--compiler=$(FPC)
+FPMAKE_OPT+=-bu
+.NOTPARALLEL:
+
+fpmake$(SRCEXEEXT): fpmake.pp
+	$(FPCFPMAKE) fpmake.pp $(FPMAKE_SKIP_CONFIG) $(addprefix -Fu,$(COMPILER_FPMAKE_UNITDIR)) $(FPCMAKEOPT) $(OPT)
+all:	fpmake$(SRCEXEEXT)
+	$(LOCALFPMAKE) compile $(FPMAKE_OPT)
+smart:	fpmake$(SRCEXEEXT)
+	$(LOCALFPMAKE) compile $(FPMAKE_OPT) -o -XX -o -CX
+release:	fpmake$(SRCEXEEXT)
+	$(LOCALFPMAKE) compile $(FPMAKE_OPT) -o -dRELEASE
+debug:	fpmake$(SRCEXEEXT)
+	$(LOCALFPMAKE) compile $(FPMAKE_OPT) -o -dDEBUG
+# If no fpmake exists and (dist)clean is called, do not try to build fpmake, it will
+# most often fail because the dependencies are cleared.
+# In case of a clean, simply do nothing
+ifeq ($(FPMAKE_BIN_CLEAN),)
+clean:
+else
+clean:
+	$(FPMAKE_BIN_CLEAN) clean $(FPMAKE_OPT)
+endif
+# In case of a distclean, perform an 'old'-style distclean. This to avoid problems
+# when the package is compiled using fpcmake prior to running this clean using fpmake
+ifeq ($(FPMAKE_BIN_CLEAN),)
+distclean:	$(addsuffix _distclean,$(TARGET_DIRS)) fpc_cleanall
+else
+distclean:
+ifdef inUnix
+        { $(FPMAKE_BIN_CLEAN) distclean $(FPMAKE_OPT); if [ $$? != "0" ]; then { echo Something wrong with fpmake exectable. Remove the executable and call make recursively to recover.; $(DEL) $(FPMAKE_BIN_CLEAN); $(MAKE) fpc_cleanall; }; fi;  }
+else
+        $(FPMAKE_BIN_CLEAN) distclean $(FPMAKE_OPT)
+endif
+	-$(DEL) $(LOCALFPMAKE)
+endif
+cleanall: distclean
+install:	fpmake$(SRCEXEEXT)
+ifdef UNIXHier
+	$(LOCALFPMAKE) install $(FPMAKE_OPT) --prefix=$(INSTALL_PREFIX) --baseinstalldir=$(INSTALL_LIBDIR)/fpc/$(FPC_VERSION) --unitinstalldir=$(INSTALL_UNITDIR)
+else
+	$(LOCALFPMAKE) install $(FPMAKE_OPT) --prefix=$(INSTALL_BASEDIR) --baseinstalldir=$(INSTALL_BASEDIR) --unitinstalldir=$(INSTALL_UNITDIR)
+endif
+# distinstall also installs the example-sources and omits the location of the source-
+# files from the fpunits.cfg files.
+distinstall:	fpmake$(SRCEXEEXT)
+ifdef UNIXHier
+	$(LOCALFPMAKE) install $(FPMAKE_OPT) --prefix=$(INSTALL_PREFIX) --baseinstalldir=$(INSTALL_LIBDIR)/fpc/$(FPC_VERSION) --unitinstalldir=$(INSTALL_UNITDIR) -ie -fsp 0
+else
+	$(LOCALFPMAKE) install $(FPMAKE_OPT) --prefix=$(INSTALL_BASEDIR) --baseinstalldir=$(INSTALL_BASEDIR) --unitinstalldir=$(INSTALL_UNITDIR) -ie -fsp 0
+endif
+zipinstall:	fpmake$(SRCEXEEXT)
+	$(LOCALFPMAKE) zipinstall $(FPMAKE_OPT) --zipprefix=$(DIST_DESTDIR)/$(ZIPPREFIX)
+zipdistinstall:	fpmake$(SRCEXEEXT)
+	$(LOCALFPMAKE) zipinstall $(FPMAKE_OPT) --zipprefix=$(DIST_DESTDIR)/$(ZIPPREFIX) -ie -fsp 0
+zipsourceinstall:	fpmake$(SRCEXEEXT)
+ifdef UNIXHier
+	$(LOCALFPMAKE) archive $(FPMAKE_OPT) --zipprefix=$(DIST_DESTDIR)/$(ZIPPREFIX) --prefix=share/src/fpc-\$$\(PACKAGEVERSION\)/$(INSTALL_FPCSUBDIR)/\$$\(PACKAGEDIRECTORY\)
+else
+	$(LOCALFPMAKE) archive $(FPMAKE_OPT) --zipprefix=$(DIST_DESTDIR)/$(ZIPPREFIX) --prefix=source\\$(INSTALL_FPCSUBDIR)\\\$$\(PACKAGEDIRECTORY\)
+endif

+ 27 - 0
packages/fcl-mustache/examples/README.txt

@@ -0,0 +1,27 @@
+demo1 sample program:
+
+Demonstrates the most basic use of the mustache parser
+
+demo2 sample program:
+
+Demonstrates the use of the mustache parser with a CSV dataset
+
+
+mustache example program:
+
+Can be used to load a template and data, and process the result.
+Output to standard output or file.
+The template and JSON value can be loaded from file (using @filename), 
+or their value can be specified directly on the command-line.
+
+Example usage:
+
+Load template from family.tmpl file, data from family.json file:
+
+./mustache -d title="my family" -t @family.tmpl -j @family.json
+
+Load template from family.tmpl file, data from family.csv file:
+
+./mustache -d title="my family" -t @family.tmpl -c family.csv
+
+Use of expressions can be enabled with the -e switch.

+ 57 - 0
packages/fcl-mustache/examples/demo1.lpi

@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CONFIG>
+  <ProjectOptions>
+    <Version Value="12"/>
+    <General>
+      <Flags>
+        <MainUnitHasCreateFormStatements Value="False"/>
+        <MainUnitHasTitleStatement Value="False"/>
+        <MainUnitHasScaledStatement Value="False"/>
+      </Flags>
+      <SessionStorage Value="InProjectDir"/>
+      <Title Value="demo1"/>
+      <UseAppBundle Value="False"/>
+      <ResourceType Value="res"/>
+    </General>
+    <BuildModes>
+      <Item Name="Default" Default="True"/>
+    </BuildModes>
+    <PublishOptions>
+      <Version Value="2"/>
+      <UseFileFilters Value="True"/>
+    </PublishOptions>
+    <RunParams>
+      <FormatVersion Value="2"/>
+    </RunParams>
+    <Units>
+      <Unit>
+        <Filename Value="demo1.lpr"/>
+        <IsPartOfProject Value="True"/>
+      </Unit>
+    </Units>
+  </ProjectOptions>
+  <CompilerOptions>
+    <Version Value="11"/>
+    <Target>
+      <Filename Value="demo1"/>
+    </Target>
+    <SearchPaths>
+      <IncludeFiles Value="$(ProjOutDir)"/>
+      <OtherUnitFiles Value="../src"/>
+      <UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/>
+    </SearchPaths>
+  </CompilerOptions>
+  <Debugging>
+    <Exceptions>
+      <Item>
+        <Name Value="EAbort"/>
+      </Item>
+      <Item>
+        <Name Value="ECodetoolError"/>
+      </Item>
+      <Item>
+        <Name Value="EFOpenError"/>
+      </Item>
+    </Exceptions>
+  </Debugging>
+</CONFIG>

+ 42 - 0
packages/fcl-mustache/examples/demo1.lpr

@@ -0,0 +1,42 @@
+{ Demo for mustache engine with JSON context
+
+  Copyright (C) 2021 michael Van Canneyt [email protected]
+
+  This source is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
+
+  This code 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.  See the GNU General Public License for more details.
+
+  A copy of the GNU General Public License is available on the World Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can
+  also obtain it by writing to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1335, USA.
+}
+program demo1;
+
+// jsonparser includes the json parser.
+
+uses jsonparser, fpmustache;
+
+Const
+  JSON = '{ "products" : [ {"name" : "BMW" }, {"name" : "Mercedes"}, { "name" : "Audi" }] }';
+
+  // Mock markdown table
+  Template =
+     '| name |'+sLineBreak+
+     '|------|'+sLineBreak+
+     '{{#products}}| {{name}} |'+sLineBreak+
+     '{{/products}}';
+
+Var
+  M : TMustache;
+
+begin
+  M:=TMustache.Create(Nil);
+  try
+   // Json support enabled by default
+   Writeln(M.Render(Template,JSON));
+  finally
+    M.Free;
+  end;
+end.
+

+ 57 - 0
packages/fcl-mustache/examples/demo2.lpi

@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CONFIG>
+  <ProjectOptions>
+    <Version Value="12"/>
+    <General>
+      <Flags>
+        <MainUnitHasCreateFormStatements Value="False"/>
+        <MainUnitHasTitleStatement Value="False"/>
+        <MainUnitHasScaledStatement Value="False"/>
+      </Flags>
+      <SessionStorage Value="InProjectDir"/>
+      <Title Value="demo2"/>
+      <UseAppBundle Value="False"/>
+      <ResourceType Value="res"/>
+    </General>
+    <BuildModes>
+      <Item Name="Default" Default="True"/>
+    </BuildModes>
+    <PublishOptions>
+      <Version Value="2"/>
+      <UseFileFilters Value="True"/>
+    </PublishOptions>
+    <RunParams>
+      <FormatVersion Value="2"/>
+    </RunParams>
+    <Units>
+      <Unit>
+        <Filename Value="demo2.lpr"/>
+        <IsPartOfProject Value="True"/>
+      </Unit>
+    </Units>
+  </ProjectOptions>
+  <CompilerOptions>
+    <Version Value="11"/>
+    <Target>
+      <Filename Value="demo2"/>
+    </Target>
+    <SearchPaths>
+      <IncludeFiles Value="$(ProjOutDir)"/>
+      <OtherUnitFiles Value="../src"/>
+      <UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/>
+    </SearchPaths>
+  </CompilerOptions>
+  <Debugging>
+    <Exceptions>
+      <Item>
+        <Name Value="EAbort"/>
+      </Item>
+      <Item>
+        <Name Value="ECodetoolError"/>
+      </Item>
+      <Item>
+        <Name Value="EFOpenError"/>
+      </Item>
+    </Exceptions>
+  </Debugging>
+</CONFIG>

+ 48 - 0
packages/fcl-mustache/examples/demo2.lpr

@@ -0,0 +1,48 @@
+{ Demo for mustache engine with database context
+
+  Copyright (C) 2021 michael Van Canneyt [email protected]
+
+  This source is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
+
+  This code 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.  See the GNU General Public License for more details.
+
+  A copy of the GNU General Public License is available on the World Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can
+  also obtain it by writing to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1335, USA.
+}
+
+program demo2;
+
+uses csvdataset, fpmustache, fpdbmustache;
+
+Const
+  // Mock markdown table
+  Template =
+     '| name | age | '+sLineBreak+
+     '|------|------|'+sLineBreak+
+     '{{#family}}| {{name}} | {{age}} |'+sLineBreak+
+     '{{/family}}';
+
+Var
+  M : TMustache;
+  C : TMustacheDBContext;
+  D : TCSVDataset;
+
+begin
+  M:=TMustache.Create(Nil);
+  try
+    D:=TCSVDataset.Create(Nil);
+    D.CSVOptions.FirstLineAsFieldNames:=True;
+    D.LoadFromFile('family.csv');
+    C:=TMustacheDBContext.Create(Nil);
+    C.AddDataset(D,'family');
+    M.Template:=Template;
+    Writeln(M.Render(C));
+  finally
+    M.Free;
+    D.Free;
+    C.Free;
+  end;
+end.
+

+ 7 - 0
packages/fcl-mustache/examples/family.csv

@@ -0,0 +1,7 @@
+name,age
+Father,30
+Mother,29
+Grandfather,62
+GrandMother,61
+Child 1,2
+Child 2,4

+ 10 - 0
packages/fcl-mustache/examples/family.json

@@ -0,0 +1,10 @@
+{
+  "data" : [
+   { "name" : "Father", "age": 30 },
+   { "name" : "Mother", "age": 29 },
+   { "name" : "Grandfather", "age": 62 },
+   { "name" : "GrandMother", "age": 61 },
+   { "name" : "Child 1", "age": 2 },
+   { "name" : "Child 2", "age": 4 }
+  ]
+}

+ 22 - 0
packages/fcl-mustache/examples/family.tmpl

@@ -0,0 +1,22 @@
+<html>
+  <head>
+    <title>{{title}}</title>
+  </head>
+    <body>
+      <h1>Family members</h1>
+      <table>
+        <thead>
+          <tr>
+            <th>Name</th><th>Age</th>
+          </tr>
+        </thead>
+        <tbody>
+{{#data}}
+        <tr>  
+          <td>{{name}}</td><td>{{age}}</td>
+        </tr> 
+{{/data}}
+        </tbody>
+      </table>
+    </body>
+</html>

+ 57 - 0
packages/fcl-mustache/examples/mustache.lpi

@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CONFIG>
+  <ProjectOptions>
+    <Version Value="12"/>
+    <General>
+      <Flags>
+        <MainUnitHasCreateFormStatements Value="False"/>
+        <MainUnitHasTitleStatement Value="False"/>
+        <MainUnitHasScaledStatement Value="False"/>
+      </Flags>
+      <SessionStorage Value="InProjectDir"/>
+      <Title Value="Mustache Templater"/>
+      <UseAppBundle Value="False"/>
+      <ResourceType Value="res"/>
+    </General>
+    <BuildModes>
+      <Item Name="Default" Default="True"/>
+    </BuildModes>
+    <PublishOptions>
+      <Version Value="2"/>
+      <UseFileFilters Value="True"/>
+    </PublishOptions>
+    <RunParams>
+      <FormatVersion Value="2"/>
+    </RunParams>
+    <Units>
+      <Unit>
+        <Filename Value="mustache.lpr"/>
+        <IsPartOfProject Value="True"/>
+      </Unit>
+    </Units>
+  </ProjectOptions>
+  <CompilerOptions>
+    <Version Value="11"/>
+    <Target>
+      <Filename Value="mustache"/>
+    </Target>
+    <SearchPaths>
+      <IncludeFiles Value="$(ProjOutDir)"/>
+      <OtherUnitFiles Value="../src"/>
+      <UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/>
+    </SearchPaths>
+  </CompilerOptions>
+  <Debugging>
+    <Exceptions>
+      <Item>
+        <Name Value="EAbort"/>
+      </Item>
+      <Item>
+        <Name Value="ECodetoolError"/>
+      </Item>
+      <Item>
+        <Name Value="EFOpenError"/>
+      </Item>
+    </Exceptions>
+  </Debugging>
+</CONFIG>

+ 207 - 0
packages/fcl-mustache/examples/mustache.lpr

@@ -0,0 +1,207 @@
+program mustache;
+
+{$mode objfpc}{$H+}
+
+uses
+  {$IFDEF UNIX}
+  cthreads,
+  {$ENDIF}
+  Classes, SysUtils, CustApp, strutils, fpjson, jsonparser, csvdataset, fpMustache, fpexmustache, fpdbmustache, iostream;
+
+type
+
+  { TMustacheApplication }
+
+  TMustacheApplication = class(TCustomApplication)
+  private
+    FTemplate : TMustacheString;
+    FJSON : TJSONStringType;
+    FCSV: TCSVDataset;
+    FPartials,
+    FDefines : TStrings;
+    FAllowExpressions : Boolean;
+    Foutput,
+    FSection,
+    FRootPath : String;
+    procedure DoGetDefine(const aName: TMustacheString; var aHandled: Boolean;
+      var aValue: TMustacheString);
+    procedure ProcessOptions;
+    Procedure Createoutput;
+    procedure Usage(ErrorMsg: String);
+  protected
+    procedure DoRun; override;
+
+  public
+    constructor Create(TheOwner: TComponent); override;
+    destructor Destroy; override;
+  end;
+
+{ TMustacheApplication }
+
+procedure TMustacheApplication.Usage(ErrorMsg : String);
+
+begin
+  If ErrorMsg<>'' then
+    Writeln('Error : ',ErrorMsg);
+  Writeln('Usage : mustache [options]');
+  Writeln('Where options is one or more of:');
+  writeln('-c --csv=FILE             Use a CSV file as data source. First line must contain column names.');
+  writeln('-d --define=name=value    Define fixed value.');
+  writeln('-e --expressions          Allow expressions.');
+  writeln('-h --help                 This message.');
+  writeln('-j --json=JSON            Use JSON as data source. @FILENAME will read JSON from file (UTF8).');
+  writeln('-o --output=FILE          output file to write output to. If empty, stdout is assumed.');
+  writeln('-p --partial=name=PARTIAL Register partial. @FILENAME reads partial from file.');
+  writeln('-r --root=PATH            Register variables at root path PATH for expression engine');
+  writeln('-s --section=SECTIOn    Section name for CSV data');
+  writeln('-t --template=TEMPLATE    Use TEMPLATE as data source. @FILENAME will read template from file (UTF8). Required.');
+  Halt(Ord(ErrorMsg<>''));
+end;
+
+procedure TMustacheApplication.ProcessOptions;
+
+  Function StringOrFile(S : String) : UTF8String;
+
+  begin
+    if Copy(S,1,1)<>'@' then
+      Result:=S
+    else
+      With TFileStream.Create(Copy(S,2,Length(S)-1),fmOpenRead or fmShareDenyNone) do
+        try
+          SetLength(Result,Size);
+          ReadBuffer(Result[1],Size);
+        finally
+          Free;
+        end;
+  end;
+
+Var
+  S : String;
+
+begin
+  if Not HasOption('t','template') then
+    Raise Exception.Create('Need a template');
+  if HasOption('c','csv') and HasOption('j','json')  then
+    Raise Exception.Create('Cannot specify both JSON or CSV');
+  FTemplate:=StringOrFile(GetOptionValue('t','template'));
+  if HasOption('j','json') then
+    FJSON:=StringOrFile(GetOptionValue('j','json'))
+  else if HasOption('c','csv') then
+    begin
+    FCSV:=TCSVDataset.Create(Self);
+    FCSV.FileName:=GetOptionValue('c','csv');
+    FCSV.CSVOptions.FirstLineAsFieldNames:=True;
+    FCSV.Open;
+    end;
+  for S in GetOptionValues('d','define') do
+    FDefines.Add(S);
+  for S in GetOptionValues('p','partial') do
+    FPartials.Add(ExtractWord(1,S,['='])+'='+StringOrFile(ExtractWord(2,S,['='])));
+  FAllowExpressions:=HasOption('e','expressions');
+  FRootPath:=GetOptionValue('r','root');
+  FSection:=GetOptionValue('s','section');
+  if FSection='' then
+    FSection:='data';
+  Foutput:=GetOptionValue('o','output');
+end;
+
+procedure TMustacheApplication.DoGetDefine(const aName: TMustacheString;
+  var aHandled: Boolean; var aValue: TMustacheString);
+
+Var
+  Idx : Integer;
+
+begin
+  Writeln('Getting define ',aName);
+  Idx:=FDefines.IndexOfName(aName);
+  aHandled:=Idx<>-1;
+  if aHandled then
+    aValue:=FDefines.ValueFromIndex[Idx]
+  else
+    aValue:='';
+end;
+
+procedure TMustacheApplication.DoRun;
+var
+  ErrorMsg: String;
+begin
+  Terminate;
+  // quick check parameters
+  ErrorMsg:=CheckOptions('het:j:c:d:o:r:', ['help','template','json','csv','define','output','expressions','root']);
+  if (ErrorMsg<>'') or HasOption('h','help') then
+    Usage(ErrorMsg);
+  ProcessOptions;
+  CreateOutput;
+end;
+
+procedure TMustacheApplication.CreateOutput;
+
+Var
+  M : TMustache;
+  C : TMustacheContext;
+  O : TStream;
+  S : TMustacheString;
+
+begin
+  O:=Nil;
+  M:=Nil;
+  C:=Nil;
+  try
+    if FAllowExpressions then
+      M:=TMustache.Create(Self)
+    else
+      begin
+      M:=TMustacheExpr.Create(Self);
+      if (FRootPath<>'') and (FJSON<>'') then
+        TMustacheExpr(M).RegisterVariables(FJSON,FRootPath,True);
+      end;
+    M.Partials:=FPartials;
+    if Assigned(FCSV) then
+      begin
+      C:=TMustacheDBContext.Create(@DoGetDefine);
+      TMustacheDBContext(C).AddDataset(FCSV,FSection);
+      end
+    else if (FJSON<>'') then
+      C:=TMustacheJSONContext.Create(GetJSON(FJSON),@DoGetDefine)
+    else
+      C:=TMustacheContext.Create(@DoGetDefine);
+    if Foutput<>'' then
+      O:=TFileStream.Create(Foutput,fmCreate)
+    else
+      O:=TIOStream.Create(iosOutput);
+    M.Template:=FTemplate;
+    S:=M.Render(C);
+    O.WriteBuffer(S[1],Length(S));
+  finally
+    O.Free;
+    C.Free;
+    M.Free;
+  end;
+end;
+
+constructor TMustacheApplication.Create(TheOwner: TComponent);
+begin
+  inherited Create(TheOwner);
+  FPartials:=TStringList.Create;
+  FDefines:=TStringList.Create;
+  StopOnException:=True;
+end;
+
+destructor TMustacheApplication.Destroy;
+begin
+  FreeAndNil(FPartials);
+  FreeAndNil(FDefines);
+  FreeAndNil(FCSV);
+  inherited Destroy;
+end;
+
+
+var
+  Application: TMustacheApplication;
+begin
+  Application:=TMustacheApplication.Create(nil);
+  Application.Title:='Mustache Templater';
+  Application.Run;
+  Application.Free;
+end.
+

+ 49 - 0
packages/fcl-mustache/fpmake.pp

@@ -0,0 +1,49 @@
+{$ifndef ALLPACKAGES}
+{$mode objfpc}{$H+}
+program fpmake;
+
+uses fpmkunit;
+
+Var
+  P : TPackage;
+  T : TTarget;
+begin
+  With Installer do
+    begin
+{$endif ALLPACKAGES}
+    P:=AddPackage('fcl-mustache');
+    P.ShortName:='mustache';
+
+{$ifdef ALLPACKAGES}
+    P.Directory:=ADirectory;
+{$endif ALLPACKAGES}
+
+    P.Author := 'Michael Van Canneyt';
+    P.License := 'LGPL with modification, ';
+    P.HomepageURL := 'www.freepascal.org';
+    P.Email := '';
+    P.Description := 'Mustache templates for FPC';
+    P.NeedLibC:= false;
+    P.SourcePath.Add('src');
+    P.OSes:=P.OSes-[embedded,win16,msdos,nativent,macosclassic,palmos,zxspectrum,msxdos,amstradcpc,sinclairql,wasi];
+    if Defaults.CPU=jvm then
+      P.OSes := P.OSes - [java,android];
+
+    P.Dependencies.Add('rtl-objpas');
+    P.Dependencies.Add('fcl-base');
+    P.Dependencies.Add('fcl-json');
+    P.Dependencies.Add('fcl-db');
+    P.Version:='3.3.1';
+    T:=P.Targets.AddUnit('src/fpmustache.pp');
+      T.ResourceStrings:=true;
+    T:=P.Targets.AddUnit('src/fpdbmustache.pp');
+      T.ResourceStrings:=true;
+      T.Dependencies.AddUnit('fpmustache');
+    T:=P.Targets.AddUnit('src/fpexmustache.pp');
+      T.ResourceStrings:=true;
+      T.Dependencies.AddUnit('fpmustache');
+{$ifndef ALLPACKAGES}
+    Run;
+    end;
+end.
+{$endif ALLPACKAGES}

+ 268 - 0
packages/fcl-mustache/src/fpdbmustache.pp

@@ -0,0 +1,268 @@
+{
+    This file is part of the Free Pascal Run time library.
+    Copyright (c) 2021 by Michael Van Canneyt ([email protected])
+
+    This file contains a Mustache DB context, getting data from a dataset
+
+    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.
+
+ **********************************************************************}
+
+unit fpdbmustache;
+
+{$mode ObjFPC}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, db, fpMustache;
+
+Type
+
+  { TDatasetCollectionItem }
+
+  TDatasetCollectionItem = Class(TCollectionItem)
+  private
+    FDataset: TDataSet;
+    FSection: String;
+  Public
+    Property Dataset : TDataSet Read FDataset Write FDataset;
+    Property SectionName : String Read FSection Write FSection;
+  end;
+
+  TDatasetCollection = Class(TCollection)
+  private
+    function GetDS(aIndex : Integer): TDatasetCollectionItem;
+  Public
+    Function IndexOfDataset(aDataset : TDataset) : Integer;
+    Function IndexOfSection(aSection : String) : Integer;
+    Property Datasets[aIndex : Integer] : TDatasetCollectionItem Read GetDS; default;
+  end;
+
+  { TMustacheDBContext }
+
+  TMustacheDBContext = Class(TMustacheContext)
+  Private
+    Type
+      TPair = Record
+        atStart : Boolean;
+        Value : TDataset;
+      end;
+  Private
+    FStack : Array of TPair;
+    FCount : Integer;
+    FStaticValues: TStrings;
+    FDatasets : TDatasetCollection;
+    Function FindField(Const aName : TMustacheString) : TField;
+    function GetDataset(aIndex : Integer): TDatasetCollectionItem;
+    function GetDatasetCount: INteger;
+    procedure SetStaticValues(AValue: TStrings);
+  Public
+    Constructor Create(aCallback : TGetTextValueEvent); override;
+    Destructor destroy; override;
+    Procedure Clear;
+    Function MoveNextSectionItem(Const aName : TMustacheString) : Boolean; override;
+    Function PushSection(Const aName : TMustacheString) : TMustacheSectionType; override;
+    Procedure PopSection(Const aName : TMustacheString); override;
+    Function GetTextValue(Const aName : TMustacheString) : TMustacheString; override;
+    Procedure AddDataset(aDataset : TDataset; aSectionName : String = '');
+    Procedure RemoveDataset(aDataset : TDataset);
+    Property StaticValues : TStrings Read FStaticValues Write SetStaticValues;
+    Property Datasets[aIndex : Integer] : TDatasetCollectionItem Read GetDataset;
+    Property DatasetCount : INteger Read GetDatasetCount;
+  end;
+
+implementation
+
+uses StrUtils;
+
+Resourcestring
+  SErrPopSectionNoPush = 'PopSection %s without push';
+  SErrDatasetNameEmpty = 'Dataset name and section cannot both be empty';
+  SErrDatasetEmpty = 'Dataset is Nil';
+  SErrDuplicateDataSetName = 'Duplicate dataset name: %s';
+
+{ TMustacheDBContext }
+
+function TMustacheDBContext.FindField(const aName: TMustacheString): TField;
+
+Var
+  aCount : Integer;
+
+begin
+  Result:=Nil;
+  aCount:=FCount-1;
+  While (Result=Nil) and (aCount>=0) do
+    begin
+    Result:=FStack[aCount].Value.FieldByName(aName);
+    Dec(aCount);
+    end;
+end;
+
+function TMustacheDBContext.GetDataset(aIndex : Integer
+  ): TDatasetCollectionItem;
+begin
+  Result:=FDatasets[aIndex];
+end;
+
+function TMustacheDBContext.GetDatasetCount: INteger;
+begin
+  Result:=FDatasets.Count;
+end;
+
+procedure TMustacheDBContext.SetStaticValues(AValue: TStrings);
+begin
+  if FStaticValues=AValue then Exit;
+  FStaticValues.Assign(AValue);
+end;
+
+constructor TMustacheDBContext.Create(aCallback: TGetTextValueEvent);
+begin
+  inherited Create(aCallback);
+  FDatasets:=TDatasetCollection.Create(TDatasetCollectionItem);
+  FStaticValues:=TStringList.Create;
+  SetLength(FStack,JSONListGrowCount);
+  FCount:=0;
+end;
+
+destructor TMustacheDBContext.destroy;
+begin
+  FreeAndNil(FStaticValues);
+  FreeAndNil(FDatasets);
+  inherited destroy;
+end;
+
+procedure TMustacheDBContext.Clear;
+begin
+  FStaticValues.Clear;
+  FDatasets.Clear;
+end;
+
+function TMustacheDBContext.MoveNextSectionItem(const aName: TMustacheString
+  ): Boolean;
+begin
+  if FStack[FCount-1].atStart then
+    FStack[FCount-1].atStart:=False
+  else
+    FStack[FCount-1].Value.Next;
+  Result:=Not FStack[FCount-1].Value.EOF;
+end;
+
+function TMustacheDBContext.PushSection(const aName: TMustacheString
+  ): TMustacheSectionType;
+
+Var
+  aDS : TDataset;
+  Idx : Integer;
+begin
+  Result:=mstNone;
+  Idx:=FDatasets.IndexOfSection(aName);
+  if Idx=-1 then
+    Exit;
+  aDS:=FDatasets[Idx].Dataset;
+  if aDS.IsEmpty then
+    exit;
+  if FCount=Length(FStack) then
+    SetLength(FStack,FCount+JSONListGrowCount);
+  FStack[FCount].Value:=aDS;
+  FStack[FCount].atStart:=True;
+  Inc(FCount,1);
+  Result:=mstList;
+end;
+
+procedure TMustacheDBContext.PopSection(const aName: TMustacheString);
+begin
+  if FCount<1 then
+    Raise EMustache.CreateFmt(SErrPopSectionNoPush,[aName]);
+  Dec(FCount,1);
+end;
+
+function TMustacheDBContext.GetTextValue(const aName: TMustacheString
+  ): TMustacheString;
+
+Var
+  F : TField;
+  idx : Integer;
+
+begin
+  F:=Nil;
+  if Pos('.',aName)=0 then
+    F:=FindField(aName)
+  else if WordCount(aName,['.'])=2 then
+    begin
+    Idx:=FDatasets.IndexOfSection(ExtractWord(1,aName,['.']));
+    if (Idx<>-1) then
+      F:=FDatasets[Idx].Dataset.FindField(ExtractWord(2,aName,['.']));
+    end;
+  If Assigned(F) then
+    Result:=F.AsString
+  else
+    begin
+    Idx:=FStaticValues.IndexOfName(aName);
+    if Idx<>-1 then
+      Result:=FStaticValues.ValueFromIndex[Idx]
+    else
+      Result:=Inherited GetTextValue(aName);
+    end;
+end;
+
+procedure TMustacheDBContext.AddDataset(aDataset: TDataset; aSectionName: String);
+
+Var
+  DCI : TDatasetCollectionItem;
+  aName : String;
+
+begin
+  aName:=aSectionName;
+  if aName='' then
+    aName:=aDataset.Name;
+  if aName='' then
+    raise EMustache.Create(SErrDatasetNameEmpty);
+  if aDataset=Nil then
+    raise EMustache.Create(SErrDatasetEmpty);
+  if FDatasets.IndexOfSection(aName)<>-1 then
+    raise EMustache.CreateFmt(SErrDuplicateDataSetName, [aName]);
+  DCI:=FDatasets.Add as TDatasetCollectionItem;
+  DCI.Dataset:=aDataset;
+  DCI.SectionName:=aName;
+end;
+
+procedure TMustacheDBContext.RemoveDataset(aDataset: TDataset);
+
+Var
+  Idx : Integer;
+
+begin
+  Idx:=FDatasets.IndexOfDataset(aDataset);
+  if Idx<>-1 then
+    FDatasets.Delete(Idx);
+end;
+
+{ TDatasetCollection }
+
+function TDatasetCollection.GetDS(aIndex : Integer): TDatasetCollectionItem;
+begin
+  Result:=Items[aIndex] as TDatasetCollectionItem;
+end;
+
+function TDatasetCollection.IndexOfDataset(aDataset: TDataset): Integer;
+begin
+  Result:=Count-1;
+  While (Result>=0) and (GetDS(Result).Dataset<>ADataset) do
+    Dec(Result);
+end;
+
+function TDatasetCollection.IndexOfSection(aSection: String): Integer;
+begin
+  Result:=Count-1;
+  While (Result>=0) and not SameText(GetDS(Result).SectionName,ASection) do
+    Dec(Result);
+end;
+
+end.
+

+ 399 - 0
packages/fcl-mustache/src/fpexmustache.pp

@@ -0,0 +1,399 @@
+{
+    This file is part of the Free Pascal Run time library.
+    Copyright (c) 2021 by Michael Van Canneyt ([email protected])
+
+    This file contains a Mustache descendent with FPExpr parser expression support
+
+    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.
+
+ **********************************************************************}
+
+unit fpexmustache;
+
+{$mode ObjFPC}{$H+}
+
+interface
+
+uses
+  Classes, fpexprpars, fpmustache, fpjson;
+
+Type
+
+  { TMustacheExprElement }
+
+  TMustacheExprElement = Class(TMustacheElement)
+  private
+    FNode: TFPExprNode;
+    FExpr : TMustacheString;
+  Protected
+    Procedure SetNode(aNode : TFPExprNode); virtual;
+    Function GetData : TMustacheString;override;
+    Procedure SetData(const aValue : TMustacheString) ; override;
+  Public
+    Destructor Destroy; override;
+    Procedure Render(aContext : TMustacheContext; aOutput : TMustacheOutput; const aPrefix : String = ''; aLast : Boolean = False); override;
+    Property Node : TFPExprNode Read FNode;
+  end;
+
+  { TMustacheExprParser }
+
+  TMustacheExprParser = class(TMustacheParser)
+  private
+    FExprEnd: Char;
+    FExprParser: TFPExpressionParser;
+    FExprStart: Char;
+  Protected
+    function CreateDefault(aParent: TMustacheElement; aPosition: Integer; const aName: String): TMustacheElement; override;
+  Public
+    Constructor Create(aTemplate : TMustacheString = '';aStart: TMustacheString='';aStop: TMustacheString = ''); override;
+    // Default [
+    Property ExprStart : Char Read FExprStart Write FExprStart;
+    // Default ]
+    Property ExprEnd : Char Read FExprEnd Write FExprEnd;
+    // Our instance
+    Property ExprParser : TFPExpressionParser Read FExprParser Write FExprParser;
+  end;
+
+  { TMustacheExpr }
+
+  TMustacheExpr = Class(TMustache)
+  private
+    FExprEndChar: String;
+    FExpressionParser: TFPExpressionParser;
+    FExprStartChar: String;
+    FCurrentContext : TMustacheContext;
+    function GetResultType(aValue: TJSONData): TResultType;
+    procedure SetExprEndChar(AValue: String);
+    procedure SetExpressionParser(AValue: TFPExpressionParser);
+    procedure SetExprStartChar(AValue: String);
+    function DoGetExpressionParser : TFPExpressionParser;
+  Protected
+    procedure DoGetVariable(var Result: TFPExpressionResult; ConstRef  AName: ShortString); virtual;
+    Procedure Notification(AComponent: TComponent; Operation: TOperation); override;
+    Function CreateParser(aTemplate: TMustacheString): TMustacheParser; override;
+    function GetExpressionParser(aOwner : TComponent): TFPExpressionParser; virtual;
+  Public
+    Constructor Create(aOwner : TComponent); override;
+    Procedure Render(aContext : TMustacheContext; aOutput : TMustacheOutput); override; overload;
+    // Register variables from JSON in the expression engine.
+    // If UseEvent is true, the variables will be retrieved while parsing with an event.
+    // If UseEvent is false, the variables will be registered as static values.
+    Procedure RegisterVariables (aContext : TMustacheJSONContext; aPath : TJSONStringType = ''; UseEvent : Boolean = True);
+    Procedure RegisterVariables (aJSON : String; aPath : TJSONStringType = ''; UseEvent : Boolean = True);
+    Procedure RegisterVariables (aJSON : TJSONObject; aPath : TJSONStringType = ''; UseEvent : Boolean = True);
+  Published
+    // Default [
+    Property ExprStartChar : String Read FExprStartChar Write SetExprStartChar;
+    // Default ]
+    Property ExprEndChar : String Read FExprEndChar Write SetExprEndChar;
+    // An expression parser instance. If none is specified, then a default is created.
+    Property ExpressionParser : TFPExpressionParser Read DoGetExpressionParser Write SetExpressionParser;
+  end;
+
+  { TMustacheExpressionParser }
+
+  TMustacheExpressionParser = class(TFPExpressionParser)
+  end;
+
+implementation
+
+uses sysutils;
+
+Resourcestring
+  SErrLengthStartMustBe1 = 'Length expression start delimiter must be 1';
+  SErrLengthEndMustBe1 = 'Length expression end delimiter must be 1';
+
+{ TMustacheExprElement }
+
+procedure TMustacheExprElement.SetNode(aNode: TFPExprNode);
+begin
+  FNode:=aNode;
+end;
+
+function TMustacheExprElement.GetData: TMustacheString;
+begin
+  Result:=FExpr;
+end;
+
+procedure TMustacheExprElement.SetData(const aValue: TMustacheString);
+begin
+  FExpr:=aValue;
+end;
+
+procedure TMustacheExprElement.Render(aContext: TMustacheContext;
+  aOutput: TMustacheOutput; const aPrefix: String; aLast: Boolean);
+
+Var
+  Res : TFPExpressionResult;
+  S : TMustacheString;
+
+begin
+  Res:=Node.NodeValue;
+  case Res.ResultType of
+    rtString   : S:=Res.ResString;
+    rtBoolean  : S:=BoolToStr(Res.ResBoolean,True);
+    rtInteger  : S:=IntToStr(Res.ResInteger);
+    rtFloat    : S:=FormatFloat('0.0#######',Res.ResFloat);
+    rtCurrency : S:=CurrToStr(Res.ResCurrency);
+    rtDateTime : S:=DateTimeToStr(Res.ResDateTime);
+  end;
+  aOutput.Output(aPrefix+S);
+end;
+
+destructor TMustacheExprElement.Destroy;
+begin
+  FreeAndNil(FNode);
+  inherited Destroy;
+end;
+
+{ TMustacheExprParser }
+
+function TMustacheExprParser.CreateDefault(aParent: TMustacheElement;
+  aPosition: Integer; const aName: String): TMustacheElement;
+
+Var
+  L : Integer;
+  N : TFPExprNode;
+
+begin
+  N:=Nil;
+  L:=Length(aName);
+  If (aName[1]=FExprStart) and (aName[L]=FExprEnd) then
+    begin
+    Result:=TMustacheExprElement.Create(metVariable,aParent,aPosition);
+    Result.Data:=Copy(aName,2,L-2);
+    ExprParser.Expression:=Result.Data;
+    ExprParser.ExtractNode(N);
+    TMustacheExprElement(Result).SetNode(N);
+    aParent.AddChild(Result);
+    end
+  else
+    Result:=Inherited CreateDefault(aParent,aPosition,aName);
+end;
+
+constructor TMustacheExprParser.Create(aTemplate: TMustacheString;
+  aStart: TMustacheString; aStop: TMustacheString);
+begin
+  inherited Create(aTemplate, aStart, aStop);
+  FExprStart:='[';
+  FExprEnd:=']';
+end;
+
+{ TMustacheExpr }
+
+procedure TMustacheExpr.SetExprEndChar(AValue: String);
+begin
+  if FExprEndChar=AValue then Exit;
+  if Length(aValue)<>1 then
+    EMustache.Create(SErrLengthStartMustBe1);
+  FExprEndChar:=AValue;
+end;
+
+function TMustacheExpr.GetExpressionParser(aOwner : TComponent): TFPExpressionParser;
+begin
+  Result:=TMustacheExpressionParser.Create(AOwner);
+end;
+
+procedure TMustacheExpr.SetExpressionParser(AValue: TFPExpressionParser);
+
+begin
+  if FExpressionParser=AValue then Exit;
+  If assigned(FExpressionParser) then
+    FExpressionParser.RemoveFreeNotification(Self);
+  FExpressionParser:=AValue;
+  If assigned(FExpressionParser) then
+    FExpressionParser.FreeNotification(Self);
+end;
+
+procedure TMustacheExpr.SetExprStartChar(AValue: String);
+begin
+  if FExprStartChar=AValue then Exit;
+  if Length(aValue)<>1 then
+    EMustache.Create(SErrLengthEndMustBe1);
+  FExprStartChar:=AValue;
+end;
+
+function TMustacheExpr.DoGetExpressionParser: TFPExpressionParser;
+begin
+  if FExpressionParser=Nil then
+    begin
+    FExpressionParser:=GetExpressionParser(Self);
+    FExpressionParser.SetSubComponent(True);
+    FExpressionParser.FreeNotification(Self);
+    end;
+  Result:=FExpressionParser;
+end;
+
+procedure TMustacheExpr.Notification(AComponent: TComponent;
+  Operation: TOperation);
+begin
+  inherited Notification(AComponent, Operation);
+  if (Operation=opRemove) and (aComponent=FExpressionParser) then
+    FExpressionParser:=Nil;
+end;
+
+function TMustacheExpr.CreateParser(aTemplate: TMustacheString ): TMustacheParser;
+
+Var
+  Exp : TMustacheExprParser;
+
+begin
+  Exp:=TMustacheExprParser.Create(aTemplate);
+  Exp.ExprParser:=Self.ExpressionParser;
+  Result:=Exp;
+end;
+
+constructor TMustacheExpr.Create(aOwner: TComponent);
+begin
+  inherited Create(aOwner);
+  DoGetExpressionParser;
+end;
+
+procedure TMustacheExpr.Render(aContext: TMustacheContext; aOutput: TMustacheOutput);
+
+begin
+  FCurrentContext:=aContext;
+  try
+    inherited Render(aContext, aOutput);
+  finally
+    FCurrentContext:=nil;
+  end;
+end;
+
+procedure TMustacheExpr.DoGetVariable(var Result: TFPExpressionResult; ConstRef
+  AName: ShortString);
+
+Var
+  S : TMustacheString;
+  V : Double;
+  C : Integer;
+
+begin
+  If not Assigned(FCurrentContext) then
+    case result.ResultType of
+      rtInteger : Result.ResInteger:=0;
+      rtDateTime : Result.ResDateTime:=0.0;
+      rtString : Result.ResString:='';
+      rtFloat: Result.ResFloat:=0.0;
+      rtCurrency: Result.ResCurrency:=0.0;
+      rtBoolean: Result.ResBoolean:=False;
+    end
+  else
+    begin
+    S:=FCurrentContext.GetTextValue(aName);
+    case result.ResultType of
+      rtInteger : Result.ResInteger:=StrToInt64Def(S,0);
+      rtDateTime : if Not TryStrToDateTime(S,Result.ResDateTime) then
+                     Result.ResDateTime:=0.0;
+      rtString : Result.ResString:=S;
+      rtFloat: begin
+               Val(S,V,C);
+               if C<>0 then
+                 Result.ResFloat:=0.0
+               else
+                 Result.ResFloat:=V;
+               end;
+      rtCurrency:
+               begin
+               Val(S,V,C);
+               if (C<>0) then
+                 Result.ResCurrency:=0.0
+               else
+                 Result.ResCurrency:=V;
+               end;
+      rtBoolean: Result.ResBoolean:=StrToBoolDef(S,False);
+    end;
+    end;
+end;
+
+function TMustacheExpr.GetResultType(aValue: TJSONData): TResultType;
+
+begin
+  Case aValue.JSONType of
+    jtBoolean : Result:=rtBoolean;
+    jtString,
+    jtArray,
+    jtObject,
+    jtNull : Result:=rtString;
+    jtNumber :
+       begin
+       Case TJSONNumber(aValue).NumberType of
+         ntFloat : Result:=rtFloat;
+         ntInteger,
+         ntInt64 : Result:=rtInteger;
+         ntQWord : Raise EMustache.Create('Unsupported JSON type');
+       end;
+       end;
+  end;
+end;
+
+procedure TMustacheExpr.RegisterVariables(aContext: TMustacheJSONContext;
+  aPath: TJSONStringType; UseEvent: Boolean);
+
+begin
+  RegisterVariables(aContext.RootData as TJSONObject,aPath,UseEvent);
+end;
+
+procedure TMustacheExpr.RegisterVariables(aJSON: String;
+  aPath: TJSONStringType; UseEvent: Boolean);
+
+Var
+  aData : TJSONData;
+  aObj : TJSONObject absolute aData;
+
+
+begin
+  aData:=getJSON(aJSON,True);
+  try
+    if aData is TJSONObject then
+      RegisterVariables(aObj,aPath,useEvent)
+    else
+      Raise EMustache.Create('Invalid JSON data to register variables');
+  finally
+    aData.Free;
+  end;
+end;
+
+procedure TMustacheExpr.RegisterVariables(aJSON: TJSONObject; aPath: TJSONStringType; UseEvent: Boolean);
+
+Var
+  aData,aValue : TJSONData;
+  aEnum : TJSONEnum;
+  aKey : TJSONStringType;
+  rt : TResultType;
+  aParser : TFPExpressionParser;
+
+begin
+  aParser:=ExpressionParser;
+  aData:=aJSON.FindPath(aPath);
+  if aData is TJSONObject then
+    for aEnum in aData do
+      begin
+      aKey:=aEnum.Key;
+      aValue:=aEnum.Value;
+      rt:=GetResultType(aValue);
+      if UseEvent then
+        aParser.Identifiers.AddVariable(aKey,rt,@DoGetVariable)
+      else
+        case rt of
+          rtBoolean: aParser.Identifiers.AddBooleanVariable(aKey,aValue.AsBoolean);
+          rtFloat: aParser.Identifiers.AddFloatVariable(aKey,aValue.AsFloat);
+          rtInteger: aParser.Identifiers.AddIntegerVariable(aKey,aValue.AsInteger);
+          rtString: Case aValue.JSONType of
+                      jtNull: aParser.Identifiers.AddStringVariable(aKey,'');
+                      jtArray,
+                      jtObject: aParser.Identifiers.AddStringVariable(aKey, aValue.AsJSON);
+                    else
+                      aParser.Identifiers.AddStringVariable(aKey,aValue.AsString);
+                    end;
+          end;
+      end;
+end;
+
+end.
+

+ 1340 - 0
packages/fcl-mustache/src/fpmustache.pp

@@ -0,0 +1,1340 @@
+{
+    This file is part of the Free Pascal Run time library.
+    Copyright (c) 2021 by Michael Van Canneyt ([email protected])
+
+    This file contains a Mustache parser and renderer.
+
+    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.
+
+ **********************************************************************}
+
+unit fpmustache;
+
+{$mode objfpc}{$H+}
+{$WARN 5024 off : Parameter "$1" not used}
+interface
+
+uses
+  Classes, SysUtils, fpjson;
+
+Type
+  EMustache = Class(Exception);
+
+  TMustacheString = UTF8String;
+  TMustacheChar = AnsiChar;
+  TMustacheContext = class;
+
+  TMustacheOutput = Class(TObject)
+  Public
+    // add atext to output
+    Procedure Output(Const aText : TMustacheString); virtual; abstract;
+    Procedure Reset; virtual; abstract;
+  end;
+
+  { TMustacheStringOutput }
+
+  TMustacheStringOutput = Class(TMustacheOutput)
+  private
+    FData: TMustacheString;
+  Public
+    // Override
+    Procedure Output(Const aText : TMustacheString); override;
+    Procedure Reset; override;
+    // The rendered TMustacheString
+    Property Data : TMustacheString Read FData;
+  end;
+
+  { TMustacheElement }
+
+  TMustacheElementType = (metRoot,metComment,metText,metVariable,metSection,metInvertedSection,metPartial);
+
+  TMustacheElement = Class(TObject)
+  private
+    FPosition: Integer;
+    FType : TMustacheElementType;
+    FParent : TMustacheElement;
+  Protected
+    function GetCount: Integer; virtual;
+    function GetElement(aIndex : Integer): TMustacheElement; virtual;
+    Function GetData : TMustacheString ; virtual; abstract;
+    Procedure SetData(Const aData : TMustacheString) ; virtual; abstract;
+    Function GetPrefix : TMustacheString; virtual;
+    Procedure SetPrefix (aValue : TMustacheString); virtual;
+    Procedure Dump(aList : Tstrings; aIndent : TMustacheString; aDumpChildren : Boolean = true); virtual;
+  Public
+    Constructor Create(aType : TMustacheElementType; aParent : TMustacheElement;aPosition : Integer); virtual;
+    // Add a child. Parent always owns child
+    Procedure AddChild(aChild : TMustacheElement); virtual;
+    // Render the text for this element
+    Procedure Render(aContext : TMustacheContext; aOutput : TMustacheOutput; const aPrefix : String = ''; aLast : Boolean = False); virtual; abstract;
+    // Position in template
+    Property Position : Integer Read FPosition;
+    // Parent element
+    Property Parent : TMustacheElement Read FParent;
+    // Access to children
+    Property Children[aIndex : Integer] : TMustacheElement Read GetElement;
+    // Child count
+    Property ChildCount : Integer Read GetCount;
+    // Element type
+    Property ElementType : TMustacheElementType Read FType;
+    // The data for this element. What this is, depends on the kind.
+    // etText : the text;
+    // etValue : the variable name
+    // etSection : the section name.
+    // etInvertedSection : the section name.
+    Property Data : TMustacheString Read GetData Write SetData;
+    // Whitespace prefix. Normally only used for partials
+    Property Prefix : TMustacheString Read GetPrefix Write SetPrefix;
+  end;
+  TMustacheElementClass = Class of TMustacheElement;
+  TMustacheElementArray = Array of TMustacheElement;
+
+  { TMustacheNamedElement }
+
+  TMustacheNamedElement = Class(TMustacheElement)
+  private
+    FName: TMustacheString;
+  Protected
+    Procedure SetData(Const aData : TMustacheString); override;
+    Function GetData : TMustacheString; override;
+  Public
+    Property Name : TMustacheString Read FName;
+  end;
+
+  { TMustacheParentElement }
+
+  TMustacheParentElement = Class(TMustacheNamedElement)
+  Private
+    FChildren : TMustacheElementArray;
+    FCount : Integer;
+  Protected
+    function GetElement(aIndex : Integer): TMustacheElement; override;
+    function GetCount : Integer; override;
+  Public
+    Destructor Destroy; override;
+    Procedure AddChild(aChild : TMustacheElement); override;
+    Procedure Render(aContext : TMustacheContext; aOutput : TMustacheOutput; const aPrefix : String = ''; aLast : Boolean = False); override;
+  end;
+
+
+  { TMustacheTextElement }
+
+  TMustacheTextElement = Class(TMustacheElement)
+  Private
+    FData : TMustacheString;
+  Protected
+    Procedure SetData(Const aData : TMustacheString) ; override;
+    Function GetData : TMustacheString; override;
+  Public
+    Procedure Render(aContext : TMustacheContext; aOutput : TMustacheOutput; const aPrefix : String = ''; aLast : Boolean = False); override;
+  end;
+
+  { TMustacheVariableElement }
+
+  TMustacheVariableElement = Class(TMustacheNamedElement)
+  private
+    FNoUnescape: Boolean;
+  Protected
+    Procedure SetData(Const aData : TMustacheString); override;
+  Public
+    Procedure Render(aContext : TMustacheContext; aOutput : TMustacheOutput; const aPrefix : String = ''; aLast : Boolean = False); override;
+    Property NoUnescape : Boolean Read FNoUnescape;
+  end;
+
+  { TMustacheSectionElement }
+
+  TMustacheSectionElement = Class(TMustacheParentElement)
+  Public
+    Procedure Render(aContext : TMustacheContext; aOutput : TMustacheOutput; const aPrefix : String = ''; aLast : Boolean = False); override;
+  end;
+
+  { TMustachePartialElement }
+
+  TMustachePartialElement = Class(TMustacheElement)
+  Private
+    FPrefix : TMustacheString;
+    FPartialName : TMustacheString;
+    FPartial : TMustacheElement;
+  Protected
+    Function GetData : TMustacheString ; override;
+    Procedure SetData(Const aData : TMustacheString) ; override;
+    Procedure Dump(aList : Tstrings; aIndent : TMustacheString; aDumpChildren : Boolean = true); override;
+    Function GetPrefix : TMustacheString; override;
+    Procedure SetPrefix (aValue : TMustacheString); override;
+  Public
+    Destructor Destroy; override;
+    Procedure AddChild(aChild: TMustacheElement); override;
+    Procedure Render(aContext : TMustacheContext; aOutput : TMustacheOutput; const aPrefix : String = ''; aLast : Boolean = False); override;
+    Property Partial : TMustacheElement Read FPartial;
+  end;
+
+  { TMustachePartialList }
+
+  TMustachePartialList = Class(TMustacheParentElement)
+  Public
+    Function FindPartial(aName : TMustacheString) : TMustacheElement;
+  end;
+
+  { TMustacheParser }
+  TGetTextValueEvent = Procedure (Const aName : TMustacheString; var aHandled : Boolean; var aValue : TMustacheString) of Object;
+
+  TMustacheParser = Class(TObject)
+  private
+    FStopTag: TMustacheString;
+    FStartTag: TMustacheString;
+    FTemplate: TMustacheString;
+    FOnGetPartial: TGetTextValueEvent;
+    FPartials: TMustachePartialList;
+    Class var DefaultTypes : Array[TMustacheElementType] of TMustacheElementClass;
+  Protected
+    // Called to create a default element for a {{ }} tag. By default creates a variable.
+    // Override this if you want to create additional elements.
+    function CreateDefault(aParent: TMustacheElement; aPosition: Integer; const aName: String): TMustacheElement; virtual;
+    // Create element for indicated type, must add it to parent.
+    // You can override this to provide customized behaviour.
+    function CreateElement(aType: TMustacheElementType; aParent: TMustacheElement; aPosition: Integer): TMustacheElement; virtual;
+    // Parse
+    Procedure DoParse(aParent : TMustacheElement; Const aTemplate, aStart, aStop : TMustacheString); virtual;
+    // Called to get the template of a partial. The template is parsed, and the result added to the partials list.
+    Function GetPartial(const aName : TMustacheString) : TMustacheString; virtual;
+    // Auxuliary functions for the peculiar whitespace handling of Mustache specs...
+    function EndsOnWhiteSpace(aElement: TMustacheElement): Boolean; virtual;
+    function GetEndingWhiteSpace(aElement: TMustacheElement): TMustacheString; virtual;
+    procedure ExtractStartStop(const aName: TMustacheString; out aStart, aStop: TMustacheString); virtual;
+    procedure TrimEndingWhiteSpace(aElement: TMustacheElement); virtual;
+  Public
+    // Create a new parser.
+    Constructor Create(aTemplate : TMustacheString = '';aStart: TMustacheString='';aStop: TMustacheString = ''); virtual;
+    // Set the default TMustacheElements for the descendents
+    Class procedure SetDefaultTypeClass(aType : TMustacheElementType; aClass: TMustacheElementClass);
+    // Parse the template and
+    Procedure Parse(aParent : TMustacheElement);
+    Function Parse : TMustacheElement;
+    // Will be used to hold partials. You must set this before calling Parse.
+    Property Partials : TMustachePartialList Read FPartials Write FPartials;
+    // The template created on startup
+    Property Template : TMustacheString Read FTemplate write FTemplate;
+    // The initial start tag marker, by default {{
+    Property StartTag : TMustacheString Read FStartTag Write FStartTag;
+    // The initial end tag marker, by default }}
+    Property StopTag : TMustacheString Read FStopTag Write FSTopTag;
+    // Event called to get the source of a partial.
+    Property OnGetPartial : TGetTextValueEvent Read FOnGetPartial Write FOnGetPartial;
+  end;
+
+  { TMustacheContext }
+  TMustacheSectionType = (mstNone,mstSingle,mstList);
+
+  TMustacheContext = Class(TObject)
+  Private
+    FCallback : TGetTextValueEvent;
+  Public
+    Constructor Create(aCallback : TGetTextValueEvent); virtual;
+    // Helper function to quote HTML
+    Class Function QuoteHTML(aString : TMustacheString) :TMustacheString; virtual;
+    // Move to next section item. aName is section name. Returns True if move successful
+    Function MoveNextSectionItem(Const aName : TMustacheString) : Boolean; virtual;
+    // Push a new section context with name aName.
+    Function PushSection(Const aName : TMustacheString) : TMustacheSectionType; virtual;
+    // Pop current section. aName is for verification.
+    Procedure PopSection(Const aName : TMustacheString); virtual;
+    // Return the value of a variable with name aName.
+    Function GetTextValue(Const aName : TMustacheString) : TMustacheString; virtual;
+  end;
+
+  { TMustacheJSONContext }
+
+  TMustacheJSONContext = Class(TMustacheContext)
+  Private
+    Type
+      TPair = Record
+        Index : Integer; // if array, index of current element.
+        Value : TJSONData;
+      end;
+  Private
+    FCurrentData: TJSONData;
+    FStack : Array of TPair;
+    FCount : Integer;
+    Function FindValue(Const aName : TMustacheString) : TJSONData;
+    function GetRootData: TJSONData;
+  Public
+    Constructor Create(aJSON : TJSONData; aCallback : TGetTextValueEvent); reintroduce;
+    Function MoveNextSectionItem(Const aName : TMustacheString) : Boolean; override;
+    Function PushSection(Const aName : TMustacheString) : TMustacheSectionType; override;
+    Procedure PopSection(Const aName : TMustacheString); override;
+    Function GetTextValue(Const aName : TMustacheString) : TMustacheString; override;
+    Property RootData : TJSONData read GetRootData;
+  end;
+
+  TMustache = Class(TComponent)
+  private
+    FCompiled: TMustacheElement;
+    FCompiledPartials: TMustachePartialList;
+    FOnGetValue: TGetTextValueEvent;
+    FPartials: TStrings;
+    FStartTag: TMustacheString;
+    FStopTag: TMustacheString;
+    FTemplate: TMustacheString;
+    procedure SetPartials(AValue: TStrings);
+    procedure SetStartTag(AValue: TMustacheString);
+    procedure SetStopTag(AValue: TMustacheString);
+    procedure SetTemplate(AValue: TMustacheString);
+  Protected
+    Procedure DoGetPartial(Const aName : TMustacheString; var aHandled : Boolean; var aValue : TMustacheString); virtual;
+    Procedure Reset; virtual;
+    Function CreatePartials : TMustachePartialList;
+    function CreateParser(aTemplate: TMustacheString): TMustacheParser; virtual;
+    Property Compiled : TMustacheElement Read FCompiled;
+    Property CompiledPartials : TMustachePartialList Read FCompiledPartials;
+  Public
+    Constructor Create(aOwner : TComponent); override;
+    Destructor Destroy; override;
+    Procedure Compile;
+    Procedure Dump(aList : Tstrings; aindent : TMustacheString); overload; virtual;
+    Function Dump: TMustacheString;overload;
+    Procedure Render(aContext : TMustacheContext; aOutput : TMustacheOutput); virtual; overload;
+    Function Render(aContext : TMustacheContext) : TMustacheString; overload;
+    Function Render(const aJSON : TJSONData) : TMustacheString; overload;
+    Function Render(const aJSON : TJSONStringType) : TMustacheString; overload;
+    Class function CreateMustache(aOwner: TComponent; aTemplate: TMustacheString): TMustache; virtual;
+    Class Function Render(aTemplate : TMustacheString; const aJSON : TJSONStringType) : TMustacheString;
+  Published
+    Property Template : TMustacheString Read FTemplate Write SetTemplate;
+    Property OnGetValue : TGetTextValueEvent Read FOnGetValue Write FOnGetValue;
+    Property StartTag : TMustacheString Read FStartTag Write SetStartTag;
+    Property StopTag : TMustacheString Read FStopTag Write SetStopTag;
+    Property Partials : TStrings Read FPartials Write SetPartials;
+  end;
+
+
+Const
+  ListGrowCount = 10;
+  JSONListGrowCount = 10;
+
+implementation
+
+uses TypInfo;
+
+
+
+Resourcestring
+  SErrNoChildForElement = 'Class %s does not support child elements.';
+  SErrInvalidIndex= '%s: Index %d is not in valid range [0..%d].';
+  SErrUnterminatedTag = 'Tag %s opened on position %d but not closed.';
+  SErrEmptyTag = 'Tag %s on position %d is empty.';
+  SErrSectionClose = 'Structural error: Section "%s" on position %d is closed by tag "%s" on position %d.';
+  SErrNotClosedSection = 'Structural error: Section "%s" on position %d is not closed.';
+  SErrNoSectionToClose = 'Structural error: Section "%s" on position %d was never opened.';
+  SErrInvalidDelimiter = 'Invalid set delimiter: %s';
+  SErrInvalidDelimiterValue = 'Invalid set delimiter %s value: %s in "%s"';
+  SErrNoPartials = 'No partials list';
+
+  // SErrPartialNotFound = 'Partial "%s" not found.';
+  SStartTag = 'Start';
+  SStopTag = 'Stop';
+
+{ TMustachePartialList }
+
+function TMustachePartialList.FindPartial(aName: TMustacheString ): TMustacheElement;
+
+Var
+  I : Integer;
+
+begin
+  Result:=Nil;
+  I:=ChildCount-1;
+  While (Result=Nil) and (I>=0) do
+    begin
+    Result:=Children[I];
+    If (Result.Data<>aName) then
+      Result:=Nil;
+    Dec(I);
+    end;
+end;
+
+{ TMustachePartialElement }
+
+function TMustachePartialElement.GetData: TMustacheString;
+begin
+  Result:=FPartialName;
+end;
+
+procedure TMustachePartialElement.SetData(const aData: TMustacheString);
+begin
+  FPartialName:=aData;
+end;
+
+procedure TMustachePartialElement.AddChild(aChild: TMustacheElement);
+begin
+  If (FPartial<>Nil) and (aChild<>Nil) then
+    Raise EMustache.Create('Cannot set partial twice');
+  FPartial:=aChild;
+end;
+
+procedure TMustachePartialElement.Dump(aList: Tstrings;
+  aIndent: TMustacheString; aDumpChildren: Boolean);
+begin
+  inherited Dump(aList, aIndent, aDumpChildren);
+  if Prefix<>'' then
+    aList[aList.Count-1]:=aList[aList.Count-1]+' Prefix: "'+Prefix+'"';
+end;
+
+function TMustachePartialElement.GetPrefix: TMustacheString;
+begin
+  Result:=FPrefix;
+end;
+
+procedure TMustachePartialElement.SetPrefix(aValue: TMustacheString);
+begin
+  FPrefix:=aValue;
+end;
+
+procedure TMustachePartialElement.Render(aContext: TMustacheContext;
+  aOutput: TMustacheOutput; const aPrefix : String = ''; aLast : Boolean = False);
+
+begin
+  FPartial.Render(aContext,aOutput,Prefix);
+end;
+
+destructor TMustachePartialElement.Destroy;
+begin
+  inherited Destroy;
+end;
+
+
+{ TMustache }
+
+function TMustache.CreateParser(aTemplate : TMustacheString): TMustacheParser;
+begin
+  Result:=TMustacheParser.Create(aTemplate);
+end;
+
+constructor TMustache.Create(aOwner: TComponent);
+begin
+  Inherited;
+  FPartials:=TStringList.Create;
+  FCompiledPartials:=CreatePartials;
+end;
+
+destructor TMustache.Destroy;
+begin
+  Reset;
+  FreeAndNil(FPartials);
+  FreeAndNil(FCompiledPartials);
+  inherited Destroy;
+end;
+
+procedure TMustache.Compile;
+
+Var
+  Parser : TMustacheParser;
+
+begin
+  Parser:=CreateParser(Self.Template);
+  try
+    Parser.OnGetPartial:=@DoGetPartial;
+    //Parser.Template:=Self.Template;
+    Parser.Partials:=Self.FCompiledPartials;
+    if Self.StartTag<>'' then
+      Parser.StartTag:=Self.StartTag;
+    if Self.StopTag<>'' then
+      Parser.StopTag:=Self.StopTag;
+    FCompiled:=Parser.Parse;
+  finally
+    Parser.Free;
+  end;
+end;
+
+procedure TMustache.Dump(aList: Tstrings; aindent: TMustacheString);
+begin
+  if Assigned(Compiled) then
+    Compiled.Dump(aList,aIndent);
+end;
+
+function TMustache.Dump: TMustacheString;
+
+Var
+  I : integer;
+  L : TStrings;
+
+begin
+  L:=TStringList.Create;
+  try
+    Dump(L,'');
+    if Partials.Count>0 then
+      begin
+      L.Add('Partials:');
+      for I:=0 to Partials.Count-1 do
+        L.Add('Partial '+IntToStr(I)+': '+Partials[i]);
+      L.Add('End of partials');
+      end;
+    Result:=L.Text;
+  finally
+    L.Free;
+  end;
+end;
+
+procedure TMustache.Render(aContext: TMustacheContext; aOutput: TMustacheOutput);
+
+begin
+  if not Assigned(Compiled) then
+    Compile;
+  Compiled.Render(aContext,aOutput);
+end;
+
+function TMustache.Render(aContext: TMustacheContext): TMustacheString;
+
+Var
+  S : TMustacheStringOutput;
+
+begin
+  S:=TMustacheStringOutput.Create;
+  try
+    Render(aContext,S);
+    Result:=S.Data;
+  finally
+    S.Free;
+  end;
+end;
+
+function TMustache.Render(const aJSON: TJSONData): TMustacheString;
+
+Var
+  C : TMustacheJSONContext;
+
+begin
+  C:=TMustacheJSONContext.Create(aJSON,FOnGetValue);
+  try
+    Result:=Render(C);
+  finally
+    C.Free;
+  end;
+end;
+
+function TMustache.Render(const aJSON: TJSONStringType): TMustacheString;
+
+Var
+  JSONData : TJSONData;
+
+begin
+  JSONData:=GetJSON(aJSON);
+  try
+    Result:=Render(JSONData);
+  finally
+    JSONData.Free;
+  end;
+end;
+
+class function TMustache.CreateMustache(aOwner : TComponent; aTemplate : TMustacheString) : TMustache;
+
+begin
+  Result:=TMustache.Create(aOwner);
+  Result.Template:=aTemplate;
+end;
+
+procedure TMustache.SetStartTag(AValue: TMustacheString);
+begin
+  if FStartTag=AValue then Exit;
+  FStartTag:=AValue;
+  Reset;
+end;
+
+procedure TMustache.SetPartials(AValue: TStrings);
+begin
+  if FPartials=AValue then Exit;
+  FPartials.Assign(AValue);
+end;
+
+procedure TMustache.SetStopTag(AValue: TMustacheString);
+begin
+  if FStopTag=AValue then Exit;
+  FStopTag:=AValue;
+  Reset;
+end;
+
+procedure TMustache.SetTemplate(AValue: TMustacheString);
+begin
+  if FTemplate=AValue then Exit;
+  FTemplate:=AValue;
+  Reset;
+end;
+
+procedure TMustache.DoGetPartial(const aName: TMustacheString;
+  var aHandled: Boolean; var aValue: TMustacheString);
+begin
+  aValue:=FPartials.Values[aName];
+  aHandled:=aValue<>'';
+  if Not aHandled then
+    aHandled:=FPartials.IndexOfName(aName)<>-1;
+end;
+
+procedure TMustache.Reset;
+begin
+  FreeAndNil(FCompiled);
+  FreeAndNil(FCompiledPartials);
+  FCompiledPartials:=CreatePartials;
+end;
+
+function TMustache.CreatePartials: TMustachePartialList;
+begin
+  Result:=TMustachePartialList.Create(metRoot,Nil,0);
+end;
+
+class function TMustache.Render(aTemplate: TMustacheString;
+  const aJSON: TJSONStringType): TMustacheString;
+
+begin
+  With CreateMustache(Nil,aTemplate) do
+    try
+      Result:=Render(aJSON);
+    finally
+      Free;
+    end;
+end;
+
+{ TMustacheJSONContext }
+
+function TMustacheJSONContext.FindValue(const aName: TMustacheString
+  ): TJSONData;
+Var
+  aCount : Integer;
+  N : TMustacheString;
+
+begin
+  Result:=Nil;
+  aCount:=FCount-1;
+  While (Result=Nil) and (aCount>=0) do
+    begin
+    N:=aName;
+    if N='.' then
+      N:='';
+    With FStack[aCount] do
+      if (Index>=0) and (Index<Value.Count) then
+        Result:=Value.Items[Index].FindPath(N)
+      else
+        Result:=Value.FindPath(N);
+    Dec(aCount);
+    end;
+end;
+
+function TMustacheJSONContext.GetRootData: TJSONData;
+begin
+  Result:=FStack[0].Value;
+end;
+
+
+constructor TMustacheJSONContext.Create(aJSON: TJSONData;
+  aCallback: TGetTextValueEvent);
+begin
+  Inherited Create(aCallBack);
+  SetLength(FStack,JSONListGrowCount);
+  FStack[0].Value:=aJSON;
+  FStack[0].Index:=-1;
+  FCount:=1;
+end;
+
+function TMustacheJSONContext.MoveNextSectionItem(const aName: TMustacheString
+  ): Boolean;
+
+begin
+  With FStack[FCount-1] do
+    begin
+    Inc(Index);
+    Result:=Index<Value.Count;
+    end;
+end;
+
+function TMustacheJSONContext.PushSection(const aName: TMustacheString
+  ): TMustacheSectionType;
+
+Var
+  S : TJSONData;
+
+begin
+  Result:=mstNone;
+  S:=FindValue(aName);
+  if S=Nil then
+    Exit;
+  if (S.JSONType=jtArray) then
+    begin
+    if (S.Count>0) then
+      Result:=mstList
+    end
+  else if Not ((S.JSONType=jtNull) or ((S.JSONType=jtBoolean) and Not S.AsBoolean)) then
+     Result:=mstSingle;
+  if Result<>mstNone then
+    begin
+    if FCount=Length(FStack) then
+      SetLength(FStack,FCount+JSONListGrowCount);
+    FStack[FCount].Value:=S;
+    FStack[FCount].Index:=-1;
+    Inc(FCount,1);
+    end;
+end;
+
+procedure TMustacheJSONContext.PopSection(const aName: TMustacheString);
+begin
+  if FCount<1 then
+    Raise EMustache.CreateFmt('PopSection %s without push',[aName]);
+  Dec(FCount,1);
+end;
+
+function TMustacheJSONContext.GetTextValue(const aName: TMustacheString): TMustacheString;
+
+Var
+  aJSON : TJSONData;
+
+begin
+  Result:='';
+  aJSON:=FindValue(aName);
+  if not Assigned(aJSON) then
+    Result:=Inherited GetTextValue(aName)
+  else
+    if (AJSON.JSONType=jtNumber) and (TJSONNumber(aJSON).NumberType=ntFloat) then
+      Result:=FormatFloat('0.0###########',aJSON.AsFloat)
+    else
+      Result:=aJSON.AsString;
+end;
+
+{ TMustacheSectionElement }
+
+procedure TMustacheSectionElement.Render(aContext: TMustacheContext;
+  aOutput: TMustacheOutput; const aPrefix: String; aLast : Boolean = False);
+
+Var
+  L : TMustacheSectionType;
+
+begin
+   L:=aContext.PushSection(Name);
+   if ElementType=metInvertedSection then
+     begin
+     if L=mstNone then
+       inherited Render(aContext, aOutput,aPrefix);
+     end
+   else
+     Case L of
+     mstSingle :
+        inherited Render(aContext, aOutput);
+     mstList :
+        while aContext.MoveNextSectionItem(Name) do
+          inherited Render(aContext, aOutput,aPrefix);
+     end;
+  if L<>mstNone then
+    aContext.PopSection(Name);
+end;
+
+{ TMustacheContext }
+
+constructor TMustacheContext.Create(aCallback: TGetTextValueEvent);
+begin
+  FCallback:=aCallback;
+end;
+
+class function TMustacheContext.QuoteHTML(aString: TMustacheString
+  ): TMustacheString;
+
+Const
+  QuoteChars = ['<','>','&','"'];
+
+Var
+  I,Last,Len : Integer;
+  Res : TMustacheString;
+
+  Procedure AddToResult; overload;
+
+  begin
+    Res:=Res+Copy(aString,Last,I-Last);
+    Last:=I;
+  end;
+
+  Procedure AddToResult(aTerm : TMustacheString); overload;
+
+  begin
+    Res:=Res+aTerm;
+    Last:=Last+1;
+  end;
+
+begin
+  Res:='';
+  Last:=1;
+  Len:=Length(Astring);
+  I:=1;
+  While (I<=Len) do
+    begin
+    While (I<=Len) and not (aString[i] in QuoteChars) do
+      Inc(I);
+    AddToResult;
+    if I<=Len then
+      Case aString[i] of
+        '<' : AddToResult('&lt;');
+        '>' : AddToResult('&gt;');
+        '&' : AddToResult('&amp;');
+        '"' : AddToResult('&quot;');
+      end;
+    Inc(i);
+    end;
+  AddToResult;
+  Result:=Res;
+end;
+
+function TMustacheContext.MoveNextSectionItem(const aName: TMustacheString): Boolean;
+begin
+  Result:=False
+end;
+
+function TMustacheContext.PushSection(const aName: TMustacheString): TMustacheSectionType;
+begin
+  Result:=mstNone;
+end;
+
+procedure TMustacheContext.PopSection(const aName: TMustacheString);
+begin
+  //
+end;
+
+function TMustacheContext.GetTextValue(const aName: TMustacheString): TMustacheString;
+
+var
+  aHandled : Boolean;
+
+begin
+  aHandled:=False;
+  Result:='';
+  if Assigned(FCallBack) then
+    FCallBack(aName,aHandled,Result);
+end;
+
+{ TMustacheTextElement }
+
+procedure TMustacheTextElement.SetData(const aData: TMustacheString);
+begin
+  FData:=aData;
+end;
+
+function TMustacheTextElement.GetData: TMustacheString;
+begin
+  Result:=FData;
+end;
+
+procedure TMustacheTextElement.Render(aContext: TMustacheContext;
+  aOutput: TMustacheOutput; const aPrefix: String; aLast : Boolean = False);
+
+Var
+  S : String;
+  L : Integer;
+
+begin
+  if (ElementType=metText) then
+    begin
+    S:=FData;
+    L:=Length(S);
+    if (aPrefix<>'')  then
+      begin
+      if (S[L]=#10) and aLast then
+        S:=StringReplace(Copy(S,1,L-1),#10,#10+aPrefix,[rfReplaceAll])+#10
+      else
+        S:=StringReplace(S,#10,#10+aPrefix,[rfReplaceAll]);
+{$IFDEF DEBUGMUSTACHE}
+      Writeln('Adding prefix =]',aPrefix,'[= to =]',FData, '[=  --->  =]',S,'["');
+{$ENDIF}
+      end;
+    aOutput.Output(S);
+    end;
+end;
+
+{ TMustacheVariableElement }
+
+procedure TMustacheVariableElement.SetData(const aData: TMustacheString);
+
+Var
+  L : Integer;
+  N : TMustacheString;
+begin
+  N:=aData;
+  L:=Length(N);
+  FNoUnescape:=(L>1) and (N[1]='{') and (N[L]='}');
+  if NoUnescape then
+    N:=Copy(N,2,L-2)
+  else
+    begin
+    FNoUnescape:=(L>0) and (N[1]='&');
+    if NoUnescape then
+      N:=Copy(N,2,L-1);
+    end;
+  inherited SetData(N);
+end;
+
+procedure TMustacheVariableElement.Render(aContext: TMustacheContext;
+  aOutput: TMustacheOutput; const aPrefix: String; aLast : Boolean = False);
+
+Var
+  aValue : TMustacheString;
+
+begin
+  aValue:='';
+  if Assigned(aContext) then
+    begin
+    aValue:=aContext.GetTextValue(Name);
+    if Not NoUnescape then
+      aValue:=aContext.QuoteHTML(aValue);
+    end;
+  aOutput.Output(aValue);
+end;
+
+{ TMustacheParser }
+
+function TMustacheParser.CreateElement(aType: TMustacheElementType; aParent : TMustacheElement; aPosition : Integer): TMustacheElement;
+
+begin
+  Result:=DefaultTypes[aType].Create(aType,aParent,aPosition);
+  if Assigned(aParent) then
+    aParent.AddChild(Result);
+end;
+
+constructor TMustacheParser.Create(aTemplate: TMustacheString; aStart: TMustacheString;
+  aStop: TMustacheString);
+begin
+  FStartTag:=aStart;
+  FStopTag:=aStop;
+  FTemplate:=aTemplate;
+  if FStartTag='' then
+    FStartTag:='{{';
+  if FStopTag='' then
+    FStopTag:='}}';
+end;
+
+class procedure TMustacheParser.SetDefaultTypeClass(aType: TMustacheElementType;
+  aClass: TMustacheElementClass);
+
+begin
+  DefaultTypes[aType]:=aClass;
+end;
+
+function TMustacheParser.GetPartial(const aName: TMustacheString): TMustacheString;
+
+Var
+  Handled : Boolean;
+begin
+  Result:='';
+  Handled:=False;
+  if Assigned(FOnGetPartial) then
+    FOnGetPartial(aName,Handled,Result);
+//  If not Handled then
+//    Raise EMustache.CreateFmt(SErrPartialNotFound,[aName]);
+end;
+
+procedure TMustacheParser.ExtractStartStop(const aName: TMustacheString; out aStart,
+  aStop: TMustacheString);
+
+  Function Invalid(S : TMustacheString) : Boolean;
+  begin
+    Invalid:=(Length(S)=0) or (Pos('=',S)<>0);
+  end;
+
+Var
+  DLen,NLen : Integer;
+  N : TMustacheString;
+
+begin
+  NLen:=Length(aName);
+  if aName[NLen]<>'=' then
+    Raise EMustache.CreateFmt(SErrInvalidDelimiter,[aName]);
+  N:=Copy(aName,1,NLen-1);
+  DLen:=(NLen-1) div 2;
+  aStart:=Trim(Copy(N,1,DLen));
+  aStop:=Trim(Copy(N,NLen-DLen,DLen));
+  // Writeln('New: "',aStart,'" - "',aStop,'" - ',DLEn);
+  if Invalid(aStop) then
+    Raise EMustache.CreateFmt(SErrInvalidDelimiterValue,[SStopTag,aStop,N]);
+  if Invalid(aStart) then
+    Raise EMustache.CreateFmt(SErrInvalidDelimiterValue,[SStartTag,aStart,N]);
+end;
+
+procedure TMustacheParser.Parse(aParent: TMustacheElement);
+
+begin
+  DoParse(aParent,FTemplate,StartTag, StopTag);
+end;
+
+function TMustacheParser.EndsOnWhiteSpace(aElement: TMustacheElement): Boolean;
+
+Var
+  I : Integer;
+  S : TMustacheString;
+
+begin
+  // if on standalone line, the entire line must be removed, see specs comments.standalone
+  Result:=(aElement.ElementType=metText);
+  s:=aElement.Data;
+  I:=Length(S);
+  While Result and (I>0) do
+     begin
+     if S[i] in [#13,#10] then
+       Break;
+     Result:=(S[I]=' ');
+     Dec(i);
+     end;
+  Result:=Result and ((I>0) or (aElement.Position=1));
+end;
+
+function TMustacheParser.GetEndingWhiteSpace(aElement: TMustacheElement): TMustacheString;
+
+Var
+  S : TMustacheString;
+  I : Integer;
+
+begin
+  s:=aElement.Data;
+  I:=Length(S);
+  While (I>0) and (S[I]=' ') do
+     Dec(i);
+  Result:=Copy(S,I+1);
+end;
+
+procedure TMustacheParser.TrimEndingWhiteSpace(aElement: TMustacheElement);
+
+Var
+  I : Integer;
+  S : TMustacheString;
+
+begin
+  s:=aElement.Data;
+  I:=Length(S);
+  While (I>0) and (S[I]=' ') do
+     Dec(i);
+  aElement.Data:=Copy(S,1,I);
+end;
+
+Function TMustacheParser.CreateDefault(aParent : TMustacheElement; aPosition : Integer;Const aName : String) : TMustacheElement;
+
+begin
+  Result:=CreateElement(metVariable,aParent,aPosition);
+  Result.SetData(aName);
+end;
+
+procedure TMustacheParser.DoParse(aParent: TMustacheElement; const aTemplate,
+  aStart, aStop: TMustacheString);
+
+Var
+  currParent : TMustacheElement;
+  aLen,clStop, lStart,lStop, NewPos, Current, Total : Integer;
+  aName,cStart,cStop,R : TMustacheString;
+  C: TMustacheChar;
+  IsWhiteSpace : Boolean;
+  Partial,WhiteSpaceEl : TMustacheELement;
+
+  Function CheckWhiteSpace : Boolean;
+
+  begin
+    WhiteSpaceEl:=Nil;
+    With CurrParent do
+      begin
+      Result:=(ChildCount=0) or EndsOnWhiteSpace(Children[ChildCount-1]);
+      if Result and (ChildCount>0) then
+         WhiteSpaceEl:=Children[ChildCount-1];
+      end;
+  end;
+
+  Procedure FinishWhiteSpace(Full : Boolean = true);
+  Var
+    I : Integer;
+  begin
+    I:=NewPos;
+    While IsWhiteSpace and (I+clStop<=Total) do
+      begin
+      C:=aTemplate[I+clStop];
+      if (C in [#13,#10]) then
+        Break;
+      isWhiteSpace:=aTemplate[I+clStop]=' ';
+      I:=I+1;
+      end;
+    if isWhiteSpace then
+      begin
+      While (I<=Total) and (aTemplate[I+clStop] in [#13,#10]) do
+        Inc(I);
+      NewPos:=I;
+      if Assigned(WhiteSpaceEl) and full then
+        TrimEndingWhiteSpace(WhiteSpaceEl);
+      end;
+  end;
+
+begin
+  currParent:=aParent;
+  cStart:=aStart;
+  cStop:=aStop;
+  lStart:=Length(cStart);
+  lStop:=Length(cStop);
+  Current:=1;
+  Total:=Length(aTemplate);
+  While (Current<=Total) do
+    begin
+    C:=Template[Current];
+    NewPos:=Pos(cStart,aTemplate,Current);
+    if NewPos=0 then
+      NewPos:=Total+1;
+    // Stash what we have till now.
+    if NewPos>Current then
+      begin
+      R:=Copy(aTemplate,Current,NewPos-Current);
+      CreateElement(metText,currParent,Current).SetData(R);
+      Current:=NewPos;
+      end;
+    if Current<Total then
+      begin
+      NewPos:=Pos(cStop,aTemplate,Current+lStart);
+      if (NewPos=0) then
+        Raise EMustache.CreateFmt(SErrUnterminatedTag,[cStart,Current]);
+      aLen:=NewPos-Current-LStart;
+      aName:=Copy(aTemplate,Current+LStart,ALen);
+      if (aName='') then
+        Raise EMustache.CreateFmt(SErrEmptyTag,[cStart,Current]);
+      C:=aName[1];
+      if C in ['=','#','^','/','!','>'] then
+        aName:=Copy(aName,2,Length(aName)-1);
+      clStop:=Lstop; // Can change.
+      case C of
+        '=' :
+          begin
+          IsWhiteSpace:=CheckWhiteSpace;
+          if IsWhiteSpace then
+            FinishWhiteSpace;
+          ExtractStartStop(aName,cStart,cStop);
+          lStart:=Length(cStart);
+          lStop:=Length(cStop);
+          //R:=Copy(aTemplate,newPos+clStop);
+          //Writeln(R);
+          end;
+        '{' :
+          begin
+          if (cStop='}}') then
+            begin
+            if (FTemplate[NewPos+lStop]<>'}') then
+              Raise EMustache.CreateFmt(SErrUnterminatedTag,[cStart,Current]);
+            inc(NewPos);
+            aName:=aName+'}';
+            end;
+          CreateElement(metVariable,currParent,Current).SetData(aName);
+          end;
+        '#' :
+          begin
+          IsWhiteSpace:=CheckWhiteSpace;
+          CurrParent:=CreateElement(metSection,currParent,Current);
+          CurrParent.SetData(aName);
+          if IsWhiteSpace then
+            FinishWhiteSpace;
+          end;
+        '!' :
+          begin
+          IsWhiteSpace:=CheckWhiteSpace;
+          CreateElement(metComment,currParent,Current).SetData(aName);
+          if IsWhiteSpace then
+            FinishWhiteSpace;
+          end;
+        '^' :
+          begin
+          IsWhiteSpace:=CheckWhiteSpace;
+          CurrParent:=CreateElement(metInvertedSection,currParent,Current);
+          CurrParent.SetData(aName);
+          if IsWhiteSpace then
+            FinishWhiteSpace;
+          end;
+        '>' :
+          begin
+          // Find or create compiled partial;
+          IsWhiteSpace:=CheckWhiteSpace;
+          aName:=Trim(aName);
+          if not Assigned(Partials) then
+            Raise EMustache.Create(SErrNoPartials);
+          Partial:=Partials.FindPartial(aName);
+          if Partial=Nil then
+            begin
+            Partial:=CreateElement(metRoot,Partials,Current);
+            Partial.Data:=aName;
+            DoParse(Partial,GetPartial(aName),FStartTag,FStopTag);
+            end;
+          // Create reference and insert into current tree
+          With CreateElement(metPartial,currParent,Current) do
+            begin
+            AddChild(Partial);
+            Data:=aName;
+            if isWhitespace and assigned(WhiteSpaceEl) then
+              Prefix:=GetEndingWhiteSpace(WhiteSpaceEl);
+            end;
+          if IsWhiteSpace then
+            FinishWhiteSpace(False);
+          end;
+        '/' :
+          begin
+          IsWhiteSpace:=CheckWhiteSpace;
+          if Not (CurrParent.ElementType in [metSection,metInvertedSection]) then
+            Raise EMustache.CreateFmt(SErrNoSectionToClose,[aName,Current])
+          else if (CurrParent.Data<>Trim(aName)) then
+            Raise EMustache.CreateFmt(SErrSectionClose,[currParent.Data,CurrParent.Position,aName,Current])
+          else
+            currParent:=currParent.Parent;
+          if IsWhiteSpace then
+            FinishWhiteSpace;
+          end
+      else
+        CreateDefault(CurrParent,Current,aName);
+      end;
+      Current:=NewPos+clStop;
+      end;
+    end;
+  if CurrParent<>aParent then
+    Raise EMustache.CreateFmt(SErrNotClosedSection,[currParent.Data,CurrParent.Position])
+
+end;
+
+function TMustacheParser.Parse: TMustacheElement;
+
+begin
+  Result:=TMustacheParentElement.Create(metRoot,Nil,1);
+  try
+    Parse(Result);
+  except
+    Result.Free;
+    Raise;
+  end;
+end;
+
+{ TMustacheNamedElement }
+
+procedure TMustacheNamedElement.SetData(Const aData: TMustacheString);
+
+begin
+  FName:=Trim(aData);
+end;
+
+function TMustacheNamedElement.GetData: TMustacheString;
+begin
+  Result:=FName;
+end;
+
+{ TMustacheParentElement }
+
+function TMustacheParentElement.GetElement(aIndex : Integer): TMustacheElement;
+begin
+  If (aIndex<0) or (aIndex>=FCount) then
+    Raise EMustache.CreateFmt(SErrInvalidIndex,[ClassName,aIndex,FCount-1]);
+  Result:=FChildren[aIndex];
+end;
+
+function TMustacheParentElement.GetCount: Integer;
+begin
+  Result:=FCount;
+end;
+
+destructor TMustacheParentElement.Destroy;
+begin
+  While FCount>0 do
+    begin
+    Dec(FCount);
+    FreeAndNil(FChildren[FCount]);
+    end;
+  inherited Destroy;
+end;
+
+
+procedure TMustacheParentElement.AddChild(aChild: TMustacheElement);
+
+Var
+  Len : Integer;
+
+begin
+  Len:=Length(FChildren);
+  if (FCount>=Len) then
+    SetLength(FChildren,Len+ListGrowCount);
+  FChildren[FCount]:=aChild;
+  Inc(FCount);
+end;
+
+procedure TMustacheParentElement.Render(aContext: TMustacheContext;
+  aOutput: TMustacheOutput; const aPrefix: String; aLast : Boolean = False);
+
+Var
+  I : integer;
+
+begin
+  For I:=0 to ChildCount-1 do
+    Children[I].Render(aContext,aOutPut,aPrefix,I=ChildCount-1);
+end;
+
+{ TMustacheElement }
+
+function TMustacheElement.GetCount: Integer;
+begin
+  Result:=0;
+end;
+
+function TMustacheElement.GetElement(aIndex : Integer): TMustacheElement;
+begin
+  Result:=Nil;
+end;
+
+function TMustacheElement.GetPrefix: TMustacheString;
+begin
+  Result:='';
+end;
+
+procedure TMustacheElement.SetPrefix(aValue: TMustacheString);
+begin
+  //
+end;
+
+procedure TMustacheElement.Dump(aList: Tstrings; aIndent: TMustacheString; aDumpChildren : Boolean = true);
+
+Var
+  I : Integer;
+
+begin
+  aList.Add(aIndent+Format('%s (%s, %d) : "%s"',[ClassName,GetEnumName(TypeInfo(TMustacheElementType),Ord(ElementType)),Position,Data]));
+  if aDumpChildren then
+    For I:=0 to ChildCount-1 do
+      Children[I].Dump(aList,'  '+aIndent);
+end;
+
+constructor TMustacheElement.Create(aType : TMustacheElementType; aParent : TMustacheElement;aPosition: Integer);
+begin
+  FType:=aType;
+  FParent:=aParent;
+  FPosition:=aPosition;
+end;
+
+procedure TMustacheElement.AddChild(aChild: TMustacheElement);
+begin
+  Raise EMustache.CreateFmt(SErrNoChildForElement,[ClassName])
+end;
+
+{ TMustacheStringOutput }
+
+procedure TMustacheStringOutput.Output(const aText: TMustacheString);
+begin
+  FData:=FData+aText;
+{$IFDEF DEBUGMUSTACHE}
+  Writeln('--');
+  Writeln('Output -]',aText,'[-');
+  Writeln('--');
+{$ENDIF}
+end;
+
+procedure TMustacheStringOutput.Reset;
+begin
+  FData:='';
+end;
+
+begin
+  TMustacheParser.SetDefaultTypeClass(metRoot,TMustacheParentElement);
+  TMustacheParser.SetDefaultTypeClass(metComment,TMustacheTextElement);
+  TMustacheParser.SetDefaultTypeClass(metText,TMustacheTextElement);
+  TMustacheParser.SetDefaultTypeClass(metVariable,TMustacheVariableElement);
+  TMustacheParser.SetDefaultTypeClass(metSection,TMustacheSectionElement);
+  TMustacheParser.SetDefaultTypeClass(metInvertedSection,TMustacheSectionElement);
+  TMustacheParser.SetDefaultTypeClass(metPartial,TMustachePartialElement);
+end.
+

File diff suppressed because it is too large
+ 0 - 0
packages/fcl-mustache/tests/spec/comments.json


File diff suppressed because it is too large
+ 0 - 0
packages/fcl-mustache/tests/spec/delimiters.json


File diff suppressed because it is too large
+ 0 - 0
packages/fcl-mustache/tests/spec/interpolation.json


File diff suppressed because it is too large
+ 0 - 0
packages/fcl-mustache/tests/spec/inverted.json


File diff suppressed because it is too large
+ 0 - 0
packages/fcl-mustache/tests/spec/partials.json


File diff suppressed because it is too large
+ 0 - 0
packages/fcl-mustache/tests/spec/sections.json


+ 290 - 0
packages/fcl-mustache/tests/tcbasemustache.pas

@@ -0,0 +1,290 @@
+{
+    This file is part of the Free Pascal Run time library.
+    Copyright (c) 2021 by Michael Van Canneyt ([email protected])
+
+    Helper classes for Mustache test cases
+
+    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.
+
+ **********************************************************************}
+unit tcbasemustache;
+
+{$mode ObjFPC}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, fpcunit, fpmustache;
+
+type
+
+  { TTestContext }
+
+  (* StringList with following encoding
+    // Null value
+    aName=<null>
+    // false value
+    aName=<null>
+    // plain value
+    aName=AValue
+    // Object value & member. Object value must be present
+    SubObj={}
+    SubObj.aName=aValue
+    // Array and members. Array value must be present
+    SubObj.SubArr=[]
+    SubObj.SubArr[0]={}
+    SubObj.SubArr[0].aName=aValue
+    SubObj.SubArr[1]={}
+    Subobj.SubArr[1].aName=aValue
+  *)
+
+  TTestContext = class (TMustacheContext)
+  Private
+    FValues : TStringList;
+    FPath : String;
+  public
+    Constructor Create(aCallback: TGetTextValueEvent); override;
+    Destructor destroy; override;
+    Function GetTextValue(Const aName : TMustacheString) : TMustacheString; override;
+    Function MoveNextSectionItem(Const aName : TMustacheString) : Boolean; override;
+    Function PushSection(Const aName : TMustacheString) : TMustacheSectionType; override;
+    Procedure PopSection(Const aName : TMustacheString); override;
+    Procedure SetValue(const aPath,aValue : string);
+    Property Values : TStringList read FValues;
+  end;
+
+  TBaseMustacheTest = class(TTestCase)
+  Private
+    FPartials: TStrings;
+    FTemplate: String;
+    FResult: TMustacheElement;
+    FParser: TMustacheParser;
+  Protected
+    Function CreateParser : TMustacheParser; virtual; abstract;
+    Procedure DoGetPartial(const aName: TMustacheString; var aHandled: Boolean;  var aValue: TMustacheString);
+  Public
+    Class Procedure AssertEquals(Msg : String; aExpected,aActual : TMustacheElementType); overload;
+    Class Function AssertElement(aParent : TMustacheElement; aIndex: Integer; aType: TMustacheElementType; aData: String; aClass : TMustacheElementClass = Nil) : TMustacheElement; overload;
+    Function AssertElement(aIndex: Integer; aType: TMustacheElementType; aData: String; aClass : TMustacheElementClass = Nil) : TMustacheElement; overload;
+    Procedure AssertResultCount(aCount : Integer);
+    procedure SetUp; override;
+    procedure TearDown; override;
+    Procedure CallParser;
+    Procedure AddPartial(Const aName,aText: TMustacheString);
+    Property Partials : TStrings Read FPartials;
+    Property Template : String Read FTemplate Write FTemplate;
+    property ParseResult : TMustacheElement Read FResult;
+    property Parser : TMustacheParser Read FParser;
+  end;
+
+
+implementation
+
+uses strutils, typinfo;
+
+{ TTestContext }
+
+constructor TTestContext.Create(aCallback: TGetTextValueEvent);
+begin
+  inherited Create(aCallback);
+  FValues:=TStringList.Create;
+  FValues.OwnsObjects:=True;
+end;
+
+destructor TTestContext.destroy;
+begin
+  FreeAndNil(FValues);
+  inherited destroy;
+end;
+
+function TTestContext.GetTextValue(const aName: TMustacheString
+  ): TMustacheString;
+
+Var
+  aPath,N : String;
+  Done : Boolean;
+begin
+  Result:='';
+  aPath:=FPath;
+  Done:=False;
+  Repeat
+    if aPath<>'' then
+      N:=aPath+'.'+aName
+    else
+      begin
+      N:=aName;
+      Done:=True;
+      end;
+    Result:=FValues.Values[N];
+    if not Done then
+      aPath:=Copy(aPath,1,RPos('.',aPath)-1);
+  until (Result<>'') or Done;
+end;
+
+function TTestContext.MoveNextSectionItem(const aName: TMustacheString
+  ): Boolean;
+
+Var
+  L,P,Idx : Integer;
+  N : String;
+
+begin
+  L:=Length(FPath);
+  if (L>0) and (FPath[L]=']') then
+    begin
+    P:=RPos('[',FPath)+1;
+    Idx:=StrToIntDef(Copy(FPath,P,L-P),-1);
+    N:=Copy(FPath,1,P-1)+IntToStr(Idx+1)+']';
+    Result:=FValues.Values[N]<>''; // We could check for {}
+    if Result then
+      FPath:=N;
+    end;
+
+end;
+
+function TTestContext.PushSection(const aName: TMustacheString): TMustacheSectionType;
+
+Var
+  aPath,S : String;
+
+begin
+  if FPath<>'' then
+    FPath:=FPath+'.';
+  aPath:=FPath+aName;
+  S:=Values.Values[aPath];
+  if S='{}' then
+    begin
+    FPath:=aPath;
+    result:=mstSingle;
+    end;
+  if S='[]' then
+    begin
+    if Values.Values[aPath+'[0]']='' then
+      Result:=mstNone
+    else
+      begin
+      FPath:=aPath+'[-1]';
+      result:=mstList;
+      end;
+    end
+  else if (s='<null>') or (s='<false>') or (s='') then
+    begin
+    Result:=mstNone;
+    end
+  else
+    begin
+    FPath:=aPath;
+    result:=mstSingle;
+    end;
+
+end;
+
+procedure TTestContext.PopSection(const aName: TMustacheString);
+begin
+  FPath:=Copy(FPath,1,RPos('.',FPath)-1);
+end;
+
+procedure TTestContext.SetValue(const aPath, aValue: string);
+begin
+  Values.Values[aPath]:=aValue;
+end;
+
+
+{ TBaseMustacheTest }
+
+procedure TBaseMustacheTest.SetUp;
+
+begin
+  Inherited;
+  FParser:=CreateParser;
+  FParser.Partials:=TMustachePartialList.Create(metRoot,Nil,0);
+  FParser.OnGetPartial:=@DoGetPartial;
+  FPartials:=TStringList.Create;
+  TStringList(FPartials).OwnsObjects:=True;
+end;
+
+procedure TBaseMustacheTest.TearDown;
+
+begin
+  FreeAndNil(FPartials);
+  FreeAndNil(FResult);
+  FParser.Partials.Free;
+  FreeAndNil(FParser);
+  Inherited;
+end;
+
+procedure TBaseMustacheTest.DoGetPartial(const aName: TMustacheString;
+  var aHandled: Boolean; var aValue: TMustacheString);
+begin
+  aValue:=FPartials.Values[aName];
+  aHandled:=FPartials.IndexOfName(aName)<>-1;
+end;
+
+class function TBaseMustacheTest.AssertElement(aParent: TMustacheElement;
+  aIndex: Integer; aType: TMustacheElementType; aData: String;
+  aClass: TMustacheElementClass): TMustacheElement;
+Var
+  El : TMustacheElement;
+  aChild : String;
+begin
+  AssertNotNull('Have parent',aParent);
+  AssertTrue(Format('Index %d in range 0..%d',[aIndex,aParent.ChildCount-1]),(aIndex>=0) and (aIndex<aParent.ChildCount));
+  EL:=aParent.Children[aIndex];
+  aChild:=Format('Child %d',[aIndex]);
+  AssertNotNull('Have result '+aChild,El);
+  AssertEquals(aChild+' has correct type',aType,El.ElementType);
+  AssertEquals(aChild+' has correct data',aData,El.Data);
+  if (aClass<>Nil) then
+    AssertEquals(aChild+' has correct class',aClass,el.Classtype);
+  Result:=El;
+end;
+
+function TBaseMustacheTest.AssertElement(aIndex: Integer;
+  aType: TMustacheElementType; aData: String; aClass : TMustacheElementClass = Nil): TMustacheElement;
+
+begin
+  AssertNotNull('Have result',FResult);
+  Result:=AssertElement(FResult,aIndex,aType,aData,aClass);
+end;
+
+procedure TBaseMustacheTest.AssertResultCount(aCount: Integer);
+begin
+  AssertNotNull('Have result',FResult);
+  AssertEquals('Result count',aCount,FResult.ChildCount);
+end;
+
+
+procedure TBaseMustacheTest.CallParser;
+
+begin
+  Parser.Template:=Template;
+  FResult:=Parser.Parse;
+end;
+
+procedure TBaseMustacheTest.AddPartial(const aName, aText: TMustacheString);
+
+//Var
+//  T : TMustacheTextElement;
+
+begin
+//  T:=TMustacheTextElement.Create(metText,Nil,0);
+//  T.Data:=aText;
+  FPartials.Add(aName+'='+atext);
+end;
+
+class procedure TBaseMustacheTest.AssertEquals(Msg: String; aExpected,
+  aActual: TMustacheElementType);
+
+begin
+  AssertEquals(Msg,GetEnumName(typeInfo(TMustacheElementType),Ord(aExpected)),
+                       GetEnumName(typeInfo(TMustacheElementType),Ord(aActual)));
+end;
+
+
+end.
+

+ 149 - 0
packages/fcl-mustache/tests/tcdbmustache.pas

@@ -0,0 +1,149 @@
+{
+    This file is part of the Free Pascal Run time library.
+    Copyright (c) 2021 by Michael Van Canneyt ([email protected])
+
+    Test cases for DB Context for Mustache
+
+    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.
+
+ **********************************************************************}
+unit tcdbmustache;
+
+{$mode ObjFPC}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, fpcunit, testregistry, fpmustache, db, bufdataset, fpdbmustache;
+
+Type
+
+  { TTestMustacheDBContext }
+
+  TTestMustacheDBContext = Class(TTestCase)
+  private
+    FContext: TMustacheDBContext;
+    FDataset1: TBufDataset;
+    FDataset2: TBufDataset;
+    FMustache: TMustache;
+  Public
+    Procedure Setup; override;
+    Procedure TearDown; override;
+    Procedure CreateDataset1;
+    Procedure CreateDataset2;
+    Property Dataset1 : TBufDataset Read FDataset1;
+    Property Dataset2 : TBufDataset Read FDataset2;
+    Property Context : TMustacheDBContext Read FContext;
+    Property Mustache : TMustache Read FMustache;
+  Published
+    Procedure TestEmpty;
+    Procedure TestSingleSection;
+    Procedure TestTwoSections;
+  end;
+
+implementation
+
+Const
+  Template1 = '{{title}}! {{#Parents}}{{name}} {{age}} - {{/Parents}}';
+  Template2 = '{{title}}! {{#Parents}}{{name}}({{age}}) : {{#Children}}{{name}} {{age}},{{/Children}} - {{/Parents}}';
+
+{ TTestMustacheDBContext }
+
+procedure TTestMustacheDBContext.Setup;
+begin
+  Inherited;
+  FDataset1:=TBufDataset.Create(Nil);
+  FDataset1.Name:='Parents';
+  FDataset2:=TBufDataset.Create(Nil);
+  FDataset2.Name:='Children';
+  FContext:=TMustacheDBContext.Create(Nil);
+  FContext.StaticValues.Values['title']:='Family';
+  FMustache:=TMustache.Create(Nil);
+end;
+
+procedure TTestMustacheDBContext.TearDown;
+begin
+  FreeAndNil(FDataset1);
+  FreeAndNil(FDataset2);
+  FreeAndNil(FContext);
+  FreeAndNil(FMustache);
+end;
+
+procedure TTestMustacheDBContext.CreateDataset1;
+begin
+  FDataset1.FieldDefs.Add('name',ftString,20);
+  FDataset1.FieldDefs.Add('age',ftInteger);
+  FDataset1.CreateDataset;
+  FDataset1.Append;
+  FDataset1.FieldByName('name').AsString:='Father';
+  FDataset1.FieldByName('age').AsInteger:=40;
+  FDataset1.Post;
+  FDataset1.Append;
+  FDataset1.FieldByName('name').AsString:='Mother';
+  FDataset1.FieldByName('age').AsInteger:=39;
+  FDataset1.Post;
+  FDataset1.First;
+end;
+
+procedure TTestMustacheDBContext.CreateDataset2;
+begin
+  FDataset2.FieldDefs.Add('name',ftString,20);
+  FDataset2.FieldDefs.Add('age',ftInteger);
+  FDataset2.CreateDataset;
+  FDataset2.Append;
+  FDataset2.FieldByName('name').AsString:='Child1';
+  FDataset2.FieldByName('age').AsInteger:=4;
+  FDataset2.Post;
+  FDataset2.Append;
+  FDataset2.FieldByName('name').AsString:='Child2';
+  FDataset2.FieldByName('age').AsInteger:=2;
+  FDataset2.Post;
+  FDataset2.First;
+end;
+
+procedure TTestMustacheDBContext.TestEmpty;
+begin
+  AssertNotNull('Mustache',Mustache);
+  AssertNotNull('Dataset1',Dataset1);
+  AssertNotNull('Dataset2',Dataset2);
+  AssertNotNull('Context',Context);
+  AssertEquals('Context static','Family',Context.StaticValues.Values['title']);
+end;
+
+procedure TTestMustacheDBContext.TestSingleSection;
+
+Var
+  S : String;
+
+begin
+  Mustache.Template:=Template1;
+  CreateDataset1;
+  Context.AddDataset(FDataset1);
+  S:=Mustache.Render(Context);
+  AssertEquals('Correct result','Family! Father 40 - Mother 39 - ',S);
+end;
+
+procedure TTestMustacheDBContext.TestTwoSections;
+
+Var
+  S : String;
+
+begin
+  Mustache.Template:=Template2;
+  CreateDataset1;
+  CreateDataset2;
+  Context.AddDataset(FDataset1);
+  Context.AddDataset(FDataset2);
+  S:=Mustache.Render(Context);
+  AssertEquals('Correct result','Family! Father(40) : Child1 4,Child2 2, - Mother(39) :  - ',S);
+end;
+
+initialization
+  RegisterTest(TTestMustacheDBContext);
+end.
+

+ 199 - 0
packages/fcl-mustache/tests/tcexmustache.pas

@@ -0,0 +1,199 @@
+{
+    This file is part of the Free Pascal Run time library.
+    Copyright (c) 2021 by Michael Van Canneyt ([email protected])
+
+    Test cases for expression parser support
+
+    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.
+
+ **********************************************************************}
+
+unit tcexmustache;
+
+{$mode ObjFPC}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, fpcunit, fpjson, testregistry, fpmustache, tcbasemustache, fpexmustache, fpexprpars;
+
+Type
+
+  { TTestExMustacheParser }
+
+  TTestExMustacheParser = Class(TBaseMustacheTest)
+  private
+    FExpr: TFPExpressionParser;
+    FOutput: TMustacheStringOutput;
+    FContext : TMustacheJSONContext;
+    FData : TJSONData;
+    procedure GetVar(var Result: TFPExpressionResult; ConstRef
+      AName: ShortString);
+  Public
+    Procedure SetUp; override;
+    Procedure TearDown; override;
+    Function CreateParser: TMustacheParser; override;
+    Property Expr : TFPExpressionParser Read FExpr;
+    Property Output : TMustacheStringOutput Read FOutput;
+  Published
+    Procedure TestSimple;
+    Procedure TestRenderSimple;
+    Procedure TestRenderSection;
+  end;
+
+  { TTestMustacheExpr }
+
+  TTestMustacheExpr = Class(TTestCase)
+  private
+    FJSON: TJSONObject;
+    FMustache: TMustacheExpr;
+  public
+    Procedure SetUp; override;
+    Procedure TearDown; override;
+    Property Mustache : TMustacheExpr Read FMustache;
+    Property JSON : TJSONObject Read FJSON;
+  Published
+    Procedure TestEmpty;
+    Procedure TestRegisterVariables;
+    Procedure TestRenderSection;
+    procedure TestRenderSectionStaticVariables;
+  end;
+
+
+implementation
+
+Const
+  STestJSON = '{ "data" : [ { "name": "me", "age" : 10}, { "name": "you",  "age" : 12  }, { "name": "he", "age" : 13 } ] }';
+
+{ TTestMustacheExpr }
+
+procedure TTestMustacheExpr.SetUp;
+begin
+  inherited SetUp;
+  FMustache:=TMustacheExpr.Create(Nil);
+  FJSON:=GetJSON(STestJSON) as TJSONObject;
+end;
+
+procedure TTestMustacheExpr.TearDown;
+begin
+  FreeAndNil(FJSON);
+  FreeAndNil(FMustache);
+  inherited TearDown;
+end;
+
+procedure TTestMustacheExpr.TestEmpty;
+begin
+  AssertNotNull('Have mustache instance',Mustache);
+  AssertNotNull('Have mustache expression engine instance',Mustache.ExpressionParser);
+end;
+
+procedure TTestMustacheExpr.TestRegisterVariables;
+begin
+  Mustache.RegisterVariables(JSON,'data[0]',True);
+  AssertEquals('Variable count',2,Mustache.ExpressionParser.Identifiers.Count);
+  AssertEquals('Variable 0','name',Mustache.ExpressionParser.Identifiers[0].Name);
+  AssertEquals('Variable 1','age',Mustache.ExpressionParser.Identifiers[1].Name);
+  AssertTrue('Variable 0 type',rtString=Mustache.ExpressionParser.Identifiers[0].ResultType);
+  AssertTrue('Variable 1 type',rtInteger=Mustache.ExpressionParser.Identifiers[1].ResultType);
+end;
+
+procedure TTestMustacheExpr.TestRenderSection;
+
+Var
+  S : String;
+
+Const
+  Template = '{{#data}}{{[name]}}:{{[age>11]}} {{/data}}';
+
+begin
+  Mustache.Template:=Template;
+  Mustache.RegisterVariables(JSON,'data[0]',True);
+  S:=Mustache.Render(JSON);
+  AssertEquals('Correct result','me:False you:True he:True ',S);
+end;
+
+procedure TTestMustacheExpr.TestRenderSectionStaticVariables;
+Var
+  S : String;
+
+Const
+  Template = '{{#data}}{{[name]}}:{{[age>11]}} {{/data}}';
+
+begin
+  Mustache.Template:=Template;
+  Mustache.RegisterVariables(JSON,'data[0]',False);
+  S:=Mustache.Render(JSON);
+  AssertEquals('Correct result','me:False me:False me:False ',S);
+end;
+
+
+{ TTestExMustacheParser }
+
+procedure TTestExMustacheParser.SetUp;
+begin
+  FExpr:=TFPExpressionParser.Create(Nil);
+  Foutput:=TMustacheStringOutput.Create;
+  inherited SetUp;
+end;
+
+procedure TTestExMustacheParser.TearDown;
+begin
+  inherited TearDown;
+  FreeAndNil(FExpr);
+  FreeAndNil(Foutput);
+  FreeAndNil(FContext);
+  FreeAndNil(FData);
+end;
+
+function TTestExMustacheParser.CreateParser: TMustacheParser;
+
+Var
+  P : TMustacheExprParser;
+
+begin
+  P:=TMustacheExprParser.Create;
+  P.ExprParser:=FExpr;
+  Result:=P;
+end;
+
+procedure TTestExMustacheParser.TestSimple;
+begin
+  Template:='{{[1+2]}}';
+  CallParser;
+  AssertElement(0,metVariable,'1+2',TMustacheExprElement);
+end;
+
+procedure TTestExMustacheParser.TestRenderSimple;
+begin
+  TestSimple;
+  ParseResult.Children[0].Render(Nil,Output,'',False);
+  AssertEquals('Correct result','3',Output.Data);
+end;
+
+procedure TTestExMustacheParser.GetVar(Var Result : TFPExpressionResult; ConstRef AName : ShortString);
+
+begin
+  Result.ResultType:=rtInteger;
+  Result.ResInteger:=StrToINt(FContext.GetTextValue('age'));
+end;
+
+procedure TTestExMustacheParser.TestRenderSection;
+begin
+  FData:=GetJSON(STestJSON);
+  FContext:=TMustacheJSONContext.Create(FData,Nil);
+  FExpr.Identifiers.AddVariable('age',rtInteger,@GetVar);
+  Template:='{{#data}}{{{name}}}:{{[age>11]}} {{/data}}';
+  CallParser;
+  ParseResult.Render(FContext,Output,'',False);
+  AssertEquals('Correct result','me:False you:True he:True ',Output.Data);
+end;
+
+initialization
+  RegisterTests([TTestExMustacheParser,TTestMustacheExpr]);
+end.
+

+ 728 - 0
packages/fcl-mustache/tests/tcmustache.pas

@@ -0,0 +1,728 @@
+{
+    This file is part of the Free Pascal Run time library.
+    Copyright (c) 2021 by Michael Van Canneyt ([email protected])
+
+    Test cases for basic mustache parser support
+
+    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.
+
+ **********************************************************************}
+
+unit tcmustache;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, fpcunit, testregistry, fpmustache, tcbasemustache;
+
+type
+
+  { TTestMustacheParser }
+
+
+  TTestMustacheParser= class(TBaseMustacheTest)
+  private
+  protected
+    Function CreateParser : TMustacheParser; override;
+  Public
+    procedure SetUp; override;
+    procedure TearDown; override;
+  published
+    procedure TestEmpty;
+    procedure TestText;
+    procedure TestVariable;
+    procedure TestVariableErrNonClosed;
+    procedure TestVariableAlternateStartStop;
+    procedure TestDottedVariable;
+    procedure TestVariableNoUnescape;
+    procedure TestVariableNoUnescapeErrNonClosed;
+    procedure TestVariableNoUnescapeAlternateStartStop;
+    procedure TestComment;
+    procedure TestCommentSurround;
+    procedure TestCommentStandalone;
+    procedure TestCommentStandaloneSpaced;
+    procedure TestSetDelimiter;
+    procedure TestSetDelimiterErrInvalid;
+    procedure TestSection;
+    procedure TestSectionNested;
+    procedure TestSectionErrNotClosed;
+    procedure TestSectionErrWrongClosed;
+    procedure TestSectionErrNotStarted;
+    procedure TestTextSection;
+    procedure TestPartial;
+  end;
+
+  { TTestMustacheOutput }
+
+  TTestMustacheOutput = class(TTestCase)
+  Published
+    Procedure TestStringOutput;
+  end;
+
+  { TTestMustacheElement }
+
+  TTestMustacheElement = class(TTestCase)
+  private
+    FContext: TTestContext;
+    FEl: TMustacheElement;
+    Foutput: TMustacheStringOutput;
+    procedure DoCallBack(const aName: TMustacheString; var aHandled: Boolean;
+      var aValue: TMustacheString);
+  Public
+    Procedure SetUp; override;
+    Procedure TearDown; override;
+    Property Context : TTestContext Read FContext;
+    Property Output : TMustacheStringOutput Read Foutput;
+    Property El : TMustacheElement Read FEl;
+  Published
+    Procedure TestEmpty;
+    Procedure TestTextElement;
+    Procedure TestTextElementNoEscape;
+    Procedure TestTextElementComment;
+    Procedure TestTextElementPrefix;
+    procedure TestTextElementPrefixNotLast;
+    procedure TestTextElementPrefixLast;
+    Procedure TestVariableElement;
+    Procedure TestVariableElementNoEscape;
+    Procedure TestVariableElementEscape;
+    Procedure TestSectionEmpty;
+    Procedure TestSectionValue;
+    Procedure TestSectionValueFalse;
+    Procedure TestSectionValueNull;
+    Procedure TestSectionValueEmptyArray;
+    Procedure TestSectionValueArray1El;
+    Procedure TestSectionValueArray2El;
+    Procedure TestSectionValueArray2ElValue;
+    Procedure TestSectionValueArray1ElValueSuper;
+    Procedure TestSectionValueArray2ElValueSuper;
+    Procedure TestParentElement;
+    Procedure TestParentElementRender;
+    Procedure TestParentElementRenderPrefix;
+  end;
+
+implementation
+
+uses Typinfo;
+
+Const
+  SNeedsQuoting = '< > & "';
+  SQuotedResult = '&lt; &gt; &amp; &quot;';
+
+
+{ TTestMustacheElement }
+
+procedure TTestMustacheElement.DoCallBack(const aName: TMustacheString;
+  var aHandled: Boolean; var aValue: TMustacheString);
+begin
+  aValue:='';
+end;
+
+procedure TTestMustacheElement.SetUp;
+begin
+  inherited SetUp;
+  FOutput:=TMustacheStringOutput.Create;
+  FContext:=TTestContext.Create(@DoCallBack);
+end;
+
+procedure TTestMustacheElement.TearDown;
+begin
+  FreeAndNil(FContext);
+  FreeAndNil(FOutput);
+  FreeAndNil(FEl);
+  inherited TearDown;
+end;
+
+procedure TTestMustacheElement.TestEmpty;
+begin
+  AssertNotNull('Have output',Output);
+end;
+
+procedure TTestMustacheElement.TestTextElement;
+
+begin
+  Fel:=TMustacheTextElement.Create(metText,Nil,0);
+  El.Render(Nil,Output);
+  AssertEquals('No output','',Output.Data);
+  El.Data:='me';
+  El.Render(Nil,Output);
+  AssertEquals('Correct output','me',Output.Data);
+end;
+
+procedure TTestMustacheElement.TestTextElementNoEscape;
+begin
+  Fel:=TMustacheTextElement.Create(metText,Nil,0);
+  El.Data:=SNeedsQuoting;
+  El.Render(Nil,Output);
+  AssertEquals('Correct output',SNeedsQuoting,Output.Data);
+end;
+
+procedure TTestMustacheElement.TestTextElementComment;
+begin
+  Fel:=TMustacheTextElement.Create(metComment,Nil,0);
+  El.Data:='Something';
+  El.Render(Nil,Output);
+  AssertEquals('Correct output','',Output.Data);
+end;
+
+procedure TTestMustacheElement.TestTextElementPrefix;
+begin
+  Fel:=TMustacheTextElement.Create(metText,Nil,0);
+  El.Data:='me'#10'you';
+  El.Render(Nil,Output,'  ');
+  AssertEquals('Correct output 1','me'#10'  you',Output.Data);
+end;
+
+procedure TTestMustacheElement.TestTextElementPrefixNotLast;
+begin
+  Fel:=TMustacheTextElement.Create(metText,Nil,0);
+  El.Data:='me'#10'you'#10;
+  El.Render(Nil,Output,'  ');
+  AssertEquals('Correct output 2','me'#10'  you'#10'  ',Output.Data);
+end;
+
+procedure TTestMustacheElement.TestTextElementPrefixLast;
+
+begin
+  Fel:=TMustacheTextElement.Create(metText,Nil,0);
+  El.Data:='me'#10'you'#10;
+  El.Render(Nil,Output,'  ',True);
+  AssertEquals('Correct output 2','me'#10'  you'#10,Output.Data);
+end;
+
+
+procedure TTestMustacheElement.TestVariableElement;
+begin
+  Fel:=TMustacheVariableElement.Create(metText,Nil,0);
+  Context.Values.Values['name']:='abc';
+  El.Data:='name';
+  El.Render(Context,Output);
+  AssertEquals('Correct output','abc',Output.Data);
+end;
+
+
+procedure TTestMustacheElement.TestVariableElementNoEscape;
+begin
+  Fel:=TMustacheVariableElement.Create(metText,Nil,0);
+  Context.Values.Values['name']:=SNeedsQuoting;
+  El.Data:='{name}';
+  El.Render(Context,Output);
+  AssertEquals('Correct output',SNeedsQuoting,Output.Data);
+end;
+
+procedure TTestMustacheElement.TestVariableElementEscape;
+begin
+  Fel:=TMustacheVariableElement.Create(metText,Nil,0);
+  Context.Values.Values['name']:=SNeedsQuoting;
+  El.Data:='name';
+  El.Render(Context,Output);
+  AssertEquals('Correct output',SQuotedResult,Output.Data);
+end;
+
+procedure TTestMustacheElement.TestSectionEmpty;
+
+Var
+  T : TMustacheTextElement;
+
+begin
+  Fel:=TMustacheSectionElement.Create(metSection,Nil,0);
+  Fel.Data:='s';
+  T:=TMustacheTextElement.Create(metText,Nil,0);
+  Fel.AddChild(T);
+  T.Data:='a';
+  Fel.Render(Context,Output);
+  AssertEquals('No output','',Output.Data);
+end;
+
+procedure TTestMustacheElement.TestSectionValue;
+Var
+  T : TMustacheTextElement;
+
+begin
+  Context.SetValue('s','b');
+  Fel:=TMustacheSectionElement.Create(metSection,Nil,0);
+  Fel.Data:='s';
+  T:=TMustacheTextElement.Create(metText,Nil,0);
+  Fel.AddChild(T);
+  T.Data:='a';
+  Fel.Render(Context,Output);
+  AssertEquals('Single pass','a',Output.Data);
+end;
+
+procedure TTestMustacheElement.TestSectionValueFalse;
+Var
+  T : TMustacheTextElement;
+
+begin
+  Context.SetValue('s','<false>');
+  Fel:=TMustacheSectionElement.Create(metSection,Nil,0);
+  Fel.Data:='s';
+  T:=TMustacheTextElement.Create(metText,Nil,0);
+  Fel.AddChild(T);
+  T.Data:='a';
+  Fel.Render(Context,Output);
+  AssertEquals('no pass','',Output.Data);
+end;
+
+procedure TTestMustacheElement.TestSectionValueNull;
+
+Var
+  T : TMustacheTextElement;
+
+begin
+  Context.SetValue('s','<null>');
+  Fel:=TMustacheSectionElement.Create(metSection,Nil,0);
+  Fel.Data:='s';
+  T:=TMustacheTextElement.Create(metText,Nil,0);
+  Fel.AddChild(T);
+  T.Data:='a';
+  Fel.Render(Context,Output);
+  AssertEquals('no pass','',Output.Data);
+end;
+
+procedure TTestMustacheElement.TestSectionValueEmptyArray;
+Var
+  T : TMustacheTextElement;
+
+begin
+  Context.SetValue('s','[]');
+  Fel:=TMustacheSectionElement.Create(metSection,Nil,0);
+  Fel.Data:='s';
+  T:=TMustacheTextElement.Create(metText,Nil,0);
+  Fel.AddChild(T);
+  T.Data:='a';
+  Fel.Render(Context,Output);
+  AssertEquals('no pass','',Output.Data);
+end;
+
+procedure TTestMustacheElement.TestSectionValueArray1El;
+Var
+  T : TMustacheTextElement;
+
+begin
+  Context.SetValue('s','[]');
+  Context.SetValue('s[0]','toto');
+  Fel:=TMustacheSectionElement.Create(metSection,Nil,0);
+  Fel.Data:='s';
+  T:=TMustacheTextElement.Create(metText,Nil,0);
+  Fel.AddChild(T);
+  T.Data:='a';
+  Fel.Render(Context,Output);
+  AssertEquals('Single pass','a',Output.Data);
+end;
+
+procedure TTestMustacheElement.TestSectionValueArray2El;
+
+Var
+  T : TMustacheTextElement;
+
+begin
+  Context.SetValue('s','[]');
+  Context.SetValue('s[0]','toto');
+  Context.SetValue('s[1]','tata');
+  Fel:=TMustacheSectionElement.Create(metSection,Nil,0);
+  Fel.Data:='s';
+  T:=TMustacheTextElement.Create(metText,Nil,0);
+  Fel.AddChild(T);
+  T.Data:='a';
+  Fel.Render(Context,Output);
+  AssertEquals('Double pass','aa',Output.Data);
+end;
+
+procedure TTestMustacheElement.TestSectionValueArray2ElValue;
+
+Var
+  T : TMustacheElement;
+
+begin
+  Context.SetValue('s','[]');
+  Context.SetValue('s[0]','{}');
+  Context.SetValue('s[0].a','1');
+  Context.SetValue('s[1]','{}');
+  Context.SetValue('s[1].a','2');
+  Fel:=TMustacheSectionElement.Create(metSection,Nil,0);
+  Fel.Data:='s';
+  T:=TMustacheVariableElement.Create(metVariable,Nil,0);
+  Fel.AddChild(T);
+  T.Data:='a';
+  Fel.Render(Context,Output);
+  AssertEquals('Double pass','12',Output.Data);
+end;
+
+procedure TTestMustacheElement.TestSectionValueArray1ElValueSuper;
+
+Var
+  T : TMustacheElement;
+
+begin
+  Context.SetValue('s','[]');
+  Context.SetValue('s[0]','{}');
+  Context.SetValue('s[0].b','1');
+  Context.SetValue('a','2');
+  Fel:=TMustacheSectionElement.Create(metSection,Nil,0);
+  Fel.Data:='s';
+  T:=TMustacheVariableElement.Create(metVariable,Nil,0);
+  Fel.AddChild(T);
+  T.Data:='a';
+  Fel.Render(Context,Output);
+  AssertEquals('Single pass','2',Output.Data);
+end;
+
+procedure TTestMustacheElement.TestSectionValueArray2ElValueSuper;
+Var
+  T : TMustacheElement;
+
+begin
+  Context.SetValue('s','[]');
+  Context.SetValue('s[0]','{}');
+  Context.SetValue('s[0].b','1');
+  Context.SetValue('s[1]','{}');
+  Context.SetValue('s[1].b','2');
+  Context.SetValue('a','.a.');
+  Fel:=TMustacheSectionElement.Create(metSection,Nil,0);
+  Fel.Data:='s';
+  T:=TMustacheVariableElement.Create(metVariable,Nil,0);
+  Fel.AddChild(T);
+  T.Data:='a';
+  T:=TMustacheVariableElement.Create(metVariable,Nil,0);
+  Fel.AddChild(T);
+  T.Data:='b';
+  Fel.Render(Context,Output);
+  AssertEquals('Single pass','.a.1.a.2',Output.Data);
+end;
+
+procedure TTestMustacheElement.TestParentElement;
+
+Var
+  SEl : TMustacheElement;
+
+begin
+  Fel:=TMustacheParentElement.Create(metSection,Nil,0);
+  Sel:=TMustacheTextElement.Create(metText,Fel,0);
+  AssertSame('Parent stored',Fel,Sel.Parent);
+  AssertEquals('Not added to parent',0,FEl.ChildCount);
+  Fel.AddChild(Sel);
+  AssertEquals('added to parent - count',1,FEl.ChildCount);
+  AssertSame('added to parent - stored',Sel,FEl.Children[0]);
+end;
+
+procedure TTestMustacheElement.TestParentElementRender;
+
+Var
+  SEl : TMustacheElement;
+
+begin
+  Fel:=TMustacheParentElement.Create(metSection,Nil,0);
+  Sel:=TMustacheTextElement.Create(metText,Fel,0);
+  Sel.Data:='a';
+  Fel.AddChild(Sel);
+  Sel:=TMustacheTextElement.Create(metText,Fel,0);
+  Sel.Data:='b';
+  Fel.AddChild(Sel);
+  Sel:=TMustacheTextElement.Create(metText,Fel,0);
+  Sel.Data:='c';
+  Fel.AddChild(Sel);
+  Fel.Render(Context,Output);
+  AssertEquals('Correct output','abc',Output.Data);
+end;
+
+procedure TTestMustacheElement.TestParentElementRenderPrefix;
+Var
+  SEl : TMustacheElement;
+
+begin
+  Fel:=TMustacheParentElement.Create(metSection,Nil,0);
+  Sel:=TMustacheTextElement.Create(metText,Fel,0);
+  Sel.Data:='a'#10'b';
+  Fel.AddChild(Sel);
+  Sel:=TMustacheTextElement.Create(metText,Fel,0);
+  Sel.Data:='d'#10'e';
+  Fel.AddChild(Sel);
+  Sel:=TMustacheTextElement.Create(metText,Fel,0);
+  Sel.Data:='f'#10;
+  Fel.AddChild(Sel);
+  Fel.Render(Context,Output,'  ');
+  AssertEquals('Correct output','a'#10'  bd'#10'  ef'#10,Output.Data);
+end;
+
+{ TTestMustacheOutput }
+
+procedure TTestMustacheOutput.TestStringOutput;
+
+Var
+  SO : TMustacheStringOutput;
+
+begin
+  SO:=TMustacheStringOutput.Create;
+  try
+     AssertEquals('Empty start','',SO.Data);
+     SO.Output('abc');
+     AssertEquals('Output 1','abc',SO.Data);
+     SO.Output('def');
+     AssertEquals('Output 2','abcdef',SO.Data);
+  finally
+    SO.Free;
+  end;
+
+end;
+
+function TTestMustacheParser.CreateParser: TMustacheParser;
+begin
+  Result:=TMustacheParser.Create;
+end;
+
+procedure TTestMustacheParser.SetUp;
+begin
+  inherited SetUp;
+end;
+
+procedure TTestMustacheParser.TearDown;
+begin
+  inherited TearDown;
+end;
+
+procedure TTestMustacheParser.TestEmpty;
+
+begin
+  AssertNotNull('Have parser',Parser);
+  AssertNull('Have no result',ParseResult);
+  AssertEquals('Have no template','',Template);
+end;
+
+
+procedure TTestMustacheParser.TestText;
+
+begin
+  Template:='a simple text';
+  CallParser;
+  AssertResultCount(1);
+  AssertElement(0,metText,'a simple text');
+end;
+
+procedure TTestMustacheParser.TestVariable;
+
+Var
+  el : TMustacheVariableElement;
+
+begin
+  Template:='{{a}}';
+  CallParser;
+  AssertResultCount(1);
+  el:=AssertElement(0,metVariable,'a',TMustacheVariableElement) as TMustacheVariableElement;
+  AssertFalse('unescape',El.NoUnescape);
+end;
+
+procedure TTestMustacheParser.TestVariableErrNonClosed;
+
+begin
+  Template:='{{a';
+  AssertException('Have error',EMustache,@CallParser,'Tag {{ opened on position 1 but not closed.');
+  Template:='{{a}';
+  AssertException('Have error',EMustache,@CallParser,'Tag {{ opened on position 1 but not closed.');
+end;
+
+procedure TTestMustacheParser.TestVariableAlternateStartStop;
+Var
+  el : TMustacheVariableElement;
+
+begin
+  Parser.StartTag:='<<';
+  Parser.StopTag:='>>';
+  Template:='<<a>>';
+  CallParser;
+  AssertResultCount(1);
+  el:=AssertElement(0,metVariable,'a',TMustacheVariableElement) as TMustacheVariableElement;
+  AssertFalse('unescape',El.NoUnescape);
+end;
+
+procedure TTestMustacheParser.TestDottedVariable;
+begin
+  Template:='{{a.b}}';
+  CallParser;
+  AssertResultCount(1);
+  AssertElement(0,metVariable,'a.b');
+end;
+
+procedure TTestMustacheParser.TestVariableNoUnescape;
+Var
+  el : TMustacheVariableElement;
+
+begin
+  Template:='{{{a}}}';
+  CallParser;
+  AssertResultCount(1);
+  el:=AssertElement(0,metVariable,'a',TMustacheVariableElement) as TMustacheVariableElement;
+  AssertTrue('unescape',El.NoUnescape);
+end;
+
+procedure TTestMustacheParser.TestVariableNoUnescapeErrNonClosed;
+begin
+  Template:='{{{a';
+  AssertException('Have error',EMustache,@CallParser,'Tag {{ opened on position 1 but not closed.');
+  Template:='{{{a}';
+  AssertException('Have error',EMustache,@CallParser,'Tag {{ opened on position 1 but not closed.');
+  Template:='{{{a}}';
+  AssertException('Have error',EMustache,@CallParser,'Tag {{ opened on position 1 but not closed.');
+end;
+
+procedure TTestMustacheParser.TestVariableNoUnescapeAlternateStartStop;
+
+Var
+  el : TMustacheVariableElement;
+
+begin
+  Parser.StartTag:='<<';
+  Parser.StopTag:='>>';
+  Template:='<<{a}>>';
+  CallParser;
+  AssertResultCount(1);
+  el:=AssertElement(0,metVariable,'a',TMustacheVariableElement) as TMustacheVariableElement;
+  AssertTrue('unescape',El.NoUnescape);
+end;
+
+procedure TTestMustacheParser.TestComment;
+
+begin
+  Parser.StartTag:='<<';
+  Parser.StopTag:='>>';
+  Template:='<<! a comment>>';
+  CallParser;
+  AssertResultCount(1);
+  AssertElement(0,metComment,' a comment',TMustacheTextElement);
+end;
+
+procedure TTestMustacheParser.TestCommentSurround;
+begin
+  Template:='ab{{! a comment}}cd';
+  CallParser;
+  AssertResultCount(3);
+  AssertElement(0,metText,'ab',TMustacheTextElement);
+  AssertElement(1,metComment,' a comment',TMustacheTextElement);
+  AssertElement(2,metText,'cd',TMustacheTextElement);
+end;
+
+procedure TTestMustacheParser.TestCommentStandalone;
+begin
+  Template:='a'+sLineBreak+'{{! a comment}}'+sLineBreak+'b';
+  CallParser;
+  AssertResultCount(3);
+  AssertElement(0,metText,'a'+sLineBreak,TMustacheTextElement);
+  AssertElement(1,metComment,' a comment',TMustacheTextElement);
+  AssertElement(2,metText,'b',TMustacheTextElement);
+end;
+
+procedure TTestMustacheParser.TestCommentStandaloneSpaced;
+begin
+  Template:='a'+sLineBreak+'  {{! a comment}}  '+sLineBreak+'b';
+  CallParser;
+  AssertResultCount(3);
+  AssertElement(0,metText,'a'+sLineBreak,TMustacheTextElement);
+  AssertElement(1,metComment,' a comment',TMustacheTextElement);
+  AssertElement(2,metText,'b',TMustacheTextElement);
+end;
+
+procedure TTestMustacheParser.TestSetDelimiter;
+
+begin
+  Template:='{{=<< >>=}}<<! a comment>>';
+  CallParser;
+  AssertResultCount(1);
+  AssertElement(0,metComment,' a comment',TMustacheTextElement);
+end;
+
+procedure TTestMustacheParser.TestSetDelimiterErrInvalid;
+begin
+  Template:='{{=== ===}}';
+  AssertException('Have error',EMustache,@CallParser,'Invalid set delimiter Stop value: == in "== =="');
+end;
+
+procedure TTestMustacheParser.TestSection;
+
+Var
+  el : TMustacheSectionElement;
+
+begin
+  Template:='{{#a}}{{/a}}';
+  CallParser;
+  AssertResultCount(1);
+  el:=AssertElement(0,metSection,'a',TMustacheSectionElement) as TMustacheSectionElement;
+  AssertEquals('No elements in section',0,el.ChildCount);
+end;
+
+procedure TTestMustacheParser.TestSectionNested;
+
+Var
+  el : TMustacheSectionElement;
+
+begin
+  Template:='{{#a}}{{#b}}{{/b}}{{/a}}';
+  CallParser;
+  AssertResultCount(1);
+  el:=AssertElement(0,metSection,'a',TMustacheSectionElement) as TMustacheSectionElement;
+  AssertEquals('elements in section',1,el.ChildCount);
+  el:=AssertElement(el,0,metSection,'b',TMustacheSectionElement) as TMustacheSectionElement;
+  AssertEquals('elements in section sub',0,el.ChildCount);
+end;
+
+procedure TTestMustacheParser.TestSectionErrNotClosed;
+
+begin
+  Template:='{{#a}}';
+  AssertException('Have error',EMustache,@CallParser,'Structural error: Section "a" on position 1 is not closed.');
+end;
+
+procedure TTestMustacheParser.TestSectionErrWrongClosed;
+begin
+  Template:='{{#a}}{{#b}}{{/a}}{{/b}}';
+  AssertException('Have error',EMustache,@CallParser,'Structural error: Section "b" on position 7 is closed by tag "a" on position 13.');
+end;
+
+procedure TTestMustacheParser.TestSectionErrNotStarted;
+begin
+  Template:='{{/a}}';
+  AssertException('Have error',EMustache,@CallParser,'Structural error: Section "a" on position 1 was never opened.');
+end;
+
+procedure TTestMustacheParser.TestTextSection;
+
+Var
+  el : TMustacheSectionElement;
+
+begin
+  Template:='{{#a}}bbb{{/a}}';
+  CallParser;
+  AssertResultCount(1);
+  el:=AssertElement(0,metSection,'a',TMustacheSectionElement) as TMustacheSectionElement;
+  AssertEquals('No elements in section',1,el.ChildCount);
+  AssertElement(el,0,metText,'bbb');
+end;
+
+procedure TTestMustacheParser.TestPartial;
+
+Var
+  el : TMustachePartialElement;
+
+begin
+  AddPartial('part','bcd');
+  Template:='a{{>part}}e';
+  CallParser;
+  AssertResultCount(3);
+  AssertElement(0,metText,'a',TMustacheTextElement);
+  el:=AssertElement(1,metPartial,'part',TMustachePartialElement) as TMustachePartialElement;
+  AssertElement(2,metText,'e',TMustacheTextElement);
+  AssertEquals('Correct partial','part',El.Partial.Data);
+  AssertEquals('Correct partial',1,El.Partial.ChildCount);
+  AssertElement(el.Partial,0,metText,'bcd',TMustacheTextElement);
+end;
+
+
+initialization
+  RegisterTests([TTestMustacheParser,TTestMustacheOutput,TTestMustacheElement]);
+end.
+

+ 188 - 0
packages/fcl-mustache/tests/tcspecs.pas

@@ -0,0 +1,188 @@
+{
+    This file is part of the Free Pascal Run time library.
+    Copyright (c) 2021 by Michael Van Canneyt ([email protected])
+
+    testcase for official Mustache tests
+
+    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.
+
+ **********************************************************************}
+unit tcspecs;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, fpcunit, testregistry, fpmustache, fpjson, jsonparser;
+
+Type
+
+  { TTestMustacheSpecs }
+
+  TTestMustacheSpecs = class(TTestCase)
+  private
+    FTests: TJSONArray;
+    procedure RunMustacheTest(aIndex: Integer; aTest: TJSONObject);
+  Public
+    class var BaseDir : string;
+  Public
+    Procedure Setup; override;
+    Procedure TearDown; override;
+    Procedure DoTest(aFileName : string);
+    Property Tests : TJSONArray Read FTests;
+  Published
+    Procedure TestComments;
+    Procedure TestDelimiters;
+    Procedure TestInterpolation;
+    Procedure TestInverted;
+    Procedure TestPartials;
+    Procedure TestSections;
+  end;
+
+
+implementation
+
+{ TTestMustacheSpecs }
+
+procedure TTestMustacheSpecs.RunMustacheTest(aIndex : Integer; aTest : TJSONObject);
+
+Var
+  M : TMustache;
+  aTempl,aErr,aRes,aName : TMustacheString;
+  Parts : TJSONObject;
+  I : Integer;
+  Ok : Boolean;
+
+  Procedure TreeDump;
+
+  begin
+    if not OK then
+      begin
+      Writeln('Tree dump:');
+      Writeln(M.Dump);
+      end;
+  end;
+
+  Procedure InputDump;
+
+  begin
+    Writeln('Test : ',aIndex);
+    writeln(aTempl);
+    writeln(StringReplace(StringReplace(aTempl,#10,' ',[rfReplaceAll]),#13,' ',[rfReplaceAll]));
+    aName:='';
+    While Length(aName)<Length(aTempl) do
+      aName:=AName+'1234567890';
+    Writeln(aName);
+  end;
+
+begin
+  OK:=False;
+  aTempl:=aTest.Get('template','');
+  // InputDump;
+  M:=TMustache.CreateMustache(Nil,aTempl);
+  try
+    // Load partials
+    Parts:=aTest.Get('partials',TJSONObject(Nil));
+    if Assigned(Parts) then
+      for I:=0 to Parts.Count-1 do
+        M.Partials.Add(Parts.Names[i]+'='+Parts.Items[i].AsString);
+    // Set test name and run tests
+    aName:='Test '+IntToStr(aIndex)+': '+aTest.Get('name','');
+    Try
+      aErr:='';
+      aRes:=m.Render(aTest.Get('data',TJSONObject(Nil)));
+    except
+      on e : exception do
+        aErr:=E.ClassName+' '+E.message;
+    end;
+    if aErr<>'' then
+      Fail(aName+': Unexpected error: '+aErr);
+    AssertEquals(aName,aTest.Get('expected',''),aRes);
+    OK:=true;
+  finally
+    // TreeDump;
+    M.Free;
+  end;
+end;
+
+procedure TTestMustacheSpecs.Setup;
+begin
+  inherited Setup;
+end;
+
+procedure TTestMustacheSpecs.TearDown;
+begin
+  inherited TearDown;
+end;
+
+procedure TTestMustacheSpecs.DoTest(aFileName: string);
+
+Var
+  I : Integer;
+  F : TFileStream;
+  D : TJSONData;
+  FN : String;
+
+begin
+  D:=Nil;
+  FN:=IncludeTrailingPathDelimiter(BaseDir)+aFileName+'.json';
+  F:=TFileStream.Create(FN,fmOpenRead or fmShareDenyWrite);
+  try
+    D:=GetJSON(F);
+    if D is TJSONObject then
+      begin
+      Ftests:=(D as TJSONObject).Get('tests',TJSONArray(Nil));
+      if (FTests=Nil) then
+        Fail('Invalid mustache tests in '+FN);
+      end
+    else
+      Fail('Invalid JSON object in '+FN);
+    For I:=0 to Tests.Count-1 do
+      RunMustacheTest(I,Tests.Items[i] as TJSONObject);
+  finally
+    D.Free;
+    F.Free;
+  end;
+end;
+
+procedure TTestMustacheSpecs.TestComments;
+begin
+  DoTest('comments');
+end;
+
+procedure TTestMustacheSpecs.TestDelimiters;
+begin
+  DoTest('delimiters');
+end;
+
+procedure TTestMustacheSpecs.TestInterpolation;
+begin
+  DoTest('interpolation');
+end;
+
+procedure TTestMustacheSpecs.TestInverted;
+begin
+  DoTest('inverted');
+end;
+
+procedure TTestMustacheSpecs.TestPartials;
+begin
+  DoTest('partials');
+end;
+
+procedure TTestMustacheSpecs.TestSections;
+begin
+  DoTest('sections');
+end;
+
+begin
+  TTestMustacheSpecs.BaseDir:='spec/';
+  RegisterTest(TTestMustacheSpecs);
+end.
+

+ 88 - 0
packages/fcl-mustache/tests/testmustache.lpi

@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CONFIG>
+  <ProjectOptions>
+    <Version Value="12"/>
+    <General>
+      <Flags>
+        <SaveOnlyProjectUnits Value="True"/>
+        <MainUnitHasCreateFormStatements Value="False"/>
+        <MainUnitHasTitleStatement Value="False"/>
+        <MainUnitHasScaledStatement Value="False"/>
+      </Flags>
+      <SessionStorage Value="InProjectDir"/>
+      <Title Value="testmustache"/>
+      <UseAppBundle Value="False"/>
+      <ResourceType Value="res"/>
+    </General>
+    <BuildModes>
+      <Item Name="Default" Default="True"/>
+    </BuildModes>
+    <PublishOptions>
+      <Version Value="2"/>
+      <UseFileFilters Value="True"/>
+    </PublishOptions>
+    <RunParams>
+      <FormatVersion Value="2"/>
+    </RunParams>
+    <RequiredPackages>
+      <Item>
+        <PackageName Value="FCL"/>
+      </Item>
+    </RequiredPackages>
+    <Units>
+      <Unit>
+        <Filename Value="testmustache.lpr"/>
+        <IsPartOfProject Value="True"/>
+      </Unit>
+      <Unit>
+        <Filename Value="tcmustache.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit>
+      <Unit>
+        <Filename Value="tcspecs.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit>
+      <Unit>
+        <Filename Value="tcexmustache.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit>
+      <Unit>
+        <Filename Value="tcbasemustache.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit>
+      <Unit>
+        <Filename Value="tcdbmustache.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit>
+    </Units>
+  </ProjectOptions>
+  <CompilerOptions>
+    <Version Value="11"/>
+    <Target>
+      <Filename Value="testmustache"/>
+    </Target>
+    <SearchPaths>
+      <IncludeFiles Value="$(ProjOutDir)"/>
+      <OtherUnitFiles Value="../src"/>
+      <UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/>
+    </SearchPaths>
+    <Linking>
+      <Debugging>
+        <UseHeaptrc Value="True"/>
+      </Debugging>
+    </Linking>
+  </CompilerOptions>
+  <Debugging>
+    <Exceptions>
+      <Item>
+        <Name Value="EAbort"/>
+      </Item>
+      <Item>
+        <Name Value="ECodetoolError"/>
+      </Item>
+      <Item>
+        <Name Value="EFOpenError"/>
+      </Item>
+    </Exceptions>
+  </Debugging>
+</CONFIG>

+ 29 - 0
packages/fcl-mustache/tests/testmustache.lpr

@@ -0,0 +1,29 @@
+program testmustache;
+
+{$mode objfpc}{$H+}
+
+uses
+  Classes, consoletestrunner, tcmustache, tcspecs,
+  tcexmustache, tcbasemustache, tcdbmustache;
+
+type
+
+  { TMyTestRunner }
+
+  TMyTestRunner = class(TTestRunner)
+  protected
+  // override the protected methods of TTestRunner to customize its behavior
+  end;
+
+var
+  Application: TMyTestRunner;
+
+begin
+  DefaultFormat:=fPlain;
+  DefaultRunAllTests:=True;
+  Application := TMyTestRunner.Create(nil);
+  Application.Initialize;
+  Application.Title := 'FPCUnit Console test runner';
+  Application.Run;
+  Application.Free;
+end.

+ 50 - 9
packages/fcl-passrc/src/pasresolver.pp

@@ -1690,6 +1690,7 @@ type
     procedure FinishMethodImplHeader(ImplProc: TPasProcedure); virtual;
     procedure FinishMethodImplHeader(ImplProc: TPasProcedure); virtual;
     procedure FinishExceptOnExpr; virtual;
     procedure FinishExceptOnExpr; virtual;
     procedure FinishExceptOnStatement; virtual;
     procedure FinishExceptOnStatement; virtual;
+    procedure FinishParserSpecializeType(El: TPasSpecializeType); virtual;
     procedure FinishWithDo(El: TPasImplWithDo); virtual;
     procedure FinishWithDo(El: TPasImplWithDo); virtual;
     procedure FinishForLoopHeader(Loop: TPasImplForLoop); virtual;
     procedure FinishForLoopHeader(Loop: TPasImplForLoop); virtual;
     procedure FinishDeclaration(El: TPasElement); virtual;
     procedure FinishDeclaration(El: TPasElement); virtual;
@@ -2153,6 +2154,7 @@ type
     function PushHelperDotScope(HiType: TPasType): TPasDotBaseScope;
     function PushHelperDotScope(HiType: TPasType): TPasDotBaseScope;
     function PushTemplateDotScope(TemplType: TPasGenericTemplateType; ErrorEl: TPasElement): TPasDotBaseScope;
     function PushTemplateDotScope(TemplType: TPasGenericTemplateType; ErrorEl: TPasElement): TPasDotBaseScope;
     function PushDotScope(HiType: TPasType): TPasDotBaseScope;
     function PushDotScope(HiType: TPasType): TPasDotBaseScope;
+    function PushParserSpecializeType(SpecType: TPasSpecializeType): TPasDotBaseScope;
     function PushWithExprScope(Expr: TPasExpr): TPasWithExprScope;
     function PushWithExprScope(Expr: TPasExpr): TPasWithExprScope;
     function StashScopes(NewScopeCnt: integer): integer; // returns old StashDepth
     function StashScopes(NewScopeCnt: integer): integer; // returns old StashDepth
     function StashSubExprScopes: integer; // returns old StashDepth
     function StashSubExprScopes: integer; // returns old StashDepth
@@ -5238,6 +5240,9 @@ begin
       begin
       begin
       // El is the first element found -> raise error
       // El is the first element found -> raise error
       // ToDo: use the ( as error position
       // ToDo: use the ( as error position
+      {$IFDEF VerbosePasResolver}
+      writeln('TPasResolver.OnFindCallElements El=',GetObjPath(El));
+      {$ENDIF}
       RaiseMsg(20170216151525,nIllegalQualifierAfter,sIllegalQualifierAfter,
       RaiseMsg(20170216151525,nIllegalQualifierAfter,sIllegalQualifierAfter,
         ['(',El.ElementTypeName],Data^.Params);
         ['(',El.ElementTypeName],Data^.Params);
       end;
       end;
@@ -7606,6 +7611,12 @@ begin
   PopScope;
   PopScope;
 end;
 end;
 
 
+procedure TPasResolver.FinishParserSpecializeType(El: TPasSpecializeType);
+begin
+  if El=nil then ;
+  PopScope;
+end;
+
 procedure TPasResolver.FinishWithDo(El: TPasImplWithDo);
 procedure TPasResolver.FinishWithDo(El: TPasImplWithDo);
 begin
 begin
   PopWithScope(El);
   PopWithScope(El);
@@ -18120,6 +18131,13 @@ begin
   SpecializeElList(GenEl,SpecEl,GenEl.Params,SpecEl.Params,true
   SpecializeElList(GenEl,SpecEl,GenEl.Params,SpecEl.Params,true
     {$IFDEF CheckPasTreeRefCount},'TPasSpecializeType.Params'{$ENDIF});
     {$IFDEF CheckPasTreeRefCount},'TPasSpecializeType.Params'{$ENDIF});
 
 
+  if GenEl.SubType<>nil then
+    begin
+    PushParserSpecializeType(SpecEl);
+    SpecializeElType(GenEl,SpecEl,GenEl.SubType,SpecEl.SubType);
+    PopScope;
+    end;
+
   FinishSpecializeType(SpecEl);
   FinishSpecializeType(SpecEl);
   {$IFDEF VerbosePasResolver}
   {$IFDEF VerbosePasResolver}
   //writeln('TPasResolver.SpecializeSpecializeType ',GetObjName(SpecEl.DestType),' ',GetObjName(SpecEl.CustomData));
   //writeln('TPasResolver.SpecializeSpecializeType ',GetObjName(SpecEl.DestType),' ',GetObjName(SpecEl.CustomData));
@@ -21807,6 +21825,7 @@ end;
 procedure TPasResolver.BeginScope(ScopeType: TPasScopeType; El: TPasElement);
 procedure TPasResolver.BeginScope(ScopeType: TPasScopeType; El: TPasElement);
 begin
 begin
   case ScopeType of
   case ScopeType of
+  stSpecializeType: PushParserSpecializeType(El as TPasSpecializeType);
   stWithExpr: PushWithExprScope(El as TPasExpr);
   stWithExpr: PushWithExprScope(El as TPasExpr);
   else
   else
     RaiseMsg(20181210163324,nNotYetImplemented,sNotYetImplemented+' BeginScope',[IntToStr(ord(ScopeType))],nil);
     RaiseMsg(20181210163324,nNotYetImplemented,sNotYetImplemented+' BeginScope',[IntToStr(ord(ScopeType))],nil);
@@ -21824,9 +21843,10 @@ begin
   stResourceString: FinishResourcestring(El as TPasResString);
   stResourceString: FinishResourcestring(El as TPasResString);
   stProcedure: FinishProcedure(El as TPasProcedure);
   stProcedure: FinishProcedure(El as TPasProcedure);
   stProcedureHeader: FinishProcedureType(El as TPasProcedureType);
   stProcedureHeader: FinishProcedureType(El as TPasProcedureType);
+  stSpecializeType: FinishParserSpecializeType(El as TPasSpecializeType);
+  stWithExpr: FinishWithDo(El as TPasImplWithDo);
   stExceptOnExpr: FinishExceptOnExpr;
   stExceptOnExpr: FinishExceptOnExpr;
   stExceptOnStatement: FinishExceptOnStatement;
   stExceptOnStatement: FinishExceptOnStatement;
-  stWithExpr: FinishWithDo(El as TPasImplWithDo);
   stForLoopHeader: FinishForLoopHeader(El as TPasImplForLoop);
   stForLoopHeader: FinishForLoopHeader(El as TPasImplForLoop);
   stDeclaration: FinishDeclaration(El);
   stDeclaration: FinishDeclaration(El);
   stAncestors: FinishAncestors(El as TPasClassType);
   stAncestors: FinishAncestors(El as TPasClassType);
@@ -22784,6 +22804,12 @@ begin
     Result:=PushHelperDotScope(HiType);
     Result:=PushHelperDotScope(HiType);
 end;
 end;
 
 
+function TPasResolver.PushParserSpecializeType(SpecType: TPasSpecializeType
+  ): TPasDotBaseScope;
+begin
+  Result:=PushDotScope(SpecType.DestType);
+end;
+
 function TPasResolver.PushWithExprScope(Expr: TPasExpr): TPasWithExprScope;
 function TPasResolver.PushWithExprScope(Expr: TPasExpr): TPasWithExprScope;
 var
 var
   WithEl: TPasImplWithDo;
   WithEl: TPasImplWithDo;
@@ -25520,6 +25546,7 @@ function TPasResolver.ResolvedElIsClassOrRecordInstance(
   const ResolvedEl: TPasResolverResult): boolean;
   const ResolvedEl: TPasResolverResult): boolean;
 var
 var
   TypeEl: TPasType;
   TypeEl: TPasType;
+  C: TClass;
 begin
 begin
   Result:=false;
   Result:=false;
   if ResolvedEl.BaseType<>btContext then exit;
   if ResolvedEl.BaseType<>btContext then exit;
@@ -25532,10 +25559,14 @@ begin
   else if TypeEl.ClassType=TPasRecordType then
   else if TypeEl.ClassType=TPasRecordType then
   else
   else
     exit;
     exit;
-  if (ResolvedEl.IdentEl is TPasVariable)
-      or (ResolvedEl.IdentEl.ClassType=TPasArgument)
-      or (ResolvedEl.IdentEl.ClassType=TPasResultElement) then
-    exit(true);
+  if ResolvedEl.IdentEl<>nil then
+    begin
+    C:=ResolvedEl.IdentEl.ClassType;
+    if C.InheritsFrom(TPasVariable)
+        or (C=TPasArgument)
+        or (C=TPasResultElement) then
+      exit(true);
+    end;
 end;
 end;
 
 
 function TPasResolver.GetResolver(El: TPasElement): TPasResolver;
 function TPasResolver.GetResolver(El: TPasElement): TPasResolver;
@@ -27709,7 +27740,9 @@ procedure TPasResolver.ComputeElement(El: TPasElement; out
   var
   var
     TypeEl: TPasType;
     TypeEl: TPasType;
   begin
   begin
-    if SpecType.CustomData is TPasSpecializeTypeData then
+    if SpecType.SubType<>nil then
+      ComputeElement(SpecType.SubType,ResolvedEl,Flags,StartEl)
+    else if SpecType.CustomData is TPasSpecializeTypeData then
       begin
       begin
       TypeEl:=TPasSpecializeTypeData(SpecType.CustomData).SpecializedType;
       TypeEl:=TPasSpecializeTypeData(SpecType.CustomData).SpecializedType;
       if TypeEl=nil then
       if TypeEl=nil then
@@ -28393,6 +28426,7 @@ function TPasResolver.ResolveAliasType(aType: TPasType; SkipTypeAlias: boolean
   ): TPasType;
   ): TPasType;
 var
 var
   C: TClass;
   C: TClass;
+  SpecType: TPasSpecializeType;
 begin
 begin
   while aType<>nil do
   while aType<>nil do
     begin
     begin
@@ -28406,9 +28440,16 @@ begin
       aType:=NoNil(TResolvedReference(aType.CustomData).Declaration) as TPasType
       aType:=NoNil(TResolvedReference(aType.CustomData).Declaration) as TPasType
     else if C=TPasSpecializeType then
     else if C=TPasSpecializeType then
       begin
       begin
-      if aType.CustomData is TPasSpecializeTypeData then
-        exit(TPasSpecializeTypeData(aType.CustomData).SpecializedType);
-      aType:=TPasSpecializeType(aType).DestType;
+      SpecType:=TPasSpecializeType(aType);
+      if SpecType.SubType<>nil then
+        // e.g. a<b>.c
+        aType:=SpecType.SubType
+      else
+        begin
+        if SpecType.CustomData is TPasSpecializeTypeData then
+          exit(TPasSpecializeTypeData(SpecType.CustomData).SpecializedType);
+        aType:=SpecType.DestType;
+        end;
       end
       end
     else
     else
       exit(aType);
       exit(aType);

+ 1 - 0
packages/fcl-passrc/src/pasuseanalyzer.pas

@@ -2471,6 +2471,7 @@ begin
     if Param is TPasGenericTemplateType then continue;
     if Param is TPasGenericTemplateType then continue;
     UseElement(Param,rraRead,false);
     UseElement(Param,rraRead,false);
     end;
     end;
+  UseElType(El,El.SubType,Mode);
 end;
 end;
 
 
 procedure TPasAnalyzer.UseVariable(El: TPasVariable;
 procedure TPasAnalyzer.UseVariable(El: TPasVariable;

+ 5 - 2
packages/fcl-passrc/src/pparser.pp

@@ -157,6 +157,7 @@ type
     stResourceString, // e.g. TPasResString
     stResourceString, // e.g. TPasResString
     stProcedure, // also method, procedure, constructor, destructor, ...
     stProcedure, // also method, procedure, constructor, destructor, ...
     stProcedureHeader,
     stProcedureHeader,
+    stSpecializeType, // calls BeginScope to resolve c in a<b>.c
     stWithExpr, // calls BeginScope after parsing every WITH-expression
     stWithExpr, // calls BeginScope after parsing every WITH-expression
     stExceptOnExpr,
     stExceptOnExpr,
     stExceptOnStatement,
     stExceptOnStatement,
@@ -1766,6 +1767,8 @@ begin
     ReadSpecializeArguments(ST,ST.Params);
     ReadSpecializeArguments(ST,ST.Params);
     if CurToken<>tkGreaterThan then
     if CurToken<>tkGreaterThan then
       ParseExcTokenError('[20190801113005]');
       ParseExcTokenError('[20190801113005]');
+    // Important: resolve type reference AFTER args, because arg count is needed
+    ST.DestType:=ResolveTypeReference(GenName,ST,ST.Params.Count);
 
 
     // Check for cascaded specialize A<B>.C or A<B>.C<D>
     // Check for cascaded specialize A<B>.C or A<B>.C<D>
     NextToken;
     NextToken;
@@ -1774,10 +1777,10 @@ begin
     else
     else
       begin
       begin
       NextToken;
       NextToken;
+      Engine.BeginScope(stSpecializeType,ST);
       ST.SubType:=ParseSimpleType(ST,CurSourcePos,GenName,False);
       ST.SubType:=ParseSimpleType(ST,CurSourcePos,GenName,False);
+      Engine.FinishScope(stSpecializeType,ST);
       end;
       end;
-    // Important: resolve type reference AFTER args, because arg count is needed
-    ST.DestType:=ResolveTypeReference(GenName,ST,ST.Params.Count);
 
 
     Engine.FinishScope(stTypeDef,ST);
     Engine.FinishScope(stTypeDef,ST);
     Result:=ST;
     Result:=ST;

+ 27 - 0
packages/fcl-passrc/tests/tcresolvegenerics.pas

@@ -157,6 +157,7 @@ type
     procedure TestGenProc_TypeParamCntOverloadNoParams;
     procedure TestGenProc_TypeParamCntOverloadNoParams;
     procedure TestGenProc_TypeParamWithDefaultParamDelphiFail;
     procedure TestGenProc_TypeParamWithDefaultParamDelphiFail;
     procedure TestGenProc_ParamSpecWithT;
     procedure TestGenProc_ParamSpecWithT;
+    procedure TestGenProc_ParamSpecWithTNestedType;
     // ToDo: NestedResultAssign
     // ToDo: NestedResultAssign
 
 
     // generic function infer types
     // generic function infer types
@@ -2554,6 +2555,32 @@ begin
   ParseProgram;
   ParseProgram;
 end;
 end;
 
 
+procedure TTestResolveGenerics.TestGenProc_ParamSpecWithTNestedType;
+begin
+  StartProgram(false);
+  Add([
+  '{$mode delphi}',
+  'type',
+  '  TObject = class end;',
+  '  TBird<T> = class',
+  '  type',
+  '    TEvent = procedure(aSender: T);',
+  '  end;',
+  'procedure Fly<T>(Event: TBird<T>.TEvent; Sender: T);',
+  'begin',
+  '  Event(Sender);',
+  'end;',
+  'procedure Run(aSender: TObject);',
+  'begin',
+  'end;',
+  'var',
+  '  Bird: TBird<TObject>;',
+  'begin',
+  '  Fly<TObject>(@Run,Bird);',
+  '']);
+  ParseProgram;
+end;
+
 procedure TTestResolveGenerics.TestGenProc_Infer_NeedExplicitFail;
 procedure TTestResolveGenerics.TestGenProc_Infer_NeedExplicitFail;
 begin
 begin
   StartProgram(false);
   StartProgram(false);

+ 13 - 3
packages/fcl-web/src/base/custhttpapp.pp

@@ -21,7 +21,7 @@ unit custhttpapp;
 Interface
 Interface
 
 
 uses
 uses
-  Classes, SysUtils, httpdefs, custweb, ssockets,  fphttpserver;
+  Classes, SysUtils, httpdefs, custweb, ssockets,  fphttpserver, sslbase;
 
 
 Type
 Type
   TCustomHTTPApplication = Class;
   TCustomHTTPApplication = Class;
@@ -76,7 +76,6 @@ Type
     Procedure InitResponse(AResponse : TResponse); override;
     Procedure InitResponse(AResponse : TResponse); override;
     function WaitForRequest(out ARequest : TRequest; out AResponse : TResponse) : boolean; override;
     function WaitForRequest(out ARequest : TRequest; out AResponse : TResponse) : boolean; override;
     Function CreateServer : TEmbeddedHttpServer; virtual;
     Function CreateServer : TEmbeddedHttpServer; virtual;
-    Property HTTPServer : TEmbeddedHttpServer Read FServer;
   Public
   Public
     Procedure Run; override;
     Procedure Run; override;
     Procedure Terminate; override;
     Procedure Terminate; override;
@@ -104,6 +103,8 @@ Type
     Property UseSSL : Boolean Read GetUseSSL Write SetUseSSL;
     Property UseSSL : Boolean Read GetUseSSL Write SetUseSSL;
     // HostName to use when using SSL
     // HostName to use when using SSL
     Property HostName : String Read GetHostName Write SetHostName;
     Property HostName : String Read GetHostName Write SetHostName;
+    // Access to server so you can set certificate data
+    Property HTTPServer : TEmbeddedHttpServer Read FServer;
   end;
   end;
 
 
   { TCustomHTTPApplication }
   { TCustomHTTPApplication }
@@ -111,6 +112,7 @@ Type
   TCustomHTTPApplication = Class(TCustomWebApplication)
   TCustomHTTPApplication = Class(TCustomWebApplication)
   private
   private
     procedure FakeConnect;
     procedure FakeConnect;
+    function GetCertificateData: TCertificateData;
     function GetHostName: String;
     function GetHostName: String;
     function GetIdle: TNotifyEvent;
     function GetIdle: TNotifyEvent;
     function GetIDleTimeOut: Cardinal;
     function GetIDleTimeOut: Cardinal;
@@ -133,9 +135,10 @@ Type
     procedure SetUseSSL(AValue: Boolean);
     procedure SetUseSSL(AValue: Boolean);
   protected
   protected
     function InitializeWebHandler: TWebHandler; override;
     function InitializeWebHandler: TWebHandler; override;
-    Function HTTPHandler : TFPHTTPServerHandler;
   Public
   Public
     procedure Terminate; override;
     procedure Terminate; override;
+    // Access to HTTP handler
+    Function HTTPHandler : TFPHTTPServerHandler;
     Property Address : string Read GetAddress Write SetAddress;
     Property Address : string Read GetAddress Write SetAddress;
     Property Port : Word Read GetPort Write SetPort Default 80;
     Property Port : Word Read GetPort Write SetPort Default 80;
     // Max connections on queue (for Listen call)
     // Max connections on queue (for Listen call)
@@ -154,6 +157,8 @@ Type
     Property UseSSL : Boolean Read GetUseSSL Write SetUseSSL;
     Property UseSSL : Boolean Read GetUseSSL Write SetUseSSL;
     // Hostname to use when using SSL
     // Hostname to use when using SSL
     Property HostName : String Read GetHostName Write SetHostName;
     Property HostName : String Read GetHostName Write SetHostName;
+    // Access to certificate data
+    Property CertificateData : TCertificateData Read GetCertificateData;
   end;
   end;
 
 
 
 
@@ -296,6 +301,11 @@ begin
   end
   end
 end;
 end;
 
 
+function TCustomHTTPApplication.GetCertificateData: TCertificateData;
+begin
+  Result:=HTTPHandler.HTTPServer.CertificateData;
+end;
+
 function TCustomHTTPApplication.GetHostName: String;
 function TCustomHTTPApplication.GetHostName: String;
 begin
 begin
   Result:=HTTPHandler.HostName;
   Result:=HTTPHandler.HostName;

+ 1 - 0
packages/fpmake_add.inc

@@ -145,4 +145,5 @@
   add_ide(ADirectory+IncludeTrailingPathDelimiter('ide'));
   add_ide(ADirectory+IncludeTrailingPathDelimiter('ide'));
   add_vclcompat(ADirectory+IncludeTrailingPathDelimiter('vcl-compat'));
   add_vclcompat(ADirectory+IncludeTrailingPathDelimiter('vcl-compat'));
   add_qlunits(ADirectory+IncludeTrailingPathDelimiter('qlunits'));
   add_qlunits(ADirectory+IncludeTrailingPathDelimiter('qlunits'));
+  add_mustache(ADirectory+IncludeTrailingPathDelimiter('fcl-mustache'));
   
   

+ 6 - 0
packages/fpmake_proc.inc

@@ -821,4 +821,10 @@ begin
 {$include qlunits/fpmake.pp}
 {$include qlunits/fpmake.pp}
 end;
 end;
 
 
+procedure add_mustache(const ADirectory: string);
+begin
+  with Installer do
+{$include fcl-mustache/fpmake.pp}
+end;
+
 {$include ide/fpmake.pp}
 {$include ide/fpmake.pp}

+ 85 - 30
packages/fpmkunit/src/fpmkunit.pp

@@ -1230,6 +1230,7 @@ Type
     FInteractive : boolean;
     FInteractive : boolean;
     FProgressMax : integer;
     FProgressMax : integer;
     FProgressCount : integer;
     FProgressCount : integer;
+    FIndentCount : integer;
     FExternalPackages : TPackages;
     FExternalPackages : TPackages;
     // Events
     // Events
     FOnLog: TLogEvent;
     FOnLog: TLogEvent;
@@ -1238,7 +1239,9 @@ Type
     FOnFinishCopy: TNotifyEvent;
     FOnFinishCopy: TNotifyEvent;
 
 
     FCachedlibcPath: string;
     FCachedlibcPath: string;
+{$ifndef NO_THREADING}
     FGeneralCriticalSection: TRTLCriticalSection;
     FGeneralCriticalSection: TRTLCriticalSection;
+{$endif NO_THREADING}
 {$ifdef HAS_UNIT_ZIPPER}
 {$ifdef HAS_UNIT_ZIPPER}
     FZipper: TZipper;
     FZipper: TZipper;
     FGZFileStream: TGZFileStream;
     FGZFileStream: TGZFileStream;
@@ -1452,6 +1455,7 @@ Type
     FCompilationOK: boolean;
     FCompilationOK: boolean;
     FDone: boolean;
     FDone: boolean;
     FErrorMessage: string;
     FErrorMessage: string;
+    FWorkerPrefix: string;
     FNotifyMainThreadEvent: PRTLEvent;
     FNotifyMainThreadEvent: PRTLEvent;
     FNotifyStartTask: PRTLEvent;
     FNotifyStartTask: PRTLEvent;
     FPackage: TPackage;
     FPackage: TPackage;
@@ -3407,17 +3411,17 @@ begin
       begin
       begin
       { synchronise with ReadWriteBarrier in mainthread for same reason as above }
       { synchronise with ReadWriteBarrier in mainthread for same reason as above }
       ReadWriteBarrier;
       ReadWriteBarrier;
-      FBuildEngine.log(vlInfo,'Compiling: '+APackage.Name);
+      FBuildEngine.log(vlInfo,FWorkerPrefix+'Compiling: '+APackage.Name);
       FCompilationOK:=false;
       FCompilationOK:=false;
       try
       try
         FBuildEngine.Compile(APackage);
         FBuildEngine.Compile(APackage);
         FCompilationOK:=true;
         FCompilationOK:=true;
-        FBuildEngine.log(vlInfo,'Done compiling: '+APackage.Name);
+        FBuildEngine.log(vlInfo,FWorkerPrefix+'Done compiling: '+APackage.Name);
         RaiseMainEvent;
         RaiseMainEvent;
       except
       except
         on E: Exception do
         on E: Exception do
           begin
           begin
-            FErrorMessage := 'Failed compiling: '+APackage.Name+': '+E.Message;
+            FErrorMessage := FWorkerPrefix+'Failed compiling: '+APackage.Name+': '+E.Message;
             FBuildEngine.log(vlInfo,FErrorMessage);
             FBuildEngine.log(vlInfo,FErrorMessage);
             RaiseMainEvent;
             RaiseMainEvent;
           end;
           end;
@@ -6007,6 +6011,7 @@ begin
   // With --start-dir=/path/to/sources.
   // With --start-dir=/path/to/sources.
   FStartDir:=includeTrailingPathDelimiter(GetCurrentDir);
   FStartDir:=includeTrailingPathDelimiter(GetCurrentDir);
   FExternalPackages:=TPackages.Create(TPackage);
   FExternalPackages:=TPackages.Create(TPackage);
+  FIndentCount:=0;
   FNotifyEventCollection := TNotifyEventCollection.create([neaAfterCompile, neaBeforeCompile, neaAfterInstall, neaBeforeInstall,
   FNotifyEventCollection := TNotifyEventCollection.create([neaAfterCompile, neaBeforeCompile, neaAfterInstall, neaBeforeInstall,
                                                            neaAfterClean, neaBeforeClean, neaAfterArchive, neaBeforeArchive,
                                                            neaAfterClean, neaBeforeClean, neaAfterArchive, neaBeforeArchive,
                                                            neaAfterManifest, neaBeforeManifest, neaAfterPkgList, neaBeforePkgList,
                                                            neaAfterManifest, neaBeforeManifest, neaAfterPkgList, neaBeforePkgList,
@@ -6021,6 +6026,8 @@ destructor TBuildEngine.Destroy;
 begin
 begin
   FreeAndNil(FExternalPackages);
   FreeAndNil(FExternalPackages);
   FreeAndNil(FNotifyEventCollection);
   FreeAndNil(FNotifyEventCollection);
+  If FIndentCount<>0 then
+    Log(vlDebug,Format('Log level at exit is %d',[FIndentCount]));
 
 
 {$ifndef NO_THREADING}
 {$ifndef NO_THREADING}
   DoneCriticalsection(FGeneralCriticalSection);
   DoneCriticalsection(FGeneralCriticalSection);
@@ -6419,13 +6426,33 @@ end;
 
 
 procedure TBuildEngine.LogIndent;
 procedure TBuildEngine.LogIndent;
 begin
 begin
-  GLogPrefix:=GLogPrefix+'  ';
+{$ifndef NO_THREADING}
+  EnterCriticalSection(FGeneralCriticalSection);
+{$endif NO_THREADING}
+  Inc(FIndentCount);
+  if not (vlDebug in Installer.FLogLevels) then
+    GLogPrefix:=GLogPrefix+'  '
+  else
+    GLogPrefix:=IntToStr(FIndentCount)+'> ';
+{$ifndef NO_THREADING}
+  LeaveCriticalSection(FGeneralCriticalSection);
+{$endif NO_THREADING}
 end;
 end;
 
 
 
 
 procedure TBuildEngine.LogUnIndent;
 procedure TBuildEngine.LogUnIndent;
 begin
 begin
-  Delete(GLogPrefix,1,2);
+{$ifndef NO_THREADING}
+  EnterCriticalSection(FGeneralCriticalSection);
+{$endif NO_THREADING}
+  Dec(FIndentCount);
+  if not (vlDebug in Installer.FLogLevels) then
+    Delete(GLogPrefix,1,2)
+  else
+    GLogPrefix:=IntToStr(FIndentCount)+'> ';
+{$ifndef NO_THREADING}
+  LeaveCriticalSection(FGeneralCriticalSection);
+{$endif NO_THREADING}
 end;
 end;
 
 
 
 
@@ -6433,10 +6460,19 @@ procedure TBuildEngine.Log(Level: TVerboseLevel; Msg: String);
 begin
 begin
   If Assigned(FOnLog) then
   If Assigned(FOnLog) then
     begin
     begin
+{$ifndef NO_THREADING}
+      EnterCriticalSection(FGeneralCriticalSection);
+      try
+{$endif NO_THREADING}
       if Level in [vlInfo,vlDebug] then
       if Level in [vlInfo,vlDebug] then
         FOnLog(Level,GLogPrefix+Msg)
         FOnLog(Level,GLogPrefix+Msg)
       else
       else
         FOnLog(Level,Msg);
         FOnLog(Level,Msg);
+{$ifndef NO_THREADING}
+      finally
+        LeaveCriticalSection(FGeneralCriticalSection);
+      end;
+{$endif NO_THREADING}
     end;
     end;
 end;
 end;
 
 
@@ -6905,32 +6941,34 @@ begin
           begin
           begin
             // Debug information
             // Debug information
             Log(vlDebug,SDbgResolvingSourcesOfTarget,[T.Name,MakeTargetString(ACPU,AOS)]);
             Log(vlDebug,SDbgResolvingSourcesOfTarget,[T.Name,MakeTargetString(ACPU,AOS)]);
-            LogIndent;
+            try
+              LogIndent;
 
 
-            case T.TargetType of
-              ttProgram,
-              ttSharedLibrary,
-              ttUnit,
-              ttImplicitUnit :
-                begin
-                  if T.FTargetSourceFileName<>'' then
-                    Log(vlDebug,SDbgSourceAlreadyResolved,[T.Name])
-                  else
-                    FindMainSource(T);
-                  if T.Dependencies.Count>0 then
-                    FindIncludeSources(T);
-                end;
-              ttExampleUnit,
-              ttExampleProgram :
-                begin
-                  if T.FTargetSourceFileName<>'' then
-                    Log(vlDebug,SDbgSourceAlreadyResolved,[T.Name])
-                  else
-                    FindExampleSource(T);
-                end;
+              case T.TargetType of
+                ttProgram,
+                ttSharedLibrary,
+                ttUnit,
+                ttImplicitUnit :
+                  begin
+                    if T.FTargetSourceFileName<>'' then
+                      Log(vlDebug,SDbgSourceAlreadyResolved,[T.Name])
+                    else
+                      FindMainSource(T);
+                    if T.Dependencies.Count>0 then
+                      FindIncludeSources(T);
+                  end;
+                ttExampleUnit,
+                ttExampleProgram :
+                  begin
+                    if T.FTargetSourceFileName<>'' then
+                      Log(vlDebug,SDbgSourceAlreadyResolved,[T.Name])
+                    else
+                      FindExampleSource(T);
+                  end;
+              end;
+            finally
+              LogUnIndent;
             end;
             end;
-
-            LogUnIndent;
           end;
           end;
       end;
       end;
   finally
   finally
@@ -7484,6 +7522,7 @@ Var
   Env : TStrings;
   Env : TStrings;
 begin
 begin
   Log(vlInfo,SInfoCompilingTarget,[ATarget.Name]);
   Log(vlInfo,SInfoCompilingTarget,[ATarget.Name]);
+  try
   LogIndent;
   LogIndent;
   ExecuteCommands(ATarget.Commands,caBeforeCompile);
   ExecuteCommands(ATarget.Commands,caBeforeCompile);
   If Assigned(ATarget.BeforeCompile) then
   If Assigned(ATarget.BeforeCompile) then
@@ -7514,7 +7553,9 @@ begin
         ATarget.AfterCompile(ATarget);
         ATarget.AfterCompile(ATarget);
       ExecuteCommands(ATarget.Commands,caAfterCompile);
       ExecuteCommands(ATarget.Commands,caAfterCompile);
     end;
     end;
+  finally
   LogUnIndent;
   LogUnIndent;
+  end;
 end;
 end;
 
 
 
 
@@ -7525,6 +7566,7 @@ Var
   D : TDependency;
   D : TDependency;
 begin
 begin
   Log(vlDebug, Format(SDbgCompilingDependenciesOfTarget, [ATarget.Name]));
   Log(vlDebug, Format(SDbgCompilingDependenciesOfTarget, [ATarget.Name]));
+  try
   LogIndent;
   LogIndent;
   For I:=0 to ATarget.Dependencies.Count-1 do
   For I:=0 to ATarget.Dependencies.Count-1 do
     begin
     begin
@@ -7558,7 +7600,9 @@ begin
             Error(SErrDepUnknownTarget,[D.Value, ATarget.Name, APackage.Name]);
             Error(SErrDepUnknownTarget,[D.Value, ATarget.Name, APackage.Name]);
         end;
         end;
     end;
     end;
+  finally
   LogUnIndent;
   LogUnIndent;
+  end;
 end;
 end;
 
 
 
 
@@ -7567,6 +7611,7 @@ begin
   if ATarget.State<>tsNeutral then
   if ATarget.State<>tsNeutral then
     Error(SErrInvalidState,[ATarget.Name]);
     Error(SErrInvalidState,[ATarget.Name]);
   Log(vlDebug, Format(SDbgConsideringTarget, [ATarget.Name]));
   Log(vlDebug, Format(SDbgConsideringTarget, [ATarget.Name]));
+  try
   LogIndent;
   LogIndent;
   ATarget.FTargetState:=tsConsidering;
   ATarget.FTargetState:=tsConsidering;
   ResolveDependencies(ATarget.Dependencies,ATarget.Collection as TTargets);
   ResolveDependencies(ATarget.Dependencies,ATarget.Collection as TTargets);
@@ -7578,7 +7623,9 @@ begin
     end
     end
   else
   else
     ATarget.FTargetState:=tsNoCompile;
     ATarget.FTargetState:=tsNoCompile;
+  finally
   LogUnIndent;
   LogUnIndent;
+  end;
 end;
 end;
 
 
 
 
@@ -8037,6 +8084,7 @@ begin
   if APackage.State<>tsNeutral then
   if APackage.State<>tsNeutral then
     Error(SErrInvalidState,[APackage.Name]);
     Error(SErrInvalidState,[APackage.Name]);
   Log(vlDebug,SDbgConsideringPackage,[APackage.Name]);
   Log(vlDebug,SDbgConsideringPackage,[APackage.Name]);
+  try
   LogIndent;
   LogIndent;
   if Defaults.ThreadsAmount=-1 then
   if Defaults.ThreadsAmount=-1 then
     APackage.FTargetState:=tsConsidering;
     APackage.FTargetState:=tsConsidering;
@@ -8049,6 +8097,7 @@ begin
   else if CheckDependencies(APackage, true)=cdNotYetAvailable then
   else if CheckDependencies(APackage, true)=cdNotYetAvailable then
     begin
     begin
       log(vlInfo,'Delaying package '+apackage.name);
       log(vlInfo,'Delaying package '+apackage.name);
+      //LogUnIndent; Done in Finally below
       result := False;
       result := False;
       Exit;
       Exit;
     end;
     end;
@@ -8062,7 +8111,9 @@ begin
       APackage.FTargetState:=tsNoCompile;
       APackage.FTargetState:=tsNoCompile;
       inc(FProgressCount);
       inc(FProgressCount);
     end;
     end;
+  finally
   LogUnIndent;
   LogUnIndent;
+  end;
 end;
 end;
 
 
 
 
@@ -8696,7 +8747,10 @@ begin
             begin
             begin
               Threads[Thr] := TCompileWorkerThread.Create(self,NotifyThreadWaiting);
               Threads[Thr] := TCompileWorkerThread.Create(self,NotifyThreadWaiting);
               if assigned(Threads[Thr]) then
               if assigned(Threads[Thr]) then
-                inc(ThreadCount);
+                begin
+                  inc(ThreadCount);
+                  Threads[Thr].FWorkerPrefix:=Format('(%d/%d) ',[Thr,Defaults.ThreadsAmount]);
+                end;
             end;
             end;
         except
         except
           on E: Exception do
           on E: Exception do
@@ -8712,6 +8766,7 @@ begin
           while not Finished do
           while not Finished do
             begin
             begin
               RTLeventWaitFor(NotifyThreadWaiting);
               RTLeventWaitFor(NotifyThreadWaiting);
+              RTLeventResetEvent(NotifyThreadWaiting);
               for Thr:=0 to Defaults.ThreadsAmount-1 do
               for Thr:=0 to Defaults.ThreadsAmount-1 do
                 if assigned(Threads[Thr]) and not Finished then
                 if assigned(Threads[Thr]) and not Finished then
                   ProcessThreadResult(Threads[Thr]);
                   ProcessThreadResult(Threads[Thr]);

+ 1 - 1
packages/openssl/src/openssl.pas

@@ -90,7 +90,7 @@ Type
 const
 const
 // SSL and Crypto DLL arrays must have the same length and contain
 // SSL and Crypto DLL arrays must have the same length and contain
 // matched pairs of DLL filenames. Place newer versions at the beginning.
 // matched pairs of DLL filenames. Place newer versions at the beginning.
-{$IFDEF WIN64}
+{$IF DEFINED(WIN64)}
   SSL_DLL_Names:    array[1..3] of string = ('libssl-1_1-x64',    'ssleay32', 'libssl32');
   SSL_DLL_Names:    array[1..3] of string = ('libssl-1_1-x64',    'ssleay32', 'libssl32');
   Crypto_DLL_Names: array[1..3] of string = ('libcrypto-1_1-x64', 'libeay32', 'libeay32');
   Crypto_DLL_Names: array[1..3] of string = ('libcrypto-1_1-x64', 'libeay32', 'libeay32');
 {$ELSEIF DEFINED(WINDOWS)}
 {$ELSEIF DEFINED(WINDOWS)}

+ 76 - 39
packages/pastojs/src/fppas2js.pp

@@ -2082,8 +2082,8 @@ type
     Procedure CreateInitSection(El: TPasModule; Src: TJSSourceElements; AContext: TConvertContext); virtual;
     Procedure CreateInitSection(El: TPasModule; Src: TJSSourceElements; AContext: TConvertContext); virtual;
     Procedure AddHeaderStatement(JS: TJSElement; PosEl: TPasElement; aContext: TConvertContext); virtual;
     Procedure AddHeaderStatement(JS: TJSElement; PosEl: TPasElement; aContext: TConvertContext); virtual;
     Procedure AddImplHeaderStatement(JS: TJSElement; PosEl: TPasElement; aContext: TConvertContext); virtual;
     Procedure AddImplHeaderStatement(JS: TJSElement; PosEl: TPasElement; aContext: TConvertContext); virtual;
-    Procedure AddDelayedInits(El: TPasModule; Src: TJSSourceElements; AContext: TConvertContext); virtual;
-    Procedure AddDelaySpecializeInit(El: TPasGenericType; Src: TJSSourceElements; AContext: TConvertContext); virtual;
+    function AddDelayedInits(El: TPasModule; Src: TJSSourceElements; AContext: TConvertContext): boolean; virtual;
+    function CreateDelaySpecializeInit(El: TPasGenericType; AContext: TConvertContext): TJSElement; virtual;
     // enum and sets
     // enum and sets
     Function CreateReferencedSet(El: TPasElement; SetExpr: TJSElement): TJSElement; virtual;
     Function CreateReferencedSet(El: TPasElement; SetExpr: TJSElement): TJSElement; virtual;
     // record
     // record
@@ -2314,6 +2314,7 @@ type
       pfVarargs = 2;
       pfVarargs = 2;
       pfExternal = 4;
       pfExternal = 4;
       pfSafeCall = 8;
       pfSafeCall = 8;
+      pfAsync = $10;
       // PropertyFlag
       // PropertyFlag
       pfGetFunction = 1; // getter is a function
       pfGetFunction = 1; // getter is a function
       pfSetProcedure = 2; // setter is a function
       pfSetProcedure = 2; // setter is a function
@@ -4488,6 +4489,9 @@ begin
       AddElevatedLocal(El);
       AddElevatedLocal(El);
       end;
       end;
     end
     end
+  else if ParentC=TPasImplExceptOn then
+    // except on var
+    RaiseVarModifierNotSupported(LocalVarModifiersAllowed)
   else if ParentC=TImplementationSection then
   else if ParentC=TImplementationSection then
     // implementation var
     // implementation var
     RaiseVarModifierNotSupported(ImplementationVarModifiersAllowed)
     RaiseVarModifierNotSupported(ImplementationVarModifiersAllowed)
@@ -4499,7 +4503,7 @@ begin
   else
   else
     begin
     begin
     {$IFDEF VerbosePas2JS}
     {$IFDEF VerbosePas2JS}
-    writeln('TPas2JSResolver.FinishVariable ',GetObjName(El),' Parent=',GetObjName(El.Parent));
+    writeln('TPas2JSResolver.FinishVariable ',GetObjPath(El));
     {$ENDIF}
     {$ENDIF}
     RaiseNotYetImplemented(20170324151259,El);
     RaiseNotYetImplemented(20170324151259,El);
     end;
     end;
@@ -8199,7 +8203,7 @@ Var
   ModuleName, ModVarName: String;
   ModuleName, ModVarName: String;
   IntfContext: TSectionContext;
   IntfContext: TSectionContext;
   ImplVarSt: TJSVariableStatement;
   ImplVarSt: TJSVariableStatement;
-  HasImplUsesClause, ok, NeedRTLCheckVersion: Boolean;
+  HasImplCode, ok, NeedRTLCheckVersion: Boolean;
   Prg: TPasProgram;
   Prg: TPasProgram;
   Lib: TPasLibrary;
   Lib: TPasLibrary;
   ImplFuncAssignSt: TJSSimpleAssignStatement;
   ImplFuncAssignSt: TJSSimpleAssignStatement;
@@ -8280,7 +8284,7 @@ begin
       Prg:=TPasProgram(El);
       Prg:=TPasProgram(El);
       if Assigned(Prg.ProgramSection) then
       if Assigned(Prg.ProgramSection) then
         AddToSourceElements(Src,ConvertDeclarations(Prg.ProgramSection,IntfContext));
         AddToSourceElements(Src,ConvertDeclarations(Prg.ProgramSection,IntfContext));
-      AddDelayedInits(Prg,Src,IntfContext);
+      HasImplCode:=AddDelayedInits(Prg,Src,IntfContext);
       CreateInitSection(Prg,Src,IntfContext);
       CreateInitSection(Prg,Src,IntfContext);
       end
       end
     else if El is TPasLibrary then
     else if El is TPasLibrary then
@@ -8288,7 +8292,7 @@ begin
       Lib:=TPasLibrary(El);
       Lib:=TPasLibrary(El);
       if Assigned(Lib.LibrarySection) then
       if Assigned(Lib.LibrarySection) then
         AddToSourceElements(Src,ConvertDeclarations(Lib.LibrarySection,IntfContext));
         AddToSourceElements(Src,ConvertDeclarations(Lib.LibrarySection,IntfContext));
-      AddDelayedInits(Lib,Src,IntfContext);
+      HasImplCode:=AddDelayedInits(Lib,Src,IntfContext);
       CreateInitSection(Lib,Src,IntfContext);
       CreateInitSection(Lib,Src,IntfContext);
       // ToDo: append exports
       // ToDo: append exports
       end
       end
@@ -8317,7 +8321,9 @@ begin
       // append initialization section
       // append initialization section
       CreateInitSection(El,Src,IntfSecCtx);
       CreateInitSection(El,Src,IntfSecCtx);
 
 
-      if TJSSourceElements(ImplFunc.AFunction.Body.A).Statements.Count=0 then
+      if TJSSourceElements(ImplFunc.AFunction.Body.A).Statements.Count>0 then
+        HasImplCode:=true
+      else
         begin
         begin
         // empty implementation
         // empty implementation
 
 
@@ -8325,18 +8331,14 @@ begin
         RemoveFromSourceElements(Src,ImplVarSt);
         RemoveFromSourceElements(Src,ImplVarSt);
         // remove unneeded $mod.$implcode = function(){}
         // remove unneeded $mod.$implcode = function(){}
         RemoveFromSourceElements(Src,ImplFuncAssignSt);
         RemoveFromSourceElements(Src,ImplFuncAssignSt);
-        HasImplUsesClause:=(El.ImplementationSection<>nil)
+        // keep impl uses section
+        HasImplCode:=(El.ImplementationSection<>nil)
                        and (length(El.ImplementationSection.UsesClause)>0);
                        and (length(El.ImplementationSection.UsesClause)>0);
-        end
-      else
-        begin
-        HasImplUsesClause:=true;
         end;
         end;
 
 
-      if HasImplUsesClause then
+      if HasImplCode then
         // add implementation uses list: [<implementation uses1>,<uses2>, ...]
         // add implementation uses list: [<implementation uses1>,<uses2>, ...]
         ArgArray.AddElement(CreateUsesList(El.ImplementationSection,AContext));
         ArgArray.AddElement(CreateUsesList(El.ImplementationSection,AContext));
-
       end; // end unit
       end; // end unit
 
 
     if (ModScope<>nil) and (coStoreImplJS in Options) then
     if (ModScope<>nil) and (coStoreImplJS in Options) then
@@ -16564,14 +16566,20 @@ begin
       if ResultTypeInfo<>nil then
       if ResultTypeInfo<>nil then
         InnerCall.AddArg(ResultTypeInfo);
         InnerCall.AddArg(ResultTypeInfo);
       end;
       end;
-    // add param flags
+    // add procedure flags
     Flags:=0;
     Flags:=0;
     if ptmVarargs in El.Modifiers then
     if ptmVarargs in El.Modifiers then
       inc(Flags,pfVarargs);
       inc(Flags,pfVarargs);
+    if ptmAsync in El.Modifiers then
+      inc(Flags,pfAsync);
     if El.CallingConvention=ccSafeCall then
     if El.CallingConvention=ccSafeCall then
       inc(Flags,pfSafeCall);
       inc(Flags,pfSafeCall);
     if Flags>0 then
     if Flags>0 then
+      begin
+      if not (El is TPasFunctionType) then
+        InnerCall.AddArg(CreateLiteralNull(El));
       InnerCall.AddArg(CreateLiteralNumber(El,Flags));
       InnerCall.AddArg(CreateLiteralNumber(El,Flags));
+      end;
 
 
     if El.IsOfObject then
     if El.IsOfObject then
       begin
       begin
@@ -17846,13 +17854,18 @@ begin
   IntfSec.AddImplHeaderStatement(JS);
   IntfSec.AddImplHeaderStatement(JS);
 end;
 end;
 
 
-procedure TPasToJSConverter.AddDelayedInits(El: TPasModule;
-  Src: TJSSourceElements; AContext: TConvertContext);
+function TPasToJSConverter.AddDelayedInits(El: TPasModule;
+  Src: TJSSourceElements; AContext: TConvertContext): boolean;
 var
 var
   aResolver: TPas2JSResolver;
   aResolver: TPas2JSResolver;
   Hub: TPas2JSResolverHub;
   Hub: TPas2JSResolverHub;
   i: Integer;
   i: Integer;
+  JS: TJSElement;
+  AssignSt: TJSSimpleAssignStatement;
+  FunDecl: TJSFunctionDeclarationStatement;
+  ImplSrc: TJSSourceElements;
 begin
 begin
+  Result:=false;
   aResolver:=AContext.Resolver;
   aResolver:=AContext.Resolver;
   if aResolver=nil then exit;
   if aResolver=nil then exit;
   if El=nil then ;
   if El=nil then ;
@@ -17860,12 +17873,29 @@ begin
   {$IFDEF VerbosePas2JS}
   {$IFDEF VerbosePas2JS}
   writeln('TPasToJSConverter.AddDelayedInits Hub.JSDelaySpecializeCount=',Hub.JSDelaySpecializeCount);
   writeln('TPasToJSConverter.AddDelayedInits Hub.JSDelaySpecializeCount=',Hub.JSDelaySpecializeCount);
   {$ENDIF}
   {$ENDIF}
+  ImplSrc:=nil;
   for i:=0 to Hub.JSDelaySpecializeCount-1 do
   for i:=0 to Hub.JSDelaySpecializeCount-1 do
-    AddDelaySpecializeInit(Hub.JSDelaySpecializes[i],Src,AContext);
+    begin
+    JS:=CreateDelaySpecializeInit(Hub.JSDelaySpecializes[i],AContext);
+    if JS=nil then continue;
+    if ImplSrc=nil then
+      begin
+      // create  "$mod.$implcode = function(){ }"
+      AssignSt:=TJSSimpleAssignStatement(CreateElement(TJSSimpleAssignStatement,El));
+      AddToSourceElements(Src,AssignSt);
+      AssignSt.LHS:=CreateMemberExpression([GetBIName(pbivnModule),GetBIName(pbivnImplCode)]);
+      // create function(){}
+      FunDecl:=CreateFunctionSt(El,true,true);
+      AssignSt.Expr:=FunDecl;
+      ImplSrc:=TJSSourceElements(FunDecl.AFunction.Body.A);
+      end;
+    AddToSourceElements(ImplSrc,JS);
+    Result:=true;
+    end;
 end;
 end;
 
 
-procedure TPasToJSConverter.AddDelaySpecializeInit(El: TPasGenericType;
-  Src: TJSSourceElements; AContext: TConvertContext);
+function TPasToJSConverter.CreateDelaySpecializeInit(El: TPasGenericType;
+  AContext: TConvertContext): TJSElement;
 var
 var
   C: TClass;
   C: TClass;
   Path: String;
   Path: String;
@@ -17876,6 +17906,7 @@ var
   ElTypeHi, ElTypeLo: TPasType;
   ElTypeHi, ElTypeLo: TPasType;
   aResolver: TPas2JSResolver;
   aResolver: TPas2JSResolver;
 begin
 begin
+  Result:=nil;
   if not IsElementUsed(El) then exit;
   if not IsElementUsed(El) then exit;
   if not AContext.Resolver.IsFullySpecialized(El) then
   if not AContext.Resolver.IsFullySpecialized(El) then
     RaiseNotSupported(El,AContext,20201202145045,'not fully specialized, probably a bug in the analyzer');
     RaiseNotSupported(El,AContext,20201202145045,'not fully specialized, probably a bug in the analyzer');
@@ -17889,7 +17920,7 @@ begin
     Path:=CreateReferencePath(El,AContext,rpkPathAndName)+'.'+GetBIName(pbifnClassInitSpecialize);
     Path:=CreateReferencePath(El,AContext,rpkPathAndName)+'.'+GetBIName(pbifnClassInitSpecialize);
     Call:=CreateCallExpression(El);
     Call:=CreateCallExpression(El);
     Call.Expr:=CreatePrimitiveDotExpr(Path,El);
     Call.Expr:=CreatePrimitiveDotExpr(Path,El);
-    AddToSourceElements(Src,Call);
+    Result:=Call;
     end
     end
   else if (C=TPasProcedureType) or (C=TPasFunctionType) then
   else if (C=TPasProcedureType) or (C=TPasFunctionType) then
     begin
     begin
@@ -17901,7 +17932,7 @@ begin
     DotExpr.Name:=TJSString(GetBIName(pbivnRTTIProc_InitSpec));
     DotExpr.Name:=TJSString(GetBIName(pbivnRTTIProc_InitSpec));
     Call:=CreateCallExpression(El);
     Call:=CreateCallExpression(El);
     Call.Expr:=DotExpr;
     Call.Expr:=DotExpr;
-    AddToSourceElements(Src,Call);
+    Result:=Call;
     end
     end
   else if (C=TPasArrayType) then
   else if (C=TPasArrayType) then
     begin
     begin
@@ -17928,7 +17959,7 @@ begin
     AssignSt.LHS:=CreateDotNameExpr(El,CreateTypeInfoRef(El,AContext,El),
     AssignSt.LHS:=CreateDotNameExpr(El,CreateTypeInfoRef(El,AContext,El),
                                    TJSString(GetBIName(pbivnRTTIArray_ElType)));
                                    TJSString(GetBIName(pbivnRTTIArray_ElType)));
     AssignSt.Expr:=CreateTypeInfoRef(ElTypeHi,AContext,El);
     AssignSt.Expr:=CreateTypeInfoRef(ElTypeHi,AContext,El);
-    AddToSourceElements(Src,AssignSt);
+    Result:=AssignSt;
     end
     end
   else
   else
     RaiseNotSupported(El,AContext,20200831115251);
     RaiseNotSupported(El,AContext,20200831115251);
@@ -19801,9 +19832,8 @@ var
 begin
 begin
   Result:=nil;
   Result:=nil;
   if Args.Count=0 then
   if Args.Count=0 then
-    Result:=CreateLiteralNull(Parent)
+    Result:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,Parent))
   else
   else
-    begin
     try
     try
       Params:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,Parent));
       Params:=TJSArrayLiteral(CreateElement(TJSArrayLiteral,Parent));
       for i:=0 to Args.Count-1 do
       for i:=0 to Args.Count-1 do
@@ -19813,7 +19843,6 @@ begin
       if Result=nil then
       if Result=nil then
         Params.Free;
         Params.Free;
     end;
     end;
-  end;
 end;
 end;
 
 
 procedure TPasToJSConverter.AddRTTIArgument(Arg: TPasArgument;
 procedure TPasToJSConverter.AddRTTIArgument(Arg: TPasArgument;
@@ -20119,6 +20148,7 @@ var
   OptionsEl: TJSObjectLiteral;
   OptionsEl: TJSObjectLiteral;
   ResultTypeInfo: TJSElement;
   ResultTypeInfo: TJSElement;
   Call: TJSCallExpression;
   Call: TJSCallExpression;
+  Flags: Integer;
 
 
   procedure AddOption(const aName: String; JS: TJSElement);
   procedure AddOption(const aName: String; JS: TJSElement);
   var
   var
@@ -20128,8 +20158,6 @@ var
     if OptionsEl=nil then
     if OptionsEl=nil then
       begin
       begin
       OptionsEl:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,Proc));
       OptionsEl:=TJSObjectLiteral(CreateElement(TJSObjectLiteral,Proc));
-      if ResultTypeInfo=nil then
-        Call.AddArg(CreateLiteralNull(Proc));
       Call.AddArg(OptionsEl);
       Call.AddArg(OptionsEl);
       end;
       end;
     ObjLit:=OptionsEl.Elements.AddElement;
     ObjLit:=OptionsEl.Elements.AddElement;
@@ -20140,7 +20168,7 @@ var
 var
 var
   FunName: String;
   FunName: String;
   C: TClass;
   C: TClass;
-  MethodKind, Flags: Integer;
+  MethodKind: Integer;
   ResultEl: TPasResultElement;
   ResultEl: TPasResultElement;
   ProcScope, OverriddenProcScope: TPasProcedureScope;
   ProcScope, OverriddenProcScope: TPasProcedureScope;
   OverriddenClass: TPasClassType;
   OverriddenClass: TPasClassType;
@@ -20198,6 +20226,19 @@ begin
     // param params as []
     // param params as []
     Call.AddArg(CreateRTTIArgList(Proc,Proc.ProcType.Args,AContext));
     Call.AddArg(CreateRTTIArgList(Proc,Proc.ProcType.Args,AContext));
 
 
+    // optional params:
+    ResultTypeInfo:=nil;
+    Flags:=0;
+    if Proc.IsStatic then
+      inc(Flags,pfStatic);
+    if ptmVarargs in Proc.ProcType.Modifiers then
+      inc(Flags,pfVarargs);
+    if ptmAsync in Proc.ProcType.Modifiers then
+      inc(Flags,pfAsync);
+    if Proc.IsExternal then
+      inc(Flags,pfExternal);
+    Attr:=aResolver.GetAttributeCalls(Members,Index);
+
     // param resulttype as typeinfo reference
     // param resulttype as typeinfo reference
     if C.InheritsFrom(TPasFunction) then
     if C.InheritsFrom(TPasFunction) then
       begin
       begin
@@ -20206,18 +20247,14 @@ begin
       if ResultTypeInfo<>nil then
       if ResultTypeInfo<>nil then
         Call.AddArg(ResultTypeInfo);
         Call.AddArg(ResultTypeInfo);
       end;
       end;
+    if (ResultTypeInfo=nil) and ((Flags>0) or (length(Attr)>0)) then
+      Call.AddArg(CreateLiteralNull(Proc));
+
+    // flags if needed
+    if (Flags>0) or (length(Attr)>0) then
+      Call.AddArg(CreateLiteralNumber(Proc,Flags));
 
 
     // param options if needed as {}
     // param options if needed as {}
-    Flags:=0;
-    if Proc.IsStatic then
-      inc(Flags,pfStatic);
-    if ptmVarargs in Proc.ProcType.Modifiers then
-      inc(Flags,pfVarargs);
-    if Proc.IsExternal then
-      inc(Flags,pfExternal);
-    if Flags>0 then
-      AddOption(GetBIName(pbivnRTTIProcFlags),CreateLiteralNumber(Proc,Flags));
-    Attr:=aResolver.GetAttributeCalls(Members,Index);
     if length(Attr)>0 then
     if length(Attr)>0 then
       AddOption(GetBIName(pbivnRTTIMemberAttributes),
       AddOption(GetBIName(pbivnRTTIMemberAttributes),
                 CreateRTTIAttributes(Attr,Proc,AContext));
                 CreateRTTIAttributes(Attr,Proc,AContext));

+ 140 - 10
packages/pastojs/tests/tcgenerics.pas

@@ -20,7 +20,7 @@ type
     Procedure TestGen_Record_ClassVarRecord_Program;
     Procedure TestGen_Record_ClassVarRecord_Program;
     Procedure TestGen_Record_ClassVarRecord_UnitImpl;
     Procedure TestGen_Record_ClassVarRecord_UnitImpl;
     Procedure TestGen_Record_RTTI_UnitImpl;
     Procedure TestGen_Record_RTTI_UnitImpl;
-    // ToDo: delay RTTI with anonymous array  a:array of T, array[1..2] of T
+    procedure TestGen_Record_Delay_UsedByImplUses;
     // ToDo: type alias type as parameter, TBird = type word;
     // ToDo: type alias type as parameter, TBird = type word;
 
 
     // generic class
     // generic class
@@ -62,6 +62,7 @@ type
     Procedure TestGen_CallUnitImplProc;
     Procedure TestGen_CallUnitImplProc;
     Procedure TestGen_IntAssignTemplVar;
     Procedure TestGen_IntAssignTemplVar;
     Procedure TestGen_TypeCastDotField;
     Procedure TestGen_TypeCastDotField;
+    Procedure TestGen_Except;
 
 
     // generic helper
     // generic helper
     procedure TestGen_HelperForArray;
     procedure TestGen_HelperForArray;
@@ -288,7 +289,9 @@ begin
     '}, []);']));
     '}, []);']));
   CheckSource('TestGen_Record_ClassVarRecord_UnitImpl',
   CheckSource('TestGen_Record_ClassVarRecord_UnitImpl',
     LinesToStr([ // statements
     LinesToStr([ // statements
-    'pas.UnitA.TAnt$G1.$initSpec();',
+    '$mod.$implcode = function () {',
+    '  pas.UnitA.TAnt$G1.$initSpec();',
+    '};',
     '']),
     '']),
     LinesToStr([ // $mod.$main
     LinesToStr([ // $mod.$main
     '']));
     '']));
@@ -355,6 +358,53 @@ begin
     '']));
     '']));
 end;
 end;
 
 
+procedure TTestGenerics.TestGen_Record_Delay_UsedByImplUses;
+begin
+  WithTypeInfo:=true;
+  StartProgram(true,[supTObject]);
+  AddModuleWithIntfImplSrc('UnitA.pas',
+  LinesToStr([
+    '{$modeswitch AdvancedRecords}',
+    'type',
+    '  generic TBird<T> = record',
+    '    class var a: T;',
+    '  end;',
+    '']),
+  LinesToStr([
+    '']));
+  AddModuleWithIntfImplSrc('UnitB.pas',
+  LinesToStr([
+    'procedure Fly;',
+    '']),
+  LinesToStr([
+    'uses UnitA;',
+    'type',
+    '  TFox = record',
+    '    B: word;',
+    '  end;',
+    'procedure Fly;',
+    'var Bird: specialize TBird<TFox>;',
+    'begin',
+    '  if typeinfo(Bird)<>nil then ;',
+    '  Bird.a:=Bird.a;',
+    'end;',
+    '']));
+  Add([
+  'uses UnitB;',
+  'begin',
+  '  Fly;']);
+  ConvertProgram;
+  CheckSource('TestGen_Record_Delay_UsedByImplUses',
+    LinesToStr([ // statements
+    '$mod.$implcode = function () {',
+    '  pas.UnitA.TBird$G1.$initSpec();',
+    '};',
+    '']),
+    LinesToStr([ // $mod.$main
+    'pas.UnitB.Fly();'
+    ]));
+end;
+
 procedure TTestGenerics.TestGen_ClassEmpty;
 procedure TTestGenerics.TestGen_ClassEmpty;
 begin
 begin
   StartProgram(false);
   StartProgram(false);
@@ -1201,7 +1251,9 @@ begin
     '']));
     '']));
   CheckSource('TestGen_Class_ClassVarRecord_UnitImpl',
   CheckSource('TestGen_Class_ClassVarRecord_UnitImpl',
     LinesToStr([ // statements
     LinesToStr([ // statements
-    'pas.UnitA.TAnt$G1.$initSpec();',
+    '$mod.$implcode = function () {',
+    '  pas.UnitA.TAnt$G1.$initSpec();',
+    '};',
     '']),
     '']),
     LinesToStr([ // $mod.$main
     LinesToStr([ // $mod.$main
     '']));
     '']));
@@ -1453,7 +1505,6 @@ begin
     '}, []);']));
     '}, []);']));
   CheckSource('TestGen_Class_ClassVarRecord_UnitImpl',
   CheckSource('TestGen_Class_ClassVarRecord_UnitImpl',
     LinesToStr([ // statements
     LinesToStr([ // statements
-    //'pas.UnitA.TAnt$G1.$initSpec();',
     '']),
     '']),
     LinesToStr([ // $mod.$main
     LinesToStr([ // $mod.$main
     '']));
     '']));
@@ -1706,7 +1757,9 @@ begin
     '  rtl.addIntf(this, pas.system.IUnknown);',
     '  rtl.addIntf(this, pas.system.IUnknown);',
     '});',
     '});',
     'this.i = null;',
     'this.i = null;',
-    'pas.UnitA.TAnt$G1.$initSpec();',
+    '$mod.$implcode = function () {',
+    '  pas.UnitA.TAnt$G1.$initSpec();',
+    '};',
     '']),
     '']),
     LinesToStr([ // $mod.$main
     LinesToStr([ // $mod.$main
     'rtl.setIntfP($mod, "i", rtl.queryIntfT($mod.TBird.$create("Create"), pas.UnitA.TAnt$G1), true);',
     'rtl.setIntfP($mod, "i", rtl.queryIntfT($mod.TBird.$create("Create"), pas.UnitA.TAnt$G1), true);',
@@ -1898,6 +1951,77 @@ begin
     '']));
     '']));
 end;
 end;
 
 
+procedure TTestGenerics.TestGen_Except;
+begin
+  StartProgram(false);
+  Add([
+  'type',
+  '  TObject = class end;',
+  '  generic TBird<T> = class',
+  '    Field: T;',
+  '    procedure Fly;',
+  '  end;',
+  '  Exception = class',
+  '  end;',
+  '  generic EBird<T> = class(Exception)',
+  '    Id: T;',
+  '  end;',
+  'var',
+  '  b: specialize TBird<word>;',
+  'procedure TBird.Fly;',
+  'begin',
+  '  try',
+  '  except',
+  '    on E: Exception do Fly;',
+  '    on EBird: specialize EBird<word> do EBird.Id:=3;',
+  '  else',
+  '    Fly;',
+  '  end;',
+  'end;',
+  'begin',
+  '']);
+  ConvertProgram;
+  CheckSource('TestGen_Except',
+    LinesToStr([ // statements
+    'rtl.createClass(this, "TObject", null, function () {',
+    '  this.$init = function () {',
+    '  };',
+    '  this.$final = function () {',
+    '  };',
+    '});',
+    'rtl.createClass(this, "Exception", this.TObject, function () {',
+    '});',
+    'rtl.createClass(this, "TBird$G1", this.TObject, function () {',
+    '  this.$init = function () {',
+    '    $mod.TObject.$init.call(this);',
+    '    this.Field = 0;',
+    '  };',
+    '  this.Fly = function () {',
+    '    try {} catch ($e) {',
+    '      if ($mod.Exception.isPrototypeOf($e)) {',
+    '        var E = $e;',
+    '        this.Fly();',
+    '      } else if ($mod.EBird$G1.isPrototypeOf($e)) {',
+    '        var EBird = $e;',
+    '        EBird.Id = 3;',
+    '      } else {',
+    '        this.Fly();',
+    '      }',
+    '    };',
+    '  };',
+    '}, "TBird<System.Word>");',
+    'this.b = null;',
+    'rtl.createClass(this, "EBird$G1", this.Exception, function () {',
+    '  this.$init = function () {',
+    '    $mod.Exception.$init.call(this);',
+    '    this.Id = 0;',
+    '  };',
+    '}, "EBird<System.Word>");',
+    '']),
+    LinesToStr([ // $mod.$main
+    '']));
+end;
+
 procedure TTestGenerics.TestGen_HelperForArray;
 procedure TTestGenerics.TestGen_HelperForArray;
 begin
 begin
   StartProgram(false);
   StartProgram(false);
@@ -2424,7 +2548,9 @@ begin
     '});']));
     '});']));
   CheckSource('TestGen_Array_OtherUnit',
   CheckSource('TestGen_Array_OtherUnit',
     LinesToStr([ // statements
     LinesToStr([ // statements
-    'pas.UnitA.$rtti["TDyn<UnitB.TAnt>"].eltype = pas.UnitB.$rtti["TAnt"];',
+    '$mod.$implcode = function () {',
+    '  pas.UnitA.$rtti["TDyn<UnitB.TAnt>"].eltype = pas.UnitB.$rtti["TAnt"];',
+    '};',
     '']),
     '']),
     LinesToStr([ // $mod.$main
     LinesToStr([ // $mod.$main
     '  pas.UnitB.Run();',
     '  pas.UnitB.Run();',
@@ -2504,9 +2630,11 @@ begin
     '}, []);']));
     '}, []);']));
   CheckSource('TestGen_ArrayOfUnitImplRec',
   CheckSource('TestGen_ArrayOfUnitImplRec',
     LinesToStr([ // statements
     LinesToStr([ // statements
-    'pas.UnitA.$rtti["TDyn<UnitA.TAnt>"].eltype = pas.UnitA.$rtti["TAnt"];',
-    'pas.UnitA.$rtti["TDyn<UnitA.TBird>"].eltype = pas.UnitA.$rtti["TBird"];',
-    'pas.UnitA.$rtti["TStatic<UnitA.TBird>"].eltype = pas.UnitA.$rtti["TBird"];',
+    '$mod.$implcode = function () {',
+    '  pas.UnitA.$rtti["TDyn<UnitA.TAnt>"].eltype = pas.UnitA.$rtti["TAnt"];',
+    '  pas.UnitA.$rtti["TDyn<UnitA.TBird>"].eltype = pas.UnitA.$rtti["TBird"];',
+    '  pas.UnitA.$rtti["TStatic<UnitA.TBird>"].eltype = pas.UnitA.$rtti["TBird"];',
+    '};',
     '']),
     '']),
     LinesToStr([ // $mod.$main
     LinesToStr([ // $mod.$main
     '']));
     '']));
@@ -2673,7 +2801,9 @@ begin
     '}, []);']));
     '}, []);']));
   CheckSource('TestGen_Class_ClassVarRecord_UnitImpl',
   CheckSource('TestGen_Class_ClassVarRecord_UnitImpl',
     LinesToStr([ // statements
     LinesToStr([ // statements
-    'pas.UnitA.$rtti["TAnt<UnitA.TBird>"].init();',
+    '$mod.$implcode = function () {',
+    '  pas.UnitA.$rtti["TAnt<UnitA.TBird>"].init();',
+    '};',
     '']),
     '']),
     LinesToStr([ // $mod.$main
     LinesToStr([ // $mod.$main
     '']));
     '']));

+ 38 - 37
packages/pastojs/tests/tcmodules.pas

@@ -29256,20 +29256,20 @@ begin
   CheckSource('TestRTTI_ProcType',
   CheckSource('TestRTTI_ProcType',
     LinesToStr([ // statements
     LinesToStr([ // statements
     'this.$rtti.$ProcVar("TProcA", {',
     'this.$rtti.$ProcVar("TProcA", {',
-    '  procsig: rtl.newTIProcSig(null)',
+    '  procsig: rtl.newTIProcSig([])',
     '});',
     '});',
     'this.$rtti.$MethodVar("TMethodB", {',
     'this.$rtti.$MethodVar("TMethodB", {',
-    '  procsig: rtl.newTIProcSig(null),',
+    '  procsig: rtl.newTIProcSig([]),',
     '  methodkind: 0',
     '  methodkind: 0',
     '});',
     '});',
     'this.$rtti.$ProcVar("TProcC", {',
     'this.$rtti.$ProcVar("TProcC", {',
-    '  procsig: rtl.newTIProcSig(null, 2)',
+    '  procsig: rtl.newTIProcSig([], null, 2)',
     '});',
     '});',
     'this.$rtti.$ProcVar("TProcD", {',
     'this.$rtti.$ProcVar("TProcD", {',
     '  procsig: rtl.newTIProcSig([["i", rtl.longint], ["j", rtl.string, 2], ["c", rtl.char, 1], ["d", rtl.double, 4]])',
     '  procsig: rtl.newTIProcSig([["i", rtl.longint], ["j", rtl.string, 2], ["c", rtl.char, 1], ["d", rtl.double, 4]])',
     '});',
     '});',
     'this.$rtti.$ProcVar("TProcE", {',
     'this.$rtti.$ProcVar("TProcE", {',
-    '  procsig: rtl.newTIProcSig(null, rtl.nativeint)',
+    '  procsig: rtl.newTIProcSig([], rtl.nativeint)',
     '});',
     '});',
     'this.$rtti.$ProcVar("TProcF", {',
     'this.$rtti.$ProcVar("TProcF", {',
     '  procsig: rtl.newTIProcSig([["p", this.$rtti["TProcA"], 2]], rtl.nativeuint)',
     '  procsig: rtl.newTIProcSig([["p", this.$rtti["TProcA"], 2]], rtl.nativeuint)',
@@ -29578,13 +29578,13 @@ begin
     '  this.Fly = function () {',
     '  this.Fly = function () {',
     '  };',
     '  };',
     '  var $r = this.$rtti;',
     '  var $r = this.$rtti;',
-    '  $r.addMethod("Fly", 0, null);',
+    '  $r.addMethod("Fly", 0, []);',
     '});',
     '});',
     'rtl.createClass(this, "TEagle", this.TBird, function () {',
     'rtl.createClass(this, "TEagle", this.TBird, function () {',
     '  this.Fly = function () {',
     '  this.Fly = function () {',
     '  };',
     '  };',
     '  var $r = this.$rtti;',
     '  var $r = this.$rtti;',
-    '  $r.addMethod("Fly", 0, null);',
+    '  $r.addMethod("Fly", 0, []);',
     '});',
     '});',
     '']),
     '']),
     LinesToStr([ // $mod.$main
     LinesToStr([ // $mod.$main
@@ -29738,17 +29738,19 @@ procedure TTestModule.TestRTTI_Class_Method;
 begin
 begin
   WithTypeInfo:=true;
   WithTypeInfo:=true;
   StartProgram(false);
   StartProgram(false);
-  Add('type');
-  Add('  TObject = class');
-  Add('  private');
-  Add('    procedure Internal; external name ''$intern'';');
-  Add('  published');
-  Add('    procedure Click; virtual; abstract;');
-  Add('    procedure Notify(Sender: TObject); virtual; abstract;');
-  Add('    function GetNotify: boolean; external name ''GetNotify'';');
-  Add('    procedure Println(a,b: longint); varargs; virtual; abstract;');
-  Add('  end;');
-  Add('begin');
+  Add([
+  'type',
+  '  TObject = class',
+  '  private',
+  '    procedure Internal; external name ''$intern'';',
+  '  published',
+  '    procedure Click; virtual; abstract;',
+  '    procedure Notify(Sender: TObject); virtual; abstract;',
+  '    function GetNotify: boolean; external name ''GetNotify'';',
+  '    procedure Println(a,b: longint); varargs; virtual; abstract;',
+  '    function Fetch(URL: string): word; async; external name ''Fetch'';',
+  '  end;',
+  'begin']);
   ConvertProgram;
   ConvertProgram;
   CheckSource('TestRTTI_Class_Method',
   CheckSource('TestRTTI_Class_Method',
     LinesToStr([ // statements
     LinesToStr([ // statements
@@ -29758,12 +29760,11 @@ begin
     '  this.$final = function () {',
     '  this.$final = function () {',
     '  };',
     '  };',
     '  var $r = this.$rtti;',
     '  var $r = this.$rtti;',
-    '  $r.addMethod("Click", 0, null);',
+    '  $r.addMethod("Click", 0, []);',
     '  $r.addMethod("Notify", 0, [["Sender", $r]]);',
     '  $r.addMethod("Notify", 0, [["Sender", $r]]);',
-    '  $r.addMethod("GetNotify", 1, null, rtl.boolean,{flags: 4});',
-    '  $r.addMethod("Println", 0, [["a", rtl.longint], ["b", rtl.longint]], null, {',
-    '    flags: 2',
-    '  });',
+    '  $r.addMethod("GetNotify", 1, [], rtl.boolean, 4);',
+    '  $r.addMethod("Println", 0, [["a", rtl.longint], ["b", rtl.longint]], null, 2);',
+    '  $r.addMethod("Fetch", 1, [["URL", rtl.string]], rtl.word, 20);',
     '});',
     '});',
     '']),
     '']),
     LinesToStr([ // $mod.$main
     LinesToStr([ // $mod.$main
@@ -30507,7 +30508,7 @@ begin
     '  this.$final = function () {',
     '  this.$final = function () {',
     '  };',
     '  };',
     '  var $r = this.$rtti;',
     '  var $r = this.$rtti;',
-    '  $r.addMethod("DoIt", 0, null);',
+    '  $r.addMethod("DoIt", 0, []);',
     '});',
     '});',
     'rtl.createClass(this, "TSky", this.TObject, function () {',
     'rtl.createClass(this, "TSky", this.TObject, function () {',
     '  this.DoIt = function () {',
     '  this.DoIt = function () {',
@@ -30549,14 +30550,14 @@ begin
     '  this.DoIt = function () {',
     '  this.DoIt = function () {',
     '  };',
     '  };',
     '  var $r = this.$rtti;',
     '  var $r = this.$rtti;',
-    '  $r.addMethod("DoIt", 0, null);',
+    '  $r.addMethod("DoIt", 0, []);',
     '});',
     '});',
     'rtl.createClass(this, "TSky", this.TObject, function () {',
     'rtl.createClass(this, "TSky", this.TObject, function () {',
     '  this.DoIt = function () {',
     '  this.DoIt = function () {',
     '    $mod.TObject.DoIt.call(this);',
     '    $mod.TObject.DoIt.call(this);',
     '  };',
     '  };',
     '  var $r = this.$rtti;',
     '  var $r = this.$rtti;',
-    '  $r.addMethod("DoIt", 0, null);',
+    '  $r.addMethod("DoIt", 0, []);',
     '});',
     '});',
     '']),
     '']),
     LinesToStr([ // $mod.$main
     LinesToStr([ // $mod.$main
@@ -30633,7 +30634,7 @@ begin
     '});',
     '});',
     'this.$rtti.$Class("TBridge");',
     'this.$rtti.$Class("TBridge");',
     'this.$rtti.$ProcVar("TProc", {',
     'this.$rtti.$ProcVar("TProc", {',
-    '  procsig: rtl.newTIProcSig(null, this.$rtti["TBridge"])',
+    '  procsig: rtl.newTIProcSig([], this.$rtti["TBridge"])',
     '});',
     '});',
     'rtl.createClass(this, "TOger", this.TObject, function () {',
     'rtl.createClass(this, "TOger", this.TObject, function () {',
     '  this.$init = function () {',
     '  this.$init = function () {',
@@ -30696,7 +30697,7 @@ begin
     '  instancetype: this.$rtti["TObject"]',
     '  instancetype: this.$rtti["TObject"]',
     '});',
     '});',
     'this.$rtti.$ProcVar("TProcA", {',
     'this.$rtti.$ProcVar("TProcA", {',
-    '  procsig: rtl.newTIProcSig(null, this.$rtti["TClass"])',
+    '  procsig: rtl.newTIProcSig([], this.$rtti["TClass"])',
     '});',
     '});',
     'rtl.createClass(this, "TObject", null, function () {',
     'rtl.createClass(this, "TObject", null, function () {',
     '  this.$init = function () {',
     '  this.$init = function () {',
@@ -31169,10 +31170,10 @@ begin
     '  eltype: rtl.string',
     '  eltype: rtl.string',
     '});',
     '});',
     'this.$rtti.$ProcVar("TProc", {',
     'this.$rtti.$ProcVar("TProc", {',
-    '  procsig: rtl.newTIProcSig(null)',
+    '  procsig: rtl.newTIProcSig([])',
     '});',
     '});',
     'this.$rtti.$MethodVar("TMethod", {',
     'this.$rtti.$MethodVar("TMethod", {',
-    '  procsig: rtl.newTIProcSig(null),',
+    '  procsig: rtl.newTIProcSig([]),',
     '  methodkind: 0',
     '  methodkind: 0',
     '});',
     '});',
     'this.StaticArray = rtl.arraySetLength(null,"",2);',
     'this.StaticArray = rtl.arraySetLength(null,"",2);',
@@ -31457,7 +31458,7 @@ begin
     '  null,',
     '  null,',
     '  function () {',
     '  function () {',
     '    var $r = this.$rtti;',
     '    var $r = this.$rtti;',
-    '    $r.addMethod("GetItem", 1, null, rtl.longint);',
+    '    $r.addMethod("GetItem", 1, [], rtl.longint);',
     '    $r.addMethod("SetItem", 0, [["Value", rtl.longint]]);',
     '    $r.addMethod("SetItem", 0, [["Value", rtl.longint]]);',
     '    $r.addProperty("Item", 3, rtl.longint, "GetItem", "SetItem");',
     '    $r.addProperty("Item", 3, rtl.longint, "GetItem", "SetItem");',
     '  }',
     '  }',
@@ -31524,8 +31525,8 @@ begin
     '    this.$kind = "com";',
     '    this.$kind = "com";',
     '    var $r = this.$rtti;',
     '    var $r = this.$rtti;',
     '    $r.addMethod("QueryInterface", 1, [["iid", $mod.$rtti["TGuid"], 2], ["obj", null, 4]], rtl.longint);',
     '    $r.addMethod("QueryInterface", 1, [["iid", $mod.$rtti["TGuid"], 2], ["obj", null, 4]], rtl.longint);',
-    '    $r.addMethod("_AddRef", 1, null, rtl.longint);',
-    '    $r.addMethod("_Release", 1, null, rtl.longint);',
+    '    $r.addMethod("_AddRef", 1, [], rtl.longint);',
+    '    $r.addMethod("_Release", 1, [], rtl.longint);',
     '  }',
     '  }',
     ');',
     ');',
     'rtl.createInterface(',
     'rtl.createInterface(',
@@ -31536,7 +31537,7 @@ begin
     '  this.IUnknown,',
     '  this.IUnknown,',
     '  function () {',
     '  function () {',
     '    var $r = this.$rtti;',
     '    var $r = this.$rtti;',
-    '    $r.addMethod("GetItem", 1, null, rtl.longint);',
+    '    $r.addMethod("GetItem", 1, [], rtl.longint);',
     '    $r.addMethod("SetItem", 0, [["Value", rtl.longint]]);',
     '    $r.addMethod("SetItem", 0, [["Value", rtl.longint]]);',
     '    $r.addProperty("Item", 3, rtl.longint, "GetItem", "SetItem");',
     '    $r.addProperty("Item", 3, rtl.longint, "GetItem", "SetItem");',
     '  }',
     '  }',
@@ -31588,7 +31589,7 @@ begin
     '    return Result;',
     '    return Result;',
     '  };',
     '  };',
     '  var $r = this.$rtti;',
     '  var $r = this.$rtti;',
-    '  $r.addMethod("GetItem", 1, null, rtl.longint);',
+    '  $r.addMethod("GetItem", 1, [], rtl.longint);',
     '  $r.addProperty("Item", 1, rtl.longint, "GetItem", "");',
     '  $r.addProperty("Item", 1, rtl.longint, "GetItem", "");',
     '});',
     '});',
     'this.t = null;',
     'this.t = null;',
@@ -31676,8 +31677,8 @@ begin
     '  pas.system.IUnknown,',
     '  pas.system.IUnknown,',
     '  function () {',
     '  function () {',
     '    var $r = this.$rtti;',
     '    var $r = this.$rtti;',
-    '    $r.addMethod("Swoop", 1, null, pas.unit2.$rtti["TWordArray"]);',
-    '    $r.addMethod("Glide", 1, null, pas.unit2.$rtti["TArray<System.Word>"]);',
+    '    $r.addMethod("Swoop", 1, [], pas.unit2.$rtti["TWordArray"]);',
+    '    $r.addMethod("Glide", 1, [], pas.unit2.$rtti["TArray<System.Word>"]);',
     '  }',
     '  }',
     ');',
     ');',
     'this.Fly = function () {',
     'this.Fly = function () {',
@@ -31882,7 +31883,7 @@ begin
     '      attr: [$mod.TCustomAttribute, "Create$1", [14]]',
     '      attr: [$mod.TCustomAttribute, "Create$1", [14]]',
     '    }',
     '    }',
     '  );',
     '  );',
-    '  $r.addMethod("Fly", 0, null, null, {',
+    '  $r.addMethod("Fly", 0, [], null, 0, {',
     '    attr: [$mod.TCustomAttribute, "Create$1", [15]]',
     '    attr: [$mod.TCustomAttribute, "Create$1", [15]]',
     '  });',
     '  });',
     '});',
     '});',

+ 5 - 2
packages/winunits-base/src/comserv.pp

@@ -205,9 +205,12 @@ end;
 function GetModuleFileName: String;
 function GetModuleFileName: String;
 const
 const
   MAX_PATH_SIZE = 2048;
   MAX_PATH_SIZE = 2048;
+var
+  FileName: WideString;
 begin
 begin
-  SetLength(Result, MAX_PATH_SIZE);
-  SetLength(Result, Windows.GetModuleFileName(HInstance, @Result[1], MAX_PATH_SIZE));
+  SetLength(FileName, MAX_PATH_SIZE);
+  SetLength(FileName, Windows.GetModuleFileNameW(HInstance, @FileName[1], MAX_PATH_SIZE));
+  Result := FileName;
 end;
 end;
 
 
 function GetModuleName: String;
 function GetModuleName: String;

+ 13 - 2
rtl/aarch64/math.inc

@@ -51,6 +51,19 @@
     {$endif FPC_SYSTEM_HAS_SQRT}
     {$endif FPC_SYSTEM_HAS_SQRT}
 
 
 
 
+{$ifndef VER3_2}
+    {$ifndef FPC_SYSTEM_HAS_FRAC}
+    {$define FPC_SYSTEM_HAS_FRAC}
+    function fpc_frac_real(d : ValReal) : ValReal;compilerproc;
+      begin
+        { Function is handled internal in the compiler }
+        runerror(207);
+        result:=0;
+      end;
+    {$endif FPC_SYSTEM_HAS_FRAC}
+{$endif VER3_2}
+
+
     {$ifndef FPC_SYSTEM_HAS_INT}
     {$ifndef FPC_SYSTEM_HAS_INT}
     {$define FPC_SYSTEM_HAS_INT}
     {$define FPC_SYSTEM_HAS_INT}
     function fpc_int_real(d : ValReal) : ValReal;assembler;nostackframe;compilerproc;
     function fpc_int_real(d : ValReal) : ValReal;assembler;nostackframe;compilerproc;
@@ -82,5 +95,3 @@
         fcvtzs x0,d0
         fcvtzs x0,d0
       end;
       end;
     {$endif FPC_SYSTEM_HAS_ROUND}
     {$endif FPC_SYSTEM_HAS_ROUND}
-
-

+ 8 - 8
rtl/aarch64/mathu.inc

@@ -14,25 +14,25 @@
 
 
 {$asmmode gas}
 {$asmmode gas}
 
 
-function getfpcr: dword; nostackframe; assembler;
+function getfpcr: qword; nostackframe; assembler;
   asm
   asm
     mrs x0,fpcr
     mrs x0,fpcr
   end;
   end;
 
 
 
 
-procedure setfpcr(val: dword); nostackframe; assembler;
+procedure setfpcr(val: qword); nostackframe; assembler;
   asm
   asm
     msr fpcr,x0
     msr fpcr,x0
   end;
   end;
 
 
 
 
-function getfpsr: dword; nostackframe; assembler;
+function getfpsr: qword; nostackframe; assembler;
   asm
   asm
     mrs x0,fpsr
     mrs x0,fpsr
   end;
   end;
 
 
 
 
-procedure setfpsr(val: dword); nostackframe; assembler;
+procedure setfpsr(val: qword); nostackframe; assembler;
   asm
   asm
     msr fpsr, x0
     msr fpsr, x0
   end;
   end;
@@ -75,7 +75,7 @@ const
   fpu_ufe = 1 shl 11;
   fpu_ufe = 1 shl 11;
   fpu_ixe = 1 shl 12;
   fpu_ixe = 1 shl 12;
   fpu_ide = 1 shl 15;
   fpu_ide = 1 shl 15;
-  fpu_exception_mask = fpu_ioe or fpu_dze or fpu_ofe or fpu_ufe or fpu_ixe or fpu_ide;
+  fpu_exception_mask = qword(fpu_ioe or fpu_dze or fpu_ofe or fpu_ufe or fpu_ixe or fpu_ide);
   fpu_exception_mask_to_status_mask_shift = 8;
   fpu_exception_mask_to_status_mask_shift = 8;
 
 
 
 
@@ -111,13 +111,13 @@ function GetExceptionMask: TFPUExceptionMask;
 
 
 function SetExceptionMask(const Mask: TFPUExceptionMask): TFPUExceptionMask;
 function SetExceptionMask(const Mask: TFPUExceptionMask): TFPUExceptionMask;
   var
   var
-    newfpcr: dword;
+    newfpcr: qword;
   begin
   begin
     { clear "exception happened" flags }
     { clear "exception happened" flags }
     ClearExceptions(false);
     ClearExceptions(false);
     softfloat_exception_mask:=mask;
     softfloat_exception_mask:=mask;
 
 
-    { at least the ThunderX AArch64 support apperently hardware exceptions,
+    { at least the ThunderX AArch64 support apparently hardware exceptions,
       so set fpcr correctly, thought it might be WI on most implementations it does not hurt
       so set fpcr correctly, thought it might be WI on most implementations it does not hurt
     }
     }
     newfpcr:=fpu_exception_mask;
     newfpcr:=fpu_exception_mask;
@@ -143,7 +143,7 @@ function SetExceptionMask(const Mask: TFPUExceptionMask): TFPUExceptionMask;
 
 
 procedure ClearExceptions(RaisePending: Boolean);
 procedure ClearExceptions(RaisePending: Boolean);
   var
   var
-    fpsr: dword;
+    fpsr: qword;
     f: TFPUException;
     f: TFPUException;
   begin
   begin
     fpsr:=getfpsr;
     fpsr:=getfpsr;

+ 1 - 1
rtl/darwin/Makefile

@@ -3293,7 +3293,7 @@ include $(INC)/makefile.inc
 SYSINCDEPS=$(addprefix $(INC)/,$(SYSINCNAMES))
 SYSINCDEPS=$(addprefix $(INC)/,$(SYSINCNAMES))
 include $(PROCINC)/makefile.cpu
 include $(PROCINC)/makefile.cpu
 SYSCPUDEPS=$(addprefix $(PROCINC)/,$(CPUINCNAMES))
 SYSCPUDEPS=$(addprefix $(PROCINC)/,$(CPUINCNAMES))
-SYSDEPS=$(SYSINCDEPS) $(SYSCPUDEPS)
+SYSDEPS=$(SYSINCDEPS) $(SYSCPUDEPS) sighnd.inc sig_cpu.inc
 $(SYSTEMUNIT)$(PPUEXT) : $(BSDINC)/$(SYSTEMUNIT).pp $(SYSDEPS)
 $(SYSTEMUNIT)$(PPUEXT) : $(BSDINC)/$(SYSTEMUNIT).pp $(SYSDEPS)
 	$(COMPILER) $(FPC_SYSTEM_OPT) -Us -Sg $(BSDINC)/$(SYSTEMUNIT).pp
 	$(COMPILER) $(FPC_SYSTEM_OPT) -Us -Sg $(BSDINC)/$(SYSTEMUNIT).pp
 sysinit$(PPUEXT) : sysinit.pas $(SYSTEMUNIT)$(PPUEXT)
 sysinit$(PPUEXT) : sysinit.pas $(SYSTEMUNIT)$(PPUEXT)

+ 1 - 1
rtl/darwin/Makefile.fpc

@@ -116,7 +116,7 @@ include $(PROCINC)/makefile.cpu
 SYSCPUDEPS=$(addprefix $(PROCINC)/,$(CPUINCNAMES))
 SYSCPUDEPS=$(addprefix $(PROCINC)/,$(CPUINCNAMES))
 
 
 # Put system unit dependencies together.
 # Put system unit dependencies together.
-SYSDEPS=$(SYSINCDEPS) $(SYSCPUDEPS)
+SYSDEPS=$(SYSINCDEPS) $(SYSCPUDEPS) sighnd.inc sig_cpu.inc
 
 
 
 
 #
 #

+ 7 - 5
rtl/objpas/sysutils/dati.inc

@@ -75,18 +75,20 @@ end;
 {   MSecsToTimeStamp   }
 {   MSecsToTimeStamp   }
 
 
 function MSecsToTimeStamp(MSecs: comp): TTimeStamp;
 function MSecsToTimeStamp(MSecs: comp): TTimeStamp;
+var
+  D1:Int64;
 begin
 begin
-  result.Date := Trunc(msecs / msecsperday);
-  msecs:= msecs-comp(result.date)*msecsperday;
-  result.Time := Round(MSecs);
-end ;
+  D1:=Trunc(msecs);
+  result.Date := D1 div msecsperday;
+  result.Time := D1 - result.date * msecsperday;
+end;
 
 
 {   TimeStampToMSecs   }
 {   TimeStampToMSecs   }
 
 
 function TimeStampToMSecs(const TimeStamp: TTimeStamp): comp;
 function TimeStampToMSecs(const TimeStamp: TTimeStamp): comp;
 begin
 begin
   result := TimeStamp.Time + comp(timestamp.date)*msecsperday;
   result := TimeStamp.Time + comp(timestamp.date)*msecsperday;
-end ;
+end;
 
 
 Function TryEncodeDate(Year,Month,Day : Word; Out Date : TDateTime) : Boolean;
 Function TryEncodeDate(Year,Month,Day : Word; Out Date : TDateTime) : Boolean;
 
 

+ 1 - 1
rtl/objpas/sysutils/filutilh.inc

@@ -17,7 +17,7 @@ Type
 
 
 
 
   // Some operating systems need FindHandle to be a Pointer
   // Some operating systems need FindHandle to be a Pointer
-{$if defined(unix) or defined(msdos) or defined(hasamiga) or defined(atari) or defined(win16)}
+{$if defined(unix) or defined(msdos) or defined(hasamiga) or defined(atari) or defined(win16) or defined(sinclairql)}
     {$define FINDHANDLE_IS_POINTER}
     {$define FINDHANDLE_IS_POINTER}
 {$endif}
 {$endif}
 
 

+ 1 - 1
rtl/objpas/sysutils/osutil.inc

@@ -245,7 +245,7 @@ begin
     Repeat
     Repeat
       Result:=Format('%s%.5d.tmp',[Start,I]);
       Result:=Format('%s%.5d.tmp',[Start,I]);
       Inc(I);
       Inc(I);
-    Until not FileExists(Result);
+    Until not (FileExists(Result) or DirectoryExists(Result));
     end;
     end;
 end;
 end;
 {$endif}
 {$endif}

+ 4 - 3
rtl/sinclairql/buildrtl.pp

@@ -4,11 +4,12 @@ unit buildrtl;
 
 
     uses
     uses
       si_prc,
       si_prc,
+      sysutils,
 
 
       ctypes, strings,
       ctypes, strings,
-      rtlconsts, {sysconst,} {math,} {types,}
-      {typinfo,} sortbase, {fgl,} {classes,}
-      charset, {character,} {getopts,}
+      rtlconsts, sysconst, math, types,
+      typinfo, sortbase, fgl, classes,
+      charset, character, getopts,
       fpwidestring;
       fpwidestring;
 
 
   implementation
   implementation

+ 50 - 0
rtl/sinclairql/classes.pp

@@ -0,0 +1,50 @@
+{
+    This file is part of the Free Component Library (FCL)
+    Copyright (c) 2021 by the Free Pascal development team
+
+    Classes unit for the Sinclair QL
+
+    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.
+
+ **********************************************************************}
+
+{$mode objfpc}
+
+{ determine the type of the resource/form file }
+{$define Win16Res}
+
+unit Classes;
+
+interface
+
+uses
+  sysutils,
+  rtlconsts,
+  types,
+  sortbase,
+{$ifdef FPC_TESTGENERICS}
+  fgl,
+{$endif}
+  typinfo;
+
+{$i classesh.inc}
+
+
+implementation
+
+{ OS - independent class implementations are in /inc directory. }
+{$i classes.inc}
+
+
+initialization
+  CommonInit;
+
+finalization
+  CommonCleanup;
+
+end.

+ 1 - 1
rtl/sinclairql/si_prc.pp

@@ -107,7 +107,7 @@ asm
     add.l d1,d2
     add.l d1,d2
     add.l d0,(a0,d2)
     add.l d0,(a0,d2)
     subq.l #1,d7
     subq.l #1,d7
-    bpl @relocloop
+    bgt @relocloop
 {$ENDIF PACKEDRELOCS}
 {$ENDIF PACKEDRELOCS}
 
 
 @noreloc:
 @noreloc:

+ 501 - 0
rtl/sinclairql/sysutils.pp

@@ -0,0 +1,501 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2021 by Free Pascal development team
+
+    Sysutils unit for Sinclair QL
+
+    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.
+
+ **********************************************************************}
+
+unit sysutils;
+
+interface
+
+{$MODE objfpc}
+{$MODESWITCH OUT}
+{ force ansistrings }
+{$H+}
+{$modeswitch typehelpers}
+{$modeswitch advancedrecords}
+
+{$DEFINE OS_FILESETDATEBYNAME}
+{$DEFINE HAS_SLEEP}
+{$DEFINE HAS_OSERROR}
+
+{OS has only 1 byte version for ExecuteProcess}
+{$define executeprocuni}
+
+{ used OS file system APIs use ansistring }
+{$define SYSUTILS_HAS_ANSISTR_FILEUTIL_IMPL}
+{ OS has an ansistring/single byte environment variable API }
+{$define SYSUTILS_HAS_ANSISTR_ENVVAR_IMPL}
+
+{ Include platform independent interface part }
+{$i sysutilh.inc}
+
+{ Platform dependent calls }
+
+
+implementation
+
+uses
+  sysconst;
+
+{$DEFINE FPC_FEXPAND_UNC} (* UNC paths are supported *)
+{$DEFINE FPC_FEXPAND_DRIVES} (* Full paths begin with drive specification *)
+
+{ Include platform independent implementation part }
+{$i sysutils.inc}
+
+{$i qdosfuncs.inc}
+{$i smsfuncs.inc}
+
+{****************************************************************************
+                              File Functions
+****************************************************************************}
+{$I-}{ Required for correct usage of these routines }
+
+
+(****** non portable routines ******)
+
+function FileOpen(const FileName: rawbytestring; Mode: Integer): THandle;
+begin
+  FileOpen:=-1;
+  if FileOpen < -1 then
+    FileOpen:=-1;
+end;
+
+
+function FileGetDate(Handle: THandle) : Int64;
+begin
+  result:=-1;
+end;
+
+
+function FileSetDate(Handle: THandle; Age: Int64) : LongInt;
+begin
+  result:=0;
+end;
+
+
+function FileSetDate(const FileName: RawByteString; Age: Int64) : LongInt;
+var
+  f: THandle;
+begin
+  result:=-1;
+  f:=FileOpen(FileName,fmOpenReadWrite);
+  if f < 0 then
+    exit;
+  result:=FileSetDate(f,Age);
+  FileClose(f);
+end;
+
+
+function FileCreate(const FileName: RawByteString) : THandle;
+begin
+  FileCreate:=-1;
+  if FileCreate < -1 then
+    FileCreate:=-1;
+end;
+
+function FileCreate(const FileName: RawByteString; Rights: integer): THandle;
+begin
+  { Rights don't exist on the QL, so we simply map this to FileCreate() }
+  FileCreate:=FileCreate(FileName);
+end;
+
+function FileCreate(const FileName: RawByteString; ShareMode: integer; Rights : integer): THandle;
+begin
+  { Rights and ShareMode don't exist on the QL so we simply map this to FileCreate() }
+  FileCreate:=FileCreate(FileName);
+end;
+
+
+function FileRead(Handle: THandle; out Buffer; Count: LongInt): LongInt;
+begin
+  FileRead:=-1;
+  if (Count<=0) then
+    exit;
+
+  FileRead:=-1;
+  if FileRead < -1 then
+    FileRead:=-1;
+end;
+
+
+function FileWrite(Handle: THandle; const Buffer; Count: LongInt): LongInt;
+begin
+  FileWrite:=-1;
+  if (Count<=0) then 
+    exit;
+
+  FileWrite:=-1;
+  if FileWrite < -1 then
+    FileWrite:=-1;
+end;
+
+
+function FileSeek(Handle: THandle; FOffset, Origin: LongInt) : LongInt;
+var
+  dosResult: longint;
+begin
+  FileSeek:=-1;
+
+  dosResult:=-1;
+  if dosResult < 0 then
+    exit;
+
+  FileSeek:=dosResult;
+end;
+
+function FileSeek(Handle: THandle; FOffset: Int64; Origin: Longint): Int64;
+begin
+  FileSeek:=FileSeek(Handle,LongInt(FOffset),Origin);
+end;
+
+
+procedure FileClose(Handle: THandle);
+begin
+end;
+
+
+function FileTruncate(Handle: THandle; Size: Int64): Boolean;
+begin
+  FileTruncate:=False;
+end;
+
+
+function DeleteFile(const FileName: RawByteString) : Boolean;
+begin
+  DeleteFile:=false;
+end;
+
+
+function RenameFile(const OldName, NewName: RawByteString): Boolean;
+begin
+  RenameFile:=false;
+end;
+
+
+
+(****** end of non portable routines ******)
+
+
+function FileAge (const FileName : RawByteString): Int64;
+var
+  f: THandle;
+begin
+  FileAge:=-1;
+  f:=FileOpen(FileName,fmOpenRead);
+  if f < 0 then
+    exit;
+  FileAge:=FileGetDate(f);
+  FileClose(f);
+end;
+
+
+function FileGetSymLinkTarget(const FileName: RawByteString; out SymLinkRec: TRawbyteSymLinkRec): Boolean;
+begin
+  Result := False;
+end;
+
+
+function FileExists (const FileName : RawByteString; FollowLink : Boolean) : Boolean;
+var
+  Attr: longint;
+begin
+  FileExists:=false;
+  Attr:=FileGetAttr(FileName);
+  if Attr < 0 then
+    exit;
+
+  result:=(Attr and (faVolumeID or faDirectory)) = 0;
+end;
+
+
+type
+  PInternalFindData = ^TInternalFindData;
+  TInternalFindData = record
+    dummy: pointer;
+  end;
+
+
+Function InternalFindFirst (Const Path : RawByteString; Attr : Longint; out Rslt : TAbstractSearchRec; var Name: RawByteString) : Longint;
+var
+  dosResult: longint;
+  IFD: PInternalFindData;
+begin
+  result:=-1; { We emulate Linux/Unix behaviour, and return -1 on errors. }
+
+  new(IFD);
+  IFD^.dummy:=nil;
+
+  Rslt.FindHandle:=nil;
+  dosResult:=-1; { add findfirst here }
+  if dosResult < 0 then
+    begin
+      InternalFindClose(IFD);
+      exit;
+    end;
+
+  Rslt.FindHandle:=IFD;
+
+  Name:='';
+  SetCodePage(Name,DefaultFileSystemCodePage,false);
+
+  Rslt.Time:=0;
+  Rslt.Size:=0;
+
+  { "128" is Windows "NORMALFILE" attribute. Some buggy code depend on this... :( (KB) }
+  Rslt.Attr := 128 or 0;
+
+  result:=0;
+end;
+
+
+Function InternalFindNext (var Rslt : TAbstractSearchRec; var Name : RawByteString) : Longint;
+var
+  dosResult: longint;
+  IFD: PInternalFindData;
+begin
+  result:=-1;
+  IFD:=PInternalFindData(Rslt.FindHandle);
+  if not assigned(IFD) then
+    exit;
+
+  dosResult:=-1;
+  if dosResult < 0 then
+    exit;
+
+  Name:='';
+  SetCodePage(Name,DefaultFileSystemCodePage,false);
+
+  Rslt.Time:=0;
+  Rslt.Size:=0;
+
+  { "128" is Windows "NORMALFILE" attribute. Some buggy code depend on this... :( (KB) }
+  Rslt.Attr := 128 or 0;
+
+  result:=0;
+end;
+
+
+Procedure InternalFindClose(var Handle: Pointer);
+var
+  IFD: PInternalFindData;
+begin
+  IFD:=PInternalFindData(Handle);
+  if not assigned(IFD) then
+    exit;
+
+  dispose(IFD);
+end;
+
+
+(****** end of non portable routines ******)
+
+Function FileGetAttr (Const FileName : RawByteString) : Longint;
+begin
+  FileGetAttr:=0;
+end;
+
+
+Function FileSetAttr (Const Filename : RawByteString; Attr: longint) : Longint;
+begin
+  FileSetAttr:=-1;
+
+  if FileSetAttr < -1 then
+    FileSetAttr:=-1
+  else
+    FileSetAttr:=0;
+end;
+
+
+
+{****************************************************************************
+                              Disk Functions
+****************************************************************************}
+
+function DiskSize(Drive: Byte): Int64;
+var
+  dosResult: longint;
+begin
+  DiskSize := -1;
+
+  dosResult:=-1;
+  if dosResult < 0 then
+    exit;
+
+  DiskSize:=0;
+end;
+
+function DiskFree(Drive: Byte): Int64;
+var
+  dosResult: longint;
+begin
+  DiskFree := -1;
+
+  dosResult:=-1;
+  if dosResult < 0 then
+    exit;
+
+  DiskFree:=0;
+end;
+
+function DirectoryExists(const Directory: RawByteString; FollowLink : Boolean): Boolean;
+var
+  Attr: longint;
+begin
+  DirectoryExists:=false;
+  Attr:=FileGetAttr(Directory);
+  if Attr < 0 then
+    exit;
+
+  result:=(Attr and faDirectory) <> 0;
+end;
+
+
+
+{****************************************************************************
+                              Locale Functions
+****************************************************************************}
+
+Procedure GetLocalTime(var SystemTime: TSystemTime);
+begin
+   DateTimeToSystemTime(FileDateToDateTime(0),SystemTime);
+end;
+
+
+Procedure InitAnsi;
+Var
+  i : longint;
+begin
+  {  Fill table entries 0 to 127  }
+  for i := 0 to 96 do
+    UpperCaseTable[i] := chr(i);
+  for i := 97 to 122 do
+    UpperCaseTable[i] := chr(i - 32);
+  for i := 123 to 191 do
+    UpperCaseTable[i] := chr(i);
+  Move (CPISO88591UCT,UpperCaseTable[192],SizeOf(CPISO88591UCT));
+
+  for i := 0 to 64 do
+    LowerCaseTable[i] := chr(i);
+  for i := 65 to 90 do
+    LowerCaseTable[i] := chr(i + 32);
+  for i := 91 to 191 do
+    LowerCaseTable[i] := chr(i);
+  Move (CPISO88591LCT,UpperCaseTable[192],SizeOf(CPISO88591UCT));
+end;
+
+
+Procedure InitInternational;
+begin
+  InitInternationalGeneric;
+  InitAnsi;
+end;
+
+function SysErrorMessage(ErrorCode: Integer): String;
+begin
+  Result:=Format(SUnknownErrorCode,[ErrorCode]);
+end;
+
+function GetLastOSError: Integer;
+begin
+  result:=-1;
+end;
+
+{****************************************************************************
+                              OS utility functions
+****************************************************************************}
+
+function GetPathString: String;
+begin
+  {writeln('Unimplemented GetPathString');}
+  result := '';
+end;
+
+Function GetEnvironmentVariable(Const EnvVar : String) : String;
+begin
+  {writeln('Unimplemented GetEnvironmentVariable');}
+  result:='';
+end;
+
+Function GetEnvironmentVariableCount : Integer;
+begin
+  {writeln('Unimplemented GetEnvironmentVariableCount');}
+  result:=0;
+end;
+
+Function GetEnvironmentString(Index : Integer) : {$ifdef FPC_RTL_UNICODE}UnicodeString{$else}AnsiString{$endif};
+begin
+  {writeln('Unimplemented GetEnvironmentString');}
+  result:='';
+end;
+
+function ExecuteProcess (const Path: RawByteString; const ComLine: RawByteString;Flags:TExecuteFlags=[]):
+                                                                       integer;
+var
+  tmpPath: RawByteString;
+  pcmdline: ShortString;
+  CommandLine: RawByteString;
+  E: EOSError;
+begin
+  tmpPath:=ToSingleByteFileSystemEncodedFileName(Path);
+  pcmdline:=ToSingleByteFileSystemEncodedFileName(ComLine);
+
+  result:=-1; { execute here }
+
+  if result < 0 then begin
+    if ComLine = '' then
+      CommandLine := Path
+    else
+      CommandLine := Path + ' ' + ComLine;
+
+    E := EOSError.CreateFmt (SExecuteProcessFailed, [CommandLine, result]);
+    E.ErrorCode := result;
+    raise E;
+  end;
+end;
+
+function ExecuteProcess (const Path: RawByteString;
+                                  const ComLine: array of RawByteString;Flags:TExecuteFlags=[]): integer;
+var
+  CommandLine: RawByteString;
+  I: integer;
+
+begin
+  Commandline := '';
+  for I := 0 to High (ComLine) do
+   if Pos (' ', ComLine [I]) <> 0 then
+    CommandLine := CommandLine + ' ' + '"' + ToSingleByteFileSystemEncodedFileName(ComLine [I]) + '"'
+   else
+    CommandLine := CommandLine + ' ' + ToSingleByteFileSystemEncodedFileName(Comline [I]);
+  ExecuteProcess := ExecuteProcess (Path, CommandLine);
+end;
+
+procedure Sleep(Milliseconds: cardinal);
+begin
+  {writeln('Unimplemented sleep');}
+end;
+
+
+{****************************************************************************
+                              Initialization code
+****************************************************************************}
+
+Initialization
+  InitExceptions;
+  InitInternational;    { Initialize internationalization settings }
+  OnBeep:=Nil;          { No SysBeep() on the QL for now. }
+
+Finalization
+  FreeTerminateProcs;
+  DoneExceptions;
+end.

+ 9 - 4
rtl/win/sysutils.pp

@@ -1037,14 +1037,19 @@ end;
                               Locale Functions
                               Locale Functions
 ****************************************************************************}
 ****************************************************************************}
 
 
-function GetLocaleStr(LID, LT: Longint; const Def: string): ShortString;
+function GetLocaleStr(LID, LT: Longint; const Def: string): AnsiString;
 var
 var
   L: Integer;
   L: Integer;
-  Buf: array[0..255] of Char;
+  Buf: unicodestring;
 begin
 begin
-  L := GetLocaleInfoA(LID, LT, Buf, SizeOf(Buf));
+  L := GetLocaleInfoW(LID, LT, nil, 0);
   if L > 0 then
   if L > 0 then
-    SetString(Result, @Buf[0], L - 1)
+    begin
+      SetLength(Buf,L-1); // L includes terminating NULL
+      if l>1 Then
+        L := GetLocaleInfoW(LID, LT, @Buf[1], L);
+      result:=buf;
+    end
   else
   else
     Result := Def;
     Result := Def;
 end;
 end;

+ 8 - 0
tests/tbf/tb0274.pp

@@ -0,0 +1,8 @@
+{ %fail }
+{ %opt=-Sew }
+var 
+  c : comp;
+
+begin
+  c:=123.123;
+end.

+ 22 - 0
tests/webtbf/tw38771.pp

@@ -0,0 +1,22 @@
+{ %FAIL }
+{$mode objfpc}
+
+program tw38771;
+
+type
+  TMyClass = class
+    generic procedure DoThis<T>(msg: T);
+    generic procedure DoThat<T>(msg: T); virtual;
+  end;
+
+generic procedure TMyClass.DoThis<T>(msg:T);
+begin
+  specialize DoThat<T>(msg);
+end;
+
+generic procedure TMyClass.DoThat<T>(msg: T);
+begin
+end;
+
+begin
+end.

+ 42 - 0
tests/webtbs/tw38353.pp

@@ -0,0 +1,42 @@
+{ %OPT=-Cg -O2 }
+{ %CPU=x86_64 }
+
+{ -Cg and -O2 options together lead to 
+  the generation of instruction:
+  testq   $15,U_$P$VECTORCALL_HVA_TEST1_$$_HVA@GOTPCREL(%rip)
+  for which the relocation was not correctly generated
+  in the internal assembler }
+
+program tw38353;
+
+{$IFNDEF CPUX86_64}
+  {$FATAL This test program can only be compiled on Windows or Linux 64-bit with an Intel processor }
+{$ENDIF}
+
+{$ASMMODE Intel}
+{$PUSH}
+{$CODEALIGN RECORDMIN=16}
+{$PACKRECORDS C}
+type
+  TM128 = record
+    case Byte of
+      0: (M128_F32: array[0..3] of Single);
+      1: (M128_F64: array[0..1] of Double);
+  end;
+{$POP}
+
+var
+  HVA: TM128;
+
+begin
+{$ifdef verbose}
+  writeln('@HVA=',hexstr(ptruint(@HVA),2*sizeof(ptruint)));
+{$endif verbose}
+  if (PtrUInt(@HVA) and $F) <> 0 then
+  begin
+{$ifdef verbose}
+    WriteLn('FAIL: HVA is not correctly aligned.');
+{$endif verbose}
+    Halt(1);
+  end;
+end.

+ 23 - 0
tests/webtbs/tw38631.pp

@@ -0,0 +1,23 @@
+{$mode objfpc}
+program msec_test1;
+uses sysutils;
+
+var
+  D: TDateTime;
+  T, T1, T2: TTimeStamp;
+  MS: Comp;
+begin
+  D:=EncodeDate(2021, 03, 16) + EncodeTime(14, 02, 15, 1);
+  WriteLn('DATE: ', DateTimeToStr(D));
+
+  T:=DateTimeToTimeStamp(D);
+  WriteLn(' T.Date=',T.Date,'   T.Time=', T.Time);
+  MS:=TimeStampToMSecs(T);
+  T1:=MSecsToTimeStamp(MS);
+  WriteLn('T1.Date=',T1.Date,'  T1.Time=', T1.Time);
+  
+  WriteLn('DATE1: ', DateTimeToStr(TimeStampToDateTime(T1)));
+  if TimeStampToDateTime(T1)<>D then
+    halt(1);
+  writeln('ok')
+end.

+ 28 - 0
tests/webtbs/tw38766.pp

@@ -0,0 +1,28 @@
+{$mode objfpc}
+
+type
+  trec = record
+    x, y: longint;
+  end;
+
+function max(x,y: longint): longint;
+begin
+  if x>y then
+    result:=x
+  else
+    result:=y;
+end;
+
+function test: trec; inline;
+begin
+ result.x:=1;
+ result.y:=2;
+ result.x:=max(result.x,result.y);
+end;
+    
+begin
+  if test.x<>2 then
+    halt(1);
+  if test.y<>2 then
+    halt(2);
+end.

Some files were not shown because too many files changed in this diff