cleanup
[minfp.git] / parse.icl
1 implementation module parse
2
3 import Control.Applicative
4 import Control.Monad
5 import Control.Monad.State
6 import Control.Monad.Trans
7 import Data.Either
8 import Data.GenEq
9 import Data.Functor
10 import Data.Func
11 import Data.List
12 import Text.GenPrint
13 import StdEnv
14
15 import ast
16
17 (<:>) infixl 0 :: a (m [a]) -> m [a] | Functor m
18 (<:>) l r = (\xs->[l:xs]) <$> r
19
20 :: Token = TTEq | TTSemiColon | TTLambda | TTDot | TTBrackOpen | TTBrackClose | TTBool Bool | TTInt Int | TTOp [Char] | TTIdent [Char]
21
22 derive gEq Token
23 derive gPrint Token
24
25 instance toString Token where toString t = printToString t
26
27 lex :: [Char] -> Either [String] [Token]
28 lex [] = pure []
29 lex [';':ts] = TTSemiColon <:> lex ts
30 lex [')':ts] = TTBrackClose <:> lex ts
31 lex ['(':ts] = TTBrackOpen <:> lex ts
32 lex ['True':ts] = TTBool True <:> lex ts
33 lex ['False':ts] = TTBool False <:> lex ts
34 lex ['-',t:ts]
35 | isDigit t = lex [t:ts] >>= \v->case v of
36 [TTInt i:rest] = Right [TTInt (~i):rest]
37 x = pure x
38 lex [t:ts]
39 | isSpace t = lex ts
40 | isDigit t
41 # (i, ts) = span isDigit [t:ts]
42 = TTInt (toInt (toString i)) <:> lex ts
43 | isAlpha t
44 # (i, ts) = span isAlpha [t:ts]
45 = TTIdent i <:> lex ts
46 | isOp t
47 # (i, ts) = span isOp [t:ts]
48 | i =: ['='] = TTEq <:> lex ts
49 | i =: ['.'] = TTDot <:> lex ts
50 | i =: ['\\'] = TTLambda <:> lex ts
51 = TTOp i <:> lex ts
52 = Left ["Unexpected: " +++ toString t +++ " ord: " +++ toString (toInt t)]
53 where
54 isOp c = isMember c ['!@#$%^&*=+/?-_|\\\'",<>.:']
55
56 :: Parser a :== StateT ParseState (Either [String]) a
57 :: ParseState =
58 { tokens :: [Token]
59 , ifxs :: [((Parser Expression) -> Parser Expression, Int)]
60 }
61
62 pTop :: Parser Token
63 pTop = getState >>= \s->case s.tokens of
64 [t:ts] = put {s & tokens=ts} >>| pure t
65 [] = liftT (Left ["Fully consumed input"])
66
67 pEof :: Parser ()
68 pEof = getState >>= \s->case s.tokens of
69 [] = pure ()
70 [t:ts] = liftT (Left ["Expected EOF but got ":map toString [t:ts]])
71
72 (?) infixl 9 :: (Parser a) (a -> Bool) -> Parser a
73 (?) p f = p >>= \v->if (f v) (pure v) empty
74
75 pToken :: (Token -> Parser Token)
76 pToken = (?) pTop o (===)
77
78 pChainl :: (Parser (a a -> a)) (Parser a) -> Parser a
79 pChainl op p = foldl (flip ($)) <$> p <*> many (flip <$> op <*> p)
80
81 pChainr :: (Parser (a a -> a)) (Parser a) -> Parser a
82 pChainr op p = flip ($) <$> p <*> (flip <$> op <*> pChainr op p) <|> p
83
84 parse :: [Token] -> Either [String] [Function]
85 parse ts = fst <$> runStateT (pAST <* pEof) {tokens=ts, ifxs=[]}
86 where
87 pAST :: Parser [Function]
88 pAST = many pFunction >>= mapM \(id, args, body)->Function id args <$
89 modify (\t->{t & tokens=body}) <*> pExpression <* pEof
90
91 pId = (\(TTIdent i)->i) <$> pTop ? (\t->t=:(TTIdent _))
92 pOp = (\(TTOp i)->i) <$> pTop ? (\t->t=:(TTOp _))
93
94 pFunction :: Parser ([Char], [[Char]], [Token])
95 pFunction
96 = (\x y z->(x, y, z))
97 <$> (pFunId <|> pId)
98 <*> many pId
99 <* pToken TTEq
100 <*> many (pTop ? ((=!=)TTSemiColon))
101 <* pToken TTSemiColon
102
103 pFunId :: Parser [Char]
104 pFunId = pOp
105 >>= \i->pChainr <$ pId ? ((==) ['ifxr']) <|> pChainl <$ pId ? ((==)['ifxl'])
106 >>= \p->(\(TTInt i)->i) <$> pTop ? (\t->t=:(TTInt _))
107 >>= \s->modify (\t->{t & ifxs=[(p (App o App (Var i) <$ pOp ? ((==)i)), s):t.ifxs]})
108 >>| pure i
109
110 pExpression :: Parser Expression
111 pExpression = getState >>= \{ifxs}->flip (foldr ($))
112 (map fst $ sortBy (on (<) snd) ifxs)
113 $ pChainl (pure App)
114 $ Lambda <$ pToken TTLambda <*> pId <* pToken TTDot <*> pExpression
115 <|> Var <$ pToken TTBrackOpen <*> pOp <* pToken TTBrackClose
116 <|> pToken TTBrackOpen *> pExpression <* pToken TTBrackClose
117 <|> (\(TTInt i)->Lit (Int i)) <$> pTop ? (\t->t=:(TTInt _))
118 <|> (\(TTBool i)->Lit (Bool i)) <$> pTop ? (\t->t=:(TTBool _))
119 <|> (\x->Var ['_':x]) <$ pId ? ((==)['code']) <*> pId
120 <|> Var <$> pId