@@ -5,9 +5,9 @@ Copyright :
5License : BSD3
5License : BSD3
6Maintainer : The Idris Community.
6Maintainer : The Idris Community.
8−{-# LANGUAGE CPP, ConstraintKinds, FlexibleInstances,
8+{-# LANGUAGE CPP, ConstraintKinds, FlexibleContexts, FlexibleInstances,
9 GeneralizedNewtypeDeriving, PatternGuards, StandaloneDeriving,
9 GeneralizedNewtypeDeriving, PatternGuards, StandaloneDeriving,
10− TypeSynonymInstances #-}
10+ TypeSynonymInstances, UndecidableInstances #-}
11module Idris.Parser.Helpers where
11module Idris.Parser.Helpers where
13import Idris.AbsSyntax
13import Idris.AbsSyntax
@@ -23,7 +23,6 @@ import Prelude hiding (pi)
23import Control.Applicative
23import Control.Applicative
24import Control.Monad
24import Control.Monad
25import Control.Monad.State.Strict
25import Control.Monad.State.Strict
26−import qualified Data.ByteString.UTF8 as UTF8
27import Data.Char
26import Data.Char
28import qualified Data.HashSet as HS
27import qualified Data.HashSet as HS
29import Data.List
28import Data.List
@@ -31,34 +30,40 @@ import qualified Data.Map as M
31import Data.Maybe
30import Data.Maybe
32import qualified Data.Text as T
31import qualified Data.Text as T
33import System.FilePath
32import System.FilePath
33+import Data.List.NonEmpty (fromList)
34−import qualified Text.Parser.Char as Chr
34+import qualified Text.Parser.Char
35−import Text.Parser.LookAhead
35+import qualified Text.Parser.Combinators
36import qualified Text.Parser.Token as Tok
36import qualified Text.Parser.Token as Tok
37import qualified Text.PrettyPrint.ANSI.Leijen as PP
37import qualified Text.PrettyPrint.ANSI.Leijen as PP
38−import Text.Trifecta ((<?>))
38+import Text.Megaparsec ((<?>))
39−import qualified Text.Trifecta as P
39+import qualified Text.Megaparsec as P
40−import qualified Text.Trifecta.Delta as P
40+import qualified Text.Megaparsec.Char as P
41+import qualified Text.Megaparsec.Char.Lexer as P hiding (space)
43+newtype ParseError = ParseError { parseErrorDoc :: PP.Doc }
42-- | Idris parser with state used during parsing
45-- | Idris parser with state used during parsing
43−type IdrisParser = StateT IState P.Parser
46+type IdrisParser = StateT IState IdrisInnerParser
44−
47+type IdrisInnerParser = P.Parsec () String
45−#if MIN_VERSION_base(4,9,0)
48+type ParseState = P.State String
46−instance {-# OVERLAPPING #-} P.DeltaParsing IdrisParser where
49+
47− line = lift P.line
50+-- | Generalized monadic parsing constraint type
48− {-# INLINE line #-}
51+type MonadicParsing m = (P.MonadParsec () String m, Tok.TokenParsing m)
49− position = lift P.position
50− {-# INLINE position #-}
51− slicedWith f (StateT m) = StateT $ \s -> P.slicedWith (\(a,s') b -> (f a b, s')) $ m s
52− {-# INLINE slicedWith #-}
55− restOfLine = lift P.restOfLine
56− {-# INLINE restOfLine #-}
59someSpace' :: MonadicParsing m => m ()
53someSpace' :: MonadicParsing m => m ()
60someSpace' = many (simpleWhiteSpace <|> singleLineComment <|> multiLineComment) *> pure ()
54someSpace' = many (simpleWhiteSpace <|> singleLineComment <|> multiLineComment) *> pure ()
56+instance Text.Parser.Combinators.Parsing IdrisInnerParser where
58+ unexpected msg = P.unexpected . P.Label . fromList $ msg
60+ p <?> s = p <?> s --FIXME:?
61+ notFollowedBy = P.notFollowedBy
63+instance Text.Parser.Char.CharParsing IdrisInnerParser where
62instance {-# OVERLAPPING #-} Tok.TokenParsing IdrisParser where
67instance {-# OVERLAPPING #-} Tok.TokenParsing IdrisParser where
63 someSpace = someSpace'
68 someSpace = someSpace'
64 token p = do s <- get
69 token p = do s <- get
@@ -70,18 +75,12 @@ instance {-# OVERLAPPING #-} Tok.TokenParsing IdrisParser where
70 put (s { lastTokenSpan = Just (FC fn (sl, sc) (el, ec)) })
75 put (s { lastTokenSpan = Just (FC fn (sl, sc) (el, ec)) })
73−-- | Generalized monadic parsing constraint type
74−type MonadicParsing m = (P.DeltaParsing m, LookAheadParsing m, Monad m)
76−newtype ParseError = ParseError { parseErrorDoc :: PP.Doc }
78-- | Helper to run Idris inner parser based stateT parsers
78-- | Helper to run Idris inner parser based stateT parsers
79−runparser :: StateT st P.Parser res -> st -> String -> String -> Either ParseError res
79+runparser :: StateT st IdrisInnerParser res -> st -> String -> String -> Either ParseError res
80runparser p i inputname s =
80runparser p i inputname s =
81− case P.parseString (evalStateT p i)
81+ case P.parse (evalStateT p i) inputname s of
82− (P.Directed (UTF8.fromString inputname) 0 0 0 0) s of
83− P.Failure (P.ErrInfo doc _) -> Left (ParseError doc)
82+ Left _ -> Left $ ParseError undefined --FIXME:
84− P.Success value -> Right value
83+ Right value -> Right value
86highlightP :: FC -> OutputAnnotation -> IdrisParser ()
85highlightP :: FC -> OutputAnnotation -> IdrisParser ()
87highlightP fc annot = do ist <- get
86highlightP fc annot = do ist <- get
@@ -130,7 +129,7 @@ isEol _ = False
131-- | A parser that succeeds at the end of the line
130-- | A parser that succeeds at the end of the line
132eol :: MonadicParsing m => m ()
131eol :: MonadicParsing m => m ()
133−eol = () <$ P.satisfy isEol <|> lookAhead P.eof <?> "end of line"
132+eol = () <$ P.satisfy isEol <|> P.lookAhead P.eof <?> "end of line"
135{- | Consumes a single-line comment
134{- | Consumes a single-line comment
@@ -202,14 +201,15 @@ docComment = do dc <- pushIndent *> docCommentLine
202 return contents)
201 return contents)
205− argDocCommentLine = do string "|||"
204+ argDocCommentLine :: IdrisParser (Name, String)
205+ argDocCommentLine = do P.string "|||"
206− many (P.satisfy isSpace)
206+ P.many (P.satisfy isSpace)
207− char '@'
207+ P.char '@'
208− many (P.satisfy isSpace)
208+ P.many (P.satisfy isSpace)
209 n <- fst <$> name
209 n <- fst <$> name
210− many (P.satisfy isSpace)
210+ P.many (P.satisfy isSpace)
211− docs <- many (P.satisfy (not . isEol))
211+ docs <- P.many (P.satisfy (not . isEol))
212− eol ; someSpace'
212+ P.eol ; someSpace'
213 return (n, docs)
213 return (n, docs)
215-- | Parses some white space
215-- | Parses some white space
@@ -254,30 +254,29 @@ reservedIdentifiers = HS.fromList
256identifierOrReserved :: MonadicParsing m => m String
256identifierOrReserved :: MonadicParsing m => m String
257−identifierOrReserved = P.token $ P.try $ do
257+identifierOrReserved = Tok.token $ P.try $ do
258 c <- P.satisfy isAlpha <|> P.oneOf "_"
258 c <- P.satisfy isAlpha <|> P.oneOf "_"
259 cs <- P.many (P.satisfy isAlphaNum <|> P.oneOf "_'.")
259 cs <- P.many (P.satisfy isAlphaNum <|> P.oneOf "_'.")
260 return $ c : cs
260 return $ c : cs
262char :: MonadicParsing m => Char -> m Char
262char :: MonadicParsing m => Char -> m Char
263−char = Chr.char
263+char = P.char
265string :: MonadicParsing m => String -> m String
265string :: MonadicParsing m => String -> m String
266−string = Chr.string
266+string = P.string
268-- | Parses a character as a token
268-- | Parses a character as a token
269lchar :: MonadicParsing m => Char -> m Char
269lchar :: MonadicParsing m => Char -> m Char
270−lchar = P.token . P.char
270+lchar = Tok.token . P.char
272-- | Parses a character as a token, returning the source span of the character
272-- | Parses a character as a token, returning the source span of the character
273lcharFC :: MonadicParsing m => Char -> m FC
273lcharFC :: MonadicParsing m => Char -> m FC
274lcharFC ch = do (FC file (l, c) _) <- getFC
274lcharFC ch = do (FC file (l, c) _) <- getFC
275− _ <- P.token (char ch)
275+ _ <- Tok.token (P.char ch)
276 return $ FC file (l, c) (l, c+1)
276 return $ FC file (l, c) (l, c+1)
278−-- | Parses string as a token
279symbol :: MonadicParsing m => String -> m ()
278symbol :: MonadicParsing m => String -> m ()
280−symbol = void . Tok.symbol
279+symbol = void . P.symbol someSpace'
282symbolFC :: MonadicParsing m => String -> m FC
281symbolFC :: MonadicParsing m => String -> m FC
283symbolFC str = do (FC file (l, c) _) <- getFC
282symbolFC str = do (FC file (l, c) _) <- getFC
@@ -286,7 +285,7 @@ symbolFC str = do (FC file (l, c) _) <- getFC
287-- | Parses a reserved identifier
286-- | Parses a reserved identifier
288reserved :: MonadicParsing m => String -> m ()
287reserved :: MonadicParsing m => String -> m ()
289−reserved name = P.token $ P.try $ do
288+reserved name = Tok.token $ P.try $ do
290 P.string name
289 P.string name
291 P.notFollowedBy (P.satisfy isAlphaNum <|> P.oneOf "_'.") <?> "end of " ++ name
290 P.notFollowedBy (P.satisfy isAlphaNum <|> P.oneOf "_'.") <?> "end of " ++ name
@@ -304,7 +303,7 @@ reservedHL str = reservedFC str >>= flip highlightP AnnKeyword
304-- Taken from Parsec (c) Daan Leijen 1999-2001, (c) Paolo Martini 2007
303-- Taken from Parsec (c) Daan Leijen 1999-2001, (c) Paolo Martini 2007
305-- | Parses a reserved operator
304-- | Parses a reserved operator
306reservedOp :: MonadicParsing m => String -> m ()
305reservedOp :: MonadicParsing m => String -> m ()
307−reservedOp name = P.token $ P.try $
306+reservedOp name = Tok.token $ P.try $
308 do string name
307 do string name
309 P.notFollowedBy operatorLetter <?> ("end of " ++ show name)
308 P.notFollowedBy operatorLetter <?> ("end of " ++ show name)
@@ -318,8 +317,8 @@ identifier :: (MonadicParsing m) => m (String, FC)
318identifier = P.try $ do
317identifier = P.try $ do
319 (FC f (l, c) _) <- getFC
318 (FC f (l, c) _) <- getFC
320 ident <- identifierOrReserved
319 ident <- identifierOrReserved
321− when (ident `HS.member` reservedIdentifiers) $ P.unexpected $ "reserved " ++ ident
320+ when (ident `HS.member` reservedIdentifiers) $ P.unexpected undefined --FIXME: $ "reserved " ++ ident
322− when (ident == "_") $ P.unexpected "wildcard"
321+ when (ident == "_") $ P.unexpected undefined --FIXME: "wildcard"
323 return (ident, FC f (l, c) (l, c + length ident))
322 return (ident, FC f (l, c) (l, c + length ident))
325-- | Parses an identifier with possible namespace as a name
324-- | Parses an identifier with possible namespace as a name
@@ -330,8 +329,8 @@ iName bad = maybeWithNS identifier False bad <?> "name"
330maybeWithNS :: (MonadicParsing m) => m (String, FC) -> Bool -> [String] -> m (Name, FC)
329maybeWithNS :: (MonadicParsing m) => m (String, FC) -> Bool -> [String] -> m (Name, FC)
331maybeWithNS parser ascend bad = do
330maybeWithNS parser ascend bad = do
332 fc <- getFC
331 fc <- getFC
333− i <- P.option "" (lookAhead (fst <$> identifier))
332+ i <- P.option "" (P.lookAhead (fst <$> identifier))
334− when (i `elem` bad) $ P.unexpected "reserved identifier"
333+ when (i `elem` bad) $ P.unexpected undefined --FIXME: "reserved identifier"
335 let transf = if ascend then id else reverse
334 let transf = if ascend then id else reverse
336 (x, xs, fc) <- P.choice (transf (parserNoNS parser : parsersNS parser i))
335 (x, xs, fc) <- P.choice (transf (parserNoNS parser : parsersNS parser i))
337 return (mkName (x, xs), fc)
336 return (mkName (x, xs), fc)
@@ -400,7 +399,7 @@ invalidOperators = [":", "=>", "->", "<-", "=", "?=", "|", "**", "==>", "\\", "%
401-- | Parses an operator
400-- | Parses an operator
402symbolicOperator :: MonadicParsing m => m String
401symbolicOperator :: MonadicParsing m => m String
403−symbolicOperator = do op <- P.token . some $ operatorLetter
402+symbolicOperator = do op <- Tok.token . some $ operatorLetter
404 when (op `elem` (invalidOperators ++ commentMarkers)) $
403 when (op `elem` (invalidOperators ++ commentMarkers)) $
405 fail $ op ++ " is not a valid operator"
404 fail $ op ++ " is not a valid operator"
406 return op
405 return op
@@ -412,32 +411,17 @@ symbolicOperatorFC = do (FC f (l, c) _) <- getFC
412 return (op, FC f (l, c) (l, c + length op))
411 return (op, FC f (l, c) (l, c + length op))
414{- * Position helpers -}
413{- * Position helpers -}
415−{- | Get filename from position (returns "(interactive)" when no source file is given) -}
416−fileName :: P.Delta -> String
417−fileName (P.Directed fn _ _ _ _) = UTF8.toString fn
418−fileName _ = "(interactive)"
420−{- | Get line number from position -}
421−lineNum :: P.Delta -> Int
422−lineNum (P.Lines l _ _ _) = fromIntegral l + 1
423−lineNum (P.Directed _ l _ _ _) = fromIntegral l + 1
426−{- | Get column number from position -}
427−columnNum :: P.Delta -> Int
428−columnNum pos = fromIntegral (P.column pos) + 1
431{- | Get file position as FC -}
414{- | Get file position as FC -}
432getFC :: MonadicParsing m => m FC
415getFC :: MonadicParsing m => m FC
433−getFC = do s <- P.position
416+getFC = do pos <- P.getPosition
417+ let columnNumber = P.unPos . P.sourceColumn $ pos
418+ let lineNumber = P.unPos . P.sourceLine $ pos
434− let (dir, file) = splitFileName (fileName s)
419+ let (dir, file) = splitFileName (P.sourceName pos)
435− let f = if dir == addTrailingPathSeparator "." then file else fileName s
420+ let f = if dir == addTrailingPathSeparator "." then file else P.sourceName pos
436− return $ FC f (lineNum s, columnNum s) (lineNum s, columnNum s) -- TODO: Change to actual spanning
421+ return $ FC f (lineNumber, columnNumber) (lineNumber, columnNumber) -- TODO: Change to actual spanning
437 -- Issue #1594 on the Issue Tracker.
422 -- Issue #1594 on the Issue Tracker.
438 -- https://github.com/idris-lang/Idris-dev/issues/1594
423 -- https://github.com/idris-lang/Idris-dev/issues/1594
441{-* Syntax helpers-}
425{-* Syntax helpers-}
442-- | Bind constraints to term
426-- | Bind constraints to term
443bindList :: (RigCount -> Name -> FC -> PTerm -> PTerm -> PTerm) -> [(RigCount, Name, FC, PTerm)] -> PTerm -> PTerm
427bindList :: (RigCount -> Name -> FC -> PTerm -> PTerm -> PTerm) -> [(RigCount, Name, FC, PTerm)] -> PTerm -> PTerm
@@ -447,15 +431,15 @@ bindList b ((r, n, fc, t):bs) sc = b r n fc t (bindList b bs sc)
447{- | @commaSeparated p@ parses one or more occurences of `p`,
431{- | @commaSeparated p@ parses one or more occurences of `p`,
448 separated by commas and optional whitespace. -}
432 separated by commas and optional whitespace. -}
449commaSeparated :: MonadicParsing m => m a -> m [a]
433commaSeparated :: MonadicParsing m => m a -> m [a]
450−commaSeparated p = p `P.sepBy1` (P.spaces >> P.char ',' >> P.spaces)
434+commaSeparated p = p `P.sepBy1` (P.space >> P.char ',' >> P.space)
452{- * Layout helpers -}
436{- * Layout helpers -}
454-- | Push indentation to stack
438-- | Push indentation to stack
455pushIndent :: IdrisParser ()
439pushIndent :: IdrisParser ()
456−pushIndent = do pos <- P.position
440+pushIndent = do columnNumber <- indent
457 ist <- get
441 ist <- get
458− put (ist { indent_stack = (fromIntegral (P.column pos) + 1) : indent_stack ist })
442+ put (ist { indent_stack = columnNumber : indent_stack ist })
460-- | Pops indentation from stack
444-- | Pops indentation from stack
461popIndent :: IdrisParser ()
445popIndent :: IdrisParser ()
@@ -466,8 +450,8 @@ popIndent = do ist <- get
468-- | Gets current indentation
452-- | Gets current indentation
469−indent :: IdrisParser Int
453+indent :: MonadicParsing m => m Int
470−indent = liftM ((+1) . fromIntegral . P.column) P.position
454+indent = P.unPos . P.sourceColumn <$> P.getPosition
472-- | Gets last indentation
456-- | Gets last indentation
473lastIndent :: IdrisParser Int
457lastIndent :: IdrisParser Int
@@ -510,8 +494,7 @@ indentedBlockS p = do openBlock
511-- | Checks if the following character matches provided parser
495-- | Checks if the following character matches provided parser
512lookAheadMatches :: MonadicParsing m => m a -> m Bool
496lookAheadMatches :: MonadicParsing m => m a -> m Bool
513−lookAheadMatches p = do match <- lookAhead (optional p)
497+lookAheadMatches p = isJust <$> P.lookAhead (P.optional p)
514− return $ isJust match
516-- | Parses a start of block
499-- | Parses a start of block
517openBlock :: IdrisParser ()
500openBlock :: IdrisParser ()
@@ -555,7 +538,7 @@ terminator = do lchar ';'; popIndent
555 if c <= l then popIndent else fail "not a terminator"
538 if c <= l then popIndent else fail "not a terminator"
556 <|> do isParen <- lookAheadMatches (P.oneOf ")}")
539 <|> do isParen <- lookAheadMatches (P.oneOf ")}")
557 if isParen then popIndent else fail "not a terminator"
540 if isParen then popIndent else fail "not a terminator"
558− <|> lookAhead P.eof
541+ <|> P.lookAhead P.eof
560-- | Parses and keeps a terminator
543-- | Parses and keeps a terminator
561keepTerminator :: IdrisParser ()
544keepTerminator :: IdrisParser ()
@@ -565,7 +548,7 @@ keepTerminator = () <$ lchar ';'
565 <|> do isParen <- lookAheadMatches (P.oneOf ")}|")
548 <|> do isParen <- lookAheadMatches (P.oneOf ")}|")
566 isIn <- lookAheadMatches (reserved "in")
549 isIn <- lookAheadMatches (reserved "in")
567 unless (isIn || isParen) $ fail "not a terminator"
550 unless (isIn || isParen) $ fail "not a terminator"
568− <|> lookAhead P.eof
551+ <|> P.lookAhead P.eof
570-- | Checks if application expression does not end
553-- | Checks if application expression does not end
571notEndApp :: IdrisParser ()
554notEndApp :: IdrisParser ()
@@ -577,7 +560,7 @@ notEndBlock :: IdrisParser ()
577notEndBlock = do ist <- get
560notEndBlock = do ist <- get
578 case brace_stack ist of
561 case brace_stack ist of
579 Just lvl : xs -> do i <- indent
562 Just lvl : xs -> do i <- indent
580− isParen <- lookAheadMatches (char ')')
563+ isParen <- lookAheadMatches (P.char ')')
581 when (i < lvl || isParen) (fail "end of block")
564 when (i < lvl || isParen) (fail "end of block")
582 _ -> return ()
565 _ -> return ()