diff options
author | Camil Staps | 2017-07-30 11:35:16 +0200 |
---|---|---|
committer | Camil Staps | 2017-07-30 11:35:16 +0200 |
commit | c5c4788b282a371fdc989e2d13430701f3457441 (patch) | |
tree | 156653073824d4e6a770d33072b0af558723f51e /Sil/Util/Parser.icl | |
parent | Add positions to Statements (diff) |
Better errors
Diffstat (limited to 'Sil/Util/Parser.icl')
-rw-r--r-- | Sil/Util/Parser.icl | 49 |
1 files changed, 34 insertions, 15 deletions
diff --git a/Sil/Util/Parser.icl b/Sil/Util/Parser.icl index 92bc08f..e730313 100644 --- a/Sil/Util/Parser.icl +++ b/Sil/Util/Parser.icl @@ -14,6 +14,8 @@ import Data.Maybe import Sil.Error +instance getPos ParsePosition where getPos pp = pp + :: *ParseState a = { ps_line :: Int , ps_input :: [ParseInput a] @@ -56,27 +58,31 @@ dropCommit ps = {ps & ps_commits=tl ps.ps_commits} restoreCommit :: (ParseState a) -> ParseState a restoreCommit ps=:{ps_commits=[c:cs]} = iter (ps.ps_pos - c) tokenBack {ps & ps_commits=cs} -instance Functor (Parser a) where +instance Functor (Parser a) +where fmap f m = liftM f m -instance Applicative (Parser a) where +instance Applicative (Parser a) +where pure a = Parser \st -> (Ok a, st) (<*>) sf p = ap sf p -instance Monad (Parser a) where +instance Monad (Parser a) +where bind p f = Parser \st -> case runParser p (commit st) of (Error e, st) -> (Error e, restoreCommit st) (Ok r, st) -> case runParser (f r) st of (Ok r, st) -> (Ok r, dropCommit st) (Error e, st) -> (Error e, restoreCommit st) -instance Alternative (Parser a) where +instance Alternative (Parser a) +where empty = Parser \st -> (Error $ UnknownError "empty in Parser", st) (<|>) p1 p2 = Parser \st -> case runParser p1 (commit st) of (Ok r, st) -> (Ok r, dropCommit st) (Error e1, st) -> case runParser p2 (commit $ restoreCommit st) of (Ok r, st) -> (Ok r, dropCommit st) - (Error e2, st) -> (Error e2, restoreCommit st) + (Error e2, st) -> (Error $ max e1 e2, restoreCommit st) instance name String where name s = s @@ -87,13 +93,16 @@ runParser :: (Parser a b) *(ParseState a) -> *(MaybeError Error b, *ParseState a runParser (Parser f) i = f i getPosition :: Parser a ParsePosition -getPosition = Parser \st=:{ps_line} -> (Ok {pp_line=ps_line}, st) +getPosition = Parser \st=:{ps_line,ps_pos} -> (Ok {pp_line=ps_line,pp_token=ps_pos}, st) (<?>) :: (Parser a b) Error -> Parser a b (<?>) p e = Parser \i -> case runParser p i of (Error _, st) -> (Error e, st) o -> o +(<#>) :: (Parser a b) String -> Parser a b | toString a +(<#>) p what = p <|> (getPosition >>= \pos -> peek >>= \e -> Parser \st -> (Error $ P_Expected (errpos pos) what e, st)) + fail :: Parser a b fail = empty @@ -128,18 +137,28 @@ where (Error e, st) -> (Error e, st) (Ok r, st) -> (Ok r, st) -item :: a -> Parser a a | ==, name a -item a = satisfy ((==) a) <?> P_Expected (name a) +item :: a -> Parser a a | ==, name, toString a +item a = satisfy ((==) a) <#> name a -list :: [a] -> Parser a [a] | ==, name a +list :: [a] -> Parser a [a] | ==, name, toString a list as = mapM item as -seplist :: a (Parser a b) -> Parser a [b] | ==, name a -seplist sep p = liftM2 (\es e-> es ++ [e]) (some (p <* item sep)) p - <|> liftM pure p +seplist :: a (Parser a b) -> Parser a [b] | ==, name, toString a +seplist sep p = liftM2 (\e es -> [e:es]) p (many (p <* item sep)) <|> pure empty -eof :: Parser a () -eof = Parser \st -> case nextToken st of +seplistUntil :: a a (Parser a b) -> Parser a [b] | ==, name, toString a +seplistUntil end sep p = + liftM2 (\e es -> [e:es]) p ((item sep *> p) until` (item end)) + <|> liftM pure (p <* item end) + <|> (pure empty <* item end) +where + (until`) infix 2 :: (Parser a b) (Parser a c) -> Parser a [b] + (until`) p1 guard = (p1 until guard) >>= \xs -> case xs of + [] -> fail + xs -> pure xs + +eof :: Parser a () | toString a +eof = Parser \st=:{ps_line,ps_pos} -> case nextToken st of (Nothing, st) -> (Ok (), st) - (t, st) -> (Error $ P_Expected "eof", st) + (Just t, st) -> (Error $ P_Expected (errpos {pp_line=ps_line,pp_token=ps_pos}) "eof" t, st) |