summaryrefslogtreecommitdiff
path: root/src/LambdaCube/Compiler/Parser.hs
diff options
context:
space:
mode:
Diffstat (limited to 'src/LambdaCube/Compiler/Parser.hs')
-rw-r--r--src/LambdaCube/Compiler/Parser.hs345
1 files changed, 33 insertions, 312 deletions
diff --git a/src/LambdaCube/Compiler/Parser.hs b/src/LambdaCube/Compiler/Parser.hs
index 2d7eb49f..31012fdd 100644
--- a/src/LambdaCube/Compiler/Parser.hs
+++ b/src/LambdaCube/Compiler/Parser.hs
@@ -7,8 +7,6 @@
7{-# LANGUAGE OverloadedStrings #-} 7{-# LANGUAGE OverloadedStrings #-}
8{-# LANGUAGE DeriveFunctor #-} 8{-# LANGUAGE DeriveFunctor #-}
9{-# LANGUAGE ScopedTypeVariables #-} 9{-# LANGUAGE ScopedTypeVariables #-}
10{-# OPTIONS_GHC -fno-warn-orphans #-} -- instance NFData SourcePos
11-- {-# OPTIONS_GHC -O0 #-}
12module LambdaCube.Compiler.Parser 10module LambdaCube.Compiler.Parser
13 {- todo ( definitions 11 {- todo ( definitions
14 , extensions 12 , extensions
@@ -28,8 +26,6 @@ import Data.Maybe
28import Data.List 26import Data.List
29import Data.Char 27import Data.Char
30import Data.String 28import Data.String
31import Data.Set (Set)
32import qualified Data.Set as Set
33import qualified Data.Map as Map 29import qualified Data.Map as Map
34 30
35import Control.Monad.Except 31import Control.Monad.Except
@@ -38,19 +34,16 @@ import Control.Monad.Writer
38import Control.Monad.State 34import Control.Monad.State
39import Control.Arrow hiding ((<+>)) 35import Control.Arrow hiding ((<+>))
40import Control.Applicative 36import Control.Applicative
41import Control.DeepSeq
42 37
43import Text.Parsec hiding (label, Empty, State, (<|>), many, try) 38import Text.Parsec hiding (label, Empty, State, (<|>), many, try)
44import qualified Text.Parsec as Pa 39import qualified Text.Parsec as Pa
45import qualified Text.Parsec.Token as Pa
46import qualified Text.ParserCombinators.Parsec.Language as Pa
47import Text.Parsec.Pos 40import Text.Parsec.Pos
48import Text.Parsec.Indentation hiding (Any) 41import Text.Parsec.Indentation hiding (Any)
49import Text.Parsec.Indentation.Char 42import Text.Parsec.Indentation.Char
50 43
51import qualified LambdaCube.Compiler.Pretty as P 44import qualified LambdaCube.Compiler.Pretty as P
52import LambdaCube.Compiler.Pretty hiding (Doc, braces, parens) 45import LambdaCube.Compiler.Pretty hiding (Doc, braces, parens)
53import LambdaCube.Compiler.Token 46import LambdaCube.Compiler.Lexer
54 47
55-------------------------------------------------------------------------------- utils 48-------------------------------------------------------------------------------- utils
56 49
@@ -78,309 +71,7 @@ traceD x = if debug then trace_ x else id
78 71
79debug = False--True--tr 72debug = False--True--tr
80 73
81-------------------------------------------------------------------------------- parser utils 74try = try_
82
83-- see http://blog.ezyang.com/2014/05/parsec-try-a-or-b-considered-harmful/comment-page-1/#comment-6602
84try s m = Pa.try m <?> s
85
86-- n, m >= 1, n < m
87manyNM n m p = do
88 xs <- many1 p
89 let lxs = length xs
90 unless (n <= lxs && lxs <= m) . fail $ unwords ["manyNM", show n, show m, "found", show lxs, "occurences."]
91 return xs
92
93-------------------------------------------------------------------------------- parser type
94
95type P = ParsecT (IndentStream (CharIndentStream String)) SourcePos InnerP
96type InnerP = WriterT [PostponedCheck] (Reader (DesugarInfo, Namespace))
97
98type PostponedCheck = Maybe String
99
100type DesugarInfo = (FixityMap, ConsMap)
101
102type ConsMap = Map.Map SName{-constructor name-}
103 (Either ((SName{-type name-}, Int{-num of indices-}), [(SName, Int)]{-constructors with arities-})
104 Int{-arity-})
105
106dsInfo :: P DesugarInfo
107dsInfo = asks fst
108
109namespace :: P Namespace
110namespace = asks snd
111
112-------------------------------------------------------------------------------- lexing
113
114{-# NOINLINE lexer #-}
115lexer :: Pa.GenTokenParser (IndentStream (CharIndentStream String)) SourcePos InnerP
116lexer = makeTokenParser lexeme $ makeIndentLanguageDef style
117 where
118 style = Pa.LanguageDef
119 { Pa.commentStart = Pa.commentStart Pa.haskellDef
120 , Pa.commentEnd = Pa.commentEnd Pa.haskellDef
121 , Pa.commentLine = Pa.commentLine Pa.haskellDef
122 , Pa.nestedComments = Pa.nestedComments Pa.haskellDef
123 , Pa.identStart = letter <|> char '_' -- '_' is included also
124 , Pa.identLetter = alphaNum <|> oneOf "_'#"
125 , Pa.opStart = Pa.opLetter style
126 , Pa.opLetter = oneOf ":!#$%&*+./<=>?@\\^|-~"
127 , Pa.reservedOpNames = Pa.reservedOpNames Pa.haskellDef
128 , Pa.reservedNames = Pa.reservedNames Pa.haskellDef
129 , Pa.caseSensitive = Pa.caseSensitive Pa.haskellDef
130 }
131
132lexeme p = p <* (getPosition >>= setState >> whiteSpace)
133
134parens = Pa.parens lexer
135braces = Pa.braces lexer
136brackets = Pa.brackets lexer
137commaSep = Pa.commaSep lexer
138commaSep1 = Pa.commaSep1 lexer
139--dot = Pa.dot lexer
140--comma = Pa.comma lexer
141colon = Pa.colon lexer
142natural = Pa.natural lexer
143--integer = Pa.integer lexer
144float = Pa.float lexer
145charLiteral = Pa.charLiteral lexer
146stringLiteral = Pa.stringLiteral lexer
147whiteSpace = Pa.whiteSpace lexer
148operator = Pa.operator lexer
149reserved = Pa.reserved lexer
150reservedOp = Pa.reservedOp lexer
151identifier = Pa.identifier lexer
152
153
154-------------------------------------------------------------------------------- names
155
156type SName = String
157
158caseName (c:cs) = toLower c: cs ++ "Case"
159
160pattern MatchName cs <- (getMatchName -> Just cs) where MatchName = matchName
161
162matchName cs = "match" ++ cs
163getMatchName ('m':'a':'t':'c':'h':cs) = Just cs
164getMatchName _ = Nothing
165
166
167-------------------------------------------------------------------------------- source infos
168
169instance NFData SourcePos where
170 rnf x = x `seq` ()
171
172data Range = Range SourcePos SourcePos
173 deriving (Eq, Ord)
174
175instance NFData Range where
176 rnf (Range a b) = rnf a `seq` rnf b `seq` ()
177
178instance PShow Range where
179 pShowPrec _ (Range b e) | sourceName b == sourceName e = text (sourceName b) <+> f b <> "-" <> f e
180 where
181 f x = pShow (sourceLine x) <> ":" <> pShow (sourceColumn x)
182
183joinRange :: Range -> Range -> Range
184joinRange (Range b e) (Range b' e') = Range (min b b') (max e e')
185
186data SI
187 = NoSI (Set String) -- no source info, attached debug info
188 | RangeSI Range
189
190instance Show SI where show _ = "SI"
191instance Eq SI where _ == _ = True
192instance Ord SI where _ `compare` _ = EQ
193
194instance Monoid SI where
195 mempty = NoSI Set.empty
196 mappend (RangeSI r1) (RangeSI r2) = RangeSI (joinRange r1 r2)
197 mappend (NoSI ds1) (NoSI ds2) = NoSI (ds1 `Set.union` ds2)
198 mappend r@RangeSI{} _ = r
199 mappend _ r@RangeSI{} = r
200
201instance PShow SI where
202 pShowPrec _ (NoSI ds) = hsep $ map pShow $ Set.toList ds
203 pShowPrec _ (RangeSI r) = pShow r
204
205showSI_ _ (NoSI ds) = unwords $ Set.toList ds
206showSI_ source (RangeSI (Range s e)) = show str
207 where
208 startLine = sourceLine s - 1
209 endline = sourceLine e - if sourceColumn e == 1 then 1 else 0
210 len = endline - startLine
211 str = vcat $ text (show s <> ":"){- <+> "-" <+> text (show e)-}:
212 map text (take len $ drop startLine $ lines source)
213 ++ [text $ replicate (sourceColumn s - 1) ' ' ++ replicate (sourceColumn e - sourceColumn s) '^' | len == 1]
214
215-- TODO: remove
216validSI RangeSI{} = True
217validSI _ = False
218
219debugSI a = NoSI (Set.singleton a)
220
221si@(RangeSI r) `validate` xs | all validSI xs && r `notElem` [r | RangeSI r <- xs] = si
222_ `validate` _ = mempty
223
224class SourceInfo si where
225 sourceInfo :: si -> SI
226
227instance SourceInfo SI where
228 sourceInfo = id
229
230instance SourceInfo si => SourceInfo [si] where
231 sourceInfo = foldMap sourceInfo
232
233instance SourceInfo ParPat where
234 sourceInfo (ParPat ps) = sourceInfo ps
235
236instance SourceInfo Pat where
237 sourceInfo = \case
238 PVar (si,_) -> si
239 PCon (si,_) ps -> si <> sourceInfo ps
240 ViewPat e ps -> sourceInfo e <> sourceInfo ps
241 PatType ps e -> sourceInfo ps <> sourceInfo e
242
243instance SourceInfo (SExp' a) where
244 sourceInfo = \case
245 SGlobal (si, _) -> si
246 SBind si _ _ e1 e2 -> si
247 SApp si _ e1 e2 -> si
248 SLet _ e1 e2 -> sourceInfo e1 <> sourceInfo e2
249 SVar (si, _) _ -> si
250 STyped si _ -> si
251 SLit si _ -> si
252
253class SetSourceInfo a where
254 setSI :: SI -> a -> a
255
256instance SetSourceInfo (SExp' a) where
257 setSI si = \case
258 SBind _ a b c d -> SBind si a b c d
259 SApp _ a b c -> SApp si a b c
260 SLet le a b -> SLet le a b
261 SVar (_, n) i -> SVar (si, n) i
262 STyped _ t -> STyped si t
263 SGlobal (_, n) -> SGlobal (si, n)
264 SLit _ l -> SLit si l
265
266appRange :: P (SI -> a) -> P a
267appRange p = (\p1 a p2 -> a $ RangeSI $ Range p1 p2) <$> getPosition <*> p <*> getState
268
269withRange :: (SI -> a -> b) -> P a -> P b
270withRange f p = appRange $ flip f <$> p
271
272infix 9 `withRange`
273
274type SIName = (SI, SName)
275
276parseSIName :: P String -> P SIName
277parseSIName = withRange (,)
278
279-------------------------------------------------------------------------------- namespace handling
280
281data Level = TypeLevel | ExpLevel
282 deriving (Eq, Show)
283
284data Namespace = Namespace
285 { namespaceLevel :: Maybe Level
286 , constructorNamespace :: Bool -- True means that the case of the first letter of identifiers matters
287 }
288 deriving (Show)
289
290tick :: Namespace -> SName -> SName
291tick = (\case TypeLevel -> switchTick; _ -> id) . fromMaybe ExpLevel . namespaceLevel
292
293switchTick ('\'': n) = n
294switchTick n = '\'': n
295
296modifyLevel f = local $ second $ \(Namespace l p) -> Namespace (f <$> l) p
297
298typeNS, expNS, switchNS :: P a -> P a
299typeNS = modifyLevel $ const TypeLevel
300expNS = modifyLevel $ const ExpLevel
301switchNS = modifyLevel $ \case ExpLevel -> TypeLevel; TypeLevel -> ExpLevel
302
303-------------------------------------------------------------------------------- identifiers
304
305check msg p m = try msg $ mfilter p m
306
307firstCaseChar ('\'': c: _) = c
308firstCaseChar (c: _) = c
309
310upperCase, lowerCase, symbols, colonSymbols :: P SName
311--upperCase NonTypeNamespace = mzero -- todo
312upperCase = namespace >>= \ns -> (if constructorNamespace ns then check "uppercase ident" (isUpper . firstCaseChar) else id) $ tick ns <$> (identifier <|> try "tick ident" (('\'':) <$ char '\'' <*> identifier))
313lowerCase = namespace >>= \ns -> (if constructorNamespace ns then check "lowercase ident" (isLower . firstCaseChar) else id) identifier
314 <|> try "underscore ident" (('_':) <$ char '_' <*> identifier)
315symbols = check "symbols" ((/=':') . head) operator
316colonSymbols = "Cons" <$ reservedOp ":" <|> check "symbols" ((==':') . head) operator
317
318moduleName = {-qualified_ todo-} expNS upperCase
319patVar = lowerCase <|> "" <$ reserved "_"
320--qIdent = {-qualified_ todo-} (lowerCase <|> upperCase)
321backquotedIdent = try "backquoted ident" $ lexeme $ char '`' *> ((:) <$> satisfy isAlpha <*> many (satisfy isAlphaNum)) <* char '`'
322operatorT = symbols <|> colonSymbols <|> backquotedIdent
323varId = lowerCase <|> parens operatorT
324
325{-
326qualified_ id = do
327 q <- try "qualification" $ upperCase' <* dot
328 (N t qs n i) <- qualified_ id
329 return $ N t (q:qs) n i
330 <|>
331 id
332 where
333 upperCase' = (:) <$> satisfy isUpper <*> many (satisfy isAlphaNum)
334-}
335
336-------------------------------------------------------------------------------- fixity handling
337
338data FixityDef = Infix | InfixL | InfixR deriving (Show)
339type Fixity = (FixityDef, Int)
340type MFixity = Maybe Fixity
341type FixityMap = Map.Map SName Fixity
342
343calcPrec
344 :: (Show e, Show f)
345 => (f -> e -> e -> e)
346 -> (f -> Fixity)
347 -> e
348 -> [(f, e)]
349 -> e
350calcPrec app getFixity e = compileOps [((Infix, -1), undefined, e)]
351 where
352 compileOps [(_, _, e)] [] = e
353 compileOps acc [] = compileOps (shrink acc) []
354 compileOps acc@((p, g, e1): ee) es_@((op, e'): es) = case compareFixity (pr, op) (p, g) of
355 Right GT -> compileOps ((pr, op, e'): acc) es
356 Right LT -> compileOps (shrink acc) es_
357 Left err -> error err
358 where
359 pr = getFixity op
360
361 shrink ((_, op, e): (pr, op', e'): es) = (pr, op', app op e' e): es
362
363 compareFixity ((dir, i), op) ((dir', i'), op')
364 | i > i' = Right GT
365 | i < i' = Right LT
366 | otherwise = case (dir, dir') of
367 (InfixL, InfixL) -> Right LT
368 (InfixR, InfixR) -> Right GT
369 _ -> Left $ "fixity error:" ++ show (op, op')
370
371parseFixityDecl :: P [Stmt]
372parseFixityDecl = do
373 dir <- Infix <$ reserved "infix"
374 <|> InfixL <$ reserved "infixl"
375 <|> InfixR <$ reserved "infixr"
376 localIndentation Gt $ do
377 i <- fromIntegral <$> natural
378 ns <- commaSep1 (parseSIName operatorT)
379 return $ PrecDef <$> ns <*> pure (dir, i)
380
381getFixity :: DesugarInfo -> SName -> Fixity
382getFixity (fm, _) n = fromMaybe (InfixL, 9) $ Map.lookup n fm
383
384 75
385-------------------------------------------------------------------------------- literals 76-------------------------------------------------------------------------------- literals
386 77
@@ -489,6 +180,26 @@ downToS n m = map (SVar (debugSI "20", ".ds")) [n+m-1, n+m-2..n]
489 180
490xSLabelEnd = id --SLabelEnd 181xSLabelEnd = id --SLabelEnd
491 182
183instance SourceInfo (SExp' a) where
184 sourceInfo = \case
185 SGlobal (si, _) -> si
186 SBind si _ _ e1 e2 -> si
187 SApp si _ e1 e2 -> si
188 SLet _ e1 e2 -> sourceInfo e1 <> sourceInfo e2
189 SVar (si, _) _ -> si
190 STyped si _ -> si
191 SLit si _ -> si
192
193instance SetSourceInfo (SExp' a) where
194 setSI si = \case
195 SBind _ a b c d -> SBind si a b c d
196 SApp _ a b c -> SApp si a b c
197 SLet le a b -> SLet le a b
198 SVar (_, n) i -> SVar (si, n) i
199 STyped _ t -> STyped si t
200 SGlobal (_, n) -> SGlobal (si, n)
201 SLit _ l -> SLit si l
202
492-------------------------------------------------------------------------------- low-level toolbox 203-------------------------------------------------------------------------------- low-level toolbox
493 204
494foldS g f i = \case 205foldS g f i = \case
@@ -767,6 +478,16 @@ getPVars_ = \case
767getPPVars_ = \case 478getPPVars_ = \case
768 ParPat pp -> foldMap getPVars_ pp 479 ParPat pp -> foldMap getPVars_ pp
769 480
481instance SourceInfo ParPat where
482 sourceInfo (ParPat ps) = sourceInfo ps
483
484instance SourceInfo Pat where
485 sourceInfo = \case
486 PVar (si,_) -> si
487 PCon (si,_) ps -> si <> sourceInfo ps
488 ViewPat e ps -> sourceInfo e <> sourceInfo ps
489 PatType ps e -> sourceInfo ps <> sourceInfo e
490
770-------------------------------------------------------------------------------- pattern parsing 491-------------------------------------------------------------------------------- pattern parsing
771 492
772parsePat :: Prec -> P Pat 493parsePat :: Prec -> P Pat
@@ -1029,7 +750,7 @@ parseDef =
1029 [{-TypeAnn x $ addParamsS ts $ SType-}{-todo-}] 750 [{-TypeAnn x $ addParamsS ts $ SType-}{-todo-}]
1030 [FunAlt x (zip ts $ map PVar $ reverse nps) $ Right rhs] 751 [FunAlt x (zip ts $ map PVar $ reverse nps) $ Right rhs]
1031 <|> do try "typed ident" $ (\(vs, t) -> TypeAnn <$> vs <*> pure t) <$> typedIds Nothing 752 <|> do try "typed ident" $ (\(vs, t) -> TypeAnn <$> vs <*> pure t) <$> typedIds Nothing
1032 <|> parseFixityDecl 753 <|> map (uncurry PrecDef) <$> parseFixityDecl
1033 <|> pure <$> funAltDef varId 754 <|> pure <$> funAltDef varId
1034 <|> pure <$> valueDef 755 <|> pure <$> valueDef
1035 where 756 where