Add ability to recursively parse #included files

This commit is contained in:
Kirill Andreev 2020-07-03 19:52:06 +04:00
parent 583d7f8997
commit b35a28853b
No known key found for this signature in database
GPG Key ID: CF7DA79DE4785A47
12 changed files with 190 additions and 133 deletions

View File

@ -8,6 +8,7 @@ import Control.Monad
import Data.Default import Data.Default
import qualified Data.Text as Text import qualified Data.Text as Text
import Data.Text (Text) import Data.Text (Text)
import Data.Foldable
import Data.String.Interpolate (i) import Data.String.Interpolate (i)
import qualified Language.Haskell.LSP.Control as CTRL import qualified Language.Haskell.LSP.Control as CTRL
@ -32,6 +33,8 @@ import Tree
main :: IO () main :: IO ()
main = do main = do
-- for_ [1.. 100] \_ -> do
-- print =<< runParser contract example
errCode <- mainLoop errCode <- mainLoop
exit errCode exit errCode
@ -165,13 +168,13 @@ eventLoop funs chan = do
_ -> U.logs "unknown msg" _ -> U.logs "unknown msg"
posToRange :: J.Position -> Range posToRange :: J.Position -> Range
posToRange (J.Position l c) = Range (l, c, 0) (l, c, 0) posToRange (J.Position l c) = Range (l, c, 0) (l, c, 0) ""
rangeToJRange :: Range -> J.Range rangeToJRange :: Range -> J.Range
rangeToJRange (Range (a, b, _) (c, d, _)) = J.Range (J.Position a b) (J.Position c d) rangeToJRange (Range (a, b, _) (c, d, _) _) = J.Range (J.Position a b) (J.Position c d)
rangeToLoc :: Range -> J.Range rangeToLoc :: Range -> J.Range
rangeToLoc (Range (a, b, _) (c, d, _)) = J.Range (J.Position a b) (J.Position c d) rangeToLoc (Range (a, b, _) (c, d, _) _) = J.Range (J.Position a b) (J.Position c d)
loadByURI :: J.Uri -> IO (Pascal (Product [[ScopedDecl], Range, [Text]])) loadByURI :: J.Uri -> IO (Pascal (Product [[ScopedDecl], Range, [Text]]))
loadByURI uri = do loadByURI uri = do
@ -197,7 +200,7 @@ collectErrors funs uri path version = do
Nothing -> error "TODO: implement URI file loading" Nothing -> error "TODO: implement URI file loading"
errorToDiag :: Error ASTInfo -> J.Diagnostic errorToDiag :: Error ASTInfo -> J.Diagnostic
errorToDiag (Expected what _ (getRange -> (Range (sl, sc, _) (el, ec, _)))) = errorToDiag (Expected what _ (getRange -> (Range (sl, sc, _) (el, ec, _) _))) =
J.Diagnostic J.Diagnostic
(J.Range begin end) (J.Range begin end)
(Just J.DsError) (Just J.DsError)

View File

@ -5,10 +5,11 @@ dependencies:
- bytestring - bytestring
- containers - containers
- data-default - data-default
- filepath
- exceptions
- fastsum - fastsum
- mtl - mtl
- pretty - pretty
- template-haskell
- text - text
- tree-sitter - tree-sitter

View File

