Git Product home page Git Product logo

ginger's People

Contributors

0x777 avatar agreif avatar danbornside avatar jkachmar avatar motching avatar mulderr avatar rcook avatar tdammers avatar tommd avatar traviscardwell avatar wchresta avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

ginger's Issues

test/Text/Ginger/SimulationTests.hs:1589 "recursive loops" test fails: expected: "a@1(b@2()c@2(d@3()))" but got: "a@1(c@2(d@3())b@2())"

Observed on current git repository and latest hackage release:

Using Parsec parser
Configuring ginger-0.10.1.0...
Dependency aeson >=1.4.2.0 && <1.6: using aeson-1.5.6.0
Dependency aeson-pretty >=0.8.7 && <0.9: using aeson-pretty-0.8.8
Dependency base >=4.8 && <5: using base-4.14.1.0
Dependency bytestring >=0.10.8.2 && <0.11: using bytestring-0.10.12.0
Dependency data-default >=0.5: using data-default-0.7.1.1
Dependency filepath >=1.3: using filepath-1.4.2.1
Dependency http-types >=0.8 && <0.11 || >=0.12: using http-types-0.12.3
Dependency mtl >=2.2: using mtl-2.2.2
Dependency parsec >=3.0: using parsec-3.1.14.0
Dependency regex-tdfa >=1.2.3 && <=1.5: using regex-tdfa-1.3.1.0
Dependency safe >=0.3: using safe-0.3.19
Dependency scientific >=0.3: using scientific-0.3.7.0
Dependency text >=1.2.3.1 && <1.3: using text-1.2.4.1
Dependency time >=0.1.6.0: using time-1.9.3
Dependency transformers >=0.3: using transformers-0.5.6.2
Dependency unordered-containers >=0.2.5: using unordered-containers-0.2.14.0
Dependency utf8-string >=1.0.1.1 && <1.1: using utf8-string-1.0.2
Dependency vector >=0.12.0.2 && <0.13: using vector-0.12.3.0
Dependency aeson >=1.4.2.0 && <1.6: using aeson-1.5.6.0
Dependency base >=4.8 && <5: using base-4.14.1.0
Dependency bytestring >=0.10.8.2 && <0.11: using bytestring-0.10.12.0
Dependency data-default >=0.5: using data-default-0.7.1.1
Dependency ginger -any: using ginger-0.10.1.0
Dependency optparse-applicative >=0.14.3.0 && <0.17: using
optparse-applicative-0.15.1.0
Dependency process >=1.6.5.0 && <1.7: using process-1.6.9.0
Dependency text >=1.2.3.1 && <1.3: using text-1.2.4.1
Dependency transformers >=0.5.6.2 && <0.6: using transformers-0.5.6.2
Dependency unordered-containers >=0.2.5: using unordered-containers-0.2.14.0
Dependency utf8-string >=1.0.1.1 && <1.1: using utf8-string-1.0.2
Dependency yaml >=0.11.0.0 && <0.12: using yaml-0.11.5.0
Dependency aeson >=1.4.2.0 && <1.6: using aeson-1.5.6.0
Dependency base >=4.8 && <5: using base-4.14.1.0
Dependency bytestring >=0.10.8.2 && <0.11: using bytestring-0.10.12.0
Dependency data-default >=0.5: using data-default-0.7.1.1
Dependency ginger -any: using ginger-0.10.1.0
Dependency mtl >=2.2.2 && <2.3: using mtl-2.2.2
Dependency tasty >=1.2 && <1.5: using tasty-1.2.3
Dependency tasty-hunit >=0.10.0.1 && <0.11: using tasty-hunit-0.10.0.3
Dependency tasty-quickcheck ==0.10.*: using tasty-quickcheck-0.10.1.2
Dependency text >=1.2.3.1 && <1.3: using text-1.2.4.1
Dependency time >=0.1.6.0: using time-1.9.3
Dependency transformers >=0.5.6.2 && <0.6: using transformers-0.5.6.2
Dependency unordered-containers >=0.2.5: using unordered-containers-0.2.14.0
Dependency utf8-string >=1.0.1.1 && <1.1: using utf8-string-1.0.2
Source component graph:
    component lib
    component exe:ginger dependency lib
    component test:tests dependency lib
Configured component graph:
    component ginger-0.10.1.0-L5phRogT5hkDDRKPTpRCGo
        include aeson-1.5.6.0-89mRhAl4FhxDxUb2oPr1Yf
        include aeson-pretty-0.8.8-ieY1twFXPI8cot6MF8MZ0
        include base-4.14.1.0
        include bytestring-0.10.12.0
        include data-default-0.7.1.1-B2xqLjZNDxg1KVbA6WyFWH
        include filepath-1.4.2.1
        include http-types-0.12.3-83JHnI2fUYa5h3vgNT9Hwz
        include mtl-2.2.2
        include parsec-3.1.14.0
        include regex-tdfa-1.3.1.0-86Ve5VgglvW23V5dPSAOm3
        include safe-0.3.19-36AYIiBjtSLS65WmTQ35k
        include scientific-0.3.7.0-2IwMamNipm4GhmqfKxrO1Z
        include text-1.2.4.1
        include time-1.9.3
        include transformers-0.5.6.2
        include unordered-containers-0.2.14.0-FjQASgh3rnkLSsvJG2xUpd
        include utf8-string-1.0.2-Lwtc54cgMl77YyeO5RGhjt
        include vector-0.12.3.0-DjRVptyTdiT3mipwWvt1jW
    component ginger-0.10.1.0-9F27pmIEmGCH0rvj1qRMKL-ginger
        include aeson-1.5.6.0-89mRhAl4FhxDxUb2oPr1Yf
        include base-4.14.1.0
        include bytestring-0.10.12.0
        include data-default-0.7.1.1-B2xqLjZNDxg1KVbA6WyFWH
        include ginger-0.10.1.0-L5phRogT5hkDDRKPTpRCGo
        include optparse-applicative-0.15.1.0-2hUbd3K4cmjHYvRpqoC7A4
        include process-1.6.9.0
        include text-1.2.4.1
        include transformers-0.5.6.2
        include unordered-containers-0.2.14.0-FjQASgh3rnkLSsvJG2xUpd
        include utf8-string-1.0.2-Lwtc54cgMl77YyeO5RGhjt
        include yaml-0.11.5.0-JSPy5Fxql0K85T1eoy4nPJ
    component ginger-0.10.1.0-7ADNA5QcqPfIMjoqXXCEiC-tests
        include aeson-1.5.6.0-89mRhAl4FhxDxUb2oPr1Yf
        include base-4.14.1.0
        include bytestring-0.10.12.0
        include data-default-0.7.1.1-B2xqLjZNDxg1KVbA6WyFWH
        include ginger-0.10.1.0-L5phRogT5hkDDRKPTpRCGo
        include mtl-2.2.2
        include tasty-1.2.3-7jQjHiJLVlG7T5lZlhi0Bc
        include tasty-hunit-0.10.0.3-5pFQPUD42om9FFVN9h9CyQ
        include tasty-quickcheck-0.10.1.2-G3SWIFemDG33gMlEXVff6g
        include text-1.2.4.1
        include time-1.9.3
        include transformers-0.5.6.2
        include unordered-containers-0.2.14.0-FjQASgh3rnkLSsvJG2xUpd
        include utf8-string-1.0.2-Lwtc54cgMl77YyeO5RGhjt
