sparsec

simple Haskell parser combinator library
git clone git://git.rr3.xyz/sparsec
Log | Files | Refs | README | LICENSE

commit 06dc23fb745d06ba346bdb643fc43358a9d9a3b3
parent 4affd9f8a6c7c6e1b4a10c092c04c937d6ef2f38
Author: Robert Russell <robert@rr3.xyz>
Date:   Sun, 14 Dec 2025 11:31:05 -0800

Make exports explicit, and add/update char/rune predicates

Diffstat:
MSparsec.hs | 189++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
1 file changed, 159 insertions(+), 30 deletions(-)

diff --git a/Sparsec.hs b/Sparsec.hs @@ -1,4 +1,94 @@ -module Sparsec where +module Sparsec ( + -- Char + charIsUpperLatin, + charIsLowerLatin, + charIsLatin, + charIsUpperGreek, + charIsLowerGreek, + charIsGreek, + charIsSafeUpperGreek, + charIsSafeLowerGreek, + charIsSafeGreek, + charIsNum2, + charIsNum4, + charIsNum8, + charIsNum10, + charIsNum16, + -- Rune + Rune (..), + runeElim, + runeIsUpperLatin, + runeIsLowerLatin, + runeIsLatin, + runeIsUpperGreek, + runeIsLowerGreek, + runeIsGreek, + runeIsSafeUpperGreek, + runeIsSafeLowerGreek, + runeIsSafeGreek, + runeIsNum2, + runeIsNum4, + runeIsNum8, + runeIsNum10, + runeIsNum16, + -- Loc + Loc (..), + locZero, + -- Span + Span (..), + -- Result + Result (..), + -- Parse monad + ParseT (..), + runParseT, + mapParseT, + Parse, + runParse, + mapParse, + -- Core combinators + read, + write, + getLoc, + putLoc, + save, + load, + fail, + notp, + err, + catch, + -- Derived combinators + eof, + lookahead, + spanOf, + bytesOf, + cut, + try, + iter, + chainl, + chainr, + branch, + choice, + match, + someSepBy, + manySepBy, + -- TODO: Byte combinators + -- Utf8 combinators + Utf8Error (..), + nextRune, + nextChar, + runeIfM, + runeIf, + charIfM, + charIf, + runeWhileM, + runeWhile, + charWhileM, + charWhile, + rune, + char, + string, + natural, +) where import Control.Applicative import Control.Monad hiding (fail) @@ -16,7 +106,33 @@ import Text.Printf import Prelude hiding (fail, read) -------------------------------------------------------------------------------- +-- Char + +charIsUpperLatin, charIsLowerLatin, charIsLatin :: Char -> Bool +charIsUpperLatin c = 'A' <= c && c <= 'Z' +charIsLowerLatin c = 'a' <= c && c <= 'z' +charIsLatin c = charIsUpperLatin c || charIsLowerLatin c + +charIsUpperGreek, charIsLowerGreek, charIsGreek :: Char -> Bool +charIsUpperGreek c = 'Α' <= c && c <= 'Ω' +charIsLowerGreek c = 'α' <= c && c <= 'ω' +charIsGreek c = charIsUpperGreek c || charIsLowerGreek c + +charIsSafeUpperGreek, charIsSafeLowerGreek, charIsSafeGreek :: Char -> Bool +charIsSafeUpperGreek c = c == 'Γ' || c == 'Δ' || c == 'Θ' || c == 'Λ' || c == 'Ξ' || c == 'Π' || c == 'Σ' || c == 'Φ' || c == 'Ψ' || c == 'Ω' +charIsSafeLowerGreek c = charIsLowerGreek c && c /= 'ο' +charIsSafeGreek c = charIsSafeUpperGreek c || charIsSafeLowerGreek c + +charIsNum2, charIsNum4, charIsNum8, charIsNum10, charIsNum16 :: Char -> Bool +charIsNum2 c = '0' <= c && c <= '1' +charIsNum4 c = '0' <= c && c <= '3' +charIsNum8 c = '0' <= c && c <= '7' +charIsNum10 c = '0' <= c && c <= '9' +charIsNum16 c = '0' <= c && c <= '9' || 'A' <= c && c <= 'F' || 'a' <= c && c <= 'f' + +-------------------------------------------------------------------------------- -- Rune +-- TODO: Are runes bloat? Should we delete them? data Rune = RuneEof | RuneChar Char deriving (Eq) @@ -30,14 +146,27 @@ runeElim eof chr = \case RuneEof -> eof RuneChar c -> chr c -runeIsSpace :: Rune -> Bool -runeIsSpace = runeElim False isSpace +runeIsUpperLatin, runeIsLowerLatin, runeIsLatin :: Rune -> Bool +runeIsUpperLatin = runeElim False charIsUpperLatin +runeIsLowerLatin = runeElim False charIsLowerLatin +runeIsLatin = runeElim False charIsLatin -runeIsLetter :: Rune -> Bool -runeIsLetter = runeElim False isLetter +runeIsUpperGreek, runeIsLowerGreek, runeIsGreek :: Rune -> Bool +runeIsUpperGreek = runeElim False charIsUpperGreek +runeIsLowerGreek = runeElim False charIsLowerGreek +runeIsGreek = runeElim False charIsGreek -runeIsDigit :: Rune -> Bool -runeIsDigit = runeElim False isDigit +runeIsSafeUpperGreek, runeIsSafeLowerGreek, runeIsSafeGreek :: Rune -> Bool +runeIsSafeUpperGreek = runeElim False charIsSafeUpperGreek +runeIsSafeLowerGreek = runeElim False charIsSafeLowerGreek +runeIsSafeGreek = runeElim False charIsSafeGreek + +runeIsNum2, runeIsNum4, runeIsNum8, runeIsNum10, runeIsNum16 :: Rune -> Bool +runeIsNum2 = runeElim False charIsNum2 +runeIsNum4 = runeElim False charIsNum4 +runeIsNum8 = runeElim False charIsNum8 +runeIsNum10 = runeElim False charIsNum10 +runeIsNum16 = runeElim False charIsNum16 -------------------------------------------------------------------------------- -- Loc @@ -122,6 +251,29 @@ runParse (ParseT f) input loc = runIdentity $ f input loc mapParse :: (Result e a -> Result e' a') -> Parse e a -> Parse e' a' mapParse f = mapParseT (Identity . f . runIdentity) +-- handle generalizes the following: +-- (<|>): provide a continuation for failure +-- catch: provide a continuation for error +-- (>>=): provide a continuation for ok +-- handle let's you specify a continuation for all three cases. +-- handle :: (Monad m) => ParseT e' m a' -> (e -> ParseT e' m a') -> (a -> ParseT e' m a') -> ParseT e m a -> ParseT e' m a' +-- handle hf he ho p = ParseT \input loc -> +-- runParseT p input loc >>= \case +-- Failure -> runParseT hf input loc +-- Error e -> runParseT (he e) input loc +-- Ok a input' loc' -> runParseT (ho a) input' loc' +-- bind2 :: (Monad m) => (a -> ParseT e m a') -> ParseT e m a -> ParseT e m a' +-- bind2 h = handle fail err h +-- catch2 :: (Monad m) => (e -> ParseT e' m a) -> ParseT e m a -> ParseT e' m a +-- catch2 h = handle fail h pure +-- alt2 :: (Monad m) => ParseT e m a -> ParseT e m a -> ParseT e m a +-- alt2 h = handle h err pure +-- branch2 :: (Monad m) => ParseT e m a' -> (a -> ParseT e m a') -> ParseT e m a -> ParseT e m a' +-- branch2 hf ho = handle hf err ho +-- -- TODO: Rename Ok to Success +-- succeed :: (Monad m) => a -> ParseT e m a +-- succeed = pure + instance (Monad m) => Functor (ParseT e m) where fmap = liftM @@ -206,29 +358,6 @@ p `catch` h = ParseT \input loc -> Error e -> runParseT (h e) input loc Ok a input' loc' -> pure $ Ok a input' loc' --- handle generalizes the following: --- (<|>): provide a continuation for failure --- catch: provide a continuation for error --- (>>=): provide a continuation for ok --- handle let's you specify a continuation for all three cases. --- handle :: (Monad m) => ParseT e' m a' -> (e -> ParseT e' m a') -> (a -> ParseT e' m a') -> ParseT e m a -> ParseT e' m a' --- handle hf he ho p = ParseT \input loc -> --- runParseT p input loc >>= \case --- Failure -> runParseT hf input loc --- Error e -> runParseT (he e) input loc --- Ok a input' loc' -> runParseT (ho a) input' loc' --- bind2 :: (Monad m) => (a -> ParseT e m a') -> ParseT e m a -> ParseT e m a' --- bind2 h = handle fail err h --- catch2 :: (Monad m) => (e -> ParseT e' m a) -> ParseT e m a -> ParseT e' m a --- catch2 h = handle fail h pure --- alt2 :: (Monad m) => ParseT e m a -> ParseT e m a -> ParseT e m a --- alt2 h = handle h err pure --- branch2 :: (Monad m) => ParseT e m a' -> (a -> ParseT e m a') -> ParseT e m a -> ParseT e m a' --- branch2 hf ho = handle hf err ho --- -- TODO: Rename Ok to Success --- succeed :: (Monad m) => a -> ParseT e m a --- succeed = pure - -------------------------------------------------------------------------------- -- General combinators