@ -5,6 +5,7 @@
module AST.Parser (example, contract) where module AST.Parser (example, contract) where
import Data.Text (Text) import Data.Text (Text)
import qualified Data.Text as Text
import Data.Sum import Data.Sum
import AST.Types import AST.Types
@ -53,10 +54,11 @@ declaration
include :: Parser (Pascal ASTInfo) include :: Parser (Pascal ASTInfo)
include = do include = do
subtree "include" do subtree "include" do
inside "filename" do
ranged do ranged do
pure Include f <- token "String"
<*> inside "filename" do t <- restart contract (init $ tail $ Text.unpack f)
token "String" return $ Include f t
typedecl :: Parser (Pascal ASTInfo) typedecl :: Parser (Pascal ASTInfo)
typedecl = do typedecl = do
@ -858,11 +860,11 @@ typeTuple = do
-- example = "../../../src/test/contracts/bytes_arithmetic.ligo" -- example = "../../../src/test/contracts/bytes_arithmetic.ligo"
-- example = "../../../src/test/contracts/bytes_unpack.ligo" -- example = "../../../src/test/contracts/bytes_unpack.ligo"
-- example = "../../../src/test/contracts/chain_id.ligo" -- example = "../../../src/test/contracts/chain_id.ligo"
example = "../../../src/test/contracts/coase.ligo" -- example = "../../../src/test/contracts/coase.ligo"
-- example = "../../../src/test/contracts/failwith.ligo" -- example = "../../../src/test/contracts/failwith.ligo"
-- example = "../../../src/test/contracts/loop.ligo" -- example = "../../../src/test/contracts/loop.ligo"
-- example = "../../../src/test/contracts/redeclaration.ligo" -- example = "../../../src/test/contracts/redeclaration.ligo"
-- example = "../../../src/test/contracts/application.ligo" example = "../../../src/test/contracts/includer.ligo"
-- example = "../../../src/test/contracts/application.ligo" -- example = "../../../src/test/contracts/application.ligo"
-- example = "../../../src/test/contracts/application.ligo" -- example = "../../../src/test/contracts/application.ligo"
-- example = "../../../src/test/contracts/application.ligo" -- example = "../../../src/test/contracts/application.ligo"

View File

@ -32,7 +32,7 @@ data Declaration it
= ValueDecl it -- ^ Binding = ValueDecl it -- ^ Binding
| TypeDecl it it -- ^ Name Type | TypeDecl it it -- ^ Name Type
| Action it -- ^ Expr | Action it -- ^ Expr
| Include Text | Include Text it
deriving (Show) via PP (Declaration it) deriving (Show) via PP (Declaration it)
deriving stock (Functor, Foldable, Traversable) deriving stock (Functor, Foldable, Traversable)
@ -186,7 +186,11 @@ instance Pretty1 Declaration where
ValueDecl binding -> binding ValueDecl binding -> binding
TypeDecl n ty -> "type" <+> n <+> "=" `indent` ty TypeDecl n ty -> "type" <+> n <+> "=" `indent` ty
Action e -> e Action e -> e
Include f -> "#include" <+> pp f
Include f t ->
"(* module" <+> pp f <+> "*)"
`indent` pp t
`above` "(* end" <+> pp f <+> "*)"
instance Pretty1 Binding where instance Pretty1 Binding where
pp1 = \case pp1 = \case

View File

@ -1,5 +1,5 @@
{- | Parsing errors and utilities. {- | Parsing Errors and utilities.
-} -}
module Error module Error
@ -9,20 +9,25 @@ module Error
) )
where where
import Control.Monad.Catch
import Data.Text (Text, pack) import Data.Text (Text, pack)
import Data.Typeable
import Pretty import Pretty
-- | Parse error. -- | Parse Error.
data Error info data Error info
= Expected = Expected
{ eMsg :: Text -- ^ Description of what was expected. { eMsg :: Text -- ^ Description of what was expected.
, eWhole :: Text -- ^ Offending text. , eWhole :: Text -- ^ Offending text.
, eInfo :: info -- ^ Location of the error. , eInfo :: info -- ^ Location of the Error.
} }
deriving (Show) via PP (Error info) deriving (Show) via PP (Error info)
deriving stock (Eq, Functor, Foldable, Traversable) deriving stock (Eq, Functor, Foldable, Traversable)
instance (Pretty i, Typeable i) => Exception (Error i)
instance Pretty1 Error where instance Pretty1 Error where
pp1 (Expected msg found r) = "" <> pp msg <> r <> "" <> pp found <> "" pp1 (Expected msg found r) = "" <> pp msg <> r <> "" <> pp found <> ""

View File

@ -40,6 +40,8 @@ import Foreign.Storable ( peek
) )
import Control.Monad ((>=>)) import Control.Monad ((>=>))
import System.FilePath
import Text.PrettyPrint hiding ((<>)) import Text.PrettyPrint hiding ((<>))
import Range import Range
@ -144,6 +146,7 @@ toParseTree fin = do
, i $ pointColumn finish2D + 1 , i $ pointColumn finish2D + 1
, i $ nodeEndByte node , i $ nodeEndByte node
) )
, rFile = takeFileName fin
} }
return $ ParseTree return $ ParseTree