Linked component graph:
    unit ginger-0.10.1.0-L5phRogT5hkDDRKPTpRCGo
        include aeson-1.5.6.0-89mRhAl4FhxDxUb2oPr1Yf
        include aeson-pretty-0.8.8-ieY1twFXPI8cot6MF8MZ0
        include base-4.14.1.0
        include bytestring-0.10.12.0
        include data-default-0.7.1.1-B2xqLjZNDxg1KVbA6WyFWH
        include filepath-1.4.2.1
        include http-types-0.12.3-83JHnI2fUYa5h3vgNT9Hwz
        include mtl-2.2.2
        include parsec-3.1.14.0
        include regex-tdfa-1.3.1.0-86Ve5VgglvW23V5dPSAOm3
        include safe-0.3.19-36AYIiBjtSLS65WmTQ35k
        include scientific-0.3.7.0-2IwMamNipm4GhmqfKxrO1Z
        include text-1.2.4.1
        include time-1.9.3
        include transformers-0.5.6.2
        include unordered-containers-0.2.14.0-FjQASgh3rnkLSsvJG2xUpd
        include utf8-string-1.0.2-Lwtc54cgMl77YyeO5RGhjt
        include vector-0.12.3.0-DjRVptyTdiT3mipwWvt1jW
        Text.Ginger=ginger-0.10.1.0-L5phRogT5hkDDRKPTpRCGo:Text.Ginger,Text.Ginger.AST=ginger-0.10.1.0-L5phRogT5hkDDRKPTpRCGo:Text.Ginger.AST,Text.Ginger.GVal=ginger-0.10.1.0-L5phRogT5hkDDRKPTpRCGo:Text.Ginger.GVal,Text.Ginger.Html=ginger-0.10.1.0-L5phRogT5hkDDRKPTpRCGo:Text.Ginger.Html,Text.Ginger.Optimizer=ginger-0.10.1.0-L5phRogT5hkDDRKPTpRCGo:Text.Ginger.Optimizer,Text.Ginger.Parse=ginger-0.10.1.0-L5phRogT5hkDDRKPTpRCGo:Text.Ginger.Parse,Text.Ginger.Run=ginger-0.10.1.0-L5phRogT5hkDDRKPTpRCGo:Text.Ginger.Run,Text.Ginger.Run.Builtins=ginger-0.10.1.0-L5phRogT5hkDDRKPTpRCGo:Text.Ginger.Run.Builtins,Text.Ginger.Run.FuncUtils=ginger-0.10.1.0-L5phRogT5hkDDRKPTpRCGo:Text.Ginger.Run.FuncUtils,Text.Ginger.Run.Type=ginger-0.10.1.0-L5phRogT5hkDDRKPTpRCGo:Text.Ginger.Run.Type,Text.Ginger.Run.VM=ginger-0.10.1.0-L5phRogT5hkDDRKPTpRCGo:Text.Ginger.Run.VM,Text.PrintfA=ginger-0.10.1.0-L5phRogT5hkDDRKPTpRCGo:Text.PrintfA
    unit ginger-0.10.1.0-9F27pmIEmGCH0rvj1qRMKL-ginger
        include aeson-1.5.6.0-89mRhAl4FhxDxUb2oPr1Yf
        include base-4.14.1.0
        include bytestring-0.10.12.0
        include data-default-0.7.1.1-B2xqLjZNDxg1KVbA6WyFWH
        include ginger-0.10.1.0-L5phRogT5hkDDRKPTpRCGo
        include optparse-applicative-0.15.1.0-2hUbd3K4cmjHYvRpqoC7A4
        include process-1.6.9.0
        include text-1.2.4.1
        include transformers-0.5.6.2
        include unordered-containers-0.2.14.0-FjQASgh3rnkLSsvJG2xUpd
        include utf8-string-1.0.2-Lwtc54cgMl77YyeO5RGhjt
        include yaml-0.11.5.0-JSPy5Fxql0K85T1eoy4nPJ
    unit ginger-0.10.1.0-7ADNA5QcqPfIMjoqXXCEiC-tests
        include aeson-1.5.6.0-89mRhAl4FhxDxUb2oPr1Yf
        include base-4.14.1.0
        include bytestring-0.10.12.0
        include data-default-0.7.1.1-B2xqLjZNDxg1KVbA6WyFWH
        include ginger-0.10.1.0-L5phRogT5hkDDRKPTpRCGo
        include mtl-2.2.2
        include tasty-1.2.3-7jQjHiJLVlG7T5lZlhi0Bc
        include tasty-hunit-0.10.0.3-5pFQPUD42om9FFVN9h9CyQ
        include tasty-quickcheck-0.10.1.2-G3SWIFemDG33gMlEXVff6g
        include text-1.2.4.1
        include time-1.9.3
        include transformers-0.5.6.2
        include unordered-containers-0.2.14.0-FjQASgh3rnkLSsvJG2xUpd
        include utf8-string-1.0.2-Lwtc54cgMl77YyeO5RGhjt
Ready component graph:
    definite ginger-0.10.1.0-L5phRogT5hkDDRKPTpRCGo
        depends aeson-1.5.6.0-89mRhAl4FhxDxUb2oPr1Yf
        depends aeson-pretty-0.8.8-ieY1twFXPI8cot6MF8MZ0
        depends base-4.14.1.0
        depends bytestring-0.10.12.0
        depends data-default-0.7.1.1-B2xqLjZNDxg1KVbA6WyFWH
        depends filepath-1.4.2.1
        depends http-types-0.12.3-83JHnI2fUYa5h3vgNT9Hwz
        depends mtl-2.2.2
        depends parsec-3.1.14.0
        depends regex-tdfa-1.3.1.0-86Ve5VgglvW23V5dPSAOm3
        depends safe-0.3.19-36AYIiBjtSLS65WmTQ35k
        depends scientific-0.3.7.0-2IwMamNipm4GhmqfKxrO1Z
        depends text-1.2.4.1
        depends time-1.9.3
        depends transformers-0.5.6.2
        depends unordered-containers-0.2.14.0-FjQASgh3rnkLSsvJG2xUpd
        depends utf8-string-1.0.2-Lwtc54cgMl77YyeO5RGhjt
        depends vector-0.12.3.0-DjRVptyTdiT3mipwWvt1jW
    definite ginger-0.10.1.0-9F27pmIEmGCH0rvj1qRMKL-ginger
        depends aeson-1.5.6.0-89mRhAl4FhxDxUb2oPr1Yf
        depends base-4.14.1.0
        depends bytestring-0.10.12.0
        depends data-default-0.7.1.1-B2xqLjZNDxg1KVbA6WyFWH
        depends ginger-0.10.1.0-L5phRogT5hkDDRKPTpRCGo
        depends optparse-applicative-0.15.1.0-2hUbd3K4cmjHYvRpqoC7A4
        depends process-1.6.9.0
        depends text-1.2.4.1
        depends transformers-0.5.6.2
        depends unordered-containers-0.2.14.0-FjQASgh3rnkLSsvJG2xUpd
        depends utf8-string-1.0.2-Lwtc54cgMl77YyeO5RGhjt
        depends yaml-0.11.5.0-JSPy5Fxql0K85T1eoy4nPJ
    definite ginger-0.10.1.0-7ADNA5QcqPfIMjoqXXCEiC-tests
        depends aeson-1.5.6.0-89mRhAl4FhxDxUb2oPr1Yf
        depends base-4.14.1.0
        depends bytestring-0.10.12.0
        depends data-default-0.7.1.1-B2xqLjZNDxg1KVbA6WyFWH
        depends ginger-0.10.1.0-L5phRogT5hkDDRKPTpRCGo
        depends mtl-2.2.2
        depends tasty-1.2.3-7jQjHiJLVlG7T5lZlhi0Bc
        depends tasty-hunit-0.10.0.3-5pFQPUD42om9FFVN9h9CyQ
        depends tasty-quickcheck-0.10.1.2-G3SWIFemDG33gMlEXVff6g
        depends text-1.2.4.1
        depends time-1.9.3
        depends transformers-0.5.6.2
        depends unordered-containers-0.2.14.0-FjQASgh3rnkLSsvJG2xUpd
        depends utf8-string-1.0.2-Lwtc54cgMl77YyeO5RGhjt
Using Cabal-3.2.1.0 compiled by ghc-8.10
Using compiler: ghc-8.10.4
Using install prefix: /usr/local
Executables installed in: /usr/local/bin
Libraries installed in:
/usr/local/lib/x86_64-linux-ghc-8.10.4/ginger-0.10.1.0-L5phRogT5hkDDRKPTpRCGo
Dynamic Libraries installed in: /usr/local/lib/x86_64-linux-ghc-8.10.4
Private executables installed in:
/usr/local/libexec/x86_64-linux-ghc-8.10.4/ginger-0.10.1.0
Data files installed in:
/usr/local/share/x86_64-linux-ghc-8.10.4/ginger-0.10.1.0
Documentation installed in:
/usr/local/share/doc/x86_64-linux-ghc-8.10.4/ginger-0.10.1.0
Configuration files installed in: /usr/local/etc
Using alex version 3.2.6 found on system at: /usr/bin/alex
Using ar found on system at: /usr/bin/x86_64-pc-linux-gnu-ar
Using c2hs version 0.28.7 found on system at: /usr/bin/c2hs
Using cpphs version 1.20.9 found on system at: /usr/bin/cpphs
Using doctest version 0.16.3 found on system at: /usr/bin/doctest
Using gcc version 12.0.0 found on system at:
/usr/lib/ccache/bin/x86_64-pc-linux-gnu-gcc
Using ghc version 8.10.4 found on system at: /usr/bin/ghc
Using ghc-pkg version 8.10.4 found on system at: /usr/bin/ghc-pkg
No ghcjs found
No ghcjs-pkg found
No greencard found
Using haddock version 2.24.0 found on system at: /usr/bin/haddock
Using happy version 1.20.0 found on system at: /usr/bin/happy
Using haskell-suite found on system at: haskell-suite-dummy-location
Using haskell-suite-pkg found on system at: haskell-suite-pkg-dummy-location
No hmake found
Using hpc version 0.68 found on system at: /usr/bin/hpc
Using hsc2hs version 0.68.7 found on system at: /usr/bin/hsc2hs
Using hscolour version 1.24 found on system at: /usr/bin/HsColour
No jhc found
Using ld found on system at: /usr/bin/x86_64-pc-linux-gnu-ld
Using pkg-config version 1.6.3 found on system at: /usr/bin/pkg-config
Using runghc version 8.10.4 found on system at: /usr/bin/runghc
No strip found
Using tar found on system at: /bin/tar
No uhc found
Preprocessing library for ginger-0.10.1.0..
Building library for ginger-0.10.1.0..
[ 1 of 12] Compiling Text.Ginger.Html ( src/Text/Ginger/Html.hs, dist/build/Text/Ginger/Html.o, dist/build/Text/Ginger/Html.dyn_o )
[ 2 of 12] Compiling Text.Ginger.GVal ( src/Text/Ginger/GVal.hs, dist/build/Text/Ginger/GVal.o, dist/build/Text/Ginger/GVal.dyn_o )

