Skip to content

Commit c1a6729

Browse files
committed
(#801) Extract HyperNerd.Parser module
1 parent 7a21bcb commit c1a6729

File tree

4 files changed

+74
-61
lines changed

4 files changed

+74
-61
lines changed

HyperNerd.cabal

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ executable HyperNerd
9292
, Entity
9393
, HyperNerd.Comonad
9494
, HyperNerd.Functor
95+
, HyperNerd.Parser
9596
, Markov
9697
, Property
9798
, Reaction
@@ -160,6 +161,7 @@ executable Fuzzy
160161
main-is: FuzzyMain.hs
161162

162163
other-modules: Bot.Expr
164+
, HyperNerd.Parser
163165

164166
build-depends: base
165167
, text
@@ -264,6 +266,7 @@ test-suite HyperNerdTest
264266
, Data.Either.Extra
265267
, Free
266268
, Bot.Expr
269+
, HyperNerd.Parser
267270

268271
other-extensions: OverloadedStrings
269272

src/Bot/Expr.hs

Lines changed: 3 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
{-# LANGUAGE DeriveFunctor #-}
21
{-# LANGUAGE OverloadedStrings #-}
32

43
module Bot.Expr where
54

65
import Control.Applicative
6+
import Data.Tuple
77
import Data.Char
88
import qualified Data.Text as T
9-
import Data.Tuple
9+
10+
import HyperNerd.Parser
1011

1112
data Expr
1213
= TextExpr T.Text
@@ -17,37 +18,6 @@ data Expr
1718

1819
type NameTable = ()
1920

20-
data ParserStop
21-
= EOF
22-
| SyntaxError T.Text
23-
deriving (Eq, Show)
24-
25-
newtype Parser a = Parser
26-
{ runParser :: T.Text -> Either ParserStop (T.Text, a)
27-
} deriving (Functor)
28-
29-
instance Applicative Parser where
30-
pure x = Parser $ \text -> Right (text, x)
31-
(Parser f) <*> (Parser x) =
32-
Parser $ \input1 -> do
33-
(input2, f') <- f input1
34-
(input3, x') <- x input2
35-
return (input3, f' x')
36-
37-
instance Monad Parser where
38-
Parser a >>= f =
39-
Parser $ \input1 -> do
40-
(input2, b) <- a input1
41-
runParser (f b) input2
42-
43-
instance Alternative Parser where
44-
empty = Parser $ const $ Left EOF
45-
(Parser p1) <|> (Parser p2) =
46-
Parser $ \input ->
47-
case (p1 input, p2 input) of
48-
(Left _, x) -> x
49-
(x, _) -> x
50-
5121
symbol :: Parser T.Text
5222
symbol = notNull "Symbol name cannot be empty" $ takeWhileP isAlphaNum
5323

@@ -58,12 +28,6 @@ stringLiteral = do
5828
_ <- charP '"'
5929
return $ TextExpr value
6030

61-
sepBy :: Parser a -> Parser b -> Parser [a]
62-
sepBy element sep = do
63-
arg <- element
64-
args <- many (sep >> element)
65-
return (arg : args)
66-
6731
funcallarg :: Parser Expr
6832
funcallarg = funcall <|> var <|> stringLiteral
6933

@@ -77,28 +41,6 @@ funcall = do
7741
_ <- whitespaces >> charP ')'
7842
return $ FunCallExpr name args
7943

80-
charP :: Char -> Parser Char
81-
charP a =
82-
Parser $ \input ->
83-
case T.uncons input of
84-
Just (b, rest)
85-
| a == b -> Right (rest, b)
86-
_ -> Left $ SyntaxError ("Expected `" <> T.pack [a] <> "`")
87-
88-
takeWhileP :: (Char -> Bool) -> Parser T.Text
89-
takeWhileP p = Parser $ \input -> return $ swap $ T.span p input
90-
91-
syntaxError :: T.Text -> Parser a
92-
syntaxError message = Parser $ \_ -> Left $ SyntaxError message
93-
94-
notNull :: T.Text -> Parser T.Text -> Parser T.Text
95-
notNull message next =
96-
next >>=
97-
(\value ->
98-
if T.null value
99-
then syntaxError message
100-
else return value)
101-
10244
whitespaces :: Parser T.Text
10345
whitespaces = takeWhileP isSpace
10446

src/FuzzyMain.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import System.Environment
1313
import System.Random
1414
import Text.Printf
1515
import qualified Data.ByteString.Lazy as BS
16+
import HyperNerd.Parser
1617

1718
data FuzzParams = FuzzParams
1819
{ fpFuzzCount :: Int

src/HyperNerd/Parser.hs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
{-# LANGUAGE OverloadedStrings #-}
2+
{-# LANGUAGE DeriveFunctor #-}
3+
4+
module HyperNerd.Parser where
5+
6+
import Control.Applicative
7+
import qualified Data.Text as T
8+
import Data.Tuple
9+
10+
data ParserStop
11+
= EOF
12+
| SyntaxError T.Text
13+
deriving (Eq, Show)
14+
15+
newtype Parser a = Parser
16+
{ runParser :: T.Text -> Either ParserStop (T.Text, a)
17+
} deriving (Functor)
18+
19+
instance Applicative Parser where
20+
pure x = Parser $ \text -> Right (text, x)
21+
(Parser f) <*> (Parser x) =
22+
Parser $ \input1 -> do
23+
(input2, f') <- f input1
24+
(input3, x') <- x input2
25+
return (input3, f' x')
26+
27+
instance Monad Parser where
28+
Parser a >>= f =
29+
Parser $ \input1 -> do
30+
(input2, b) <- a input1
31+
runParser (f b) input2
32+
33+
instance Alternative Parser where
34+
empty = Parser $ const $ Left EOF
35+
(Parser p1) <|> (Parser p2) =
36+
Parser $ \input ->
37+
case (p1 input, p2 input) of
38+
(Left _, x) -> x
39+
(x, _) -> x
40+
41+
sepBy :: Parser a -> Parser b -> Parser [a]
42+
sepBy element sep = do
43+
arg <- element
44+
args <- many (sep >> element)
45+
return (arg : args)
46+
47+
takeWhileP :: (Char -> Bool) -> Parser T.Text
48+
takeWhileP p = Parser $ \input -> return $ swap $ T.span p input
49+
50+
charP :: Char -> Parser Char
51+
charP a =
52+
Parser $ \input ->
53+
case T.uncons input of
54+
Just (b, rest)
55+
| a == b -> Right (rest, b)
56+
_ -> Left $ SyntaxError ("Expected `" <> T.pack [a] <> "`")
57+
58+
notNull :: T.Text -> Parser T.Text -> Parser T.Text
59+
notNull message next =
60+
next >>=
61+
(\value ->
62+
if T.null value
63+
then syntaxError message
64+
else return value)
65+
66+
syntaxError :: T.Text -> Parser a
67+
syntaxError message = Parser $ \_ -> Left $ SyntaxError message

0 commit comments

Comments
 (0)