-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathParserPlus.hs
243 lines (209 loc) · 5.59 KB
/
ParserPlus.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
module ParserPlus where
import CorePlus
import Control.Monad
import Data.List
import qualified Data.Map.Strict as M
import Text.Parsec
import Text.Parsec.Char
import Text.Parsec.Combinator (many1)
type Ctx = [String]
type Ref = M.Map String Term
type PState = (Ctx, Ref)
type Term' = [Term] -> Term
type Parser u a = Parsec String u a
which :: Parser u a -> Parser u b -> Parser u (Either a b)
which p q = (Left <$> p) <|> (Right <$> q)
tokn :: Parser u a -> Parser u a
tokn p = do
a <- p
spaces
return a
reserved :: String -> Parser u String
reserved s = tokn $ try $ string s
keywords = ["new", "use1", "use2", "rec", "let", "def", "Typ"]
name :: Bool -> Parser u String
name empty = tokn $ do
nam <- (if empty then many else many1) alphaNum
case find (nam ==) keywords of
Just nam -> fail $ nam ++ " is a keyword."
Nothing -> return nam
delim :: Parser u a -> String -> String -> Parser u a
delim p delim1 delim2 = tokn $ do
reserved delim1
a <- p
reserved delim2
return a
parens p = delim p "(" ")"
parens' p = delim p "<" ">"
bind :: Parser PState (String, Term')
bind = do
nam <- name True
reserved ":"
bnd <- term
return (nam, bnd)
trycomma :: Parser u Bool
trycomma = do
c <- reserved ","
return $ c == ","
binds :: Parser PState ([String], [Term'])
binds = do
(nam, bnd) <- bind
comma <- option False trycomma
if comma
then do
(nams, bnds) <- binds
return $ (nam : nams, bnd : bnds)
else
return ([nam], [bnd])
vars :: Parser PState [String]
vars = do
var <- name True
comma <- option False trycomma
if comma
then do
rest <- vars
return $ var : rest
else
return [var]
terms :: Parser PState [Term']
terms = do
trm <- term
comma <- option False trycomma
if comma
then do
rest <- terms
return $ trm : rest
else
return [trm]
pTyp :: Parser PState Term'
pTyp = do
reserved "Type"
return $ \_ -> Typ
pVar :: Parser PState Term'
pVar = do
nam <- name False
(ctx, refs) <- getState
case (findIndex (== nam) ctx, M.lookup nam refs) of
(Just idx, _) -> return $ \clos -> clos !! idx
(_, Just trm) -> return $ \clos -> trm
(_, _) -> fail $ "Unbound variable " ++ nam
pLam :: Parser PState Term'
pLam = do
x <- try $ which (parens vars) (parens' vars)
let (eras, ctx') = case x of
Left ctx' -> (False, reverse ctx')
Right ctx' -> (True, reverse ctx')
(ctx, trms) <- getState
modifyState $ \(ctx, trms) -> (ctx' ++ ctx, trms)
bod <- term
putState (ctx, trms)
let traverse bod nam = \ctx -> Lam eras nam $ \x -> bod (x : ctx)
return $ foldl traverse bod ctx'
pAll :: Parser PState Term'
pAll = do
x <- try $ which (parens binds) (parens' binds)
reserved "->"
let (eras, ctx', bnds) = case x of
Left (ctx', bnds) -> (False, reverse ctx', reverse bnds)
Right (ctx', bnds) -> (True, reverse ctx', reverse bnds)
(ctx, trms) <- getState
modifyState $ \(ctx, trms) -> (ctx' ++ ctx, trms)
bod <- term
putState (ctx, trms)
let traverse bod (nam, bnd) = \ctx -> All eras nam (bnd ctx) $ \x -> bod (x : ctx)
return $ foldl traverse bod $ zip ctx' bnds
pFix :: Parser PState Term'
pFix = do
reserved "rec "
nam <- name False
reserved "."
(ctx, trms) <- getState
modifyState $ \(ctx, trms) -> (nam : ctx, trms)
bod <- term
putState (ctx, trms)
return $ \ctx -> Fix nam $ \x -> bod (x : ctx)
pSec :: Parser PState Term'
pSec = do
reserved "${"
(nam, bnd) <- bind
reserved "}"
(ctx, trms) <- getState
modifyState $ \(ctx, trms) -> (nam : ctx, trms)
bod <- term
putState (ctx, trms)
return $ \ctx -> Sec nam (bnd ctx) $ \x -> bod (x : ctx)
pNew :: Parser PState Term'
pNew = do
reserved "new("
trm <- term
reserved ")"
return $ \ctx -> New $ trm ctx
pUs1 :: Parser PState Term'
pUs1 = do
reserved "use1("
trm <- term
reserved ")"
return $ \ctx -> New $ trm ctx
pUs2 :: Parser PState Term'
pUs2 = do
reserved "use2("
trm <- term
reserved ")"
return $ \ctx -> New $ trm ctx
pAnn :: Parser PState Term'
pAnn = try $ parens $ do
trm <- term
reserved "::"
bnd <- term
return $ \ctx -> (Ann False (trm ctx) (bnd ctx))
pApp :: Parser PState (Term' -> Term')
pApp = do
x <- try $ which (parens terms) (parens' terms)
let (eras, args) = case x of
Left args -> (False, args)
Right args -> (True, args)
let traverse func arg = \ctx -> App eras (func ctx) (arg ctx)
return $ \func -> foldl traverse func args
pCom :: Parser PState ()
pCom = do
reserved "/*"
manyTill anyChar (reserved "*/")
return ()
term :: Parser PState Term'
term = do
let prim = pAnn <|> pLam <|> pAll <|> pFix <|> pSec <|> pTyp <|> pNew <|> pUs1 <|> pUs2
let app = pVar <|> parens term
trm <- which prim app
case trm of
Left trm -> return trm
Right func -> do
conts <- many pApp
return $ foldl (flip ($)) func conts
def :: Parser PState (String, Term, Term)
def = do
nam <- name False
reserved ":"
typ <- term
reserved "="
modifyState $ \(_, trms) -> ([], trms)
trm <- term
let def = Ann False (trm []) (typ [])
modifyState $ \(_, trms) -> ([], M.insert nam def trms)
return (nam, trm [], typ [])
defs :: Parser PState [(String, Term, Term)]
defs = do
pCom <|> return ()
ref <- def
refs <- option [] $ try defs
return $ ref : refs
runFile :: SourceName -> String -> Either ParseError [(String, Term, Term)]
runFile srcnam src = runParser p ([], M.empty) srcnam src
where p = do
spaces
refs <- defs
pCom <|> return ()
eof
return refs
parseTrm src = case runParser term ([], M.empty) "" src of
Left err -> error $ show err
Right trm -> trm []