View File

@ -45,6 +45,7 @@ module Parser
, stubbed , stubbed
, getInfo , getInfo
, inside , inside
, restart
-- * Error -- * Error
, die , die
@ -63,16 +64,19 @@ module Parser
, ASTInfo(..) , ASTInfo(..)
) where ) where
import Control.Monad.State
import Control.Monad.Writer hiding (Product) import Control.Monad.Writer hiding (Product)
import Control.Monad.Except import Control.Monad.State
import Control.Monad.Identity import Control.Monad.Catch
import qualified Control.Monad.Reader as MTL
import Data.Functor ((<&>)) import Data.Functor ((<&>))
import Data.Foldable import Data.Foldable
import Data.IORef
import Data.Text (Text, unpack) import Data.Text (Text, unpack)
import qualified Data.Text as Text import qualified Data.Text as Text
import System.FilePath
import ParseTree import ParseTree
import Range import Range
import Pretty import Pretty
@ -86,22 +90,45 @@ import Debug.Trace
-- --
-- TODO: separate state. Polysemy? -- TODO: separate state. Polysemy?
-- --
newtype Parser a = Parser type Parser =
{ unParser WriterT [Error ASTInfo]
:: WriterT [Error ASTInfo] -- Early I though to report errors that way. (StateT (Product PList)
( StateT (ParseForest, [Text]) -- Current forest to recognise + comments. IO)
( ExceptT (Error ASTInfo) -- Backtracking. Change `Error` to `()`?
( Identity ))) -- I forgot why. `#include`? Debug via `print`? type PList = [ParseForest, [Text], FilePath]
a
} -- | Auto-accumulated information to be put into AST being build.
deriving newtype type ASTInfo = Product [Range, [Text]]
( Functor
, Applicative runParser
, Monad :: Parser a
, MonadState (ParseForest, [Text]) -> FilePath
, MonadWriter [Error ASTInfo] -> IO (a, [Error ASTInfo])
, MonadError (Error ASTInfo) runParser parser fin = do
) pforest <- toParseTree fin
let dir = takeDirectory fin
runWriterT parser `evalStateT` Cons pforest (Cons [] (Cons dir Nil))
restart :: Parser a -> FilePath -> Parser a
restart p fin = do
dir <- get' @FilePath
(a, errs) <- liftIO do runParser p (dir </> fin)
tell errs
return a
get' :: forall x. Contains x PList => Parser x
get' = gets getElem
gets' :: forall x a. Contains x PList => (x -> a) -> Parser a
gets' f = gets (f . getElem)
put' :: forall x. Contains x PList => x -> Parser ()
put' x = modify $ modElem $ const x
mod' :: forall x. Contains x PList => (x -> x) -> Parser ()
mod' = modify . modElem
-- | Generate error originating at current location. -- | Generate error originating at current location.
makeError :: Text -> Parser (Error ASTInfo) makeError :: Text -> Parser (Error ASTInfo)
@ -112,7 +139,7 @@ makeError msg = do
-- | Generate error originating at given location. -- | Generate error originating at given location.
makeError' :: Text -> info -> Parser (Error info) makeError' :: Text -> info -> Parser (Error info)
makeError' msg i = do makeError' msg i = do
src <- gets (pfGrove . fst) <&> \case src <- gets' pfGrove <&> \case
[] -> "" [] -> ""
(,) _ ParseTree { ptSource } : _ -> ptSource (,) _ ParseTree { ptSource } : _ -> ptSource
return Expected return Expected
@ -124,23 +151,18 @@ makeError' msg i = do
-- | Pick next tree in a forest or die with msg. -- | Pick next tree in a forest or die with msg.
takeNext :: Text -> Parser ParseTree takeNext :: Text -> Parser ParseTree
takeNext msg = do takeNext msg = do
(st@Forest {pfGrove, pfRange}, comms) <- get gets' pfGrove >>= \case
case pfGrove of
[] -> die msg [] -> die msg
(_, t) : f -> do (_, t) : f -> do
if "comment" `Text.isSuffixOf` ptName t if "comment" `Text.isSuffixOf` ptName t
then do then do
(st', comms') <- get mod' (ptSource t :)
put (st', ptSource t : comms')
takeNext msg takeNext msg
else do else do
put mod' \st -> st
( st { pfRange = diffRange (pfRange st) (ptRange t)
{ pfRange = diffRange pfRange (ptRange t)
, pfGrove = f , pfGrove = f
} }
, comms
)
return t return t
--fields :: Text -> Parser a -> Parser [a] --fields :: Text -> Parser a -> Parser [a]
@ -168,39 +190,35 @@ takeNext msg = do
-- --
field :: Text -> Parser a -> Parser a field :: Text -> Parser a -> Parser a
field name parser = do field name parser = do
grove <- gets (pfGrove . fst) gets' pfGrove >>= \case
case grove of
(name', t) : _ (name', t) : _
| name == name' -> do | name == name' -> do
sandbox True t sandbox True t
_ -> do grove -> do
case lookup name grove of case lookup name grove of
Just tree -> sandbox False tree Just tree -> sandbox False tree
Nothing -> die name Nothing -> die name
where where
sandbox firstOne tree@ParseTree {ptID, ptRange} = do sandbox firstOne tree@ParseTree {ptID, ptRange} = do
(st@Forest {pfGrove = grove, pfRange = rng}, comments) <- get st@Forest {pfGrove = grove, pfRange = rng} <- get'
let (errs, new_comments, grove') = delete name grove let (errs, new_comments, grove') = delete name grove
put mod' (++ new_comments)
( Forest put' Forest
{ pfID = ptID { pfID = ptID
, pfGrove = [(name, tree)] , pfGrove = [(name, tree)]
, pfRange = ptRange , pfRange = ptRange
} }
, comments ++ new_comments
)
res <- parser res <- parser
put put' st
( st
{ pfGrove = grove' { pfGrove = grove'
, pfRange = if firstOne then diffRange rng ptRange else rng , pfRange = if firstOne then diffRange rng ptRange else rng
} }
, []
) put' @[Text] []
for_ errs (tell . pure . unexpected) for_ errs (tell . pure . unexpected)
@ -211,10 +229,10 @@ fallback msg = pure . stub =<< makeError msg
-- | Produce "expected ${X}" error at this point. -- | Produce "expected ${X}" error at this point.
die :: Text -> Parser a die :: Text -> Parser a
die msg = throwError =<< makeError msg die msg = throwM =<< makeError msg
die' ::Text -> ASTInfo -> Parser a die' ::Text -> ASTInfo -> Parser a
die' msg rng = throwError =<< makeError' msg rng die' msg rng = throwM =<< makeError' msg rng
-- | When tree-sitter found something it was unable to process. -- | When tree-sitter found something it was unable to process.
unexpected :: ParseTree -> Error ASTInfo unexpected :: ParseTree -> Error ASTInfo
@ -233,18 +251,23 @@ subtree msg parser = do
ParseTree {ptChildren, ptName} <- takeNext msg ParseTree {ptChildren, ptName} <- takeNext msg
if ptName == msg if ptName == msg
then do then do
(save, comms) <- get save <- get' @ParseForest
put (ptChildren, comms) put' ptChildren
rest <- gets (pfGrove . fst) rest <- gets' pfGrove
collectErrors rest collectErrors rest
(_, comms') <- get parser <* put' save
parser <* put (save, comms')
else do else do
die msg die msg
-- | Because `ExceptT` requires error to be `Monoid` for `Alternative`. -- | Because `ExceptT` requires error to be `Monoid` for `Alternative`.
(<|>) :: Parser a -> Parser a -> Parser a (<|>) :: Parser a -> Parser a -> Parser a
Parser l <|> Parser r = Parser (l `catchError` const r) l <|> r = do
s <- get' @ParseForest
c <- get' @[Text]
l `catch` \(e :: Error ASTInfo) -> do
put' s
put' c
r
-- | Custom @foldl1 (<|>)@. -- | Custom @foldl1 (<|>)@.
select :: [Parser a] -> Parser a select :: [Parser a] -> Parser a
@ -278,22 +301,6 @@ some p = some'
xs <- many' xs <- many'
return (x : xs) return (x : xs)
-- | Run parser on given file.
--
runParser :: Parser a -> FilePath -> IO (a, [Error ASTInfo])
runParser parser fin = do
pforest <- toParseTree fin
let
res =
runIdentity
$ runExceptT
$ flip runStateT (pforest, [])
$ runWriterT
$ unParser
$ parser
either (error . show) (return . fst) res
-- | Run parser on given file and pretty-print stuff. -- | Run parser on given file and pretty-print stuff.
-- --
debugParser :: Show a => Parser a -> FilePath -> IO () debugParser :: Show a => Parser a -> FilePath -> IO ()
@ -301,7 +308,7 @@ debugParser parser fin = do
(res, errs) <- runParser parser fin (res, errs) <- runParser parser fin
putStrLn "Result:" putStrLn "Result:"
print res print res
unless (null errs) do MTL.unless (null errs) do
putStrLn "" putStrLn ""
putStrLn "Errors:" putStrLn "Errors:"
for_ errs (print . nest 2 . pp) for_ errs (print . nest 2 . pp)
@ -324,12 +331,12 @@ anything = do
-- | Get range of the current tree (or forest) before the parser was run. -- | Get range of the current tree (or forest) before the parser was run.
range :: Parser a -> Parser (a, Range) range :: Parser a -> Parser (a, Range)
range parser = range parser =
get >>= \case get' >>= \case
(,) Forest {pfGrove = [(,) _ ParseTree {ptRange}]} _ -> do Forest {pfGrove = [(,) _ ParseTree {ptRange}]} -> do
a <- parser a <- parser
return (a, ptRange) return (a, ptRange)
(,) Forest {pfRange} _ -> do Forest {pfRange} -> do
a <- parser a <- parser
return (a, pfRange) return (a, pfRange)
@ -367,7 +374,7 @@ delete k ((k', v) : rest) =
collectErrors :: [(Text, ParseTree)] -> Parser () collectErrors :: [(Text, ParseTree)] -> Parser ()
collectErrors vs = collectErrors vs =
for_ vs \(_, v) -> do for_ vs \(_, v) -> do
when (ptName v == "ERROR") do MTL.when (ptName v == "ERROR") do
tell [unexpected v] tell [unexpected v]
-- | Universal accessor. -- | Universal accessor.
@ -398,9 +405,6 @@ inside sig parser = do
subtree st do subtree st do
parser parser
-- | Auto-accumulated information to be put into AST being build.
type ASTInfo = Product [Range, [Text]]
-- | Equip given constructor with info. -- | Equip given constructor with info.
getInfo :: Parser ASTInfo getInfo :: Parser ASTInfo
getInfo = Cons <$> currentRange <*> do Cons <$> grabComments <*> pure Nil getInfo = Cons <$> currentRange <*> do Cons <$> grabComments <*> pure Nil
@ -408,10 +412,10 @@ getInfo = Cons <$> currentRange <*> do Cons <$> grabComments <*> pure Nil
-- | Take the accumulated comments, clean the accumulator. -- | Take the accumulated comments, clean the accumulator.
grabComments :: Parser [Text] grabComments :: Parser [Text]
grabComments = do grabComments = do
(st, comms) <- get comms <- get'
put (st, []) mod' @[Text] $ const []
return comms return comms
-- | /Actual/ debug pring. -- | /Actual/ debug pring.
dump :: Parser () dump :: Parser ()
dump = gets (pfGrove . fst) >>= traceShowM dump = gets' pfGrove >>= traceShowM

View File

@ -37,6 +37,8 @@ import Data.Text (Text, pack)
import Text.PrettyPrint hiding ((<>)) import Text.PrettyPrint hiding ((<>))
import Product
-- | Pretty-print to `Text`. Through `String`. Yep. -- | Pretty-print to `Text`. Through `String`. Yep.
ppToText :: Pretty a => a -> Text ppToText :: Pretty a => a -> Text
ppToText = pack . show . pp ppToText = pack . show . pp
@ -132,3 +134,9 @@ color c d = zeroWidthText begin <> d <> zeroWidthText end
where where
begin = "\x1b[" ++ show (30 + c) ++ "m" begin = "\x1b[" ++ show (30 + c) ++ "m"
end = "\x1b[0m" end = "\x1b[0m"
instance Pretty (Product '[]) where
pp _ = "{}"
instance (Pretty x, Pretty (Product xs)) => Pretty (Product (x : xs)) where
pp (Cons x xs) = pp x <+> "&" <+> pp xs

View File

@ -1,39 +1,44 @@
{-|
The heterogeneous list.
-}
module Product where module Product where
import qualified Data.Text as Text -- | `Product xs` contains elements of each of the types from the `xs` list.
import Pretty
data Product xs where data Product xs where
Cons :: x -> Product xs -> Product (x : xs)
Nil :: Product '[] Nil :: Product '[]
Cons :: { pHead :: x, pTail :: Product xs } -> Product (x : xs)
instance Pretty (Product xs) => Show (Product xs) where
show = show . PP
-- | Find/modify the element with a given type.
--
-- If you want to have same-types, use newtype wrappers.
--
class Contains x xs where class Contains x xs where
getElem :: Product xs -> x getElem :: Product xs -> x
putElem :: x -> Product xs -> Product xs modElem :: (x -> x) -> Product xs -> Product xs
instance {-# OVERLAPS #-} Contains x (x : xs) where instance {-# OVERLAPS #-} Contains x (x : xs) where
getElem (Cons x _) = x getElem (Cons x _) = x
putElem x (Cons _ xs) = Cons x xs modElem f (Cons x xs) = Cons (f x) xs
instance Contains x xs => Contains x (y : xs) where instance Contains x xs => Contains x (y : xs) where
getElem (Cons _ xs) = getElem xs getElem (Cons _ xs) = getElem xs
putElem x (Cons y xs) = Cons y (putElem x xs) modElem f (Cons x xs) = Cons x (modElem f xs)
modElem :: Contains x xs => (x -> x) -> Product xs -> Product xs -- | Add a name to the type.
modElem f xs = putElem (f $ getElem xs) xs --
newtype (s :: String) := t = Tag { unTag :: t }
instance Pretty (Product '[]) where -- | Retrieve a type associated with the given name.
pp _ = "{}" --
getTag :: forall s t xs. Contains (s := t) xs => Product xs -> t
getTag = unTag . getElem @(s := t)
instance (Pretty x, Pretty (Product xs)) => Pretty (Product (x : xs)) where -- | Modify a type associated with the given name.
pp (Cons x xs) = --
if Text.null $ Text.strip ppx modTag
then pp xs :: forall s t xs
else pp ppx <+> "&" <+> pp xs . Contains (s := t) xs
where => (t -> t)
ppx = ppToText x -> Product xs -> Product xs
modTag f = modElem @(s := t) (Tag . f . unTag)

View File

@ -15,6 +15,8 @@ import Data.ByteString (ByteString)
import Data.Text (Text) import Data.Text (Text)
import Data.Text.Encoding import Data.Text.Encoding
import System.FilePath
import Pretty import Pretty
import Lattice import Lattice
import Product import Product
@ -23,19 +25,24 @@ import Product
data Range = Range data Range = Range
{ rStart :: (Int, Int, Int) -- ^ [Start: line, col, byte-offset... { rStart :: (Int, Int, Int) -- ^ [Start: line, col, byte-offset...
, rFinish :: (Int, Int, Int) -- ^ ... End: line, col, byte-offset). , rFinish :: (Int, Int, Int) -- ^ ... End: line, col, byte-offset).
, rFile :: FilePath
} }
deriving (Show) via PP Range deriving (Show) via PP Range
deriving stock (Ord) deriving stock (Ord)
-- | TODO: Ugh. Purge it. -- | TODO: Ugh. Purge it.
diffRange :: Range -> Range -> Range diffRange :: Range -> Range -> Range
diffRange (Range ws wf) (Range ps _) = Range (max ws ps) wf diffRange (Range ws wf f) (Range ps _ _) = Range (max ws ps) wf f
instance Pretty Range where instance Pretty Range where
pp (Range (ll, lc, _) (rl, rc, _)) = pp (Range (ll, lc, _) (rl, rc, _) f) =
color 2 do color 2 do
brackets do brackets do
int ll <> ":" <> int lc <> "-" <> int rl <> ":" <> int rc text f <> ":"
<> int ll <> ":"
<> int lc <> "-"
<> int rl <> ":"
<> int rc
-- | Ability to get range out of something. -- | Ability to get range out of something.
class HasRange a where class HasRange a where
@ -49,17 +56,17 @@ instance Contains Range xs => HasRange (Product xs) where
-- | Extract textual representation of given range. -- | Extract textual representation of given range.
cutOut :: Range -> ByteString -> Text cutOut :: Range -> ByteString -> Text
cutOut (Range (_, _, s) (_, _, f)) bs = cutOut (Range (_, _, s) (_, _, f) _) bs =
decodeUtf8 decodeUtf8
$ BS.take (f - s) $ BS.take (f - s)
$ BS.drop s $ BS.drop s
bs bs
instance Lattice Range where instance Lattice Range where
Range (ll1, lc1, _) (ll2, lc2, _) <? Range (rl1, rc1, _) (rl2, rc2, _) = Range (ll1, lc1, _) (ll2, lc2, _) _ <? Range (rl1, rc1, _) (rl2, rc2, _) _ =
(rl1 < ll1 || rl1 == ll1 && rc1 <= lc1) && (rl1 < ll1 || rl1 == ll1 && rc1 <= lc1) &&
(rl2 > ll2 || rl2 == ll2 && rc2 >= lc2) (rl2 > ll2 || rl2 == ll2 && rc2 >= lc2)
instance Eq Range where instance Eq Range where
Range (l, c, _) (r, d, _) == Range (l1, c1, _) (r1, d1, _) = Range (l, c, _) (r, d, _) f == Range (l1, c1, _) (r1, d1, _) f1 =
(l, c, r, d) == (l1, c1, r1, d1) (l, c, r, d, f) == (l1, c1, r1, d1, f1)

View File

@ -40,7 +40,8 @@ extra-deps:
- lingo-0.3.2.0@sha256:80b9ded65f2ddc0272a2872d9c3fc43c37934accae076d3e547dfc6c6b6e16d3,1899 - lingo-0.3.2.0@sha256:80b9ded65f2ddc0272a2872d9c3fc43c37934accae076d3e547dfc6c6b6e16d3,1899
- semilattices-0.0.0.4@sha256:333707e460923711d1edbdd02ebe1c3957d4e0808eab9886747b52ee3e443639,1909 - semilattices-0.0.0.4@sha256:333707e460923711d1edbdd02ebe1c3957d4e0808eab9886747b52ee3e443639,1909
- fastsum-0.1.1.1 - fastsum-0.1.1.1
- git: https://github.com/Heimdell/dual-effects.git
commit: dc3e8bcd0aa00b9264e86293ec42c0b5835e930c
# - acme-missiles-0.3 # - acme-missiles-0.3
# - git: https://github.com/commercialhaskell/stack.git # - git: https://github.com/commercialhaskell/stack.git
# commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a # commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a

View File

@ -39,6 +39,20 @@ packages:
sha256: 1c89d4034e6d06e15ff0ec421a95206c030ddc2d35b9eee7f0a02aa30c6051c1 sha256: 1c89d4034e6d06e15ff0ec421a95206c030ddc2d35b9eee7f0a02aa30c6051c1
original: original:
hackage: fastsum-0.1.1.1 hackage: fastsum-0.1.1.1
- completed:
cabal-file:
size: 1569
sha256: 828a5bc60b97347d491038b435da664ae281a6dab26e9beb261d319c2601c4dc
name: eff
version: 0.0.0
git: https://github.com/Heimdell/dual-effects.git
pantry-tree:
size: 972
sha256: 4443705f2fc31929822a3cda4036f9a93950686f4729cd28280253e981828391
commit: dc3e8bcd0aa00b9264e86293ec42c0b5835e930c
original:
git: https://github.com/Heimdell/dual-effects.git
commit: dc3e8bcd0aa00b9264e86293ec42c0b5835e930c
snapshots: snapshots:
- completed: - completed:
size: 493124 size: 493124