src/Text/Ginger/GVal.hs:816:10: warning: [-Winline-rule-shadowing]
    Rule "GVal/round-trip-Maybe" may never fire
      because ‘.’ might inline first
    Probable fix: add an INLINE[n] or NOINLINE[n] pragma for ‘.’
    |
816 | {-#RULES "GVal/round-trip-Maybe" fromGVal . toGVal = Just #-}
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

src/Text/Ginger/GVal.hs:816:10: warning: [-Winline-rule-shadowing]
    Rule "GVal/round-trip-Maybe" may never fire
      because ‘toGVal’ might inline first
    Probable fix: add an INLINE[n] or NOINLINE[n] pragma for ‘toGVal’
    |
816 | {-#RULES "GVal/round-trip-Maybe" fromGVal . toGVal = Just #-}
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

src/Text/Ginger/GVal.hs:816:10: warning: [-Winline-rule-shadowing]
    Rule "GVal/round-trip-Maybe" may never fire
      because rule "Class op fromGVal" for ‘fromGVal’ might fire first
    Probable fix: add phase [n] or [~n] to the competing rule
    |
816 | {-#RULES "GVal/round-trip-Maybe" fromGVal . toGVal = Just #-}
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

src/Text/Ginger/GVal.hs:817:10: warning: [-Winline-rule-shadowing]
    Rule "GVal/round-trip-Either" may never fire
      because ‘.’ might inline first
    Probable fix: add an INLINE[n] or NOINLINE[n] pragma for ‘.’
    |
817 | {-#RULES "GVal/round-trip-Either" fromGValEither . toGVal = Right #-}
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

src/Text/Ginger/GVal.hs:817:10: warning: [-Winline-rule-shadowing]
    Rule "GVal/round-trip-Either" may never fire
      because ‘toGVal’ might inline first
    Probable fix: add an INLINE[n] or NOINLINE[n] pragma for ‘toGVal’
    |
817 | {-#RULES "GVal/round-trip-Either" fromGValEither . toGVal = Right #-}
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

src/Text/Ginger/GVal.hs:817:10: warning: [-Winline-rule-shadowing]
    Rule "GVal/round-trip-Either" may never fire
      because rule "Class op fromGValEither" for ‘fromGValEither’ might fire first
    Probable fix: add phase [n] or [~n] to the competing rule
    |
817 | {-#RULES "GVal/round-trip-Either" fromGValEither . toGVal = Right #-}
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

src/Text/Ginger/GVal.hs:818:10: warning: [-Winline-rule-shadowing]
    Rule "GVal/text-shortcut" may never fire
      because ‘.’ might inline first
    Probable fix: add an INLINE[n] or NOINLINE[n] pragma for ‘.’
    |
818 | {-#RULES "GVal/text-shortcut" asText . toGVal = id #-}
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

src/Text/Ginger/GVal.hs:818:10: warning: [-Winline-rule-shadowing]
    Rule "GVal/text-shortcut" may never fire
      because ‘toGVal’ might inline first
    Probable fix: add an INLINE[n] or NOINLINE[n] pragma for ‘toGVal’
    |
818 | {-#RULES "GVal/text-shortcut" asText . toGVal = id #-}
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

src/Text/Ginger/GVal.hs:818:10: warning: [-Winline-rule-shadowing]
    Rule "GVal/text-shortcut" may never fire
      because ‘asText’ might inline first
    Probable fix: add an INLINE[n] or NOINLINE[n] pragma for ‘asText’
    |
818 | {-#RULES "GVal/text-shortcut" asText . toGVal = id #-}
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[ 3 of 12] Compiling Text.Ginger.AST  ( src/Text/Ginger/AST.hs, dist/build/Text/Ginger/AST.o, dist/build/Text/Ginger/AST.dyn_o )
[ 4 of 12] Compiling Text.Ginger.Parse ( src/Text/Ginger/Parse.hs, dist/build/Text/Ginger/Parse.o, dist/build/Text/Ginger/Parse.dyn_o )
[ 5 of 12] Compiling Text.PrintfA     ( src/Text/PrintfA.hs, dist/build/Text/PrintfA.o, dist/build/Text/PrintfA.dyn_o )
[ 6 of 12] Compiling Text.Ginger.Run.Type ( src/Text/Ginger/Run/Type.hs, dist/build/Text/Ginger/Run/Type.o, dist/build/Text/Ginger/Run/Type.dyn_o )
[ 7 of 12] Compiling Text.Ginger.Run.FuncUtils ( src/Text/Ginger/Run/FuncUtils.hs, dist/build/Text/Ginger/Run/FuncUtils.o, dist/build/Text/Ginger/Run/FuncUtils.dyn_o )
[ 8 of 12] Compiling Text.Ginger.Run.VM ( src/Text/Ginger/Run/VM.hs, dist/build/Text/Ginger/Run/VM.o, dist/build/Text/Ginger/Run/VM.dyn_o )
[ 9 of 12] Compiling Text.Ginger.Run.Builtins ( src/Text/Ginger/Run/Builtins.hs, dist/build/Text/Ginger/Run/Builtins.o, dist/build/Text/Ginger/Run/Builtins.dyn_o )

src/Text/Ginger/Run/Builtins.hs:41:1: warning: [-Wdeprecations]
    Module ‘Control.Monad.Error’ is deprecated:
      Use "Control.Monad.Except" instead
   |
41 | import Control.Monad.Error (runErrorT)
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

src/Text/Ginger/Run/Builtins.hs:855:33: warning: [-Wdeprecations]
    In the use of ‘runErrorT’
    (imported from Control.Monad.Error, but defined in Control.Monad.Trans.Error):
    Deprecated: "Use Control.Monad.Trans.Except instead"
    |
855 |         let reM = runIdentity . runErrorT $
    |                                 ^^^^^^^^^
[10 of 12] Compiling Text.Ginger.Run  ( src/Text/Ginger/Run.hs, dist/build/Text/Ginger/Run.o, dist/build/Text/Ginger/Run.dyn_o )
[11 of 12] Compiling Text.Ginger.Optimizer ( src/Text/Ginger/Optimizer.hs, dist/build/Text/Ginger/Optimizer.o, dist/build/Text/Ginger/Optimizer.dyn_o )
[12 of 12] Compiling Text.Ginger      ( src/Text/Ginger.hs, dist/build/Text/Ginger.o, dist/build/Text/Ginger.dyn_o )
Preprocessing executable 'ginger' for ginger-0.10.1.0..
Building executable 'ginger' for ginger-0.10.1.0..
[1 of 2] Compiling Options          ( cli/Options.hs, dist/build/ginger/ginger-tmp/Options.dyn_o )
[2 of 2] Compiling Main             ( cli/GingerCLI.hs, dist/build/ginger/ginger-tmp/Main.dyn_o )

cli/GingerCLI.hs:120:17: warning: [-Wdeprecations]
    In the use of ‘decode’ (imported from Data.Yaml):
    Deprecated: "Please use decodeEither or decodeThrow, which provide information on how the decode failed"
    |
120 | decodeFile fn = YAML.decode <$> (openFile fn ReadMode >>= BS.hGetContents)
    |                 ^^^^^^^^^^^

cli/GingerCLI.hs:123:25: warning: [-Wdeprecations]
    In the use of ‘decode’ (imported from Data.Yaml):
    Deprecated: "Please use decodeEither or decodeThrow, which provide information on how the decode failed"
    |
123 | decodeString = return . YAML.decode . UTF8.fromString
    |                         ^^^^^^^^^^^

cli/GingerCLI.hs:126:15: warning: [-Wdeprecations]
    In the use of ‘decode’ (imported from Data.Yaml):
    Deprecated: "Please use decodeEither or decodeThrow, which provide information on how the decode failed"
    |
126 | decodeStdin = YAML.decode <$> BS.getContents
    |               ^^^^^^^^^^^
Linking dist/build/ginger/ginger ...
Preprocessing test suite 'tests' for ginger-0.10.1.0..
Building test suite 'tests' for ginger-0.10.1.0..
[1 of 3] Compiling Text.Ginger.PropertyTests ( test/Text/Ginger/PropertyTests.hs, dist/build/tests/tests-tmp/Text/Ginger/PropertyTests.dyn_o )
[2 of 3] Compiling Text.Ginger.SimulationTests ( test/Text/Ginger/SimulationTests.hs, dist/build/tests/tests-tmp/Text/Ginger/SimulationTests.dyn_o )
[3 of 3] Compiling Main             ( test/Spec.hs, dist/build/tests/tests-tmp/Main.dyn_o )
Linking dist/build/tests/tests ...
Running 1 test suites...
Test suite tests: RUNNING...
All Tests
  Simulation
    Smoke Test:                                                                   OK
    Comments
      Comment does not appear in output:                                          OK
    Dashed delimiters eat whitespace
      comments:                                                                   OK
      interpolations:                                                             OK
      flow:                                                                       OK
    Default delimiters eat whitespace with LStripBlocks
      comments:                                                                   OK
      interpolations:                                                             OK
      flow:                                                                       OK
      interpolations, left-only:                                                  OK
    Default delimiters eat whitespace with TrimBlocks
      comments:                                                                   OK
      interpolations:                                                             OK
      flow:                                                                       OK
      interpolations, right-only:                                                 OK
    Plussed delimiters override LStrip/TrimBlocks
      comments:                                                                   OK
      interpolations:                                                             OK
      flow:                                                                       OK
    Trailing newlines
      eaten after blocks:                                                         OK
      not eaten after interpolations:                                             OK
      not eaten after blocks when keepTrailingNewline is on:                      OK
    Literals
      Strings
        String: "foobar":                                                         OK
        String: "\r\n\t\b":                                                       OK
      Numbers
        123:                                                                      OK
        3.1415:                                                                   OK
      Booleans
        true:                                                                     OK
        True:                                                                     OK
        false:                                                                    OK
        False:                                                                    OK
      Null:                                                                       OK
    Simple list/object constructs
      Lists:                                                                      OK
      Nested lists:                                                               OK
      Objects:                                                                    OK
      Nested object/list constructs:                                              OK
    Accessing object/list members
      by integer index:                                                           OK
      by string key:                                                              OK
      by property name:                                                           OK
      multi-level mixed:                                                          OK
    Function calls
      print("Hello"):                                                             OK
      "Hello"|print:                                                              OK
    Addition
      1 + 1 = 2:                                                                  OK
      1 + 1 = 2:                                                                  OK
    Subtraction
      1 - 1 = 0:                                                                  OK
    Concatenation
      1 ~ "foo" = 1foo:                                                           OK
    Multiplication
      5 * 5 = 25:                                                                 OK
    Division
      24 / 6 = 4:                                                                 OK
      3 / 2 = 1.5:                                                                OK
    Integer Division
      24 // 6 = 4:                                                                OK
      3 // 2 = 1:                                                                 OK
    Modulo
      7 % 3 = 2:                                                                  OK
    Iteration
      for x in [ "foo", "bar", "baz" ]: <x>:                                      OK
      for x in []: <x> else <no>:                                                 OK
      for x in [a]: <x> else <no>:                                                OK
    The `loop` auto-variable
      loop.cycle:                                                                 OK
      recursive loops:                                                            RuntimeErrorAt "<<unknown>>" (line 1, column 83) (TypeError ["list","dictionary"] (Just "null"))
RuntimeErrorAt "<<unknown>>" (line 1, column 83) (TypeError ["list","dictionary"] (Just "null"))
FAIL
        test/Text/Ginger/SimulationTests.hs:1589:
        expected: "a@1(b@2()c@2(d@3()))"
         but got: "a@1(c@2(d@3())b@2())"
    Conditionals
      if true then "yes" else "no":                                               OK
      if false then "yes" else if false then "maybe" else "no":                   OK
      if false then "yes" else if true then "maybe" else "no":                    OK
      if null should be false:                                                    OK
    Exceptions
      try/catch, no exception:                                                    OK
      try/finally, no exception:                                                  OK
      try/catch, trigger arguments exception:                                     OK
      try/finally, trigger arguments exception:                                   OK
      try/catch, catch selectively (string syntax):                               OK
      try/catch, catch selectively (identifier syntax):                           OK
      try/catch, skip non-matching catches:                                       OK
    Switch
      switch 1 of 1, 2, default:                                                  OK
      switch 1 of 1, 2:                                                           OK
    Comparisons
      if 1 == 1 then "yes" else "no":                                             OK
      if 1 > 0 then "yes" else "no":                                              OK
      if 1 > null then "yes" else "no":                                           OK
      if 1 < 2 then "yes" else "no":                                              OK
      if null < 1 then "yes" else "no":                                           OK
    Boolean AND
      AND (both) (and):                                                           OK
      AND (only one) (and):                                                       OK
      AND (neither) (and):                                                        OK
      AND (both) (&&):                                                            OK
      AND (only one) (&&):                                                        OK
      AND (neither) (&&):                                                         OK
    Boolean OR
      OR (both) (or):                                                             OK
      OR (only one) (or):                                                         OK
      OR (either) (or):                                                           OK
      OR (both) (||):                                                             OK
      OR (only one) (||):                                                         OK
      OR (either) (||):                                                           OK
    Slicing brackets
      from/to, both positive:                                                     OK
      from/to, from negative:                                                     OK
      from/to, to implicit:                                                       OK
      from/to, from implicit:                                                     OK
    Built-in tests
      "divisibleby"
        divisibleby(14,7):                                                        OK
        divisibleby(14,6):                                                        OK
      "even"
        even(3):                                                                  OK
        even("2"):                                                                OK
        even("3"):                                                                OK
        even("two"):                                                              OK
      "eq":                                                                       OK
      "equalto":                                                                  OK
      "ge":                                                                       OK
      "greaterthan":                                                              OK
      "gt":                                                                       OK
      "le":                                                                       OK
      "lessthan":                                                                 OK
      "lt":                                                                       OK
      "ne":                                                                       OK
      "odd"
        odd(2):                                                                   OK
        odd(3):                                                                   OK
        odd("2"):                                                                 OK
        odd("3"):                                                                 OK
    Built-in filters/functions
      "abs":                                                                      OK
      "any"
        "any" (both):                                                             OK
        "any" (just one):                                                         OK
        "any" (neither):                                                          OK
      "all"
        "all" (both):                                                             OK
        "all" (just one):                                                         OK
        "all" (neither):                                                          OK
      "ceil"
        14.1:                                                                     OK
        -14.1:                                                                    OK
        -14.8:                                                                    OK
      "capitalize":                                                               OK
      "upper":                                                                    OK
      "lower":                                                                    OK
      "center"
        extra space:                                                              OK
        no extra space:                                                           OK
      "compose":                                                                  OK
      "concat":                                                                   OK
      "contains"
        single match:                                                             OK
        multi match:                                                              OK
        non-match:                                                                OK
      "date"
        format a date:                                                            OK
        format a list as a date:                                                  OK
        format a 5-element list as a date:                                        OK
        format a 3-element list as a date:                                        OK
        use correct default time (noon) with 3-element list:                      OK
        format a string as a date:                                                OK
        format a string as a date (JSON-style formatting):                        OK
        format a string with fractional seconds as a date (all variants):         OK
        format a string as a time-of-day:                                         OK
        format a string as a date, with timezone:                                 OK
        format a local-time string as a date + time, with explicit timezone:      OK
        format a zoned-time string as a date, with explicit timezone:             OK
        use a custom locale:                                                      OK
      "default"
        trigger default:                                                          OK
        use truthy value:                                                         OK
      "difference":                                                               OK
      "dictsort"
        by key:                                                                   OK
        by value:                                                                 OK
      "escape"
        single item:                                                              OK
        multiple items:                                                           OK
      "equals"
        two equal:                                                                OK
        all equal:                                                                OK
        some equal:                                                               OK
      "eval"
        simple:                                                                   OK
        with extra state:                                                         OK
        outside state does not bleed into eval():                                 OK
        standard functions available inside eval:                                 OK
      "filesizeformat"
        bytes:                                                                    OK
        kilobytes:                                                                OK
        megabytes:                                                                OK
        bytes (2-based):                                                          OK
        kibibytes:                                                                OK
        mebibytes:                                                                OK
      "filter"
        simple case:                                                              OK
        with extra argument:                                                      OK
      "format"
        jinja.pocoo.org example:                                                  OK
      "map"
        map function over list:                                                   OK
        map function over dictionary:                                             OK
        map to extract attribute:                                                 OK
      "not-equals"
        all equal:                                                                OK
        not all equal:                                                            OK
      "floor"
        14.1:                                                                     OK
        14.8:                                                                     OK
        -14.1:                                                                    OK
        -14.8:                                                                    OK
      "int"
        14.1:                                                                     OK
        14.8:                                                                     OK
        -14.1:                                                                    OK
        -14.8:                                                                    OK
      "length"
        list:                                                                     OK
        dict:                                                                     OK
        string:                                                                   OK
      "partial"
        partial:                                                                  OK
      "printf"
        %i, passed as int:                                                        OK
        %i, passed as string:                                                     OK
        %i, passed as float:                                                      OK
        %f, passed as int:                                                        OK
        %.3f, passed as int:                                                      OK
        %s, string:                                                               OK
      "product":                                                                  OK
      "ratio":                                                                    OK
      "round"
        14.1:                                                                     OK
        14.8:                                                                     OK
        -14.1:                                                                    OK
        -14.8:                                                                    OK
      "str":                                                                      OK
      "sum":                                                                      OK
      "truncate"
        14.1:                                                                     OK
        14.8:                                                                     OK
        -14.1:                                                                    OK
        -14.8:                                                                    OK
      "urlencode":                                                                OK
      "sort"
        simple:                                                                   OK
        reverse:                                                                  OK
        sort by key:                                                              OK
        sort by key, reverse:                                                     OK
        sort dictionary by keys:                                                  OK
        sort by a projection function:                                            OK
        sort by a path:                                                           OK
      "slice"
        full positional args:                                                     OK
        implicit 'to end':                                                        OK
        full named args:                                                          OK
        negative offset:                                                          OK
        call on string subject:                                                   OK
      "split"
        word-splitting:                                                           OK
        word-splitting, more spaces:                                              OK
        word-splitting, more spaces, explicit delim:                              OK
      "replace"
        simple case:                                                              OK
        multiple replacements:                                                    OK
        longer replacements:                                                      OK
        deletion:                                                                 OK
      "zip"
        lists:                                                                    OK
      "zipwith"
        sum:                                                                      OK
      "json"
        null:                                                                     OK
        [1,2,3]:                                                                  OK
      "in"
        elem in list:                                                             OK
        elem not in list:                                                         OK
        elem in dict:                                                             OK
        elem not in dict:                                                         OK
      "apply"
        sum:                                                                      OK
    Setting variables
      plain:                                                                      OK
      self-referential:                                                           OK
    HTML encoding
      no encoding outside of constructs:                                          OK
      auto-encode inside interpolations:                                          OK
      raw filter bypasses encoding:                                               OK
    Includes
      include plain:                                                              OK
      include with a variable:                                                    OK
      not eaten after blocks in included template when keepTrailingNewline is on: OK
      include referencing an included variable:                                   OK
    Explicit Local Scopes
      baseline:                                                                   OK
      inside local scope:                                                         OK
      after exiting local scope:                                                  OK
    Indentation
      stripping leading spaces:                                                   OK
      explicit indent string:                                                     OK
      implicit indent string:                                                     OK
      explicit non-whitespace indent string:                                      OK
      explicit indent string from more complex expression:                        OK
      discarding level-0 indents:                                                 OK
      indentation levels inherited at runtime (dynamic):                          OK
    Macros
      simple:                                                                     OK
      with args:                                                                  OK
    Lambdas
      single arg:                                                                 OK
      two args:                                                                   OK
    Ternary operator
      C syntax:                                                                   OK
      python syntax:                                                              OK
      C syntax, nested, true/false:                                               OK
      Python syntax, nested, true/false:                                          OK
      C syntax, nested, true/true:                                                OK
      Python syntax, nested, true/true:                                           OK
    Call syntax
      "caller":                                                                   OK
    Inheritance
      inheritance:                                                                OK
      multi-tier inheritance:                                                     OK
    Non-HTML Output
      text:                                                                       OK
      json:                                                                       OK
    Script mode
      empty script block:                                                         OK
      comments
        simple:                                                                   OK
        multiple:                                                                 OK
        inside expressions:                                                       OK
      echo:                                                                       OK
      expression statement:                                                       OK
      grouped statements:                                                         OK
      if:                                                                         OK
      if/else:                                                                    OK
      switch:                                                                     OK
      for:                                                                        OK
      for/else (loop):                                                            OK
      for/else (recover):                                                         OK
      set:                                                                        OK
      include:                                                                    OK
      macro:                                                                      OK
      Script statment blocks
        baseline:                                                                 OK
        inside local scope:                                                       OK
        after exiting block:                                                      OK
      Explicit Local Scopes
        baseline:                                                                 OK
        inside local scope:                                                       OK
        after exiting local scope:                                                OK
    do expressions
      single statement:                                                           OK
      statement block:                                                            OK
    overriding delimiters
      angle brackets:                                                             OK
      evil mode:                                                                  OK
    is-tests
      basic is-test, true:                                                        OK
      basic is-test, false:                                                       OK
      parens-less argument syntax:                                                OK
      precedence vs booleans:                                                     OK
      precedence vs addition:                                                     OK
    regex module
      regex.test
        simple match:                                                             OK
        simple match:                                                             OK
      regex.match
        simple match:                                                             OK
        string representation of multiple matches returns only whole match:       OK
        html representation of multiple matches returns only whole match:         OK
      regex.matches
        simple match:                                                             OK
  Properties
    Optimizer
      optimizer doesn't change behavior:                                          OK (0.03s)
        +++ OK, passed 100 tests.
    ToGVal / FromGVal round tripping
      Int:                                                                        OK
        +++ OK, passed 100 tests.
      Bool:                                                                       OK
        +++ OK, passed 100 tests.
      [Text]:                                                                     OK
        +++ OK, passed 100 tests.
      Maybe Text:                                                                 OK
        +++ OK, passed 100 tests.
      ByteString:                                                                 OK
        +++ OK, passed 100 tests.
      Text:                                                                       OK
        +++ OK, passed 100 tests.
      LocalTime:                                                                  OK
        +++ OK, passed 100 tests.
      TimeZone:                                                                   OK
        +++ OK, passed 100 tests.
      ZonedTime:                                                                  OK
        +++ OK, passed 100 tests.

1 out of 307 tests failed (0.09s)
Test suite tests: FAIL
Test suite logged to: dist/test/ginger-0.10.1.0-tests.log
0 of 1 test suites (0 of 1 test cases) passed.

injection seems to be http escaped

I inject content
"content": "<p>What should go into a homepage</p>\n<ul>\n<li>name and address</li>\n</ul>",
into {{ content }} and get

  &lt;p&gt;What should go into a homepage&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;name and address&lt;/li&gt;
&lt;/ul&gt;

for mustache syntax I would use {{{ context }}} to avoid the http-escaping, but I thought this would not be required for jinja2. What is it I am doing wrong?
Thank you for help!

Aeson 2 support

Aeson 2 changes the way that JSON objects are represented, in order to mitigate denial-of-service attacks where an attacker provides an object that has many keys that hash to the same value. The Object type now uses an opaque KeyMap type instead of HashMap Text. Currently, it may be implemented as a Map or a HashMap depending on a compile-time flag, but there may be additional implementations in the future. Additionally, a new Key type is used for keys instead of Text. It is a currently a newtype wrapper around Text, but it looks like that may also change in the future.

The aeson-pretty library was recently updated to support Aeson 2, so there are no more dependencies blocking ginger. It should be easy to update ginger to support Aeson 2, as only the rawJSONToGVal function needs to be changed. I have experimented with an implementation that uses a data structure according to the data structure that Aeson is configured to use.

#if MIN_VERSION_aeson(2,0,0)
rawJSONToGVal (JSON.Object km) =
    let keyToText = Prelude.maybe AK.toText Coercion.coerceWith AK.coercionToText
    in case (AKM.coercionToHashMap, AKM.coercionToMap) of
        (Just coercion, _mMapCoercion) ->
            toGVal . HashMap.mapKeys keyToText $ Coercion.coerceWith (Coercion.sym coercion) km
        (Nothing, Just coercion) ->
            toGVal . Map.mapKeys keyToText $ Coercion.coerceWith (Coercion.sym coercion) km
        (Nothing, Nothing) ->
            toGVal . Map.fromList . List.map (first keyToText) $ AKM.toList km
#else
rawJSONToGVal (JSON.Object o) = toGVal o
#endif

Currently, the first case (HashMap) or second case (Map) should always be selected, as there are no other possibilities. If a different data structure is used in the future, this code defaults to using a Map to avoid the denial-of-service vulnerability that use of HashMap introduces. Alternatively, the default could use a HashMap in order to prioritize (non-attack-scenario) performance.

What are your thoughts? If this looks like an acceptable way to add support for Aeson 2, I am happy to submit a pull request.

Implement `{% filter %}`

Original jinja2 feature.

Rundown:

  • Parse {% filter %} tags
  • Generate AST that captures the tag's body and feeds it to the given filter function

This should be possible entirely at the syntax level, without touching the AST.

Compile / embed

Currently, ginger templates can only be interpreted.

Make a backend that instead outputs TH AST so that ginger templates can be compiled right into a Haskell project.

does not compile with ghc-8.4

   /tmp/stack26892/ginger-0.7.3.0/src/Text/Ginger/Html.hs:24:15: error:
        • No instance for (Semigroup Html)
            arising from the 'deriving' clause of a data type declaration
          Possible fix:
            use a standalone 'deriving instance' declaration,
              so you can specify the instance context yourself
        • When deriving the instance for (Monoid Html)
       |
    24 |     deriving (Monoid, Show, Eq, Ord)
       |               ^^^^^^

I fixed this at https://github.com/hasura/ginger. I can submit a PR if needed.

Track constness / purity for optimizations

One of the optimization steps we perform is compile-time evaluation of subexpression that are completely known at compile time.

E.g., in the template <h1>{{ "hello & goodbye"|capitalize }}</h1>, everything we need to calculate the correct output is already known at runtime - we have a string literal, the pure capitalize function, an interpolation statement, and two literal output statements. This means that we can evaluate the entire thing at compile time, and replace it with just one literal output statement: <h1>Hello &amp; Goodbye</h1>.

The problem however lies in accurately determining const-ness and purity: in order to judge whether a value is pure, we need to know what's in the current scope, but the scope contains the context passed in at runtime.

A proposed solution would work as follows.

First, we define a data structure that represents our knowledge about the current execution context. Essentially, this would be a list of constraints on names in the current namespace, and such a constraint might be something like "is definitely a pure function", "is a constant value", etc.

While traversing the template AST, we can then thread this knowledge data structure through the traversal, updating it as we go. E.g., when we encounter a let block that binds a literal to some variable, then we can add an entry to our knowledgebase that says that this variable now holds a const value. Or, when a variable is bound to a lambda expression that we can infer as pure, we add to our knowledgebase the factoid that this variable now holds a pure function.

Now, the conservative approach is to start with an empty slate: we know nothing, but we gain knowledge as we traverse the AST. However, this isn't going to be optimal in the typical use case, where all the built-in global bindings are intact - many builtin functions are in fact pure, and while the host application can change this, people will rarely do this in a way that changes contracts - so we need to cater for the possible case of changing purity semantics of builtins, but at the same time, we also don't want to miss out on the possible optimization when the semantics are intact.

A fairly simple way to solve this is to put the responsibility in the hands of the caller: simply add an argument to the parser that is used to seed the knowledge base. Host applications that never touch any of the builtins can simply pass the "default" knowledge base, telling the parser to generate code that will be correct as long as the host application does in fact stay away from the builtins. Host applications that do touch builtins could either simply pass an empty seed knowledge, or they could modify the default knowledge to reflect the changes they intend to make. Either way though, it's going to be an honor system.

To make it safer, one would have to tag GVals themselves with purity information, and then check whether the passed-in context matches what was declared at compile time. Since this involves deriving the seed knowledge from the context provided by the host, exposing this derivation makes sense, because then host applications can reuse the code to automatically generate the right seed knowledge for the context they intend to pass to the template. It would also require remembering the seed knowledge in the template itself, so that it becomes possible to check that the runtime context matches the compile-time promises. And if it doesn't, we can either reject the template (conservative choice), or we can run it anyway ("dangerous mode"), or we can fall back to an alternative compilate that assumes nothing (empty context), or we could simply fall back to the entirely unoptimized version of the AST.

How to check if all variables were filled in rendered template?

Hello,
given the following simple template

Hello, {{name}} {{surname}}!

and function for rendering:

renderTemplate :: HashMap Text Text -> Template SourcePos -> Text
renderTemplate = easyRender

Is there any built-in way how to check that the rendered template has all variables filled in? I.e. that the given HashMap contains keys for both existing variables name and surname and if not, then return some error, etc?

I tried to search source codes and documentation but didn't find anything that would help me.
Thanks a lot in advance.

a way to display a structured variable

When i have a nest structure of arrays and objects and do {{var}} it concatenates all values. Instead could it print a JSON like format to see the structure? If this is not desirable with the plain {{}} maybe a function like twig's dump could be added.

Passing local variables while including a template?

I'm trying to descend a recursive data-structure and recursively render the same template [1] Forget the recursive part, I'm unable to pass local variables to an included template. I've tried the following, and nothing works:

{% include "includes/toc.html" with tocItems = page.toc %}
{% with tocItems = page.toc %}
  {% include "includes/toc.html" %}
{% endwith %}
{% scope %}
  {% set tocItems = page.toc %}
  {% include "includes/toc.html" %}
{% endscope %}

[1] I'm trying to generate a page's TOC -- which is why the recursion

`MonadFail` compliance

See #48: ginger currently fails to compile on GHC 8.8 due to MonadFail.

PR #48 suggests widening Monad constraints to arbitrary MonadFail instances, but I think it would be more prudent to integrate error handling into the runXXXX functions and the Run monad stack itself (e.g. using ExceptT), and while we're at it, introduce a saner / more specific error type. We're going to break the API anyway, might as well use this as an opportunity for improvement.

Test failure with http-types 0.11

As seen on the Stackage build server:

ginger: Process exited with ExitFailure 1: dist/build/tests/tests (pending: 146$
, failures: 0)

      "urlencode":
  FAIL
        test/Text/Ginger/SimulationTests.hs:1294:
        expected: "a%2Fb%20c"
         but got: "a%2fb%20c"

1 out of 249 tests failed (0.22s)

What is your take on the severity of this? I'm not necessarily recommending that any action be taken on your part, since I think that http-types should return to uppercasing.

See also: commercialhaskell/stackage#3226

Implement missing built-ins

Ginger does not currently implement all the built-in functions, filters and tests that jinja2 defines.

For reference:

Note that in Ginger, these things are all just syntax sugar for function calls, while Jinja2 has separate namespaces for each of them - we are not looking to change this, just implementing missing things.

don't ignore non-existent variables

Right now when printing {{doesnt_exist}} it just doesn't print anything. Rather i would like to have throw an exception or even better check on compile time. Now bugs are there and they are not notified about.

Not using bytestring-builder internally?

I'm planning to use ginger as the underlying library for a static site generator. However, I'm puzzled why the only two types types implementing ContextEncodable are Text and Html (which itself is a newtype over Text).

Doesn't ginger internally use lazy-text, lazy-bytestring, or a bytestring-builder? Wouldn't appending to a strict-text repeatedly be very expensive?

Implement whitespace control

template:
Hello, {{ name }},\nwelcome in {{ location|upper }}!
result:
Hello, Alice,
welcome in WONDERLAND!

but if in the first line the variable is the last thing on the line, then the \n is removed:

template:
Hello, {{ name }}\nwelcome in {{ location|upper }}!
result:
Hello, Alicewelcome in WONDERLAND!

is this a bug? Or Do I need another syntax for the variable closing token?

Alex.

Implement `is` (tests)

Jinja2 uses the is keyword to express "test expressions". Here's the relevant Jinja2 documentation.

In Ginger, since we want tests, functions, and filter, to all be just different syntax for function calls, this is simply a matter of adding syntax sugar that turns expression is test(arg0,arg1,...) into test(expression, arg0, arg1, ...), similar to the syntax sugar for filters (expression|filter(args)filter(expression, args)). Thus, it can (and should) be implemented entirely in the parser.

Best way to deal with lists and maps as variables

Hello,

First off, congrats for the work on Ginger. Being a long-time Jinja2 user I can definitely appreciate a similar template engine running on Haskell.

I managed to run the simple examples from the docs, but I'm having a hard time figuring out how to pass anything else than a HashMap Text Text as the source of input variables.

For instance, consider this template:

Hello {{ name }},
You have {% for item in items %}{{ item }}{% if not loop.last %}, {% endif %}{% endfor %}.

I'm trying to feed this template with the following elements:

import Data.HashMap.Strict (HashMap, fromList)

data Value =
    VText Text
  | VList [Text]
  deriving Show

context :: HashMap Text Value
context = fromList [
        ("name", VText "John"),
        ("items", VList ["car", "truck", "house", "phone"])
    ]

scopeLookup :: (Hashable k, Eq k, ToGVal m b) => k -> HashMap.HashMap k b -> GVal m
scopeLookup key context =
    toGVal $ HashMap.lookup key context

render :: Template SourcePos -> HashMap VarName Value -> Text
render template contextMap =
  let contextLookup = flip scopeLookup contextMap
      context = makeContextHtml contextLookup
  in htmlSource $ runGinger context template

With the code and the template above, I would expect the output to be:

Hello John,
You have car, truck, house, phone.

The problem is that Value doesn't derive ToGVal according to the compiler. I've tried different ways to fix it, but none has worked so far, which leads me to think that maybe I'm just doing it wrong entirely.

Is there any recommended way to inject a sum type like this, or any other way to deal with variables that can be either Text, or [Text], or HashMap Text Text?

extend tag not implemented

I have the impression that the extend tag (as shown in the documentation is not implemented in ginger 0.8.4.0. Correct?
Is there a list of what is implemented or what is missing? would reduce time chasing bugs.
Nevertheless, thank you for the implementation!

Here's a simple example of rendering

I felt that the docs were missing a simple, copy + paste-able example of how to render a template. I would have made a PR but I'm not sure what file this would go in

{-# LANGUAGE OverloadedStrings #-}
module Lib where

import Data.HashMap.Strict (fromList, HashMap)
import qualified Data.HashMap.Strict as HashMap
import Data.Hashable
import Data.Text (Text)
import System.Exit (exitFailure)
import System.IO (IOMode(ReadMode), openFile, hGetContents)
import System.IO.Error (tryIOError)
import Text.Ginger
       (makeContextHtml, Template, toGVal, runGinger, parseGingerFile, VarName)
import Text.Ginger.GVal (ToGVal, GVal)
import Text.Ginger.Html (htmlSource)


-- A simple hashmap that we'll use as our template context
sampleContext :: HashMap Text Text
sampleContext = fromList [("name", "Alice")]


-- Given a Template and a HashMap of context, render the template to Text
render :: Template -> HashMap VarName Text -> Text
render template contextMap =
  let contextLookup = flip scopeLookup contextMap
      context = makeContextHtml contextLookup
  in htmlSource $ runGinger context template


-- Wrapper around HashMap.lookup that applies toGVal to the value found.
-- Any value referenced in a template, returned from within a template, or used
-- in a template context, will be a GVal
scopeLookup
  :: (Hashable k, Eq k, ToGVal m b)
  => k -> HashMap.HashMap k b -> GVal m
scopeLookup key context = toGVal $ HashMap.lookup key context


loadFileMay :: FilePath -> IO (Maybe String)
loadFileMay fn =
  tryIOError (loadFile fn) >>= \e ->
    case e of
      Right contents -> return (Just contents)
      Left _ -> return Nothing

  where
    loadFile :: FilePath -> IO String
    loadFile fn' = openFile fn' ReadMode >>= hGetContents


-- Assuming there's an html file called "base.html" in the current directory and
-- that html file's contents are `Hi, {{ name }}`, attempt to parse "base.html"
-- and print the rendered template
-- >>> run
-- "Hi, Alice"
run :: IO ()
run = do
  template <- parseGingerFile loadFileMay "base.html"
  case template of
    Left err -> print err >> exitFailure
    Right template' -> print $ render template' sampleContext

Add support for records as GVal

Would it be possible to add support for records that become GVal dictionaries? Maybe with GHC.Generics instances can automatically be derived. I would prefer to just put my records straight into the template instead of writing conversion functions from record to hashmap.

GHC 9 build fails

The Text.PrintfA module fails to build when using GHC 9.0.1, giving the following error:

     • Couldn't match type ‘t’ with ‘forall r. PrintfType r => r’
       Expected: PrintfTypeT -> t
         Actual: PrintfTypeT -> forall r. PrintfType r => r
       ‘t’ is a rigid type variable bound by
         the type signature for:
           printfa :: forall t. PrintfType t => String -> [PrintfArgT] -> t
         at src/Text/PrintfA.hs:11:1-56
     • In the first argument of ‘(.)’, namely ‘unT’
       In the expression:
         unT . foldl (\ (T r) (P a) -> T $ r a) (T $ printf format)
       In an equation for ‘printfa’:
           printfa format
             = unT . foldl (\ (T r) (P a) -> T $ r a) (T $ printf format)
     • Relevant bindings include
         printfa :: String -> [PrintfArgT] -> t
           (bound at src/Text/PrintfA.hs:12:1)
    |
 12 | printfa format = unT . foldl (\(T r) (P a) -> T $ r a ) (T $ printf format)
    |                  ^^^

This error has to do with simplified subsumption and is easily resolved by using a lambda instead of unT in the implementation of printfa. I will submit a pull request with the fix.

How to render a template given template text and context with ToJSON?

Hello,

I am trying to use the library in very simple way (no external files, no passing of functions, pure):

renderTemplate :: ToJSON c => Text -> c -> Either Text Text
renderTemplate template ctx = do
  tpl <- tplEither
  let ctxGVal :: GVal Identity = rawJSONToGVal $ toJSON ctx
  let r :: Text = easyRender ctxGVal tpl
  return r
  where
    tplEither :: Either Text (Template SourcePos)
    tplEither = parseGinger nullResolver Nothing (toS template) & runIdentity & mapLeft tshow
    nullResolver :: IncludeResolver Identity
    nullResolver = const $ return Nothing

I am getting an error on a line with easyRender:

Could not deduce (ToGVal
                          (Text.Ginger.Run.Type.Run
                             SourcePos (Control.Monad.Trans.Writer.Lazy.Writer Text) Text)
                          (GVal Identity))
        arising from a use of ‘easyRender’
      from the context: ToJSON c
        bound by the type signature for:
                   renderTemplate :: forall c.
                                     ToJSON c =>
                                     Text -> c -> Either Text Text

I don't understand what is the problem. I would appreciate any help.

Logical operators should be and/or instead of &&/||

Jinja2 uses the python-style logical operators:

>>> Template('{{ False and True or False }}').render()
'False'

while ginger uses && and || and rejects and and or.
Ginger should use the python-style logic operators and reject &&.

Let RuntimeError exposed

Hi!

I'm making an original built-in function like bellow. And I want to use throwError $ ArgumentsError (Just "foo") "". But RuntimeError is in Text.Ginger.Run.Type, which is not exposed.

I want RuntimeError exposed, or are there any other good ways?

main = do
  
  context = HashMap.singleton ("foo", fromFunction fooFunc)
  

fooFunc :: Function (Run SourcePos (Writer Text) Text)
fooFunc args = do
  
  when invalidArguments $ throwError $ ArgumentsError (Just "foo") ""
  

passing variable to a template

from the documentation:

<!DOCTYPE html>
<html>
    <head>
        <title>{{ title }}</title>
    </head>
    {# This is a comment. Comments are removed from the output. #}
    <body>
        <menu id="nav-main">
        {% for item in navigation %}
            <li><a href="{{ item.url }}">{{ item.label }}</a></li>
        {% endfor %}
        </menu>
        <div class="layout-content-main">
            <h1>{{ title }}</h1>
            {{ body }}
        </div>
    </body>
</html>

how am I supposed to pass these variables -- title, naviagation, body -- to this template?

Do we want `ToGVal` instances for string types to parse strings as numbers?

In Jinja2, the following is a type error:

{{ "2" + 2 }}

But in Ginger, we currently have a ToGVal instance for Text (and other string types) that tries to parse the string into a Scientific, and if that succeeds, exposes it in the asNumber field, which means that in Ginger, the above template prints "4".

So the question here is whether it is more important to keep the current convenience of being able to use numeric strings as numbers, or to be more compatible with jinja2.

I am leaning slightly towards keeping the current behavior, because the problem is essentially just being too lenient (accepting templates that Jinja2 rejects), but everything that works fine on Jinja2 will also work fine on Ginger (i.e. we accept templates that Jinja2 accepts).

Efficiency of macros

Hello,
We are using Ginger to generate documents based on questionnaires where are follow-up questions leading us to recursion. For that, we use macros in the template, but the "deeper" is the questionnaire, it gets significantly slower. I found out that macros are causing this problem, the "more" is the output inside a macro, the worse it gets. I made a simple example (of course this could be written totally without any macro, but we need recursion in the template):

{%- macro lipsum() %}
  <!-- some content, e.g., 5 paragraphs of lorem ipsum -->
{% endmacro -%}
{%- macro nLipsum(xs) -%}
  {%- for x in xs -%}
    {{ lipsum() }}
  {%- endfor -%}
{%- endmacro -%}
{%- macro twiceNLipsum(xs) -%}
  {{ nLipsum(xs) }}
  {{ nLipsum(xs) }}
{%- endmacro -%}
{{  twiceNLipsum(xs) }}
{%- macro lipsum() %}
  <!-- some content, e.g., 5 paragraphs of lorem ipsum -->
{% endmacro -%}
{%- for x in xs -%}
    {{ lipsum() }}
{%- endfor -%}
{%- for x in xs -%}
    {{ lipsum() }}
{%- endfor -%}

The first one takes me approx. 4.5-5 seconds but the second one less than 0.4 seconds, both with 200 calls of lipsum macro in total (i.e. xs of length 100). In our real case, it was around 25 seconds; by removing macros, I managed to get to something like 3 seconds, but it is still quite a lot 😞

Can we avoid this effect somehow?

Thank you in advance 😸

performance comparison to yesod hamlet

Hi,
is there any performace comparison to yesod hamlet?
AFAIK yesod hamlet is compiled by template haskell, so that the templates do not have to be reparsed on every request.
Would it make sense to use ginger in webapps eg. replacing hamlet by ginger?

thanks,
Alex.

Proper CLI arguments

The CLI could use a proper argument parser and more flexible arguments to support the following use cases:

  • Interactively process template source while drawing context data from a file
  • Read a template from stdin while drawing context data from a file
  • Read context data from stdin, loading templates from files
  • Processing multiple template files
  • Processing multiple input files

The overhauled argument processing code should also provide self-documentation (--help).

Need help with (untyped ?) / heterogeneous dictionary as context to template

Hello

From https://github.com/tdammers/ginger/blob/master/doc/getting-started.markdown#running---the-easy-interface

Note that, because Ginger is a dynamically typed language (or, actually, an untyped language), passing values to a template execution context requires conversion to Ginger values, represented on the Haskell side as the GVal type. The ToGVal typeclass exposes a number of convenience functions that can be used for this purpose, and there are instances for many of Haskell's standard data types.

I wanted to model a dictionary with different types of values. When i adapt the easyRender example in the manual it gets really complicated (for me personally it was anyway).

Here is the changed code with the type errors it yields: >>> CODE <<<

context :: HashMap Text (GVal (Run SourcePos (Writer Text) Text))
context = HashMap.fromList
    [ ("name", toGVal ("Alice" :: Text))
    , ("location", toGVal ("Wonderland" :: String))
    , ("age", toGVal (155 :: Int))
    ]

Maybe this could be the right type ?? It typechecked on this level but still throw another type error near easyRender

Proposed was the following patch:

-- This would work with the patch below
context :: HashMap Text (GVal m)
context = HashMap.fromList
    [ ("name", toGVal ("Alice" :: Text))
    , ("location", toGVal ("Wonderland" :: String))
    , ("age", toGVal (155 :: Int))
    ]

{-

--- ginger-0.10.1.0/src/Text/Ginger/GVal.hs     2001-09-09 03:46:40.000000000 +0200
+++ ginger-0.10.1.0-my/src/Text/Ginger/GVal.hs  2020-09-02 10:10:21.853396692 +0200
@@ -3,6 +3,7 @@
 {-#LANGUAGE FlexibleInstances #-}
 {-#LANGUAGE ScopedTypeVariables #-}
 {-#LANGUAGE RankNTypes #-}
+{-#LANGUAGE TypeFamilies #-}
 
 -- | GVal is a generic unitype value, representing the kind of values that
 -- Ginger can understand.
@@ -314,7 +315,7 @@
     toGVal :: a -> GVal m
 
 -- | Trivial instance for 'GVal' itself.
-instance ToGVal m (GVal m) where
+instance (m ~ m') => ToGVal m (GVal m') where
     toGVal = id
 
 instance ToGVal m () where

-}

Supposingly the code could then look like this

{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}

-- ...

newtype GVal' m = GVal' { unGVal' :: GVal m }

toGVal' v = GVal' (toGVal v)

instance (m ~ m') => ToGVal m (GVal' m') where
    toGVal = unGVal'

context :: HashMap Text (GVal' m)
context = HashMap.fromList
    [ ("name", toGVal' ("Alice" :: Text))
    , ("location", toGVal' ("Wonderland" :: String))
    , ("age", toGVal' (155 :: Int))
    ]

I didn't look if this patch makes sense but it seemed a very helpful suggestion.

For me the documentation is not clear about how to handle this scenario. I think it's quite common to have a dictionary with different types. Think of person with age int and name string. Maybe also something in ginger can be changed to simplify types or instances, i don't know.

Other than this it looks like a really nice package, i'm eager to get my first template working :)

Inconsistency with lower & upper

ginger decided that there is no difference between functions, tests and filters. Unfortunately, there is a clash for the tests and filters lower and upper:

In jinja2:
|upper returns an uppercased string which is always truthy
is upper returns true only if the string is already uppercased

The same goes for lower respectively

This blocks #18

Compile to PHP

While PHP deeply disgusts me in general, being able to compile Ginger templates into something that can run on a run-of-the-mill cheap shared hosting environment (which, let's face it, is still a painful reality out there) without actually having to touch any PHP code does have some use cases.

This would require:

  • Adding a suitable backend to output PHP code
  • Implementing the built-in functions in PHP
  • Boring shenanigans such as hooking it all up into a CLI, adding testing facilities, etc.

update stackage

Hi,
could you please update stackage? There is still the ginger-0.5.3.0 version.
Thanks, ALex.

Implement `defined`

We need to make a special case here, because defined cannot be implemented as a function - any argument passed to a function is evaluated before passing it in, and evaluating undefined variables simply yields null. I can see two ways in which this could be done.

The first one is to make defined a very restricted special case in the parser, which emits a separate kind of expression, let's say CheckDefinedE p VarName; and the interpreter would then simply take the varname and check it against the current scope. This is easy to implement, but not very featureful: e.g., {% if foo.bar is defined %} will not be possible this way.

The second solution would be more involved. First, we would need a way to mark functions as macros; the operations semantics would then be as follows:

  • function: evaluate all arguments, pass results of evaluation to function and return output.
  • macro: pass unevaluated arguments to function, evaluate output and return.

Thus, a macro would decide on its own whether it wants to evaluate its arguments.

Armed with this, we would then have to implement a function that, instead of completely evaluating an expression, merely checks for definedness. This is thin ice though, there are plenty of cases where the answer isn't obvious, e.g., in {{ defined(foo(bar)) }}, is it enough for foo to be a function, and for bar to be defined? Or do all identifiers that foo closes over also need to be defined? And if so, how are we going to check this?

`keepTrailingNewline` option not passed on to includes

With 'poKeepTrailingNewline = True' the main template keeps the newline but the included templates still swallow it. Here is a sample...
my template:
line1: {{v1}}\nline2: {% include 'line2inc' %}\nline3: {{v2}}!\nline4: {% for i in [1,2,3] %}{{i}}{% endfor %}\nline5
with this include:
{% for i in [1,2,3] %}{{i}}{% endfor %}\n(2nd inc line)

produces this:
line1: v1
line2: 123(2nd inc line)
line3: v2!
line4: 123
line5

but it should keep the newline in front of '(2nd inc line)'

(Split off from #8)

Custom filter

Hello, is it possible to pass own function through the context to be used as function/filter?

I tried after going though the files below but couldn't get it working... Some note on that in docs would be helpful.

defaultScope =
[ ("raw", fromFunction gfnRawHtml)
, ("abs", fromFunction . unaryNumericFunc 0 $ Prelude.abs)
, ("any", fromFunction gfnAny)
, ("all", fromFunction gfnAll)
, ("apply", fromFunction gfnApply)
-- TODO: batch
, ("capitalize", fromFunction . variadicStringFunc $ mconcat . Prelude.map capitalize)

gfnRawHtml :: Monad m => Function (Run p m h)
gfnRawHtml = unaryFunc (toGVal . unsafeRawHtml . asText)

Thanks,
Marek

Support syntactic sugar for unary operators `not`, `+` and `-`

The not unary is missing.
This is easily testable with the following test case:

, testCase "if not true then \"yes\" else \"no\"" $ do
              mkTestHtml [] [] "{% if not true %}yes{% else %}no{% endif %}" "no"

which is failing at the moment.
Jinja2 does support this.

More optimizations

The optimizer is currently quite rudimentary / incomplete. There is a lot of room for improvement here.

Implement "tojson" filter

Need tojson filter in which {{ info | tojson }} should interpolate JSON value of info while rendering.

For example, my data type is
data Interpolate = Interpolate { info :: Data.Aeson.Object } which is ToJSON instance.

README typo

I think you're missing an "avoid" or something similar:

We do, however, some of the most blatant Pythonisms

minor cut and paste error

--- ginger-0.7.1.0/test/Text/Ginger/SimulationTests.hs.~1~	2017-09-22 11:31:28.000000000 -0400
+++ ginger-0.7.1.0/test/Text/Ginger/SimulationTests.hs	2017-09-22 17:17:26.000000000 -0400
@@ -295,7 +295,7 @@
         , testCase "AND (neither)" $ do
             mkTestHtml [] [] "{% if 0 && 0 %}yes{% else %}no{% endif %}" "no"
         ]
-    , testGroup "Boolean AND"
+    , testGroup "Boolean OR"
         [ testCase "OR (both)" $ do
             mkTestHtml [] [] "{% if 1 || 2 %}yes{% else %}no{% endif %}" "yes"
         , testCase "OR (only one)" $ do

Fraction of second in date

Hi,

dateformat only supports whole seconds but JSON date strings may include fractions ex. 2020-08-21T19:35:42.994Z.

Use case:

  1. fetch some data from db
  2. convert to aeson Value using toJSON
  3. pass as context to easyRender

Expected behavior:
Dates can be formatted using dateformat.

Actual behavior:
In case the date has an exact number of seconds everything works fine. However, when fractions of seconds are present ex. 2020-08-21T19:35:42.994Z then dateformat produces no output.

I think the only change needed would be to add %Q to the first 4 formats here. This handles both cases:

λ> parseTimeOrError False defaultTimeLocale "%Y-%m-%dT%H:%M:%S%Q%Z" "2020-08-21T19:35:42.994Z" :: UTCTime
2020-08-21 19:35:42.994 UTC
it :: UTCTime
λ> parseTimeOrError False defaultTimeLocale "%Y-%m-%dT%H:%M:%S%Q%Z" "2020-08-21T19:35:42Z" :: UTCTime
2020-08-21 19:35:42 UTC
it :: UTCTime

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.