Add ability to recursively parse #included files
This commit is contained in:
parent
583d7f8997
commit
b35a28853b
@ -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)
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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"
|
||||||
|
@ -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
|
||||||
|
@ -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 <> "▓"
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
@ -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)
|
@ -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)
|
@ -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
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user