1- module Bot.Expr
2- ( parseExprs
3- , interpretExprs
4- ) where
1+ {-# LANGUAGE DeriveFunctor #-}
2+ {-# LANGUAGE OverloadedStrings #-}
53
4+ module Bot.Expr where
5+
6+ import Control.Applicative
7+ import Data.Char
68import qualified Data.Text as T
9+ import Data.Tuple
710import Effect
811
912data Expr
@@ -13,10 +16,108 @@ data Expr
1316 | VarExpr T. Text
1417 deriving (Eq , Show )
1518
16- -- TODO(#599): parseExprs is not implemented
17- parseExprs :: T. Text -> Either String [Expr ]
18- parseExprs = undefined
19+ type NameTable = ()
20+
21+ data ParserStop
22+ = EOF
23+ | SyntaxError T. Text
24+ deriving (Eq , Show )
25+
26+ newtype Parser a = Parser
27+ { runParser :: T. Text -> Either ParserStop (T. Text , a )
28+ } deriving (Functor )
29+
30+ instance Applicative Parser where
31+ pure x = Parser $ \ text -> Right (text, x)
32+ (Parser f) <*> (Parser x) =
33+ Parser $ \ input1 -> do
34+ (input2, f') <- f input1
35+ (input3, x') <- x input2
36+ return (input3, f' x')
37+
38+ instance Monad Parser where
39+ Parser a >>= f =
40+ Parser $ \ input1 -> do
41+ (input2, b) <- a input1
42+ runParser (f b) input2
43+
44+ instance Alternative Parser where
45+ empty = Parser $ const $ Left EOF
46+ (Parser p1) <|> (Parser p2) =
47+ Parser $ \ input ->
48+ case (p1 input, p2 input) of
49+ (Left _, x) -> x
50+ (x, _) -> x
51+
52+ symbol :: Parser T. Text
53+ symbol = notNull " Symbol name cannot be empty" $ takeWhileP isAlphaNum
54+
55+ stringLiteral :: Parser Expr
56+ stringLiteral = do
57+ _ <- charP ' "'
58+ value <- takeWhileP (/= ' "' )
59+ _ <- charP ' "'
60+ return $ TextExpr value
61+
62+ sepBy :: Parser a -> Parser b -> Parser [a ]
63+ sepBy element sep = do
64+ arg <- element
65+ args <- many (sep >> element)
66+ return (arg : args)
67+
68+ funcall :: Parser Expr
69+ funcall = do
70+ _ <- charP ' %' >> whitespaces
71+ name <- symbol
72+ _ <- whitespaces >> charP ' (' >> whitespaces
73+ args <-
74+ sepBy (funcall <|> var <|> stringLiteral) (whitespaces >> charP ' ,' ) <|>
75+ return []
76+ _ <- whitespaces >> charP ' )'
77+ return $ FunCallExpr name args
78+
79+ charP :: Char -> Parser Char
80+ charP a =
81+ Parser $ \ input ->
82+ case T. uncons input of
83+ Just (b, rest)
84+ | a == b -> Right (rest, b)
85+ _ -> Left $ SyntaxError (" Expected `" <> T. pack [a] <> " `" )
86+
87+ takeWhileP :: (Char -> Bool ) -> Parser T. Text
88+ takeWhileP p = Parser $ \ input -> return $ swap $ T. span p input
89+
90+ syntaxError :: T. Text -> Parser a
91+ syntaxError message = Parser $ \ _ -> Left $ SyntaxError message
92+
93+ notNull :: T. Text -> Parser T. Text -> Parser T. Text
94+ notNull message next =
95+ next >>=
96+ (\ value ->
97+ if T. null value
98+ then syntaxError message
99+ else return value)
100+
101+ whitespaces :: Parser T. Text
102+ whitespaces = takeWhileP isSpace
103+
104+ var :: Parser Expr
105+ var = charP ' %' >> whitespaces >> (VarExpr <$> symbol)
106+
107+ textBlock :: Parser Expr
108+ textBlock =
109+ Parser $ \ input ->
110+ case T. uncons input of
111+ Nothing -> Left EOF
112+ Just (' %' , _) -> Left (SyntaxError " Text block does not start with %" )
113+ _ -> return $ fmap TextExpr $ swap $ T. span (/= ' %' ) input
114+
115+ expr :: Parser Expr
116+ expr = funcall <|> var <|> textBlock
117+
118+ exprs :: Parser [Expr ]
119+ exprs = many expr
19120
20121-- TODO(#600): interpretExprs is not implemented
21- interpretExprs :: [Expr ] -> Effect T. Text
122+ interpretExprs :: NameTable -> [Expr ] -> Effect T. Text
22123interpretExprs = undefined
0 commit comments