parsley-core 1.7.2.0 → 1.8.0.0
raw patch · 32 files changed
+888/−335 lines, 32 filesdep +deepseqdep +th-test-utilsdep ~basedep ~template-haskellPVP ok
version bump matches the API change (PVP)
Dependencies added: deepseq, th-test-utils
Dependency ranges changed: base, template-haskell
API changes (from Hackage documentation)
- Parsley.Internal.Backend.Machine.Defunc: [OFFSET] :: Offset o -> Defunc o
- Parsley.Internal.Backend.Machine.Types.Offset: data Offset o
- Parsley.Internal.Backend.Machine.Types.Offset: instance GHC.Classes.Eq Parsley.Internal.Backend.Machine.Types.Offset.Amount
- Parsley.Internal.Backend.Machine.Types.Offset: instance GHC.Show.Show (Parsley.Internal.Backend.Machine.Types.Offset.Offset o)
- Parsley.Internal.Backend.Machine.Types.Offset: instance GHC.Show.Show Parsley.Internal.Backend.Machine.Types.Offset.Amount
- Parsley.Internal.Backend.Machine.Types.Offset: mkOffset :: Code (Rep o) -> Word -> Offset o
- Parsley.Internal.Backend.Machine.Types.Offset: moveN :: Maybe Word -> Offset o -> Code (Rep o) -> Offset o
- Parsley.Internal.Backend.Machine.Types.Offset: moveOne :: Offset o -> Code (Rep o) -> Offset o
- Parsley.Internal.Backend.Machine.Types.Offset: offset :: Offset o -> Code (Rep o)
- Parsley.Internal.Backend.Machine.Types.Offset: same :: Offset o -> Offset o -> Maybe Bool
+ Parsley.Internal: col :: Parser Int
+ Parsley.Internal: line :: Parser Int
+ Parsley.Internal.Backend.Machine.Defunc: [INPUT] :: Input o -> Defunc o
+ Parsley.Internal.Backend.Machine.Instructions: [Col] :: PosSelector
+ Parsley.Internal.Backend.Machine.Instructions: [Line] :: PosSelector
+ Parsley.Internal.Backend.Machine.Instructions: [SelectPos] :: PosSelector -> k (Int : xs) n r a -> Instr o k xs n r a
+ Parsley.Internal.Backend.Machine.Instructions: data PosSelector
+ Parsley.Internal.Backend.Machine.PosOps: extractCol :: Code Pos -> Code Int
+ Parsley.Internal.Backend.Machine.PosOps: extractLine :: Code Pos -> Code Int
+ Parsley.Internal.Backend.Machine.PosOps: initPos :: Code Pos
+ Parsley.Internal.Backend.Machine.PosOps: updatePos :: Code Pos -> Code Char -> Code Pos
+ Parsley.Internal.Backend.Machine.PosOps: updatePos# :: Pos -> Char -> Pos
+ Parsley.Internal.Backend.Machine.Types.Base: type Pos = Word#
+ Parsley.Internal.Backend.Machine.Types.Input: Input :: Offset o -> Code Pos -> Input o
+ Parsley.Internal.Backend.Machine.Types.Input: Input# :: Code (Rep o) -> Code Pos -> Input# o
+ Parsley.Internal.Backend.Machine.Types.Input: [off#] :: Input# o -> Code (Rep o)
+ Parsley.Internal.Backend.Machine.Types.Input: [off] :: Input o -> Offset o
+ Parsley.Internal.Backend.Machine.Types.Input: [pos#] :: Input# o -> Code Pos
+ Parsley.Internal.Backend.Machine.Types.Input: [pos] :: Input o -> Code Pos
+ Parsley.Internal.Backend.Machine.Types.Input: data Input o
+ Parsley.Internal.Backend.Machine.Types.Input: data Input# o
+ Parsley.Internal.Backend.Machine.Types.Input: fromInput :: Input o -> Input# o
+ Parsley.Internal.Backend.Machine.Types.Input: toInput :: Word -> Input# o -> Input o
+ Parsley.Internal.Backend.Machine.Types.Input.Offset: data Offset o
+ Parsley.Internal.Backend.Machine.Types.Input.Offset: instance GHC.Classes.Eq Parsley.Internal.Backend.Machine.Types.Input.Offset.Amount
+ Parsley.Internal.Backend.Machine.Types.Input.Offset: instance GHC.Show.Show (Parsley.Internal.Backend.Machine.Types.Input.Offset.Offset o)
+ Parsley.Internal.Backend.Machine.Types.Input.Offset: instance GHC.Show.Show Parsley.Internal.Backend.Machine.Types.Input.Offset.Amount
+ Parsley.Internal.Backend.Machine.Types.Input.Offset: mkOffset :: Code (Rep o) -> Word -> Offset o
+ Parsley.Internal.Backend.Machine.Types.Input.Offset: moveN :: Maybe Word -> Offset o -> Code (Rep o) -> Offset o
+ Parsley.Internal.Backend.Machine.Types.Input.Offset: moveOne :: Offset o -> Code (Rep o) -> Offset o
+ Parsley.Internal.Backend.Machine.Types.Input.Offset: offset :: Offset o -> Code (Rep o)
+ Parsley.Internal.Backend.Machine.Types.Input.Offset: same :: Offset o -> Offset o -> Maybe Bool
+ Parsley.Internal.Core.CombinatorAST: [Col] :: PosSelector
+ Parsley.Internal.Core.CombinatorAST: [Line] :: PosSelector
+ Parsley.Internal.Core.CombinatorAST: [Position] :: PosSelector -> Combinator k Int
+ Parsley.Internal.Core.CombinatorAST: data PosSelector
+ Parsley.Internal.Core.Primitives: col :: Parser Int
+ Parsley.Internal.Core.Primitives: line :: Parser Int
- Parsley.Internal.Backend.Machine.BindingOps: bindIter# :: RecBuilder o => Code (Rep o) -> (DynHandler s o a -> Code (Rep o) -> Code (ST s (Maybe a))) -> Code (ST s (Maybe a))
+ Parsley.Internal.Backend.Machine.BindingOps: bindIter# :: RecBuilder o => Input# o -> (Code (Pos -> Rep o -> ST s (Maybe a)) -> Input# o -> Code (ST s (Maybe a))) -> Code (ST s (Maybe a))
- Parsley.Internal.Backend.Machine.BindingOps: bindIterHandler# :: RecBuilder o => (Code (Rep o) -> StaHandler# s o a) -> (Code (Rep o -> Handler# s o a) -> Code b) -> Code b
+ Parsley.Internal.Backend.Machine.BindingOps: bindIterHandler# :: RecBuilder o => (Input# o -> StaHandler# s o a) -> (Code (Pos -> Rep o -> Handler# s o a) -> Code b) -> Code b
- Parsley.Internal.Backend.Machine.BindingOps: bindRec# :: RecBuilder o => (DynSubroutine s o a x -> DynCont s o a x -> Code (Rep o) -> DynHandler s o a -> Code (ST s (Maybe a))) -> DynSubroutine s o a x
+ Parsley.Internal.Backend.Machine.BindingOps: bindRec# :: RecBuilder o => (DynSubroutine s o a x -> StaSubroutine# s o a x) -> DynSubroutine s o a x
- Parsley.Internal.Backend.Machine.Ops: bindIterAlways :: forall s o a. RecBuilder o => Ctx s o a -> MVar Void -> Machine s o '[] One Void a -> Bool -> StaHandlerBuilder s o a -> Offset o -> Word -> Code (ST s (Maybe a))
+ Parsley.Internal.Backend.Machine.Ops: bindIterAlways :: forall s o a. RecBuilder o => Ctx s o a -> MVar Void -> Machine s o '[] One Void a -> Bool -> StaHandlerBuilder s o a -> Input o -> Word -> Code (ST s (Maybe a))
- Parsley.Internal.Backend.Machine.Ops: bindIterSame :: forall s o a. (RecBuilder o, HandlerOps o, PositionOps (Rep o)) => Ctx s o a -> MVar Void -> Machine s o '[] One Void a -> Bool -> StaHandler s o a -> Bool -> StaHandlerBuilder s o a -> Offset o -> Word -> Code (ST s (Maybe a))
+ Parsley.Internal.Backend.Machine.Ops: bindIterSame :: forall s o a. (RecBuilder o, HandlerOps o, PositionOps (Rep o)) => Ctx s o a -> MVar Void -> Machine s o '[] One Void a -> Bool -> StaHandler s o a -> Bool -> StaHandlerBuilder s o a -> Input o -> Word -> Code (ST s (Maybe a))
- Parsley.Internal.Backend.Machine.Ops: callWithContinuation :: MarshalOps o => StaSubroutine s o a x -> StaCont s o a x -> Code (Rep o) -> Vec (Succ n) (AugmentedStaHandler s o a) -> Code (ST s (Maybe a))
+ Parsley.Internal.Backend.Machine.Ops: callWithContinuation :: MarshalOps o => StaSubroutine s o a x -> StaCont s o a x -> Input o -> Vec (Succ n) (AugmentedStaHandler s o a) -> Code (ST s (Maybe a))
- Parsley.Internal.Backend.Machine.Ops: fetch :: (?ops :: InputOps (Rep o)) => Offset o -> (Code Char -> Offset o -> Code b) -> Code b
+ Parsley.Internal.Backend.Machine.Ops: fetch :: (?ops :: InputOps (Rep o)) => Input o -> (Code Char -> Input o -> Code b) -> Code b
- Parsley.Internal.Backend.Machine.Ops: sat :: (Defunc Char -> Defunc Bool) -> ((Code Char -> Offset o -> aux -> Code b) -> Code b) -> (Defunc Char -> Offset o -> aux -> Code b) -> Code b -> Code b
+ Parsley.Internal.Backend.Machine.Ops: sat :: (Defunc Char -> Defunc Bool) -> ((Code Char -> Input o -> aux -> Code b) -> Code b) -> (Defunc Char -> Input o -> aux -> Code b) -> Code b -> Code b
- Parsley.Internal.Backend.Machine.Ops: suspend :: (Γ s o (x : xs) n r a -> Code (ST s (Maybe a))) -> Γ s o xs n r a -> (Code (Rep o) -> Offset o) -> StaCont s o a x
+ Parsley.Internal.Backend.Machine.Ops: suspend :: (Γ s o (x : xs) n r a -> Code (ST s (Maybe a))) -> Γ s o xs n r a -> (Input# o -> Input o) -> StaCont s o a x
- Parsley.Internal.Backend.Machine.Ops: type StaHandlerBuilder s o a = Offset o -> StaHandler s o a
+ Parsley.Internal.Backend.Machine.Ops: type StaHandlerBuilder s o a = Input o -> StaHandler s o a
- Parsley.Internal.Backend.Machine.Types.Base: type Cont# s o a x = x " The value to be returned to the caller" -> Rep o " The new input after the call is executed" -> ST s (Maybe a)
+ Parsley.Internal.Backend.Machine.Types.Base: type Cont# s o a x = x " The value to be returned to the caller" -> Pos " The current position" -> Rep o " The new input after the call is executed" -> ST s (Maybe a)
- Parsley.Internal.Backend.Machine.Types.Base: type Handler# s o a = Rep o " The current input on failure " -> ST s (Maybe a)
+ Parsley.Internal.Backend.Machine.Types.Base: type Handler# s o a = Pos " The current position" -> Rep o " The current input on failure" -> ST s (Maybe a)
- Parsley.Internal.Backend.Machine.Types.Base: type Subroutine# s o a x = Cont# s o a x " What to do when this parser returns" -> Rep o " The input on entry to the call" -> Handler# s o a " How to handle failure within the call" -> ST s (Maybe a)
+ Parsley.Internal.Backend.Machine.Types.Base: type Subroutine# s o a x = Cont# s o a x " What to do when this parser returns" -> Handler# s o a " How to handle failure within the call" -> Pos " The current position" -> Rep o " The input on entry to the call" -> ST s (Maybe a)
- Parsley.Internal.Backend.Machine.Types.Context: addChar :: Code Char -> Offset o -> Ctx s o a -> Ctx s o a
+ Parsley.Internal.Backend.Machine.Types.Context: addChar :: Code Char -> Input o -> Ctx s o a -> Ctx s o a
- Parsley.Internal.Backend.Machine.Types.Context: readChar :: Ctx s o a -> ((Code Char -> Offset o -> Code b) -> Code b) -> (Code Char -> Offset o -> Ctx s o a -> Code b) -> Code b
+ Parsley.Internal.Backend.Machine.Types.Context: readChar :: Ctx s o a -> ((Code Char -> Input o -> Code b) -> Code b) -> (Code Char -> Input o -> Ctx s o a -> Code b) -> Code b
- Parsley.Internal.Backend.Machine.Types.State: [input] :: Γ s o xs n r a -> Offset o
+ Parsley.Internal.Backend.Machine.Types.State: [input] :: Γ s o xs n r a -> Input o
- Parsley.Internal.Backend.Machine.Types.State: Γ :: OpStack xs -> StaCont s o a r -> Offset o -> Vec n (AugmentedStaHandler s o a) -> Γ s o xs n r a
+ Parsley.Internal.Backend.Machine.Types.State: Γ :: OpStack xs -> StaCont s o a r -> Input o -> Vec n (AugmentedStaHandler s o a) -> Γ s o xs n r a
- Parsley.Internal.Backend.Machine.Types.Statics: augmentHandler :: Maybe (Offset o) -> StaHandler s o a -> AugmentedStaHandler s o a
+ Parsley.Internal.Backend.Machine.Types.Statics: augmentHandler :: Maybe (Input o) -> StaHandler s o a -> AugmentedStaHandler s o a
- Parsley.Internal.Backend.Machine.Types.Statics: augmentHandlerDyn :: forall s o a. Maybe (Offset o) -> DynHandler s o a -> AugmentedStaHandler s o a
+ Parsley.Internal.Backend.Machine.Types.Statics: augmentHandlerDyn :: forall s o a. Maybe (Input o) -> DynHandler s o a -> AugmentedStaHandler s o a
- Parsley.Internal.Backend.Machine.Types.Statics: augmentHandlerFull :: Offset o -> StaHandler s o a -> Code (ST s (Maybe a)) -> StaHandler s o a -> AugmentedStaHandler s o a
+ Parsley.Internal.Backend.Machine.Types.Statics: augmentHandlerFull :: Input o -> StaHandler s o a -> Code (ST s (Maybe a)) -> StaHandler s o a -> AugmentedStaHandler s o a
- Parsley.Internal.Backend.Machine.Types.Statics: augmentHandlerSta :: Maybe (Offset o) -> StaHandler# s o a -> AugmentedStaHandler s o a
+ Parsley.Internal.Backend.Machine.Types.Statics: augmentHandlerSta :: Maybe (Input o) -> StaHandler# s o a -> AugmentedStaHandler s o a
- Parsley.Internal.Backend.Machine.Types.Statics: staHandlerEval :: AugmentedStaHandler s o a -> Offset o -> Code (ST s (Maybe a))
+ Parsley.Internal.Backend.Machine.Types.Statics: staHandlerEval :: AugmentedStaHandler s o a -> Input o -> Code (ST s (Maybe a))
- Parsley.Internal.Backend.Machine.Types.Statics: type StaCont# s o a x = Code x -> Code (Rep o) -> Code (ST s (Maybe a))
+ Parsley.Internal.Backend.Machine.Types.Statics: type StaCont# s o a x = Code x -> Input# o -> Code (ST s (Maybe a))
- Parsley.Internal.Backend.Machine.Types.Statics: type StaHandler# s o a = Code (Rep o) -> Code (ST s (Maybe a))
+ Parsley.Internal.Backend.Machine.Types.Statics: type StaHandler# s o a = Input# o -> Code (ST s (Maybe a))
- Parsley.Internal.Backend.Machine.Types.Statics: type StaSubroutine# s o a x = DynCont s o a x -> Code (Rep o) -> DynHandler s o a -> Code (ST s (Maybe a))
+ Parsley.Internal.Backend.Machine.Types.Statics: type StaSubroutine# s o a x = DynCont s o a x -> DynHandler s o a -> Input# o -> Code (ST s (Maybe a))
Files
- ChangeLog.md +10/−0
- parsley-core.cabal +22/−4
- src/ghc-8.10+/Parsley/Internal/Backend/Machine/BindingOps.hs +46/−40
- src/ghc-8.10+/Parsley/Internal/Backend/Machine/Defunc.hs +8/−8
- src/ghc-8.10+/Parsley/Internal/Backend/Machine/Eval.hs +37/−28
- src/ghc-8.10+/Parsley/Internal/Backend/Machine/InputOps.hs +15/−15
- src/ghc-8.10+/Parsley/Internal/Backend/Machine/Ops.hs +65/−58
- src/ghc-8.10+/Parsley/Internal/Backend/Machine/PosOps.hs +89/−0
- src/ghc-8.10+/Parsley/Internal/Backend/Machine/Types/Base.hs +27/−5
- src/ghc-8.10+/Parsley/Internal/Backend/Machine/Types/Context.hs +9/−8
- src/ghc-8.10+/Parsley/Internal/Backend/Machine/Types/Dynamics.hs +1/−1
- src/ghc-8.10+/Parsley/Internal/Backend/Machine/Types/Input.hs +57/−0
- src/ghc-8.10+/Parsley/Internal/Backend/Machine/Types/Input/Offset.hs +100/−0
- src/ghc-8.10+/Parsley/Internal/Backend/Machine/Types/Offset.hs +0/−100
- src/ghc-8.10+/Parsley/Internal/Backend/Machine/Types/State.hs +2/−2
- src/ghc-8.10+/Parsley/Internal/Backend/Machine/Types/Statics.hs +34/−32
- src/ghc-8.6+/Parsley/Internal/Backend/Machine/Eval.hs +10/−5
- src/ghc-8.6+/Parsley/Internal/Backend/Machine/Ops.hs +38/−24
- src/ghc-8.6+/Parsley/Internal/Backend/Machine/Types/State.hs +4/−3
- src/ghc/Parsley/Internal.hs +1/−0
- src/ghc/Parsley/Internal/Backend/Analysis/Coins.hs +1/−0
- src/ghc/Parsley/Internal/Backend/Analysis/Inliner.hs +1/−0
- src/ghc/Parsley/Internal/Backend/Analysis/Relevancy.hs +1/−0
- src/ghc/Parsley/Internal/Backend/CodeGenerator.hs +1/−0
- src/ghc/Parsley/Internal/Backend/Machine/Instructions.hs +8/−1
- src/ghc/Parsley/Internal/Core/CombinatorAST.hs +9/−0
- src/ghc/Parsley/Internal/Core/Primitives.hs +9/−1
- src/ghc/Parsley/Internal/Frontend/Analysis/Cut.hs +2/−0
- src/ghc/Parsley/Internal/Frontend/Analysis/Inliner.hs +1/−0
- test/Primitive.hs +142/−0
- test/Primitive/Parsers.hs +50/−0
- test/TestUtils.hs +88/−0
ChangeLog.md view
@@ -121,3 +121,13 @@ * Added `reclaimable` to backend analysis, this allows `lookAhead` to calculate reclaim ignoring `BlockCoins` * Fixed small bug in coin analysis that meant that `lookAhead` always contributes `0` coins (`min 0` vs `max 0`).++## 1.8.0.0 -- 2021-11-13++* Reversed order of arguments on `Subroutine#`, offset comes last.+* Added `Pos` type, and threaded it through+* Added `Input o` and `Input# o`, which package an `Offset o` or `Code (Rep o)` with `Pos` information.+* Added cabal flag to control the packed or unpacked representation of positions+* Added `PosSelector`+* Added `line` and `col` to primitives and `Position` to Combinator AST, as well as `SelectPos` to instructions.+* Changed `OFFSET` to `INPUT` in `Defunc`
parsley-core.cabal view
@@ -5,7 +5,7 @@ -- | +------- breaking internal API changes -- | | +----- non-breaking API additions -- | | | +--- code changes with no API change-version: 1.7.2.0+version: 1.8.0.0 synopsis: A fast parser combinator library backed by Typed Template Haskell description: This package contains the internals of the @parsley@ package. .@@ -28,9 +28,14 @@ README.md tested-with: GHC == 8.6.1, GHC == 8.6.2, GHC == 8.6.3, GHC == 8.6.4, GHC == 8.6.5, GHC == 8.8.1, GHC == 8.8.2, GHC == 8.8.3, GHC == 8.8.4,- GHC == 8.10.4, GHC == 8.10.5,+ GHC == 8.10.4, GHC == 8.10.5, GHC == 8.10.7, GHC == 9.0.1 +flag full-width-positions+ description: Make line and column numbers 64-bit (on 64-bit platforms): normally they are 32-bits each for line and column.+ default: False+ manual: True+ library exposed-modules: Parsley.Internal, Parsley.Internal.Trace,@@ -95,13 +100,17 @@ if impl(ghc >= 8.10) exposed-modules: Parsley.Internal.Backend.Machine.BindingOps,+ Parsley.Internal.Backend.Machine.PosOps, Parsley.Internal.Backend.Machine.Types.Base, Parsley.Internal.Backend.Machine.Types.Context, Parsley.Internal.Backend.Machine.Types.Dynamics,- Parsley.Internal.Backend.Machine.Types.Offset,- Parsley.Internal.Backend.Machine.Types.Statics+ Parsley.Internal.Backend.Machine.Types.Input,+ Parsley.Internal.Backend.Machine.Types.Statics, + Parsley.Internal.Backend.Machine.Types.Input.Offset+ --Parsley.Internal.Backend.Machine.Types.Input.Pos+ default-extensions: BangPatterns, DataKinds, GADTs,@@ -156,6 +165,8 @@ ghc-options: -Wno-missing-safe-haskell-mode -Wno-prepositive-qualified-module -Wno-unused-packages+ if flag(full-width-positions)+ cpp-options: -DFULL_WIDTH_POSITIONS common test-common build-depends: base >=4.10 && <5,@@ -163,6 +174,13 @@ tasty hs-source-dirs: test default-language: Haskell2010++test-suite primitives-test+ import: test-common+ type: exitcode-stdio-1.0+ build-depends: tasty-hunit, tasty-quickcheck, th-test-utils, deepseq, template-haskell+ main-is: Primitive.hs+ other-modules: Primitive.Parsers, TestUtils test-suite common-test import: test-common
src/ghc-8.10+/Parsley/Internal/Backend/Machine/BindingOps.hs view
@@ -1,7 +1,8 @@ {-# OPTIONS_GHC -Wno-monomorphism-restriction #-} {-# LANGUAGE AllowAmbiguousTypes, CPP,- MagicHash #-}+ MagicHash,+ UnboxedTuples #-} {-| Module : Parsley.Internal.Backend.Machine.BindingOps Description : Various functions that handle levity-polymorphic code bindings@@ -27,9 +28,10 @@ import Data.ByteString.Internal (ByteString) import Data.Text (Text) import Parsley.Internal.Backend.Machine.InputRep (Rep)-import Parsley.Internal.Backend.Machine.Types.Base (Handler#)+import Parsley.Internal.Backend.Machine.Types.Base (Handler#, Pos) import Parsley.Internal.Backend.Machine.Types.Dynamics (DynSubroutine, DynCont, DynHandler)-import Parsley.Internal.Backend.Machine.Types.Statics (StaCont#, StaHandler#)+import Parsley.Internal.Backend.Machine.Types.Input (Input#(..))+import Parsley.Internal.Backend.Machine.Types.Statics (StaCont#, StaHandler#, StaSubroutine#) import Parsley.Internal.Common.Utils (Code) import Parsley.Internal.Core.InputTypes (Text16, CharList, Stream) @@ -60,13 +62,14 @@ -> (DynHandler s o a -> Code b) -- ^ The continuation that expects the bound handler -> Code b -#define deriveHandlerOps(_o) \-instance HandlerOps _o where \-{ \- bindHandler# h k = [|| \- let handler (o# :: Rep _o) = $$(h [||o#||]) \- in $$(k [||handler||]) \- ||]; \+#define deriveHandlerOps(_o) \+instance HandlerOps _o where \+{ \+ bindHandler# h k = [|| \+ let handler (pos :: Pos) (o# :: Rep _o) = \+ $$(h (Input# [||o#||] [||pos||])) \+ in $$(k [||handler||]) \+ ||]; \ }; inputInstances(deriveHandlerOps) @@ -85,11 +88,12 @@ -> (DynCont s o a x -> Code b) -- ^ The continuation that expects the bound join point -> Code b -#define deriveJoinBuilder(_o) \-instance JoinBuilder _o where \-{ \- setupJoinPoint# binding k = \- [|| let join x !(o# :: Rep _o) = $$(binding [||x||] [||o#||]) in $$(k [||join||]) ||] \+#define deriveJoinBuilder(_o) \+instance JoinBuilder _o where \+{ \+ setupJoinPoint# binding k = \+ [|| let join x (pos :: Pos) !(o# :: Rep _o) = \+ $$(binding [||x||] (Input# [||o#||] [||pos||])) in $$(k [||join||]) ||] \ }; inputInstances(deriveJoinBuilder) @@ -106,8 +110,8 @@ @since 1.4.0.0 -}- bindIterHandler# :: (Code (Rep o) -> StaHandler# s o a) -- ^ The iter handler to bind- -> (Code (Rep o -> Handler# s o a) -> Code b) -- ^ The continuation that accepts the bound handler+ bindIterHandler# :: (Input# o -> StaHandler# s o a) -- ^ The iter handler to bind+ -> (Code (Pos -> Rep o -> Handler# s o a) -> Code b) -- ^ The continuation that accepts the bound handler -> Code b {-|@@ -115,31 +119,33 @@ @since 1.4.0.0 -}- bindIter# :: Code (Rep o) -- ^ Initial offset for the loop.- -> (DynHandler s o a -> Code (Rep o) -> Code (ST s (Maybe a))) -- ^ The code for the loop given handler and offset.- -> Code (ST s (Maybe a)) -- ^ Code of the executing loop.+ bindIter# :: Input# o -- ^ Initial offset for the loop.+ -> (Code (Pos -> Rep o -> ST s (Maybe a)) -> Input# o -> Code (ST s (Maybe a))) -- ^ The code for the loop given self-call and offset.+ -> Code (ST s (Maybe a)) -- ^ Code of the executing loop. {-| Creates a binding for a regular let-bound parser. @since 1.4.0.0 -}- bindRec# :: (DynSubroutine s o a x -> DynCont s o a x -> Code (Rep o) -> DynHandler s o a -> Code (ST s (Maybe a))) -- ^ Code for the binding, accepting itself as an argument.- -> DynSubroutine s o a x -- ^ The code that represents this binding's name.+ bindRec# :: (DynSubroutine s o a x -> StaSubroutine# s o a x) -- ^ Code for the binding, accepting itself as an argument.+ -> DynSubroutine s o a x -- ^ The code that represents this binding's name. -#define deriveRecBuilder(_o) \-instance RecBuilder _o where \-{ \- bindIterHandler# h k = [|| \- let handler (c# :: Rep _o) (o# :: Rep _o) = $$(h [||c#||] [||o#||]) in $$(k [||handler||]) \- ||]; \- bindIter# o l = [|| \- let loop !(o# :: Rep _o) = $$(l [||loop||] [||o#||]) \- in loop $$o \- ||]; \- bindRec# binding = \- {- The idea here is to try and reduce the number of times registers have to be passed around -} \- [|| let self ret !(o# :: Rep _o) h = $$(binding [||self||] [||ret||] [||o#||] [||h||]) in self ||] \+#define deriveRecBuilder(_o) \+instance RecBuilder _o where \+{ \+ bindIterHandler# h k = [|| \+ let handler (posc :: Pos) (c# :: Rep _o) (poso :: Pos) (o# :: Rep _o) = \+ $$(h (Input# [||c#||] [||posc||]) (Input# [||o#||] [||poso||])) in $$(k [||handler||]) \+ ||]; \+ bindIter# inp l = [|| \+ let loop (pos :: Pos) !(o# :: Rep _o) = $$(l [||loop||] (Input# [||o#||] [||pos||])) \+ in loop $$(pos# inp) $$(off# inp) \+ ||]; \+ bindRec# binding = \+ {- The idea here is to try and reduce the number of times registers have to be passed around -} \+ [|| let self ret h (pos :: Pos) !(o# :: Rep _o) = \+ $$(binding [||self||] [||ret||] [||h||] (Input# [||o#||] [||pos||])) in self ||] \ }; inputInstances(deriveRecBuilder) @@ -166,10 +172,10 @@ -} dynCont# :: StaCont# s o a x -> DynCont s o a x -#define deriveMarshalOps(_o) \-instance MarshalOps _o where \-{ \- dynHandler# sh = [||\ (o# :: Rep _o) -> $$(sh [||o#||]) ||]; \- dynCont# sk = [||\ x (o# :: Rep _o) -> $$(sk [||x||] [||o#||]) ||]; \+#define deriveMarshalOps(_o) \+instance MarshalOps _o where \+{ \+ dynHandler# sh = [||\ (pos :: Pos) (o# :: Rep _o) -> $$(sh (Input# [||o#||] [||pos||])) ||]; \+ dynCont# sk = [||\ x (pos :: Pos) (o# :: Rep _o) -> $$(sk [||x||] (Input# [||o#||] [||pos||])) ||]; \ }; inputInstances(deriveMarshalOps)
src/ghc-8.10+/Parsley/Internal/Backend/Machine/Defunc.hs view
@@ -20,9 +20,9 @@ pattern NormLam, pattern FREEVAR ) where -import Parsley.Internal.Backend.Machine.Types.Offset (Offset)-import Parsley.Internal.Common.Utils (Code)-import Parsley.Internal.Core.Lam (Lam, normaliseGen, normalise)+import Parsley.Internal.Backend.Machine.Types.Input (Input(off))+import Parsley.Internal.Common.Utils (Code)+import Parsley.Internal.Core.Lam (Lam, normaliseGen, normalise) import qualified Parsley.Internal.Core.Defunc as Core (Defunc, lamTerm, lamTermBool) import qualified Parsley.Internal.Core.Lam as Lam (Lam(..))@@ -48,14 +48,14 @@ -} BOTTOM :: Defunc a {-|- Allows the static `Offset`s to be pushed onto the operand stack, which+ Allows the static `Input`s to be pushed onto the operand stack, which is the easiest way to get them to persist as arguments to handlers, and interact with `Parsley.Internal.Backend.Machine.Instructions.Seek` and `Parsley.Internal.Backend.Machine.Instructions.Tell`. - @since 1.4.0.0+ @since 1.8.0.0 -}- OFFSET :: Offset o -> Defunc o+ INPUT :: Input o -> Defunc o {-| Promotes a @Defunc@ value from the Frontend API into a Backend one.@@ -110,7 +110,7 @@ genDefunc :: Defunc a -> Code a genDefunc (LAM x) = normaliseGen x genDefunc BOTTOM = [||undefined||]-genDefunc (OFFSET _) = error "Cannot materialise an unboxed offset in the regular way"+genDefunc (INPUT _) = error "Cannot materialise an input in the regular way" {-| Pattern that normalises a `Lam` before returning it.@@ -135,4 +135,4 @@ show (LAM x) = show x show BOTTOM = "[[irrelevant]]" show (FREEVAR _) = "x"- show (OFFSET o) = "offset " ++ show o+ show (INPUT inp) = "input " ++ show (off inp)
src/ghc-8.10+/Parsley/Internal/Backend/Machine/Eval.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE ImplicitParams,+ MagicHash, MultiWayIf, PatternSynonyms, RecordWildCards,@@ -17,28 +18,30 @@ -} module Parsley.Internal.Backend.Machine.Eval (eval) where -import Data.Dependent.Map (DMap)-import Data.Functor ((<&>))-import Data.Void (Void)-import Control.Monad (forM, liftM2, liftM3, when)-import Control.Monad.Reader (ask, asks, reader, local)-import Control.Monad.ST (runST)-import Parsley.Internal.Backend.Machine.Defunc (Defunc(OFFSET), pattern FREEVAR, genDefunc, ap, ap2, _if)-import Parsley.Internal.Backend.Machine.Identifiers (MVar(..), ΦVar, ΣVar)-import Parsley.Internal.Backend.Machine.InputOps (InputDependant, InputOps(InputOps))-import Parsley.Internal.Backend.Machine.InputRep (Rep)-import Parsley.Internal.Backend.Machine.Instructions (Instr(..), MetaInstr(..), Access(..), Handler(..))-import Parsley.Internal.Backend.Machine.LetBindings (LetBinding(body))-import Parsley.Internal.Backend.Machine.LetRecBuilder (letRec)+import Data.Dependent.Map (DMap)+import Data.Functor ((<&>))+import Data.Void (Void)+import Control.Monad (forM, liftM2, liftM3, when)+import Control.Monad.Reader (ask, asks, reader, local)+import Control.Monad.ST (runST)+import Parsley.Internal.Backend.Machine.Defunc (Defunc(INPUT), pattern FREEVAR, genDefunc, ap, ap2, _if)+import Parsley.Internal.Backend.Machine.Identifiers (MVar(..), ΦVar, ΣVar)+import Parsley.Internal.Backend.Machine.InputOps (InputDependant, InputOps(InputOps))+import Parsley.Internal.Backend.Machine.InputRep (Rep)+import Parsley.Internal.Backend.Machine.Instructions (Instr(..), MetaInstr(..), Access(..), Handler(..), PosSelector(..))+import Parsley.Internal.Backend.Machine.LetBindings (LetBinding(body))+import Parsley.Internal.Backend.Machine.LetRecBuilder (letRec) import Parsley.Internal.Backend.Machine.Ops-import Parsley.Internal.Backend.Machine.Types (MachineMonad, Machine(..), run)+import Parsley.Internal.Backend.Machine.Types (MachineMonad, Machine(..), run)+import Parsley.Internal.Backend.Machine.PosOps (initPos, extractCol, extractLine) import Parsley.Internal.Backend.Machine.Types.Context-import Parsley.Internal.Backend.Machine.Types.Coins (willConsume, int)-import Parsley.Internal.Backend.Machine.Types.Offset (mkOffset, offset)-import Parsley.Internal.Backend.Machine.Types.State (Γ(..), OpStack(..))-import Parsley.Internal.Common (Fix4, cata4, One, Code, Vec(..), Nat(..))-import Parsley.Internal.Trace (Trace(trace))-import System.Console.Pretty (color, Color(Green))+import Parsley.Internal.Backend.Machine.Types.Coins (willConsume, int)+import Parsley.Internal.Backend.Machine.Types.Input (Input(Input, off, pos))+import Parsley.Internal.Backend.Machine.Types.Input.Offset (mkOffset)+import Parsley.Internal.Backend.Machine.Types.State (Γ(..), OpStack(..))+import Parsley.Internal.Common (Fix4, cata4, One, Code, Vec(..), Nat(..))+import Parsley.Internal.Trace (Trace(trace))+import System.Console.Pretty (color, Color(Green)) import qualified Debug.Trace (trace) @@ -58,7 +61,7 @@ in letRec fs nameLet (\μ exp rs names -> buildRec μ rs (emptyCtx names) (readyMachine exp))- (run (readyMachine (body binding)) (Γ Empty halt (mkOffset [||offset||] 0) (VCons fatal VNil)) . nextUnique . emptyCtx))+ (run (readyMachine (body binding)) (Γ Empty halt (Input (mkOffset [||offset||] 0) initPos) (VCons fatal VNil)) . nextUnique . emptyCtx)) ||] where nameLet :: MVar x -> String@@ -90,6 +93,7 @@ alg (Make σ c k) = evalMake σ c k alg (Get σ c k) = evalGet σ c k alg (Put σ c k) = evalPut σ c k+ alg (SelectPos sel k) = evalSelectPos sel k alg (LogEnter name k) = evalLogEnter name k alg (LogExit name k) = evalLogExit name k alg (MetaInstr m k) = evalMeta m k@@ -101,7 +105,7 @@ evalCall μ (Machine k) = freshUnique $ \u -> liftM2 (callCC u) (askSub μ) k evalJump :: forall s o a x n. MarshalOps o => MVar x -> MachineMonad s o '[] (Succ n) x a-evalJump μ = askSub μ <&> \sub Γ{..} -> callWithContinuation @o sub retCont (offset input) handlers+evalJump μ = askSub μ <&> \sub Γ{..} -> callWithContinuation @o sub retCont input handlers evalPush :: Defunc x -> Machine s o (x : xs) n r a -> MachineMonad s o xs n r a evalPush x (Machine k) = k <&> \m γ -> m (γ {operands = Op x (operands γ)})@@ -137,7 +141,7 @@ -> MachineMonad s o xs (Succ n) r a emitCheckAndFetch n mk = do sat <- satFetch mk- return $ \γ -> emitLengthCheck n (sat γ) (raise γ) (input γ)+ return $ \γ -> emitLengthCheck n (sat γ) (raise γ) (off (input γ)) continue mk γ c input' = run mk (γ {input = input', operands = Op c (operands γ)}) @@ -155,10 +159,10 @@ liftM3 (\mk myes mno γ -> bindSameHandler γ gyes (buildYesHandler γ myes u) gno (buildHandler γ mno u) mk) k yes no evalTell :: Machine s o (o : xs) n r a -> MachineMonad s o xs n r a-evalTell (Machine k) = k <&> \mk γ -> mk (γ {operands = Op (OFFSET (input γ)) (operands γ)})+evalTell (Machine k) = k <&> \mk γ -> mk (γ {operands = Op (INPUT (input γ)) (operands γ)}) evalSeek :: Machine s o xs n r a -> MachineMonad s o (o : xs) n r a-evalSeek (Machine k) = k <&> \mk γ -> let Op (OFFSET input) xs = operands γ in mk (γ {operands = xs, input = input})+evalSeek (Machine k) = k <&> \mk γ -> let Op (INPUT input) xs = operands γ in mk (γ {operands = xs, input = input}) evalCase :: Machine s o (x : xs) n r a -> Machine s o (y : xs) n r a -> MachineMonad s o (Either x y : xs) n r a evalCase (Machine p) (Machine q) = liftM2 (\mp mq γ ->@@ -214,6 +218,11 @@ let Op x xs = operands γ in writeΣ σ a x (run k (γ {operands = xs})) ctx +-- TODO: FREEVAR is the wrong abstraction really...+evalSelectPos :: PosSelector -> Machine s o (Int : xs) n r a -> MachineMonad s o xs n r a+evalSelectPos Line (Machine k) = k <&> \m γ -> m (γ {operands = Op (FREEVAR (extractLine (pos (input γ)))) (operands γ)})+evalSelectPos Col (Machine k) = k <&> \m γ -> m (γ {operands = Op (FREEVAR (extractCol (pos (input γ)))) (operands γ)})+ evalLogEnter :: (?ops :: InputOps (Rep o), LogHandler o, HandlerOps o) => String -> Machine s o xs (Succ (Succ n)) r a -> MachineMonad s o xs (Succ n) r a evalLogEnter name (Machine mk) = freshUnique $ \u ->@@ -231,13 +240,13 @@ evalMeta (AddCoins coins) (Machine k) = do requiresPiggy <- asks hasCoin if requiresPiggy then local (storePiggy coins) k- else local (giveCoins coins) k <&> \mk γ -> emitLengthCheck (willConsume coins) (mk γ) (raise γ) (input γ)+ else local (giveCoins coins) k <&> \mk γ -> emitLengthCheck (willConsume coins) (mk γ) (raise γ) (off (input γ)) evalMeta (RefundCoins coins) (Machine k) = local (refundCoins coins) k -- No interaction with input reclamation here! evalMeta (DrainCoins coins) (Machine k) = -- If there are enough coins left to cover the cost, no length check is required -- Otherwise, the full length check is required (partial doesn't work until the right offset is reached)- liftM2 (\canAfford mk γ -> if canAfford then mk γ else emitLengthCheck (willConsume coins) (mk γ) (raise γ) (input γ))+ liftM2 (\canAfford mk γ -> if canAfford then mk γ else emitLengthCheck (willConsume coins) (mk γ) (raise γ) (off (input γ))) (asks (canAfford (willConsume coins))) k evalMeta (GiveBursary coins) (Machine k) = local (giveCoins coins) k@@ -246,7 +255,7 @@ when (not bankrupt && check) (error "must be bankrupt to generate a prefetch check") mkCheck check (reader $ \ctx γ -> prefetch (input γ) ctx (run k γ)) where- mkCheck True k = local (giveCoins (int 1)) k <&> \mk γ -> emitLengthCheck 1 (mk γ) (raise γ) (input γ)+ mkCheck True k = local (giveCoins (int 1)) k <&> \mk γ -> emitLengthCheck 1 (mk γ) (raise γ) (off (input γ)) mkCheck False k = k prefetch o ctx k = fetch o (\c o' -> k (addChar c o' ctx)) evalMeta BlockCoins (Machine k) = k
src/ghc-8.10+/Parsley/Internal/Backend/Machine/InputOps.hs view
@@ -18,23 +18,23 @@ module Parsley.Internal.Backend.Machine.InputOps ( InputPrep(..), PositionOps(..), LogOps(..), InputOps(..), more, next,- InputDependant,+ InputDependant ) where -import Data.Array.Base (UArray(..), listArray)-import Data.ByteString.Internal (ByteString(..))-import Data.Text.Array (aBA{-, empty-})-import Data.Text.Internal (Text(..))-import Data.Text.Unsafe (iter, Iter(..){-, iter_, reverseIter_-})-import GHC.Exts (Int(..), Char(..), TYPE, Int#)-import GHC.ForeignPtr (ForeignPtr(..))-import GHC.Prim (indexWideCharArray#, indexWord16Array#, readWord8OffAddr#, word2Int#, chr#, touch#, realWorld#, plusAddr#, (+#), (-#))-import Parsley.Internal.Backend.Machine.InputRep (Stream(..), CharList(..), Text16(..), Rep, UnpackedLazyByteString,- offWith, emptyUnpackedLazyByteString, intSame, intLess,- offsetText, offWithSame, offWithShiftRight, dropStream,- textShiftRight, textShiftLeft, byteStringShiftRight,- byteStringShiftLeft, max#)-import Parsley.Internal.Common.Utils (Code)+import Data.Array.Base (UArray(..), listArray)+import Data.ByteString.Internal (ByteString(..))+import Data.Text.Array (aBA{-, empty-})+import Data.Text.Internal (Text(..))+import Data.Text.Unsafe (iter, Iter(..){-, iter_, reverseIter_-})+import GHC.Exts (Int(..), Char(..), TYPE, Int#)+import GHC.ForeignPtr (ForeignPtr(..))+import GHC.Prim (indexWideCharArray#, indexWord16Array#, readWord8OffAddr#, word2Int#, chr#, touch#, realWorld#, plusAddr#, (+#), (-#))+import Parsley.Internal.Backend.Machine.InputRep (Stream(..), CharList(..), Text16(..), Rep, UnpackedLazyByteString,+ offWith, emptyUnpackedLazyByteString, intSame, intLess,+ offsetText, offWithSame, offWithShiftRight, dropStream,+ textShiftRight, textShiftLeft, byteStringShiftRight,+ byteStringShiftLeft, max#)+import Parsley.Internal.Common.Utils (Code) import qualified Data.ByteString.Lazy.Internal as Lazy (ByteString(..)) --import qualified Data.Text as Text (length, index)
src/ghc-8.10+/Parsley/Internal/Backend/Machine/Ops.hs view
@@ -8,7 +8,8 @@ NamedFieldPuns, PatternSynonyms, RecordWildCards,- TypeApplications #-}+ TypeApplications,+ UnboxedTuples #-} {-| Module : Parsley.Internal.Backend.Machine.Ops Description : Higher-level operations used by evaluation.@@ -68,22 +69,24 @@ import GHC.Exts (Int(..), (-#)) import Language.Haskell.TH.Syntax (liftTyped) import Parsley.Internal.Backend.Machine.BindingOps-import Parsley.Internal.Backend.Machine.Defunc (Defunc(OFFSET), genDefunc, _if, pattern FREEVAR)+import Parsley.Internal.Backend.Machine.Defunc (Defunc(INPUT), genDefunc, _if, pattern FREEVAR) import Parsley.Internal.Backend.Machine.Identifiers (MVar, ΦVar, ΣVar) import Parsley.Internal.Backend.Machine.InputOps (PositionOps(..), LogOps(..), InputOps, next, more) import Parsley.Internal.Backend.Machine.InputRep (Rep) import Parsley.Internal.Backend.Machine.Instructions (Access(..)) import Parsley.Internal.Backend.Machine.LetBindings (Regs(..), Metadata(failureInputCharacteristic, successInputCharacteristic), InputCharacteristic(..))+import Parsley.Internal.Backend.Machine.PosOps (updatePos) import Parsley.Internal.Backend.Machine.THUtils (eta) import Parsley.Internal.Backend.Machine.Types (MachineMonad, Machine(..), run) import Parsley.Internal.Backend.Machine.Types.Context import Parsley.Internal.Backend.Machine.Types.Dynamics (DynFunc, DynCont, DynHandler)+import Parsley.Internal.Backend.Machine.Types.Input (Input(..), Input#(..), toInput, fromInput) import Parsley.Internal.Backend.Machine.Types.State (Γ(..), OpStack(..)) import Parsley.Internal.Backend.Machine.Types.Statics import Parsley.Internal.Common (One, Code, Vec(..), Nat(..)) import System.Console.Pretty (color, Color(Green, White, Red, Blue)) -import Parsley.Internal.Backend.Machine.Types.Offset as Offset (Offset(..), moveOne, mkOffset, moveN)+import Parsley.Internal.Backend.Machine.Types.Input.Offset as Offset (Offset(..), moveOne, moveN) {- General Operations -} {-|@@ -94,7 +97,7 @@ -} dup :: Defunc x -> (Defunc x -> Code r) -> Code r dup (FREEVAR x) k = k (FREEVAR x)-dup (OFFSET o) k = k (OFFSET o)+dup (INPUT o) k = k (INPUT o) dup x k = [|| let !dupx = $$(genDefunc x) in $$(k (FREEVAR [||dupx||])) ||] {-|@@ -115,24 +118,25 @@ from the input within @γ@, executing the failure code if it does not exist or does not match. -@since 1.5.0.0+@since 1.8.0.0 -}-sat :: (Defunc Char -> Defunc Bool) -- ^ Predicate to test the character with.- -> ((Code Char -> Offset o -> aux -> Code b) -> Code b) -- ^ The source of the character- -> (Defunc Char -> Offset o -> aux -> Code b) -- ^ Code to execute on success.- -> Code b -- ^ Code to execute on failure.+sat :: (Defunc Char -> Defunc Bool) -- ^ Predicate to test the character with.+ -> ((Code Char -> Input o -> aux -> Code b) -> Code b) -- ^ The source of the character+ -> (Defunc Char -> Input o -> aux -> Code b) -- ^ Code to execute on success.+ -> Code b -- ^ Code to execute on failure. -> Code b sat p src good bad = src $ \c input' aux -> let v = FREEVAR c in _if (p v) (good v input' aux) bad {-| Consumes the next character and adjusts the offset to match. -@since 1.5.0.0+@since 1.8.0.0 -} fetch :: (?ops :: InputOps (Rep o))- => Offset o -> (Code Char -> Offset o -> Code b) -> Code b-fetch input k = next (offset input) $ \c offset' -> k c (moveOne input offset')-+ => Input o -> (Code Char -> Input o -> Code b) -> Code b+fetch input k = next (offset (off input)) $ \c offset' ->+ k c (input {off = moveOne (off input) offset',+ pos = updatePos (pos input) c}) {-| Emits a length check for a number of characters \(n\) in the most efficient way it can. It takes two continuations a @good@ and a @bad@: the @good@ is used@@ -227,7 +231,7 @@ -> (Γ s o (o : xs) n r a -> Code (ST s (Maybe a))) -- ^ Partial parser accepting the modified state. -> Word -- ^ The unique identifier for the offset on failure. -> StaHandlerBuilder s o a-buildHandler γ h u c = fromStaHandler# $ \o# -> h (γ {operands = Op (OFFSET c) (operands γ), input = mkOffset o# u})+buildHandler γ h u c = fromStaHandler# $ \inp -> h (γ {operands = Op (INPUT c) (operands γ), input = toInput u inp}) {-| Converts a partially evaluated parser into a "yes" handler: this means that@@ -240,7 +244,7 @@ -> (Γ s o xs n r a -> Code (ST s (Maybe a))) -> Word -> StaHandler s o a-buildYesHandler γ h u = fromStaHandler# $ \o# -> h (γ {input = mkOffset o# u})+buildYesHandler γ h u = fromStaHandler# $ \inp -> h (γ {input = toInput u inp}) -- Handler binding {-|@@ -276,9 +280,9 @@ -> (Γ s o xs (Succ n) r a -> Code b) -- ^ The parser to receive the composite handler. -> Code b bindSameHandler γ yesNeeded yes noNeeded no k =- bindYesInline# yesNeeded (staHandler# yes (offset (input γ))) $ \qyes ->+ bindYesInline# yesNeeded (staHandler# yes (fromInput (input γ))) $ \qyes -> bindHandlerInline# noNeeded (staHandler# (no (input γ))) $ \qno ->- let handler o = [||if $$(same (offset (input γ)) o) then $$qyes else $$(staHandler# qno o)||]+ let handler inp = [||if $$(same (offset (off (input γ))) (off# inp)) then $$qyes else $$(staHandler# qno inp)||] in bindHandlerInline# @o True handler $ \qhandler -> k (γ {handlers = VCons (augmentHandlerFull (input γ) qhandler qyes qno) (handlers γ)}) @@ -311,33 +315,33 @@ @since 1.2.0.0 -} resume :: StaCont s o a x -> Γ s o (x : xs) n r a -> Code (ST s (Maybe a))-resume k γ = let Op x _ = operands γ in staCont# k (genDefunc x) (offset (input γ))+resume k γ = let Op x _ = operands γ in staCont# k (genDefunc x) (fromInput (input γ)) {-| A form of @callCC@, this calls a subroutine with a given return continuation passed to it. This may be the current continuation, but also may just be a previous return continuation in the case of a tail call. -@since 1.2.0.0+@since 1.8.0.0 -} callWithContinuation :: MarshalOps o => StaSubroutine s o a x -- ^ The subroutine @sub@ that will be called. -> StaCont s o a x -- ^ The return continuation for the subroutine.- -> Code (Rep o) -- ^ The input to feed to @sub@.+ -> Input o -- ^ The input to feed to @sub@. -> Vec (Succ n) (AugmentedStaHandler s o a) -- ^ The stack from which to obtain the handler to pass to @sub@. -> Code (ST s (Maybe a))-callWithContinuation sub ret input (VCons h _) = staSubroutine# sub (dynCont ret) input (dynHandler h (failureInputCharacteristic (meta sub)))+callWithContinuation sub ret input (VCons h _) = staSubroutine# sub (dynCont ret) (dynHandler h (failureInputCharacteristic (meta sub))) (fromInput input) -- Continuation preparation {-| Converts a partial parser into a return continuation in a manner similar to `buildHandler`. -@since 1.5.0.0+@since 1.8.0.0 -} suspend :: (Γ s o (x : xs) n r a -> Code (ST s (Maybe a))) -- ^ The partial parser to turn into a return continuation. -> Γ s o xs n r a -- ^ The state to execute the continuation with.- -> (Code (Rep o) -> Offset o) -- ^ Function used to generate the offset+ -> (Input# o -> Input o) -- ^ Function used to generate the offset -> StaCont s o a x suspend m γ off = mkStaCont $ \x o# -> m (γ {operands = Op (FREEVAR x) (operands γ), input = off o#}) @@ -353,15 +357,18 @@ -> (Γ s o (x : xs) (Succ n) r a -> Code (ST s (Maybe a))) -- ^ The return continuation to generate -> Γ s o xs (Succ n) r a -- -> Code (ST s (Maybe a))-callCC u sub k γ = callWithContinuation sub (suspend k γ (chooseOffset (successInputCharacteristic (meta sub)) o)) (offset o) (handlers γ)+callCC u sub k γ = callWithContinuation sub (suspend k γ (chooseOffset (successInputCharacteristic (meta sub)))) inp (handlers γ) where- o :: Offset o- o = input γ+ inp :: Input o+ inp = input γ - chooseOffset :: InputCharacteristic -> Offset o -> Code (Rep o) -> Offset o- chooseOffset (AlwaysConsumes n) o qo# = moveN n o qo#- chooseOffset NeverConsumes o qo# = o {offset = qo#}- chooseOffset MayConsume _ qo# = mkOffset qo# u+ -- TODO: move to Offset module (along with Input#?)+ chooseOffset :: InputCharacteristic -> Input# o -> Input o+ chooseOffset (AlwaysConsumes n) inp# = inp { off = moveN n (off inp) (off# inp#), pos = pos# inp# }+ -- Technically, in this case, we know the whole input is unchanged. This essentially ignores the continuation arguments+ -- hopefully GHC could optimise this better?+ chooseOffset NeverConsumes _inp# = inp -- { off = (off inp) {offset = off# inp# }, pos = pos# inp# }+ chooseOffset MayConsume inp# = toInput u inp# {- Join Point Operations -} {-|@@ -378,7 +385,7 @@ setupJoinPoint φ (Machine k) mx = freshUnique $ \u -> liftM2 (\mk ctx γ -> setupJoinPoint# @o- (\qx qo# -> mk (γ {operands = Op (FREEVAR qx) (operands γ), input = mkOffset qo# u}))+ (\qx inp -> mk (γ {operands = Op (FREEVAR qx) (operands γ), input = toInput u inp})) (\qjoin -> run mx γ (insertΦ φ (mkStaContDyn qjoin) ctx))) (local voidCoins k) ask @@ -389,7 +396,7 @@ using failure, and this failure does not discriminate whether or not the loop consumed input in its final iteration. -@since 1.4.0.0+@since 1.8.0.0 -} bindIterAlways :: forall s o a. RecBuilder o => Ctx s o a -- ^ The context to keep the binding@@ -397,21 +404,21 @@ -> Machine s o '[] One Void a -- ^ The body of the loop. -> Bool -- ^ Does loop exit require a binding? -> StaHandlerBuilder s o a -- ^ What to do after the loop exits (by failing)- -> Offset o -- ^ The initial offset to provide to the loop+ -> Input o -- ^ The initial offset to provide to the loop -> Word -- ^ The unique name for captured offset /and/ iteration offset -> Code (ST s (Maybe a))-bindIterAlways ctx μ l needed h o u =- bindIterHandlerInline# @o needed (\qc# -> staHandler# (h (mkOffset qc# u))) $ \qhandler ->- bindIter# @o (offset o) $ \qloop qo# ->- let off = mkOffset qo# u- in run l (Γ Empty noreturn off (VCons (augmentHandler (Just off) (qhandler qo#)) VNil))- (voidCoins (insertSub μ (mkStaSubroutine $ \_ o# _ -> [|| $$qloop $$(o#) ||]) ctx))+bindIterAlways ctx μ l needed h inp u =+ bindIterHandlerInline# @o needed (staHandler# . h . toInput u) $ \qhandler ->+ bindIter# @o (fromInput inp) $ \qloop inp# ->+ let inp = toInput u inp#+ in run l (Γ Empty noreturn inp (VCons (augmentHandler (Just inp) (qhandler inp#)) VNil))+ (voidCoins (insertSub μ (mkStaSubroutine $ \_ _ inp -> [|| $$qloop $$(pos# inp) $$(off# inp) ||]) ctx)) {-| Similar to `bindIterAlways`, but builds a handler that performs in the same way as `bindSameHandler`. -@since 1.4.0.0+@since 1.8.0.0 -} bindIterSame :: forall s o a. (RecBuilder o, HandlerOps o, PositionOps (Rep o)) => Ctx s o a -- ^ The context to store the binding in.@@ -421,18 +428,18 @@ -> StaHandler s o a -- ^ The handler when input is the same. -> Bool -- ^ Is a binding required for the differing handler? -> StaHandlerBuilder s o a -- ^ The handler when input differs.- -> Offset o -- ^ The initial offset of the loop.+ -> Input o -- ^ The initial offset of the loop. -> Word -- ^ The unique name of the captured offsets /and/ the iteration offset. -> Code (ST s (Maybe a))-bindIterSame ctx μ l neededYes yes neededNo no o u =+bindIterSame ctx μ l neededYes yes neededNo no inp u = bindHandlerInline# @o neededYes (staHandler# yes) $ \qyes ->- bindIterHandlerInline# neededNo (\qc# -> staHandler# (no (mkOffset qc# u))) $ \qno ->- let handler qc# o = [||if $$(same qc# o) then $$(staHandler# qyes qc#) else $$(staHandler# (qno qc#) o)||]+ bindIterHandlerInline# neededNo (staHandler# . no . toInput u) $ \qno ->+ let handler inpc inpo = [||if $$(same (off# inpc) (off# inpo)) then $$(staHandler# qyes inpc) else $$(staHandler# (qno inpc) inpo)||] in bindIterHandlerInline# @o True handler $ \qhandler ->- bindIter# @o (offset o) $ \qloop qo# ->- let off = mkOffset qo# u- in run l (Γ Empty noreturn off (VCons (augmentHandlerFull off (qhandler qo#) (staHandler# qyes qo#) (qno qo#)) VNil))- (voidCoins (insertSub μ (mkStaSubroutine $ \_ o# _ -> [|| $$qloop $$(o#) ||]) ctx))+ bindIter# @o (fromInput inp) $ \qloop inp# ->+ let off = toInput u inp#+ in run l (Γ Empty noreturn off (VCons (augmentHandlerFull off (qhandler inp#) (staHandler# qyes inp#) (qno inp#)) VNil))+ (voidCoins (insertSub μ (mkStaSubroutine $ \_ _ inp -> [|| $$qloop $$(pos# inp) $$(off# inp) ||]) ctx)) {- Recursion Operations -} {-|@@ -452,9 +459,9 @@ -> DynFunc rs s o a r buildRec μ rs ctx k meta = takeFreeRegisters rs ctx $ \ctx ->- bindRec# @o $ \qself qret qo# qh ->- run k (Γ Empty (mkStaContDyn qret) (mkOffset qo# 0) (VCons (augmentHandlerDyn Nothing qh) VNil))- (insertSub μ (mkStaSubroutineMeta meta $ \k o# h -> [|| $$qself $$k $$(o#) $$h ||]) (nextUnique ctx))+ bindRec# @o $ \qself qret qh inp ->+ run k (Γ Empty (mkStaContDyn qret) (toInput 0 inp) (VCons (augmentHandlerDyn Nothing qh) VNil))+ (insertSub μ (mkStaSubroutineMeta meta $ \k h inp -> [|| $$qself $$k $$h $$(pos# inp) $$(off# inp) ||]) (nextUnique ctx)) {- Binding Operations -} bindHandlerInline# :: forall o s a b. HandlerOps o@@ -471,10 +478,10 @@ bindIterHandlerInline# :: forall o s a b. RecBuilder o => Bool- -> (Code (Rep o) -> StaHandler# s o a)- -> ((Code (Rep o) -> StaHandler s o a) -> Code b)+ -> (Input# o -> StaHandler# s o a)+ -> ((Input# o -> StaHandler s o a) -> Code b) -> Code b-bindIterHandlerInline# True h k = bindIterHandler# @o h $ \qh -> k (\qo -> fromDynHandler [||$$qh $$qo||])+bindIterHandlerInline# True h k = bindIterHandler# @o h $ \qh -> k (\inp -> fromDynHandler [||$$qh $$(pos# inp) $$(off# inp)||]) bindIterHandlerInline# False h k = k (fromStaHandler# . h) {- Marshalling Operations -}@@ -508,8 +515,8 @@ @since 1.2.0.0 -} logHandler :: (?ops :: InputOps (Rep o), LogHandler o) => String -> Ctx s o a -> Γ s o xs (Succ n) ks a -> Word -> StaHandlerBuilder s o a-logHandler name ctx γ u _ = let VCons h _ = handlers γ in fromStaHandler# $ \o# -> let o = mkOffset o# u in [||- trace $$(preludeString name '<' (γ {input = o}) ctx (color Red " Fail")) $$(staHandlerEval h o)+logHandler name ctx γ u _ = let VCons h _ = handlers γ in fromStaHandler# $ \inp# -> let inp = toInput u inp# in [||+ trace $$(preludeString name '<' (γ {input = inp}) ctx (color Red " Fail")) $$(staHandlerEval h inp) ||] {-|@@ -527,7 +534,7 @@ -> Code String preludeString name dir γ ctx ends = [|| concat [$$prelude, $$eof, ends, '\n' : $$caretSpace, color Blue "^"] ||] where- offset = Offset.offset (input γ)+ offset = Offset.offset (off (input γ)) indent = replicate (debugLevel ctx * 2) ' ' start = shiftLeft offset [||5#||] end = shiftRight offset [||5#||]@@ -569,4 +576,4 @@ @since 1.2.0.0 -}-type StaHandlerBuilder s o a = Offset o -> StaHandler s o a+type StaHandlerBuilder s o a = Input o -> StaHandler s o a
+ src/ghc-8.10+/Parsley/Internal/Backend/Machine/PosOps.hs view
@@ -0,0 +1,89 @@+{-# LANGUAGE CPP, MagicHash, UnboxedTuples, NumericUnderscores #-}+{-|+Module : Parsley.Internal.Backend.Machine.PosOps+Description : Collection of platform dependent position operations+License : BSD-3-Clause+Maintainer : Jamie Willis+Stability : experimental++This module contains the implementations of updates on positions: these depend on the number of+bits in a word, or if the @full-width-positions@ flag was set on the @parsley-core@ library.++@since 1.8.0.0+-}+module Parsley.Internal.Backend.Machine.PosOps (module Parsley.Internal.Backend.Machine.PosOps) where++#include "MachDeps.h"+#if WORD_SIZE_IN_BITS < 64+#define FULL_WIDTH_POSITIONS+#endif++import Parsley.Internal.Backend.Machine.Types.Base (Pos)+import Parsley.Internal.Common (Code)+import GHC.Exts (Int(..))+import GHC.Prim (plusWord#, and#, or#, word2Int#,+#ifdef FULL_WIDTH_POSITIONS+ minusWord#+#else+ uncheckedShiftRL#+#endif+ )++{-|+Given a position and a character, returns the representation of the updated position.++@since 1.8.0.0+-}+updatePos :: Code Pos -> Code Char -> Code Pos+updatePos pos c = [||updatePos# $$pos $$c||]++{-|+The initial position used by the parser. This is some representation of (1, 1).++@since 1.8.0.0+-}+initPos :: Code Pos++{-# INLINEABLE updatePos# #-}+{-|+Updates a given position assuming the given character was read. Tab characters are aligned to the+nearest 4th space boundary.++@since 1.8.0.0+-}+updatePos# :: Pos -> Char -> Pos++{-|+Given the opaque representation of a position, extracts the line number out of it.++@since 1.8.0.0+-}+extractLine :: Code Pos -> Code Int++{-|+Given the opaque representation of a position, extracts the column number out of it.++@since 1.8.0.0+-}+extractCol :: Code Pos -> Code Int++#ifndef FULL_WIDTH_POSITIONS+initPos = [|| 0x00000001_00000001## ||]++updatePos# pos '\n' = (pos `and#` 0xffffffff_00000000##) `plusWord#` 0x00000001_00000001##+updatePos# pos '\t' = ((pos `plusWord#` 0x00000000_00000003##) `and#` 0xffffffff_fffffffc##) `or#` 0x00000000_00000001##+updatePos# pos _ = pos `plusWord#` 0x00000000_00000001##++extractLine qpos = [||I# (word2Int# ($$qpos `uncheckedShiftRL#` 32#))||]+extractCol qpos = [||I# (word2Int# ($$qpos `and#` 0x00000000_ffffffff##))||]++#else+initPos = [|| (# 1##, 1## #) ||]++updatePos# (# line, _ #) '\n' = (# line `plusWord#` 1##, 1## #)+updatePos# (# line, col #) '\t' = (# line, ((col `plusWord#` 3##) `and#` (0## `minusWord#` 4##)) `or#` 1## #) -- nearest tab boundary `c + (4 - (c - 1) % 4)`+updatePos# (# line, col #) _ = (# line, col `plusWord#` 1## #)++extractLine qpos = [|| case $$qpos of (# line, _ #) -> I# (word2Int# line) ||]+extractCol qpos = [|| case $$qpos of (# _, col #) -> I# (word2Int# col) ||]+#endif
src/ghc-8.10+/Parsley/Internal/Backend/Machine/Types/Base.hs view
@@ -1,5 +1,7 @@-{-# LANGUAGE MagicHash,- TypeFamilies #-}+{-# LANGUAGE CPP,+ MagicHash,+ TypeFamilies,+ UnboxedTuples #-} {-| Module : Parsley.Internal.Backend.Machine.Types.Base Description : Base types representing core machine components@@ -19,17 +21,35 @@ import Control.Monad.ST (ST) import Data.STRef (STRef) import Data.Kind (Type)+import GHC.Prim (Word#) import Parsley.Internal.Backend.Machine.InputRep (Rep) +#include "MachDeps.h"+#if WORD_SIZE_IN_BITS < 64+#define FULL_WIDTH_POSITIONS+#endif+ {-|+The type of positions within a parser. This may or may not be packed into a single `Word#`++@since 1.8.0.0+-}+#ifndef FULL_WIDTH_POSITIONS+type Pos = Word#+#else+type Pos = (# Word#, Word# #)+#endif++{-| @Handler#@ represents the functions that handle failure within a-parser. For most of their life, handlers are represented as +parser. For most of their life, handlers are represented as `Parsley.Internal.Backend.Machine.Types.Statics.StaHandler`, but @Handler#@ is used at the boundaries, such as for recursion. @since 1.4.0.0 -}-type Handler# s o a = Rep o -- ^ The current input on failure +type Handler# s o a = Pos -- ^ The current position+ -> Rep o -- ^ The current input on failure -> ST s (Maybe a) {-|@@ -39,6 +59,7 @@ @since 1.4.0.0 -} type Cont# s o a x = x -- ^ The value to be returned to the caller+ -> Pos -- ^ The current position -> Rep o -- ^ The new input after the call is executed -> ST s (Maybe a) @@ -49,8 +70,9 @@ @since 1.4.0.0 -} type Subroutine# s o a x = Cont# s o a x -- ^ What to do when this parser returns- -> Rep o -- ^ The input on entry to the call -> Handler# s o a -- ^ How to handle failure within the call+ -> Pos -- ^ The current position+ -> Rep o -- ^ The input on entry to the call -> ST s (Maybe a) {-|
src/ghc-8.10+/Parsley/Internal/Backend/Machine/Types/Context.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE DeriveAnyClass, MagicHash,- DerivingStrategies #-}+ DerivingStrategies,+ UnboxedTuples #-} {-| Module : Parsley.Internal.Backend.Machine.Types.Context Description : Fully static context required to generate a parser@@ -66,7 +67,7 @@ import Parsley.Internal.Backend.Machine.LetBindings (Regs(..)) import Parsley.Internal.Backend.Machine.Types.Coins (Coins, willConsume, canReclaim) import Parsley.Internal.Backend.Machine.Types.Dynamics (DynFunc, DynSubroutine)-import Parsley.Internal.Backend.Machine.Types.Offset (Offset)+import Parsley.Internal.Backend.Machine.Types.Input (Input) import Parsley.Internal.Backend.Machine.Types.Statics (QSubroutine(..), StaFunc, StaSubroutine, StaCont) import Parsley.Internal.Common (Queue, enqueue, dequeue, Code, RewindQueue) @@ -89,7 +90,7 @@ , coins :: Int -- ^ Number of tokens free to consume without length check. , offsetUniq :: Word -- ^ Next unique offset identifier. , piggies :: Queue Coins -- ^ Queue of future length check credit.- , knownChars :: RewindQueue (Code Char, Offset o) -- ^ Characters that can be reclaimed on backtrack.+ , knownChars :: RewindQueue (Code Char, Input o) -- ^ Characters that can be reclaimed on backtrack. } {-|@@ -409,7 +410,7 @@ {-| Asks if the current coin total can afford a charge of \(n\) characters. -This is used by `DrainCoins`, which will have to emit a full length check+This is used by `Parsley.Internal.Backend.Instructions.DrainCoins`, which will have to emit a full length check of size \(n\) if this quota cannot be reached. @since 1.5.0.0@@ -423,7 +424,7 @@ @since 1.5.0.0 -}-addChar :: Code Char -> Offset o -> Ctx s o a -> Ctx s o a+addChar :: Code Char -> Input o -> Ctx s o a -> Ctx s o a addChar c o ctx = ctx { knownChars = enqueue (c, o) (knownChars ctx) } {-|@@ -433,9 +434,9 @@ @since 1.5.0.0 -}-readChar :: Ctx s o a -- ^ The original context.- -> ((Code Char -> Offset o -> Code b) -> Code b) -- ^ The fallback source of input.- -> (Code Char -> Offset o -> Ctx s o a -> Code b) -- ^ The continuation that needs the read characters and updated context.+readChar :: Ctx s o a -- ^ The original context.+ -> ((Code Char -> Input o -> Code b) -> Code b) -- ^ The fallback source of input.+ -> (Code Char -> Input o -> Ctx s o a -> Code b) -- ^ The continuation that needs the read characters and updated context. -> Code b readChar ctx fallback k | reclaimable = unsafeReadChar ctx k
src/ghc-8.10+/Parsley/Internal/Backend/Machine/Types/Dynamics.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE MagicHash #-}+{-# LANGUAGE MagicHash, UnboxedTuples #-} {-| Module : Parsley.Internal.Backend.Machine.Types.Dynamics Description : Representation of components that cross function boundaries
+ src/ghc-8.10+/Parsley/Internal/Backend/Machine/Types/Input.hs view
@@ -0,0 +1,57 @@+{-# LANGUAGE UnboxedTuples, MagicHash, RecordWildCards #-}+{-|+Module : Parsley.Internal.Backend.Machine.Types.Input+Description : Packaging of offsets and positions.+License : BSD-3-Clause+Maintainer : Jamie Willis+Stability : experimental++Exposes abstractions for working with combined offset and position information. `Input` is used+for static augmented information, and `Input#` is a raw combination of the two components.++@since 1.8.0.0+-}+module Parsley.Internal.Backend.Machine.Types.Input (module Parsley.Internal.Backend.Machine.Types.Input) where++import Parsley.Internal.Backend.Machine.InputRep (Rep)+import Parsley.Internal.Backend.Machine.Types.Base (Pos)+import Parsley.Internal.Backend.Machine.Types.Input.Offset (Offset(offset), mkOffset)+--import Parsley.Internal.Backend.Machine.Types.Input.Pos ()+import Parsley.Internal.Common.Utils (Code)++{-|+Packages known static information about offsets (via `Offset`) with static information about positions+(currently unavailable).++@since 1.8.0.0+-}+data Input o = Input {+ off :: Offset o,+ pos :: Code Pos+ }++{-|+Packages a dynamic offset with a dynamic position.++@since 1.8.0.0+-}+data Input# o = Input# {+ off# :: Code (Rep o),+ pos# :: Code Pos+ }++{-|+Strips away static information, returning the raw dynamic components.++@since 1.8.0.0+-}+fromInput :: Input o -> Input# o+fromInput Input{..} = Input# (offset off) pos++{-|+Given a unique identifier, forms a plainly annotated static combination of position and offset.++@since 1.8.0.0+-}+toInput :: Word -> Input# o -> Input o+toInput u Input#{..} = Input (mkOffset off# u) pos#
+ src/ghc-8.10+/Parsley/Internal/Backend/Machine/Types/Input/Offset.hs view
@@ -0,0 +1,100 @@+{-# LANGUAGE DerivingStrategies, UnboxedTuples #-}+{-|+Module : Parsley.Internal.Backend.Machine.Types.Input.Offset+Description : Statically refined offsets.+License : BSD-3-Clause+Maintainer : Jamie Willis+Stability : experimental++This module contains the statically refined `Offset` type,+which can be used to reason about input in different parts of+a parser as it is evaluated.++@since 1.8.0.0+-}+module Parsley.Internal.Backend.Machine.Types.Input.Offset (+ Offset, mkOffset, offset, moveOne, moveN, same,+ ) where++import Parsley.Internal.Backend.Machine.InputRep (Rep)+import Parsley.Internal.Common.Utils (Code)++{-|+Augments a regular @'Code' ('Rep' o)@ with information about its origins and+how much input is known to have been consumed since it came into existence.+This can be used to statically evaluate handlers (see+`Parsley.Internal.Backend.Machine.Types.Statics.staHandlerEval`).++@since 1.5.0.0+-}+data Offset o = Offset {+ -- | The underlying code that represents the current offset into the input.+ offset :: Code (Rep o),+ -- | The unique identifier that determines where this offset originated from.+ unique :: Word,+ -- | The amount of input that has been consumed on this offset since it was born.+ moved :: Amount+ }++data Amount = Amount Word {- ^ The multiplicity. -} Word {- ^ The additive offset. -}+ deriving stock Eq++{-|+Given two `Offset`s, this determines whether or not they represent the same+offset into the input stream at runtime. This comparison only makes sense when+both `Offset`s share the same origin, hence the @Maybe@.++@since 1.4.0.0+-}+same :: Offset o -> Offset o -> Maybe Bool+same o1 o2+ | unique o1 == unique o2 = Just (moved o1 == moved o2)+ | otherwise = Nothing++{-|+Updates an `Offset` with its new underlying representation of a real+runtime offset and records that another character has been consumed.++@since 1.4.0.0+-}+moveOne :: Offset o -> Code (Rep o) -> Offset o+moveOne = moveN (Just 1)++{-|+Updates an `Offset` with its new underlying representation of a real+runtime offset and records that several more characters have been consumed.+Here, `Nothing` represents an unknown but non-zero amount of characters.++@since 1.5.0.0+-}+moveN :: Maybe Word -> Offset o -> Code (Rep o) -> Offset o+moveN n off o = off { offset = o, moved = moved off `add` toAmount n }+ where+ toAmount :: Maybe Word -> Amount+ toAmount Nothing = Amount 1 0+ toAmount (Just n) = Amount 0 n++{-|+Makes a fresh `Offset` that has not had any input consumed off of it+yet.++@since 1.4.0.0+-}+mkOffset :: Code (Rep o) -> Word -> Offset o+mkOffset offset unique = Offset offset unique (Amount 0 0)++add :: Amount -> Amount -> Amount+add a1@(Amount n i) a2@(Amount m j)+ -- If the multiplicites don't match then this is _even_ more unknowable+ | n /= m, n /= 0, m /= 0 = Amount (n + m) 0+ -- This is a funny case, it shouldn't happen and it's not really clear what happens if it does+ | n /= 0, m /= 0 = error ("adding " ++ show a1 ++ " and " ++ show a2 ++ " makes no sense?")+ -- If one of the multiplicites is 0 then the offset can be added+ | otherwise = Amount (max n m) (i + j)++-- Instances+instance Show (Offset o) where+ show o = show (unique o) ++ "+" ++ show (moved o)++instance Show Amount where+ show (Amount n m) = show n ++ "*n+" ++ show m
− src/ghc-8.10+/Parsley/Internal/Backend/Machine/Types/Offset.hs
@@ -1,100 +0,0 @@-{-# LANGUAGE DerivingStrategies #-}-{-|-Module : Parsley.Internal.Backend.Machine.Types.Offset-Description : Statically refined offsets.-License : BSD-3-Clause-Maintainer : Jamie Willis-Stability : experimental--This module contains the statically refined `Offset` type,-which can be used to reason about input in different parts of-a parser as it is evaluated.--@since 1.4.0.0--}-module Parsley.Internal.Backend.Machine.Types.Offset (- Offset, mkOffset, offset, moveOne, moveN, same- ) where--import Parsley.Internal.Backend.Machine.InputRep (Rep)-import Parsley.Internal.Common.Utils (Code)--{-|-Augments a regular @'Code' ('Rep' o)@ with information about its origins and-how much input is known to have been consumed since it came into existence.-This can be used to statically evaluate handlers (see-`Parsley.Internal.Backend.Machine.Types.Statics.staHandlerEval`).--@since 1.5.0.0--}-data Offset o = Offset {- -- | The underlying code that represents the current offset into the input.- offset :: Code (Rep o),- -- | The unique identifier that determines where this offset originated from.- unique :: Word,- -- | The amount of input that has been consumed on this offset since it was born.- moved :: Amount- }--data Amount = Amount Word {- ^ The multiplicity. -} Word {- ^ The additive offset. -}- deriving stock Eq--{-|-Given two `Offset`s, this determines whether or not they represent the same-offset into the input stream at runtime. This comparison only makes sense when-both `Offset`s share the same origin, hence the @Maybe@.--@since 1.4.0.0--}-same :: Offset o -> Offset o -> Maybe Bool-same o1 o2- | unique o1 == unique o2 = Just (moved o1 == moved o2)- | otherwise = Nothing--{-|-Updates an `Offset` with its new underlying representation of a real-runtime offset and records that another character has been consumed.--@since 1.4.0.0--}-moveOne :: Offset o -> Code (Rep o) -> Offset o-moveOne = moveN (Just 1)--{-|-Updates an `Offset` with its new underlying representation of a real-runtime offset and records that several more characters have been consumed.-Here, `Nothing` represents an unknown but non-zero amount of characters.--@since 1.5.0.0--}-moveN :: Maybe Word -> Offset o -> Code (Rep o) -> Offset o-moveN n off o = off { offset = o, moved = moved off `add` toAmount n }- where- toAmount :: Maybe Word -> Amount- toAmount Nothing = Amount 1 0- toAmount (Just n) = Amount 0 n--{-|-Makes a fresh `Offset` that has not had any input consumed off of it-yet.--@since 1.4.0.0--}-mkOffset :: Code (Rep o) -> Word -> Offset o-mkOffset offset unique = Offset offset unique (Amount 0 0)--add :: Amount -> Amount -> Amount-add a1@(Amount n i) a2@(Amount m j)- -- If the multiplicites don't match then this is _even_ more unknowable- | n /= m, n /= 0, m /= 0 = Amount (n + m) 0- -- This is a funny case, it shouldn't happen and it's not really clear what happens if it does- | n /= 0, m /= 0 = error ("adding " ++ show a1 ++ " and " ++ show a2 ++ " makes no sense?")- -- If one of the multiplicites is 0 then the offset can be added- | otherwise = Amount (max n m) (i + j)---- Instances-instance Show (Offset o) where- show o = show (unique o) ++ "+" ++ show (moved o)--instance Show Amount where- show (Amount n m) = show n ++ "*n+" ++ show m
src/ghc-8.10+/Parsley/Internal/Backend/Machine/Types/State.hs view
@@ -17,7 +17,7 @@ ) where import Parsley.Internal.Backend.Machine.Defunc (Defunc)-import Parsley.Internal.Backend.Machine.Types.Offset (Offset)+import Parsley.Internal.Backend.Machine.Types.Input (Input) import Parsley.Internal.Backend.Machine.Types.Statics (StaCont, AugmentedStaHandler) import Parsley.Internal.Common.Vec (Vec) @@ -43,6 +43,6 @@ -} data Γ s o xs n r a = Γ { operands :: OpStack xs -- ^ The current values available for applicative application. , retCont :: StaCont s o a r -- ^ The current return continuation when this parser is finished.- , input :: Offset o -- ^ The current offset into the input of the parser.+ , input :: Input o -- ^ The current offset into the input of the parser. , handlers :: Vec n (AugmentedStaHandler s o a) -- ^ The failure handlers that are used to process failure during a parser. }
src/ghc-8.10+/Parsley/Internal/Backend/Machine/Types/Statics.hs view
@@ -1,7 +1,9 @@ {-# LANGUAGE AllowAmbiguousTypes, MagicHash,+ RecordWildCards, TypeApplications,- TypeFamilies #-}+ TypeFamilies,+ UnboxedTuples #-} {-| Module : Parsley.Internal.Backend.Machine.Types.Statics Description : Representation of components that exist within a statically known component@@ -44,15 +46,15 @@ staSubroutine#, meta, ) where -import Control.Monad.ST (ST)-import Data.STRef (STRef)-import Data.Kind (Type)-import Data.Maybe (fromMaybe)-import Parsley.Internal.Backend.Machine.InputRep (Rep)-import Parsley.Internal.Backend.Machine.LetBindings (Regs(..), Metadata, newMeta, InputCharacteristic(..))-import Parsley.Internal.Backend.Machine.Types.Dynamics (DynCont, DynHandler, DynFunc)-import Parsley.Internal.Backend.Machine.Types.Offset (Offset(offset), same)-import Parsley.Internal.Common.Utils (Code)+import Control.Monad.ST (ST)+import Data.STRef (STRef)+import Data.Kind (Type)+import Data.Maybe (fromMaybe)+import Parsley.Internal.Backend.Machine.LetBindings (Regs(..), Metadata, newMeta, InputCharacteristic(..))+import Parsley.Internal.Backend.Machine.Types.Dynamics (DynCont, DynHandler, DynFunc)+import Parsley.Internal.Backend.Machine.Types.Input (Input(..), Input#(..), fromInput)+import Parsley.Internal.Backend.Machine.Types.Input.Offset (Offset, same)+import Parsley.Internal.Common.Utils (Code) -- Handlers {-|@@ -60,12 +62,12 @@ but where the static function structure has been exposed. This allows for β-reduction on handlers, a simple form of inlining optimisation. -@since 1.4.0.0+@since 1.8.0.0 -}-type StaHandler# s o a = Code (Rep o) -> Code (ST s (Maybe a))+type StaHandler# s o a = Input# o -> Code (ST s (Maybe a)) mkStaHandler# :: forall o s a. DynHandler s o a -> StaHandler# s o a-mkStaHandler# dh qo# = [||$$dh $$(qo#)||]+mkStaHandler# dh inp = [||$$dh $$(pos# inp) $$(off# inp)||] {-| Encapsulates a static handler with its possible dynamic origin for costless conversion.@@ -119,9 +121,9 @@ the handler has captured. This is a purely static handler, which is not derived from a dynamic one. -@since 1.7.0.0+@since 1.8.0.0 -}-augmentHandlerSta :: Maybe (Offset o) -> StaHandler# s o a -> AugmentedStaHandler s o a+augmentHandlerSta :: Maybe (Input o) -> StaHandler# s o a -> AugmentedStaHandler s o a augmentHandlerSta o = augmentHandler o . fromStaHandler# {-|@@ -133,7 +135,7 @@ @since 1.7.0.0 -}-augmentHandlerDyn :: forall s o a. Maybe (Offset o) -> DynHandler s o a -> AugmentedStaHandler s o a+augmentHandlerDyn :: forall s o a. Maybe (Input o) -> DynHandler s o a -> AugmentedStaHandler s o a augmentHandlerDyn c = augmentHandler c . fromDynHandler {-|@@ -141,8 +143,8 @@ @since 1.7.0.0 -}-augmentHandler :: Maybe (Offset o) -> StaHandler s o a -> AugmentedStaHandler s o a-augmentHandler c = AugmentedStaHandler c . mkUnknown+augmentHandler :: Maybe (Input o) -> StaHandler s o a -> AugmentedStaHandler s o a+augmentHandler c = AugmentedStaHandler (fmap off c) . mkUnknown {-| When the behaviours of a handler given input that matches or does not match@@ -153,18 +155,18 @@ @since 1.7.0.0 -}-augmentHandlerFull :: Offset o -- ^ The offset captured by the creation of the handler.+augmentHandlerFull :: Input o -- ^ The offset captured by the creation of the handler. -> StaHandler s o a -- ^ The full handler, which can be used when offsets are incomparable and must perform the check. -> Code (ST s (Maybe a)) -- ^ The code that is executed when the captured offset matches the input. -> StaHandler s o a -- ^ The handler to be executed when offsets are known not to match. -> AugmentedStaHandler s o a -- ^ A handler that carries this information around for later refinement.-augmentHandlerFull c handler yes no = AugmentedStaHandler (Just c)+augmentHandlerFull c handler yes no = AugmentedStaHandler (Just (off c)) (mkFull handler yes no) {-|-Unlike `staHandler#`, which returns a handler that accepts @'Code' ('Rep' o)@, this+Unlike `staHandler#`, which returns a handler that accepts @'Input' o@, this function accepts a full `Parsley.Internal.Backend.Machine.Types.Offset.Offset`, which can be used to refine the outcome of the execution of the handler as follows: @@ -178,11 +180,11 @@ @since 1.7.0.0 -}-staHandlerEval :: AugmentedStaHandler s o a -> Offset o -> Code (ST s (Maybe a))-staHandlerEval (AugmentedStaHandler (Just c) sh) o- | Just True <- same c o = maybe (staHandler# (unknown sh)) const (yesSame sh) (offset o)- | Just False <- same c o = staHandler# (fromMaybe (unknown sh) (notSame sh)) (offset o)-staHandlerEval (AugmentedStaHandler _ sh) o = staHandler# (unknown sh) (offset o)+staHandlerEval :: AugmentedStaHandler s o a -> Input o -> Code (ST s (Maybe a))+staHandlerEval (AugmentedStaHandler (Just c) sh) inp+ | Just True <- same c (off inp) = maybe (staHandler# (unknown sh)) const (yesSame sh) (fromInput inp)+ | Just False <- same c (off inp) = staHandler# (fromMaybe (unknown sh) (notSame sh)) (fromInput inp)+staHandlerEval (AugmentedStaHandler _ sh) inp = staHandler# (unknown sh) (fromInput inp) {-| Selects the correct case out of a `AugmentedStaHandler` depending on what the `InputCharacteristic` that@@ -242,9 +244,9 @@ but where the static function structure has been exposed. This allows for β-reduction on continuations, a simple form of inlining optimisation. -@since 1.4.0.0+@since 1.8.0.0 -}-type StaCont# s o a x = Code x -> Code (Rep o) -> Code (ST s (Maybe a))+type StaCont# s o a x = Code x -> Input# o -> Code (ST s (Maybe a)) {-| Compared with `StaCont#`, this type also bundles the static continuation@@ -263,7 +265,7 @@ @since 1.4.0.0 -} mkStaContDyn :: DynCont s o a x -> StaCont s o a x-mkStaContDyn dk = StaCont (\x o# -> [|| $$dk $$x $$(o#) ||]) (Just dk)+mkStaContDyn dk = StaCont (\x inp -> [|| $$dk $$x $$(pos# inp) $$(off# inp) ||]) (Just dk) {-| Given a static continuation, extracts the underlying continuation which@@ -290,9 +292,9 @@ but where the static function structure has been exposed. This allows for β-reduction on subroutines, a simple form of inlining optimisation: useful for iteration. -@since 1.5.0.0+@since 1.8.0.0 -}-type StaSubroutine# s o a x = DynCont s o a x -> Code (Rep o) -> DynHandler s o a -> Code (ST s (Maybe a))+type StaSubroutine# s o a x = DynCont s o a x -> DynHandler s o a -> Input# o -> Code (ST s (Maybe a)) {-| Packages a `StaSubroutine#` along with statically determined metadata that describes it derived from@@ -352,5 +354,5 @@ qSubroutine func frees meta = QSubroutine (staFunc frees func) frees where staFunc :: forall rs. Regs rs -> DynFunc rs s o a x -> StaFunc rs s o a x- staFunc NoRegs func = StaSubroutine (\dk o# dh -> [|| $$func $$dk $$(o#) $$dh ||]) meta+ staFunc NoRegs func = StaSubroutine (\dk dh inp -> [|| $$func $$dk $$dh $$(pos# inp) $$(off# inp) ||]) meta staFunc (FreeReg _ witness) func = \r -> staFunc witness [|| $$func $$r ||]
src/ghc-8.6+/Parsley/Internal/Backend/Machine/Eval.hs view
@@ -14,7 +14,7 @@ import Parsley.Internal.Backend.Machine.Defunc (Defunc(LAM, SAME), pattern FREEVAR, genDefunc, ap, ap2, _if) import Parsley.Internal.Backend.Machine.Identifiers (MVar(..), ΦVar, ΣVar) import Parsley.Internal.Backend.Machine.InputOps (InputDependant(..), PositionOps, BoxOps, LogOps, InputOps(InputOps))-import Parsley.Internal.Backend.Machine.Instructions (Instr(..), MetaInstr(..), Access(..))+import Parsley.Internal.Backend.Machine.Instructions (Instr(..), MetaInstr(..), Access(..), PosSelector(..)) import Parsley.Internal.Backend.Machine.LetBindings (LetBinding(..)) import Parsley.Internal.Backend.Machine.LetRecBuilder import Parsley.Internal.Backend.Machine.Ops@@ -36,7 +36,7 @@ in letRec fs nameLet (\μ exp rs names _meta -> buildRec μ rs (emptyCtx names) (readyMachine exp))- (run (readyMachine (body binding)) (Γ Empty (halt @o) [||offset||] (VCons (fatal @o) VNil)) . emptyCtx))+ (run (readyMachine (body binding)) (Γ Empty (halt @o) [||offset||] ([||1||], [||1||]) (VCons (fatal @o) VNil)) . emptyCtx)) ||] where nameLet :: MVar x -> String@@ -68,6 +68,7 @@ alg (Make σ c k) = evalMake σ c k alg (Get σ c k) = evalGet σ c k alg (Put σ c k) = evalPut σ c k+ alg (SelectPos sel k) = evalSelectPos sel k alg (LogEnter name k) = evalLogEnter name k alg (LogExit name k) = evalLogExit name k alg (MetaInstr m k) = evalMeta m k@@ -76,10 +77,10 @@ evalRet = return $! retCont >>= resume evalCall :: ContOps o => MVar x -> Machine s o (x : xs) (Succ n) r a -> MachineMonad s o xs (Succ n) r a-evalCall μ (Machine k) = liftM2 (\mk sub γ@Γ{..} -> callWithContinuation sub (suspend mk γ) input handlers) k (askSub μ)+evalCall μ (Machine k) = liftM2 (\mk sub γ@Γ{..} -> callWithContinuation sub (suspend mk γ) input pos handlers) k (askSub μ) evalJump :: ContOps o => MVar x -> MachineMonad s o '[] (Succ n) x a-evalJump μ = askSub μ <&> \sub Γ{..} -> callWithContinuation sub retCont input handlers+evalJump μ = askSub μ <&> \sub Γ{..} -> callWithContinuation sub retCont input pos handlers evalPush :: Defunc x -> Machine s o (x : xs) n r a -> MachineMonad s o xs n r a evalPush x (Machine k) = k <&> \m γ -> m (γ {operands = Op x (operands γ)})@@ -143,7 +144,7 @@ evalIter :: (RecBuilder o, ReturnOps o, HandlerOps o) => MVar Void -> Machine s o '[] One Void a -> Machine s o (o : xs) n r a -> MachineMonad s o xs n r a-evalIter μ l (Machine h) = liftM2 (\mh ctx γ -> buildIter ctx μ l (buildHandler γ mh) (input γ)) h ask+evalIter μ l (Machine h) = liftM2 (\mh ctx γ -> buildIter ctx μ l (buildHandler γ mh) (input γ) (pos γ)) h ask evalJoin :: ContOps o => ΦVar x -> MachineMonad s o (x : xs) n r a evalJoin φ = askΦ φ <&> resume@@ -171,6 +172,10 @@ evalPut σ a k = asks $ \ctx γ -> let Op x xs = operands γ in writeΣ σ a x (run k (γ {operands = xs})) ctx++evalSelectPos :: PosSelector -> Machine s o (Int : xs) n r a -> MachineMonad s o xs n r a+evalSelectPos Line (Machine k) = k <&> \m γ -> m (γ {operands = Op (FREEVAR (fst (pos γ))) (operands γ)})+evalSelectPos Col (Machine k) = k <&> \m γ -> m (γ {operands = Op (FREEVAR (snd (pos γ))) (operands γ)}) evalLogEnter :: (?ops :: InputOps o, LogHandler o) => String -> Machine s o xs (Succ (Succ n)) r a -> MachineMonad s o xs (Succ n) r a evalLogEnter name (Machine mk) =
src/ghc-8.6+/Parsley/Internal/Backend/Machine/Ops.hs view
@@ -7,12 +7,14 @@ MagicHash, PatternSynonyms, RecordWildCards,- TypeApplications #-}+ TypeApplications,+ UnboxedTuples #-} module Parsley.Internal.Backend.Machine.Ops (module Parsley.Internal.Backend.Machine.Ops) where import Control.Monad (liftM2) import Control.Monad.Reader (ask, local) import Control.Monad.ST (ST)+import Data.Bits ((.&.), (.|.)) import Data.STRef (writeSTRef, readSTRef, newSTRef) import Data.Text (Text) import Data.Void (Void)@@ -37,9 +39,21 @@ type Ops o = (LogHandler o, ContOps o, HandlerOps o, JoinBuilder o, RecBuilder o, ReturnOps o, PositionOps o, BoxOps o, LogOps o) +updatePos# :: Int -> Int -> Char -> (# Int, Int #)+updatePos# !line !_ '\n' = (# line + 1, 1 #)+updatePos# !line !col '\t' = (# line, ((col + 3) .&. (-4)) .|. 1 #) -- nearest tab boundary `c + (4 - (c - 1) % 4)`+updatePos# !line !col _ = (# line, col + 1 #)++updatePos :: (Code Int, Code Int) -> Code Char -> ((Code Int, Code Int) -> Code r) -> Code r+updatePos (qline, qcol) qc k = [|| case updatePos# $$qline $$qcol $$qc of (# line', col' #) -> $$(k ([||line'||], [||col'||])) ||]+ {- Input Operations -} sat :: (?ops :: InputOps o) => (Defunc Char -> Defunc Bool) -> (Γ s o (Char : xs) n r a -> Code (ST s (Maybe a))) -> Code (ST s (Maybe a)) -> Γ s o xs n r a -> Code (ST s (Maybe a))-sat p k bad γ@Γ{..} = next input $ \c input' -> let v = FREEVAR c in _if (p v) (k (γ {operands = Op v operands, input = input'})) bad+sat p k bad γ@Γ{..} = next input $ \c input' -> let v = FREEVAR c in+ updatePos pos c $ \pos' ->+ _if (p v)+ (k (γ {operands = Op v operands, input = input', pos = pos'}))+ bad emitLengthCheck :: (?ops :: InputOps o, PositionOps o) => Int -> (Γ s o xs n r a -> Code (ST s (Maybe a))) -> Code (ST s (Maybe a)) -> Γ s o xs n r a -> Code (ST s (Maybe a)) emitLengthCheck 0 good _ γ = good γ@@ -99,12 +113,12 @@ #define deriveHandlerOps(_o) \ instance HandlerOps _o where \ { \- buildHandler γ h c = [||\(o# :: Unboxed _o) -> \+ buildHandler γ h c = [||\(o# :: Unboxed _o) !(line :: Int) !(col :: Int) -> \ $$(h (γ {operands = Op (FREEVAR c) (operands γ), \- input = [||$$box o#||]}))||]; \- fatal = [||\(!_) -> returnST Nothing ||]; \+ input = [||$$box o#||], pos = ([||line||], [||col||])}))||]; \+ fatal = [||\(!_) !_ !_ -> returnST Nothing ||]; \ raise γ = let VCons h _ = handlers γ \- in [|| $$h ($$unbox $$(input γ)) ||]; \+ in [|| $$h ($$unbox $$(input γ)) $$(fst (pos γ)) $$(snd (pos γ)) ||]; \ }; inputInstances(deriveHandlerOps) @@ -112,7 +126,7 @@ class BoxOps o => ContOps o where suspend :: (Γ s o (x : xs) n r a -> Code (ST s (Maybe a))) -> Γ s o xs n r a -> Code (Cont s o a x) resume :: Code (Cont s o a x) -> Γ s o (x : xs) n r a -> Code (ST s (Maybe a))- callWithContinuation :: Code (Subroutine s o a x) -> Code (Cont s o a x) -> Code o -> Vec (Succ n) (Code (Handler s o a)) -> Code (ST s (Maybe a))+ callWithContinuation :: Code (Subroutine s o a x) -> Code (Cont s o a x) -> Code o -> (Code Int, Code Int) -> Vec (Succ n) (Code (Handler s o a)) -> Code (ST s (Maybe a)) class ReturnOps o where halt :: Code (Cont s o a a)@@ -121,18 +135,18 @@ #define deriveContOps(_o) \ instance ContOps _o where \ { \- suspend m γ = [|| \x (!o#) -> $$(m (γ {operands = Op (FREEVAR [||x||]) (operands γ), \- input = [||$$box o#||]})) ||]; \- resume k γ = let Op x _ = operands γ in [|| $$k $$(genDefunc x) ($$unbox $$(input γ)) ||]; \- callWithContinuation sub ret input (VCons h _) = [||$$sub $$ret ($$unbox $$input) $! $$h||]; \+ suspend m γ = [|| \x (!o#) !l !c -> $$(m (γ {operands = Op (FREEVAR [||x||]) (operands γ), \+ input = [||$$box o#||], pos = ([||l||], [||c||])})) ||]; \+ resume k γ = let Op x _ = operands γ in [|| $$k $$(genDefunc x) ($$unbox $$(input γ)) $$(fst (pos γ)) $$(snd (pos γ)) ||]; \+ callWithContinuation sub ret input (ql, qc) (VCons h _) = [||$$sub $$ret ($$unbox $$input) $$ql $$qc $! $$h||]; \ }; inputInstances(deriveContOps) #define deriveReturnOps(_o) \ instance ReturnOps _o where \ { \- halt = [||\x _ -> returnST $! Just x||]; \- noreturn = [||\_ _ -> error "Return is not permitted here"||]; \+ halt = [||\x _ _ _ -> returnST $! Just x||]; \+ noreturn = [||\_ _ _ _ -> error "Return is not permitted here"||]; \ }; inputInstances(deriveReturnOps) @@ -143,7 +157,7 @@ class BoxOps o => RecBuilder o where buildIter :: ReturnOps o => Ctx s o a -> MVar Void -> Machine s o '[] One Void a- -> (Code o -> Code (Handler s o a)) -> Code o -> Code (ST s (Maybe a))+ -> (Code o -> Code (Handler s o a)) -> Code o -> (Code Int, Code Int) -> Code (ST s (Maybe a)) buildRec :: MVar r -> Regs rs -> Ctx s o a@@ -155,8 +169,8 @@ { \ setupJoinPoint φ (Machine k) mx = \ liftM2 (\mk ctx γ -> [|| \- let join x !(o# :: Unboxed _o) = \- $$(mk (γ {operands = Op (FREEVAR [||x||]) (operands γ), input = [||$$box o#||]})) \+ let join x !(o# :: Unboxed _o) !(line :: Int) !(col :: Int) = \+ $$(mk (γ {operands = Op (FREEVAR [||x||]) (operands γ), input = [||$$box o#||], pos = ([||line||], [||col||])})) \ in $$(run mx γ (insertΦ φ [||join||] ctx)) \ ||]) (local voidCoins k) ask; \ };@@ -165,17 +179,17 @@ #define deriveRecBuilder(_o) \ instance RecBuilder _o where \ { \- buildIter ctx μ l h o = let bx = box in [|| \- let handler !o# = $$(h [||$$bx o#||]); \- loop !o# = \+ buildIter ctx μ l h o (line, col) = let bx = box in [|| \+ let handler !o# !line !col = $$(h [||$$bx o#||]) line col; \+ loop !o# !line !col = \ $$(run l \- (Γ Empty (noreturn @_o) [||$$bx o#||] (VCons [||handler o#||] VNil)) \- (voidCoins (insertSub μ [||\_ (!o#) _ -> loop o#||] ctx))) \- in loop ($$unbox $$o) \+ (Γ Empty (noreturn @_o) [||$$bx o#||] ([||line||], [||col||]) (VCons [||handler o#||] VNil)) \+ (voidCoins (insertSub μ [||\_ (!o#) !line !col _ -> loop o# line col||] ctx))) \+ in loop ($$unbox $$o) $$line $$col \ ||]; \ buildRec _ rs ctx k = let bx = box in takeFreeRegisters rs ctx (\ctx -> \- [|| \(!ret) (!o#) h -> \- $$(run k (Γ Empty [||ret||] [||$$bx o#||] (VCons [||h||] VNil)) ctx) ||]); \+ [|| \(!ret) (!o#) !line !col h -> \+ $$(run k (Γ Empty [||ret||] [||$$bx o#||] ([||line||], [||col||]) (VCons [||h||] VNil)) ctx) ||]); \ }; inputInstances(deriveRecBuilder)
src/ghc-8.6+/Parsley/Internal/Backend/Machine/Types/State.hs view
@@ -33,9 +33,9 @@ import qualified Parsley.Internal.Common.Queue as Queue (empty, null) type HandlerStack n s o a = Vec n (Code (Handler s o a))-type Handler s o a = Unboxed o -> ST s (Maybe a)-type Cont s o a x = x -> Unboxed o -> ST s (Maybe a)-type Subroutine s o a x = Cont s o a x -> Unboxed o -> Handler s o a -> ST s (Maybe a)+type Handler s o a = Unboxed o -> Int -> Int -> ST s (Maybe a)+type Cont s o a x = x -> Unboxed o -> Int -> Int -> ST s (Maybe a)+type Subroutine s o a x = Cont s o a x -> Unboxed o -> Int -> Int -> Handler s o a -> ST s (Maybe a) type MachineMonad s o xs n r a = Reader (Ctx s o a) (Γ s o xs n r a -> Code (ST s (Maybe a))) type family Func (rs :: [Type]) s o a x where@@ -63,6 +63,7 @@ data Γ s o xs n r a = Γ { operands :: OpStack xs , retCont :: Code (Cont s o a r) , input :: Code o+ , pos :: (Code Int, Code Int) , handlers :: HandlerStack n s o a } data Ctx s o a = Ctx { μs :: DMap MVar (QSubroutine s o a)
src/ghc/Parsley/Internal.hs view
@@ -48,6 +48,7 @@ loop, Reg, newRegister, get, put, conditional, branch,+ line, col, debug ) import Parsley.Internal.Common.Utils as THUtils (Quapplicative(..), WQ, Code, makeQ)
src/ghc/Parsley/Internal/Backend/Analysis/Coins.hs view
@@ -68,6 +68,7 @@ alg _ (Make _ _ k) = getConst4 k alg _ (Get _ _ k) = getConst4 k alg _ (Put _ _ k) = getConst4 k+alg _ (SelectPos _ k) = getConst4 k alg _ (LogEnter _ k) = getConst4 k alg _ (LogExit _ k) = getConst4 k alg _ (MetaInstr (AddCoins _) (Const4 k)) = k
src/ghc/Parsley/Internal/Backend/Analysis/Inliner.hs view
@@ -53,6 +53,7 @@ alg (Make _ Hard k) = 1 % 3 + getWeight k alg (Get _ Hard k) = 1 % 3 + getWeight k alg (Put _ Hard k) = 1 % 3 + getWeight k+alg (SelectPos _ k) = 1 % 5 + getWeight k alg (Make _ Soft k) = 1 % 10 + getWeight k alg (Get _ Soft k) = 0 + getWeight k alg (Put _ Soft k) = 1 % 10 + getWeight k
src/ghc/Parsley/Internal/Backend/Analysis/Relevancy.hs view
@@ -68,6 +68,7 @@ alg (Make _ _ k) (SSucc n) = VCons False (getStack k n) alg (Get _ _ k) n = let VCons _ xs = getStack k (SSucc n) in xs alg (Put _ _ k) (SSucc n) = VCons False (getStack k n)+alg (SelectPos _ k) n = let VCons _ xs = getStack k (SSucc n) in xs alg (LogEnter _ k) n = getStack k n alg (LogExit _ k) n = getStack k n alg (MetaInstr _ k) n = getStack k n
src/ghc/Parsley/Internal/Backend/CodeGenerator.hs view
@@ -154,6 +154,7 @@ shallow (MakeRegister σ p q) m = do qc <- runCodeGen q m; runCodeGen p (In4 (_Make σ qc)) shallow (GetRegister σ) m = do return $! In4 (_Get σ m) shallow (PutRegister σ p) m = do runCodeGen p (In4 (_Put σ (In4 (Push (user UNIT) m))))+shallow (Position sel) m = do return $! In4 (SelectPos sel m) shallow (Debug name p) m = do fmap (In4 . LogEnter name) (runCodeGen p (In4 (Commit (In4 (LogExit name m))))) shallow (MetaCombinator Cut p) m = do blockCoins <$> runCodeGen p (addCoins (coinsNeeded m) m) shallow (MetaCombinator CutImmune p) m = do addCoins . coinsNeeded <$> runCodeGen p (In4 Ret) <*> runCodeGen p m
src/ghc/Parsley/Internal/Backend/Machine/Instructions.hs view
@@ -24,7 +24,9 @@ -- * Smart Instructions _App, _Fmap, _Modify, _Make, _Put, _Get, -- * Smart Meta-Instructions- addCoins, refundCoins, drainCoins, giveBursary, prefetchChar, blockCoins+ addCoins, refundCoins, drainCoins, giveBursary, prefetchChar, blockCoins,+ -- * Re-exports+ PosSelector(..) ) where import Data.Kind (Type)@@ -32,6 +34,7 @@ import Parsley.Internal.Backend.Machine.Identifiers (MVar, ΦVar, ΣVar) import Parsley.Internal.Backend.Machine.Types.Coins (Coins(Coins)) import Parsley.Internal.Common (IFunctor4, Fix4(In4), Const4(..), imap4, cata4, Nat(..), One, intercalateDiff)+import Parsley.Internal.Core.CombinatorAST (PosSelector(..)) import Parsley.Internal.Backend.Machine.Defunc as Machine (Defunc, user) import Parsley.Internal.Core.Defunc as Core (Defunc(ID), pattern FLIP_H)@@ -168,6 +171,7 @@ -> Access {- ^ Whether or not the value needs to be stored in a concrete register. -} -> k xs n r a -> Instr o k (x : xs) n r a+ SelectPos :: PosSelector -> k (Int : xs) n r a -> Instr o k xs n r a {-| Begins a debugging scope, the inner scope requires /two/ handlers, the first is the log handler itself, and then the second is the "real" fail handler for when the log handler is executed.@@ -396,6 +400,7 @@ imap4 f (Make σ a k) = Make σ a (f k) imap4 f (Get σ a k) = Get σ a (f k) imap4 f (Put σ a k) = Put σ a (f k)+ imap4 f (SelectPos sel k) = SelectPos sel (f k) imap4 f (LogEnter name k) = LogEnter name (f k) imap4 f (LogExit name k) = LogExit name (f k) imap4 f (MetaInstr m k) = MetaInstr m (f k)@@ -430,6 +435,8 @@ alg (Make σ a k) = "(Make " . shows σ . " " . shows a . " " . getConst4 k . ")" alg (Get σ a k) = "(Get " . shows σ . " " . shows a . " " . getConst4 k . ")" alg (Put σ a k) = "(Put " . shows σ . " " . shows a . " " . getConst4 k . ")"+ alg (SelectPos Line k) = "(Line " . getConst4 k . ")"+ alg (SelectPos Col k) = "(Col " . getConst4 k . ")" alg (LogEnter _ k) = getConst4 k alg (LogExit _ k) = getConst4 k alg (MetaInstr BlockCoins k) = getConst4 k
src/ghc/Parsley/Internal/Core/CombinatorAST.hs view
@@ -32,12 +32,17 @@ MakeRegister :: ΣVar a -> k a -> k b -> Combinator k b GetRegister :: ΣVar a -> Combinator k a PutRegister :: ΣVar a -> k a -> Combinator k ()+ Position :: PosSelector -> Combinator k Int Debug :: String -> k a -> Combinator k a MetaCombinator :: MetaCombinator -> k a -> Combinator k a data ScopeRegister (k :: Type -> Type) (a :: Type) where ScopeRegister :: k a -> (forall r. Reg r a -> k b) -> ScopeRegister k b +data PosSelector where+ Line :: PosSelector+ Col :: PosSelector+ {-| This is an opaque representation of a parsing register. It cannot be manipulated as a user, and the type parameter @r@ is used to ensure that it cannot leak out of the scope it has been created in.@@ -76,6 +81,7 @@ imap f (MakeRegister σ p q) = MakeRegister σ (f p) (f q) imap _ (GetRegister σ) = GetRegister σ imap f (PutRegister σ p) = PutRegister σ (f p)+ imap _ (Position sel) = Position sel imap f (Debug name p) = Debug name (f p) imap f (MetaCombinator m p) = MetaCombinator m (f p) @@ -100,6 +106,8 @@ alg (MakeRegister σ (Const1 p) (Const1 q)) = "make " . shows σ . " (" . p . ") (" . q . ")" alg (GetRegister σ) = "get " . shows σ alg (PutRegister σ (Const1 p)) = "put " . shows σ . " (" . p . ")"+ alg (Position Line) = "line"+ alg (Position Col) = "col" alg (Debug _ (Const1 p)) = p alg (MetaCombinator m (Const1 p)) = p . " [" . shows m . "]" @@ -127,6 +135,7 @@ traverseCombinator expose (MakeRegister σ p q) = MakeRegister σ <$> expose p <*> expose q traverseCombinator _ (GetRegister σ) = pure (GetRegister σ) traverseCombinator expose (PutRegister σ p) = PutRegister σ <$> expose p+traverseCombinator _ (Position sel) = pure (Position sel) traverseCombinator expose (Debug name p) = Debug name <$> expose p traverseCombinator _ (Pure x) = pure (Pure x) traverseCombinator _ (Satisfy f) = pure (Satisfy f)
src/ghc/Parsley/Internal/Core/Primitives.hs view
@@ -7,7 +7,7 @@ import Prelude hiding (pure, (<*>)) import Control.Arrow (first)-import Parsley.Internal.Core.CombinatorAST (Combinator(..), ScopeRegister(..), Reg(..), Parser(..))+import Parsley.Internal.Core.CombinatorAST (Combinator(..), ScopeRegister(..), Reg(..), Parser(..), PosSelector(..)) #if MIN_VERSION_parsley_core(2,0,0) import Parsley.Internal.Core.Defunc (Defunc) #else@@ -133,6 +133,14 @@ {-# INLINE put #-} put :: Reg r a -> Parser a -> Parser () put (Reg reg) (Parser p) = Parser (In (L (PutRegister reg p)))++{-# INLINE line #-}+line :: Parser Int+line = Parser (In (L (Position Line)))++{-# INLINE col #-}+col :: Parser Int+col = Parser (In (L (Position Col))) {-# INLINE debug #-} debug :: String -> Parser a -> Parser a
src/ghc/Parsley/Internal/Frontend/Analysis/Cut.hs view
@@ -64,6 +64,7 @@ compliance (Match p _ qs def) = seqCompliance p (foldr1 caseCompliance (def:qs)) compliance (MakeRegister _ l r) = seqCompliance l r compliance (GetRegister _) = FullPure+compliance (Position _) = FullPure compliance (PutRegister _ c) = coerce c compliance (MetaCombinator _ c) = c @@ -118,6 +119,7 @@ cutAlg (MakeRegister σ l r) cut = seqCutAlg (MakeRegister σ) cut (ifst l) (ifst r) cutAlg (GetRegister σ) _ = (In (GetRegister σ), False) cutAlg (PutRegister σ p) cut = rewrap (PutRegister σ) cut (ifst p)+cutAlg (Position sel) _ = (In (Position sel), False) cutAlg (MetaCombinator m p) cut = rewrap (MetaCombinator m) cut (ifst p) mkCut :: Bool -> Fix Combinator a -> Fix Combinator a
src/ghc/Parsley/Internal/Frontend/Analysis/Inliner.hs view
@@ -53,4 +53,5 @@ alg (MakeRegister _ l r) = 1 % 3 + getWeight l + getWeight r alg (GetRegister _) = 1 % 3 alg (PutRegister _ c) = 1 % 3 + getWeight c+alg (Position _) = 1 % 5 alg (MetaCombinator _ c) = getWeight c
+ test/Primitive.hs view
@@ -0,0 +1,142 @@+{-# LANGUAGE TemplateHaskell, UnboxedTuples, ScopedTypeVariables, TypeApplications #-}+module Main where+import Test.Tasty+import Test.Tasty.HUnit+import TestUtils+import qualified Primitive.Parsers as Parsers++import Parsley.Internal (empty, line, col)++main :: IO ()+main = defaultMain tests++tests :: TestTree+tests = testGroup "Primitive Combinator Tests" [ pureTests+ , apTests+ , thenTests+ , prevTests+ , altTests+ , emptyTests+ , satisfyTests+ , lookAheadTests+ , notFollowedByTests+ , tryTests+ , branchTests+ , conditionalTests+ , recursionTests+ , positionTests+ ]++pure7 :: String -> Maybe Int+pure7 = $$(parseMocked Parsers.pure7 [||Parsers.pure7||])++pureTests :: TestTree+pureTests = testGroup "pure should"+ [ testCase "not need to consume input" $ pure7 "" @?= Just 7+ , testCase "not fail if there is input" $ pure7 "a" @?= Just 7+ ]++apTests :: TestTree+apTests = testGroup "<*> should" []++thenTests :: TestTree+thenTests = testGroup "*> should" []++prevTests :: TestTree+prevTests = testGroup "<* should" []++abOrC :: String -> Maybe String+abOrC = $$(parseMocked Parsers.abOrC [||Parsers.abOrC||])++abOrCThenD :: String -> Maybe String+abOrCThenD = $$(parseMocked Parsers.abOrCThenD [||Parsers.abOrCThenD||])++altTests :: TestTree+altTests = testGroup "<|> should"+ [ testCase "take the left branch if it succeeds" $ do+ abOrC "ab" @?= Just "ab"+ abOrCThenD "abd" @?= Just "ab"+ , testCase "take the right branch if left failed without consumption" $ do+ abOrC "c" @?= Just "c"+ abOrC "d" @?= Nothing+ abOrCThenD "cd" @?= Just "c"+ abOrCThenD "d" @?= Nothing+ , testCase "fail if the left branch fails and consumes input" $ abOrC "a" @?= Nothing+ ]++constNothing :: String -> Maybe ()+constNothing = $$(parseMocked empty [||empty||])++emptyTests :: TestTree+emptyTests = testGroup "empty should"+ [ testCase "fail the parser with no input" $ constNothing "" @?= Nothing+ , testCase "fail the parser with input" $ constNothing "a" @?= Nothing+ ]++digit :: String -> Maybe Char+digit = $$(parseMocked Parsers.digit [||Parsers.digit||])++twoDigits :: String -> Maybe Char+twoDigits = $$(parseMocked Parsers.twoDigits [||Parsers.twoDigits||])++satisfyTests :: TestTree+satisfyTests = testGroup "satisfy should"+ [ testCase "fail when given no input" $ digit "" @?= Nothing+ , testCase "fail when given incorrect input" $ digit "a" @?= Nothing+ , testCase "succeed when given correct input" $ digit "1" @?= Just '1'+ , testCase "actually consume input" $ twoDigits "1" @?= Nothing+ , testCase "consume more than 1 piece of input with two" $ twoDigits "12" @?= Just '2'+ ]++lookAheadDigit :: String -> Maybe Char+lookAheadDigit = $$(parseMocked Parsers.lookAheadDigit [||Parsers.lookAheadDigit||])++lookAheadTests :: TestTree+lookAheadTests = testGroup "lookAhead should"+ [ testCase "rollback consumed input" $ lookAheadDigit "9" @?= Just '9'+ , testCase "fail when given no input when expected" $ lookAheadDigit "" @?= Nothing+ ]++notFollowedByTests :: TestTree+notFollowedByTests = testGroup "notFollowedBy should" []++tryTests :: TestTree+tryTests = testGroup "try should" []++branchTests :: TestTree+branchTests = testGroup "branch should" []++conditionalTests :: TestTree+conditionalTests = testGroup "conditional should" []++manyAny :: String -> Maybe String+manyAny = $$(parseMocked Parsers.recursive [||Parsers.recursive||])++recursionTests :: TestTree+recursionTests = testGroup "recursion should"+ [ testCase "work properly" $ manyAny "abc" @?= Just "abc"+ ]++lineStarts1 :: String -> Maybe Int+lineStarts1 = $$(parseMocked line [||line||])++columnStarts1 :: String -> Maybe Int+columnStarts1 = $$(parseMocked col [||col||])++posAfterA :: String -> Maybe (Int, Int)+posAfterA = $$(parseMocked Parsers.posAfterA [||Parsers.posAfterA||])++posAfterNewline :: String -> Maybe ((Int, Int), (Int, Int))+posAfterNewline = $$(parseMocked Parsers.posAfterNewline [||Parsers.posAfterNewline||])++posAfterTab :: String -> Maybe ((Int, Int), (Int, Int))+posAfterTab = $$(parseMocked Parsers.posAfterTab [||Parsers.posAfterTab||])++positionTests :: TestTree+positionTests = testGroup "position combinators should"+ [ testCase "start at line 1" $ lineStarts1 "" @?= Just 1+ , testCase "start at column 1" $ columnStarts1 "" @?= Just 1+ , testCase "advance by 1 column only after regular character" $ posAfterA "a" @?= Just (1, 2)+ , testCase "advance by 1 line and reset column after newline" $ posAfterNewline "a\n\n" @?= Just ((2, 1), (3, 1))+ , testCase "advance to nearest tab boundary on tab" $ posAfterTab "\ta\t" @?= Just ((1, 5), (1, 9))+ ]
+ test/Primitive/Parsers.hs view
@@ -0,0 +1,50 @@+{-# LANGUAGE TemplateHaskell #-}+module Primitive.Parsers where++import Prelude hiding (pure, (<*>), (*>), (<*))+import Data.Char (isDigit)+import Parsley.Internal (Parser, Defunc(EMPTY, LIFTED, EQ_H, CONS, LAM_S), makeQ, pure, satisfy, (*>), (<*), (<|>), (<*>), satisfy, lookAhead, line, col)++char :: Char -> Parser Char+char c = satisfy (EQ_H (LIFTED c))++item :: Parser Char+item = satisfy (LAM_S (const (LIFTED True)))++pure7 :: Parser Int+pure7 = pure (LIFTED 7)++digit :: Parser Char+digit = satisfy (makeQ isDigit [||isDigit||])++twoDigits :: Parser Char+twoDigits = digit *> digit++abOrC :: Parser String+abOrC = (char 'a' *> char 'b' *> pure (LIFTED "ab")) <|> (char 'c' *> pure (LIFTED "c"))++abOrCThenD :: Parser String+abOrCThenD = abOrC <* char 'd'++recursive :: Parser [Char]+recursive =+ let r = pure CONS <*> item <*> r <|> pure EMPTY+ in r++lookAheadDigit :: Parser Char+lookAheadDigit = lookAhead digit *> digit++(<~>) :: Parser a -> Parser b -> Parser (a, b)+mx <~> my = pure (makeQ (,) [||(,)||]) <*> mx <*> my++pos :: Parser (Int, Int)+pos = line <~> col++posAfterA :: Parser (Int, Int)+posAfterA = char 'a' *> pos++posAfterNewline :: Parser ((Int, Int), (Int, Int))+posAfterNewline = (char 'a' *> char '\n' *> pos) <~> (char '\n' *> pos)++posAfterTab :: Parser ((Int, Int), (Int, Int))+posAfterTab = (char '\t' *> pos) <~> (char 'a' *> char '\t' *> pos)
+ test/TestUtils.hs view
@@ -0,0 +1,88 @@+{-# LANGUAGE TemplateHaskell, TypeApplications, DeriveAnyClass, StandaloneDeriving, CPP, FlexibleInstances, MonoLocalBinds, MultiParamTypeClasses #-}+module TestUtils where++import Parsley.Internal (parse, Parser, Code)+import Parsley.Internal.Trace (Trace(..))+import Language.Haskell.TH.Syntax+#if MIN_VERSION_template_haskell(2,17,0)+ hiding (Code)+#endif+import Language.Haskell.TH.TestUtils+import Language.Haskell.TH.TestUtils.QMode+import Control.DeepSeq++#if MIN_VERSION_template_haskell(2,16,0)+import GHC.ForeignPtr+#endif++#if MIN_VERSION_template_haskell(2,17,0)+#else+unTypeCode = unTypeQ+#endif++instance {-# INCOHERENT #-} Trace where+ trace = flip const++-- TODO Use WQ: requires lift plugin to not require any Lift instance for variables (if missing)+parseMocked :: Trace => Parser a -> Code (Parser a) -> Code (String -> Maybe a)+parseMocked p qp = [|| \s ->+ parseMocked' $$qp `deepseq` $$(parse p) s+ ||]++parseMocked' :: Parser a -> Exp+parseMocked' = runTestQ (QState MockQ [] []) . unTypeCode . parse @String++deriving instance NFData Exp+deriving instance NFData Name+deriving instance NFData OccName+deriving instance NFData NameFlavour+deriving instance NFData ModName+deriving instance NFData NameSpace+deriving instance NFData PkgName+deriving instance NFData Lit+#if MIN_VERSION_template_haskell(2,16,0)+deriving instance NFData Bytes+instance NFData (ForeignPtr a) where rnf = rwhnf+#endif+deriving instance NFData Type+#if MIN_VERSION_template_haskell(2,17,0)+deriving instance NFData a => NFData (TyVarBndr a)+deriving instance NFData Specificity+#else+deriving instance NFData TyVarBndr+#endif+deriving instance NFData Pat+deriving instance NFData TyLit+deriving instance NFData Match+deriving instance NFData Body+deriving instance NFData Guard+deriving instance NFData Stmt+deriving instance NFData Dec+deriving instance NFData Clause+deriving instance NFData Con+deriving instance NFData Bang+deriving instance NFData SourceUnpackedness+deriving instance NFData SourceStrictness+deriving instance NFData DerivClause+deriving instance NFData Range+deriving instance NFData DerivStrategy+deriving instance NFData FunDep+deriving instance NFData Overlap+deriving instance NFData Foreign+deriving instance NFData Callconv+deriving instance NFData Fixity+deriving instance NFData FixityDirection+deriving instance NFData Safety+deriving instance NFData Pragma+deriving instance NFData Inline+deriving instance NFData TySynEqn+deriving instance NFData RuleMatch+deriving instance NFData TypeFamilyHead+deriving instance NFData FamilyResultSig+deriving instance NFData Phases+deriving instance NFData Role+deriving instance NFData InjectivityAnn+deriving instance NFData RuleBndr+deriving instance NFData PatSynArgs+deriving instance NFData AnnTarget+deriving instance NFData PatSynDir