PyF 0.11.0.0 → 0.11.1.0
raw patch · 6 files changed
+47/−11 lines, 6 filesdep ~ghc-bootPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependency ranges changed: ghc-boot
API changes (from Hackage documentation)
- PyF.Internal.ParserEx: parseExpression :: RealSrcLoc -> String -> DynFlags -> ParseResult (Located (HsExpr GhcPs))
+ PyF.Internal.ParserEx: parseExpression :: RealSrcLoc -> String -> DynFlags -> ParseResult (LocatedA (HsExpr GhcPs))
Files
- ChangeLog.md +5/−0
- PyF.cabal +6/−6
- Readme.md +8/−0
- src/PyF/Internal/Meta.hs +7/−0
- src/PyF/Internal/QQ.hs +18/−5
- test/Spec.hs +3/−0
ChangeLog.md view
@@ -1,5 +1,10 @@ # Revision history for PyF +## 0.11.1.0 -- 2022-09-24++- Support for OverloadedRecordsDot syntax in Meta. Thank you @Profpatsch for the report.+- In some context, the error reporting for variable not found in the quasi quote expression was incorrectly reporting existing variables as not found. See https://github.com/guibou/PyF/issues/115 for details. This is now fixed by not abusing GHC api. Thank you @michaelpj for reporting this really weird problem.+ ## 0.11.0.0 -- 2022-08-10 - Support for GHC 9.4. (Written with a pre-release of GHC 9.4, hopefully it won't change too much before the release).
PyF.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.4 name: PyF-version: 0.11.0.0+version: 0.11.1.0 synopsis: Quasiquotations for a python like interpolated string formatter description: Quasiquotations for a python like interpolated string formatter. license: BSD-3-Clause@@ -27,15 +27,15 @@ PyF.Internal.ParserEx PyF.Internal.Parser - build-depends: base >= 4.12 && < 4.17+ build-depends: base >= 4.12 && < 4.18 , bytestring >= 0.10.8 && < 0.12- , template-haskell >= 2.14.0 && < 2.19- , text >= 1.2.3 && <= 2.0+ , template-haskell >= 2.14.0 && < 2.20+ , text >= 1.2.3 && <= 2.1 , time >= 1.8.0 && < 1.13 , parsec >= 3.1.13 && < 3.2 , mtl >= 2.2.2 && < 2.3- , ghc >= 8.6.1 && < 9.4- , ghc-boot >= 8.6.1 && < 9.4+ , ghc >= 8.6.1 && < 9.6+ , ghc-boot >= 8.6.1 && < 9.5 hs-source-dirs: src ghc-options: -Wall -Wunused-packages -Wincomplete-uni-patterns default-language: Haskell2010
Readme.md view
@@ -373,3 +373,11 @@ - `nix run .\#run-ormolu` Before submitting.++## Treesitter support++Have a look in the [./tree-sitter-pyf/](./tree-sitter-pyf) directory for a+parser of PyF which can be integrated in your treesitter compatible editor to+get syntax highlighting for PyF.++
src/PyF/Internal/Meta.hs view
@@ -212,6 +212,13 @@ -- enabled thus match on Nothing toExp _ (HsOverLabel _ Nothing lbl) = TH.LabelE (unpackFS lbl) #endif+#if MIN_VERSION_ghc(9, 4, 0)+toExp dynFlags (HsGetField _ expr field) = TH.GetFieldE (toExp dynFlags (unLoc expr)) (unpackFS . unLoc . dfoLabel . unLoc $ field)+toExp _ (HsProjection _ fields) = TH.ProjectionE (fmap (unpackFS . unLoc . dfoLabel . unLoc) fields)+#elif MIN_VERSION_ghc(9, 2, 0)+toExp dynFlags (HsGetField _ expr field) = TH.GetFieldE (toExp dynFlags (unLoc expr)) (unpackFS . unLoc . hflLabel . unLoc $ field)+toExp _ (HsProjection _ fields) = TH.ProjectionE (fmap (unpackFS . unLoc . hflLabel . unLoc) fields)+#endif toExp dynFlags e = todo "toExp" (showSDoc dynFlags . ppr $ e) todo :: (HasCallStack, Show e) => String -> e -> a
src/PyF/Internal/QQ.hs view
@@ -34,13 +34,14 @@ import Data.Maybe (catMaybes, fromMaybe) import Data.Proxy import Data.String (fromString)-import GHC (GenLocated (L))+import GHC (GenLocated (L), moduleNameString) #if MIN_VERSION_ghc(9,0,0) import GHC.Tc.Utils.Monad (addErrAt) import GHC.Tc.Types (TcM)-import GHC.Tc.Gen.Splice (lookupThName_maybe)+import GHC.Types.Name (occNameString) #else+import OccName import TcRnTypes (TcM) import TcSplice (lookupThName_maybe) import TcRnMonad (addErrAt)@@ -106,6 +107,7 @@ import Text.Parsec.Pos (newPos, initialPos) import Text.ParserCombinators.Parsec.Error (Message (..)) import Unsafe.Coerce (unsafeCoerce)+import Data.Maybe (isJust) -- | Configuration for the quasiquoter data Config = Config@@ -212,12 +214,20 @@ allVars = concat $ gmapQ f [item] allNames = map (\(L l e) -> (l, e)) allVars +lookupName :: RdrName -> Q Bool+lookupName n = case n of+ (Unqual o) -> isJust <$> lookupValueName (occNameString o)+ (Qual m o) -> isJust <$> lookupValueName (moduleNameString m <> "." <> occNameString o)+ -- No idea how to lookup for theses names, so consider that they exists+ (Orig _m _o) -> pure True+ (Exact _) -> pure True+ doesExists :: (b, RdrName) -> Q (Maybe (String, b)) doesExists (loc, name) = do- res <- unsafeRunTcM $ lookupThName_maybe (toName name)+ res <- lookupName name case res of- Nothing -> pure (Just ("Variable not in scope: " <> show (toName name), loc))- Just _ -> pure Nothing+ False -> pure (Just ("Variable not in scope: " <> show (toName name), loc))+ True -> pure Nothing -- | Check that all variables used in 'Item' exists, otherwise, fail. checkVariables :: [Item] -> Q (Maybe (SrcSpan, String))@@ -230,6 +240,9 @@ -- Stolen from: https://www.tweag.io/blog/2021-01-07-haskell-dark-arts-part-i/ -- This allows to hack inside the the GHC api and use function not exported by template haskell.+-- This may not be always safe, see https://github.com/guibou/PyF/issues/115,+-- hence keep that for "failing path" (i.e. error reporting), but not on+-- codepath which are executed otherwise. unsafeRunTcM :: TcM a -> Q a unsafeRunTcM m = Q (unsafeCoerce m)
test/Spec.hs view
@@ -35,6 +35,7 @@ import SpecCustomDelimiters import SpecUtils import Test.Hspec+import qualified Data.Text as Text {- - Normal tests are done using the recommanded API: [fmt|.....|]@@ -546,3 +547,5 @@ let padding = 10 let precision = 3 [fmt|pi = {pi:{padding}.{precision}}|] `shouldBe` "pi = 3.142"+ it "an expression with module.variable" $ do+ [fmt|{Text.intercalate " " ["a" :: Text.Text, "b" :: Text.Text]}|] `shouldBe` "a b"