1-- |
2-- Module      :  Cryptol.Parser.ParserUtils
3-- Copyright   :  (c) 2013-2016 Galois, Inc.
4-- License     :  BSD3
5-- Maintainer  :  cryptol@galois.com
6-- Stability   :  provisional
7-- Portability :  portable
8
9{-# LANGUAGE Safe #-}
10
11{-# LANGUAGE CPP #-}
12{-# LANGUAGE DeriveAnyClass #-}
13{-# LANGUAGE DeriveGeneric #-}
14{-# LANGUAGE PatternGuards #-}
15{-# LANGUAGE OverloadedStrings #-}
16module Cryptol.Parser.ParserUtils where
17
18import Data.Maybe(fromMaybe)
19import Data.Bits(testBit,setBit)
20import Data.List.NonEmpty ( NonEmpty(..) )
21import qualified Data.List.NonEmpty as NE
22import Control.Monad(liftM,ap,unless,guard)
23import qualified Control.Monad.Fail as Fail
24import           Data.Text(Text)
25import qualified Data.Text as T
26import qualified Data.Map as Map
27import Text.Read(readMaybe)
28
29import GHC.Generics (Generic)
30import Control.DeepSeq
31
32import Prelude ()
33import Prelude.Compat
34
35
36import Cryptol.Parser.AST
37import Cryptol.Parser.Lexer
38import Cryptol.Parser.LexerUtils(SelectorType(..))
39import Cryptol.Parser.Position
40import Cryptol.Parser.Utils (translateExprToNumT,widthIdent)
41import Cryptol.Utils.Ident(packModName)
42import Cryptol.Utils.PP
43import Cryptol.Utils.Panic
44import Cryptol.Utils.RecordMap
45
46
47parseString :: Config -> ParseM a -> String -> Either ParseError a
48parseString cfg p cs = parse cfg p (T.pack cs)
49
50parse :: Config -> ParseM a -> Text -> Either ParseError a
51parse cfg p cs    = case unP p cfg eofPos S { sPrevTok = Nothing
52                                            , sTokens = toks
53                                            , sNextTyParamNum = 0
54                                            } of
55                      Left err    -> Left err
56                      Right (a,_) -> Right a
57  where (toks,eofPos) = lexer cfg cs
58
59
60{- The parser is parameterized by the pozition of the final token. -}
61newtype ParseM a =
62  P { unP :: Config -> Position -> S -> Either ParseError (a,S) }
63
64
65lexerP :: (Located Token -> ParseM a) -> ParseM a
66lexerP k = P $ \cfg p s ->
67  case sTokens s of
68    t : _ | Err e <- tokenType it ->
69      Left $ HappyErrorMsg (srcRange t) $
70        [case e of
71           UnterminatedComment -> "unterminated comment"
72           UnterminatedString  -> "unterminated string"
73           UnterminatedChar    -> "unterminated character"
74           InvalidString       -> "invalid string literal: " ++
75                                    T.unpack (tokenText it)
76           InvalidChar         -> "invalid character literal: " ++
77                                    T.unpack (tokenText it)
78           LexicalError        -> "unrecognized character: " ++
79                                    T.unpack (tokenText it)
80           MalformedLiteral    -> "malformed literal: " ++
81                                    T.unpack (tokenText it)
82           MalformedSelector   -> "malformed selector: " ++
83                                    T.unpack (tokenText it)
84        ]
85      where it = thing t
86
87    t : more -> unP (k t) cfg p s { sPrevTok = Just t, sTokens = more }
88    [] -> Left (HappyOutOfTokens (cfgSource cfg) p)
89
90data ParseError = HappyError FilePath         {- Name of source file -}
91                             (Located Token)  {- Offending token -}
92                | HappyErrorMsg Range [String]
93                | HappyUnexpected FilePath (Maybe (Located Token)) String
94                | HappyOutOfTokens FilePath Position
95                  deriving (Show, Generic, NFData)
96
97data S = S { sPrevTok :: Maybe (Located Token)
98           , sTokens :: [Located Token]
99           , sNextTyParamNum :: !Int
100             -- ^ Keep track of the type parameters as they appear in the input
101           }
102
103ppError :: ParseError -> Doc
104
105ppError (HappyError path ltok)
106  | Err _ <- tokenType tok =
107    text "Parse error at" <+>
108    text path <.> char ':' <.> pp pos <.> comma <+>
109    pp tok
110
111  | White DocStr <- tokenType tok =
112    "Unexpected documentation (/**) comment at" <+>
113    text path <.> char ':' <.> pp pos <.> colon $$
114    nest 2
115      "Documentation comments need to be followed by something to document."
116
117  | otherwise =
118    text "Parse error at" <+>
119    text path <.> char ':' <.> pp pos <.> comma $$
120    nest 2 (text "unexpected:" <+> pp tok)
121  where
122  pos = from (srcRange ltok)
123  tok = thing ltok
124
125ppError (HappyOutOfTokens path pos) =
126  text "Unexpected end of file at:" <+>
127    text path <.> char ':' <.> pp pos
128
129ppError (HappyErrorMsg p xs)  = text "Parse error at" <+> pp p $$ nest 2 (vcat (map text xs))
130
131ppError (HappyUnexpected path ltok e) =
132  text "Parse error at" <+>
133   text path <.> char ':' <.> pp pos <.> comma $$
134   nest 2 unexp $$
135   nest 2 ("expected:" <+> text e)
136  where
137  (unexp,pos) =
138    case ltok of
139      Nothing -> (empty,start)
140      Just t  -> ( "unexpected:" <+> text (T.unpack (tokenText (thing t)))
141                 , from (srcRange t)
142                 )
143
144instance Functor ParseM where
145  fmap = liftM
146
147instance Applicative ParseM where
148  pure  = return
149  (<*>) = ap
150
151instance Monad ParseM where
152  return a  = P (\_ _ s -> Right (a,s))
153  m >>= k   = P (\cfg p s1 -> case unP m cfg p s1 of
154                            Left e       -> Left e
155                            Right (a,s2) -> unP (k a) cfg p s2)
156
157instance Fail.MonadFail ParseM where
158  fail s    = panic "[Parser] fail" [s]
159
160happyError :: ParseM a
161happyError = P $ \cfg _ s ->
162  case sPrevTok s of
163    Just t  -> Left (HappyError (cfgSource cfg) t)
164    Nothing ->
165      Left (HappyErrorMsg emptyRange ["Parse error at the beginning of the file"])
166
167errorMessage :: Range -> [String] -> ParseM a
168errorMessage r xs = P $ \_ _ _ -> Left (HappyErrorMsg r xs)
169
170customError :: String -> Located Token -> ParseM a
171customError x t = P $ \_ _ _ -> Left (HappyErrorMsg (srcRange t) [x])
172
173expected :: String -> ParseM a
174expected x = P $ \cfg _ s ->
175                    Left (HappyUnexpected (cfgSource cfg) (sPrevTok s) x)
176
177
178
179
180
181
182
183
184
185mkModName :: [Text] -> ModName
186mkModName = packModName
187
188-- Note that type variables are not resolved at this point: they are tcons.
189mkSchema :: [TParam PName] -> [Prop PName] -> Type PName -> Schema PName
190mkSchema xs ps t = Forall xs ps t Nothing
191
192getName :: Located Token -> PName
193getName l = case thing l of
194              Token (Ident [] x) _ -> mkUnqual (mkIdent x)
195              _ -> panic "[Parser] getName" ["not an Ident:", show l]
196
197getNum :: Located Token -> Integer
198getNum l = case thing l of
199             Token (Num x _ _) _ -> x
200             Token (ChrLit x) _  -> toInteger (fromEnum x)
201             _ -> panic "[Parser] getNum" ["not a number:", show l]
202
203getChr :: Located Token -> Char
204getChr l = case thing l of
205             Token (ChrLit x) _  -> x
206             _ -> panic "[Parser] getChr" ["not a char:", show l]
207
208getStr :: Located Token -> String
209getStr l = case thing l of
210             Token (StrLit x) _ -> x
211             _ -> panic "[Parser] getStr" ["not a string:", show l]
212
213numLit :: Token -> Expr PName
214numLit Token { tokenText = txt, tokenType = Num x base digs }
215  | base == 2   = ELit $ ECNum x (BinLit txt digs)
216  | base == 8   = ELit $ ECNum x (OctLit txt digs)
217  | base == 10  = ELit $ ECNum x (DecLit txt)
218  | base == 16  = ELit $ ECNum x (HexLit txt digs)
219
220numLit x = panic "[Parser] numLit" ["invalid numeric literal", show x]
221
222fracLit :: Token -> Expr PName
223fracLit tok =
224  case tokenType tok of
225    Frac x base
226      | base == 2   -> ELit $ ECFrac x $ BinFrac $ tokenText tok
227      | base == 8   -> ELit $ ECFrac x $ OctFrac $ tokenText tok
228      | base == 10  -> ELit $ ECFrac x $ DecFrac $ tokenText tok
229      | base == 16  -> ELit $ ECFrac x $ HexFrac $ tokenText tok
230    _ -> panic "[Parser] fracLit" [ "Invalid fraction", show tok ]
231
232
233intVal :: Located Token -> ParseM Integer
234intVal tok =
235  case tokenType (thing tok) of
236    Num x _ _ -> return x
237    _         -> errorMessage (srcRange tok) ["Expected an integer"]
238
239mkFixity :: Assoc -> Located Token -> [LPName] -> ParseM (Decl PName)
240mkFixity assoc tok qns =
241  do l <- intVal tok
242     unless (l >= 1 && l <= 100)
243          (errorMessage (srcRange tok) ["Fixity levels must be between 1 and 100"])
244     return (DFixity (Fixity assoc (fromInteger l)) qns)
245
246fromStrLit :: Located Token -> ParseM (Located String)
247fromStrLit loc = case tokenType (thing loc) of
248  StrLit str -> return loc { thing = str }
249  _          -> errorMessage (srcRange loc) ["Expected a string literal"]
250
251
252validDemotedType :: Range -> Type PName -> ParseM (Type PName)
253validDemotedType rng ty =
254  case ty of
255    TLocated t r -> validDemotedType r t
256    TRecord {}   -> bad "Record types"
257    TTyApp {}    -> bad "Explicit type application"
258    TTuple {}    -> bad "Tuple types"
259    TFun {}      -> bad "Function types"
260    TSeq {}      -> bad "Sequence types"
261    TBit         -> bad "Type bit"
262    TNum {}      -> ok
263    TChar {}     -> ok
264    TWild        -> bad "Wildcard types"
265    TUser {}     -> ok
266
267    TParens t    -> validDemotedType rng t
268    TInfix{}     -> ok
269
270  where bad x = errorMessage rng [x ++ " cannot be demoted."]
271        ok    = return $ at rng ty
272
273-- | Input fields are reversed!
274mkRecord :: AddLoc b => Range -> (RecordMap Ident (Range, a) -> b) -> [Named a] -> ParseM b
275mkRecord rng f xs =
276   case res of
277     Left (nm,(nmRng,_)) -> errorMessage nmRng ["Record has repeated field: " ++ show (pp nm)]
278     Right r -> pure $ at rng (f r)
279
280  where
281  res = recordFromFieldsErr ys
282  ys = map (\ (Named (Located r nm) x) -> (nm,(r,x))) (reverse xs)
283
284
285-- | Input expression are reversed
286mkEApp :: NonEmpty (Expr PName) -> ParseM (Expr PName)
287
288mkEApp es@(eLast :| _) =
289    do f :| xs <- cvtTypeParams eFirst rest
290       pure (at (eFirst,eLast) $ foldl EApp f xs)
291
292  where
293  eFirst :| rest = NE.reverse es
294
295  {- Type applications are parsed as `ETypeVal (TTyApp fs)` expressions.
296     Here we associate them with their corresponding functions,
297     converting them into `EAppT` constructs.  For example:
298
299     [ f, x, `{ a = 2 }, y ]
300     becomes
301     [ f, x ` { a = 2 }, y ]
302
303     The parser associates field and tuple projectors that follow an
304     explicit type application onto the TTyApp term, so we also
305     have to unwind those projections and reapply them.  For example:
306
307     [ f, x, `{ a = 2 }.f.2, y ]
308     becomes
309     [ f, (x`{ a = 2 }).f.2, y ]
310
311  -}
312  cvtTypeParams e [] = pure (e :| [])
313  cvtTypeParams e (p : ps) =
314    case toTypeParam p Nothing of
315      Nothing -> NE.cons e <$> cvtTypeParams p ps
316
317      Just (fs,ss,rng) ->
318        if checkAppExpr e then
319          let e'  = foldr (flip ESel) (EAppT e fs) ss
320              e'' = case rCombMaybe (getLoc e) rng of
321                      Just r -> ELocated e' r
322                      Nothing -> e'
323           in cvtTypeParams e'' ps
324        else
325          errorMessage (fromMaybe emptyRange (getLoc e))
326                  [ "Explicit type applications can only be applied to named values."
327                  , "Unexpected: " ++ show (pp e)
328                  ]
329
330  {- Check if the given expression is a legal target for explicit type application.
331     This is basically only variables, but we also allow the parenthesis and
332     the phantom "located" AST node.
333   -}
334  checkAppExpr e =
335    case e of
336      ELocated e' _ -> checkAppExpr e'
337      EParens e'    -> checkAppExpr e'
338      EVar{}        -> True
339      _             -> False
340
341  {- Look under a potential chain of selectors to see if we have a TTyApp.
342     If so, return the ty app information and the collected selectors
343     to reapply.
344   -}
345  toTypeParam e mr =
346    case e of
347      ELocated e' rng -> toTypeParam e' (rCombMaybe mr (Just rng))
348      ETypeVal t -> toTypeParam' t mr
349      ESel e' s  -> ( \(fs,ss,r) -> (fs,s:ss,r) ) <$> toTypeParam e' mr
350      _          ->  Nothing
351
352  toTypeParam' t mr =
353    case t of
354      TLocated t' rng -> toTypeParam' t' (rCombMaybe mr (Just rng))
355      TTyApp fs -> Just (map mkTypeInst fs, [], mr)
356      _ -> Nothing
357
358unOp :: Expr PName -> Expr PName -> Expr PName
359unOp f x = at (f,x) $ EApp f x
360
361-- Use defaultFixity as a placeholder, it will be fixed during renaming.
362binOp :: Expr PName -> Located PName -> Expr PName -> Expr PName
363binOp x f y = at (x,y) $ EInfix x f defaultFixity y
364
365-- An element type ascription is allowed to appear on one of the arguments.
366eFromTo :: Range -> Expr PName -> Maybe (Expr PName) -> Expr PName -> ParseM (Expr PName)
367eFromTo r e1 e2 e3 =
368  case (asETyped e1, asETyped =<< e2, asETyped e3) of
369    (Just (e1', t), Nothing, Nothing) -> eFromToType r e1' e2 e3 (Just t)
370    (Nothing, Just (e2', t), Nothing) -> eFromToType r e1 (Just e2') e3 (Just t)
371    (Nothing, Nothing, Just (e3', t)) -> eFromToType r e1 e2 e3' (Just t)
372    (Nothing, Nothing, Nothing) -> eFromToType r e1 e2 e3 Nothing
373    _ -> errorMessage r ["A sequence enumeration may have at most one element type annotation."]
374
375asETyped :: Expr n -> Maybe (Expr n, Type n)
376asETyped (ELocated e _) = asETyped e
377asETyped (ETyped e t) = Just (e, t)
378asETyped _ = Nothing
379
380eFromToType ::
381  Range -> Expr PName -> Maybe (Expr PName) -> Expr PName -> Maybe (Type PName) -> ParseM (Expr PName)
382eFromToType r e1 e2 e3 t =
383  EFromTo <$> exprToNumT r e1
384          <*> mapM (exprToNumT r) e2
385          <*> exprToNumT r e3
386          <*> pure t
387
388eFromToLessThan ::
389  Range -> Expr PName -> Expr PName -> ParseM (Expr PName)
390eFromToLessThan r e1 e2 =
391  case asETyped e2 of
392    Just _  -> errorMessage r ["The exclusive upper bound of an enumeration may not have a type annotation."]
393    Nothing ->
394      case asETyped e1 of
395        Nothing      -> eFromToLessThanType r e1  e2 Nothing
396        Just (e1',t) -> eFromToLessThanType r e1' e2 (Just t)
397
398eFromToLessThanType ::
399  Range -> Expr PName -> Expr PName -> Maybe (Type PName) -> ParseM (Expr PName)
400eFromToLessThanType r e1 e2 t =
401  EFromToLessThan
402    <$> exprToNumT r e1
403    <*> exprToNumT r e2
404    <*> pure t
405
406exprToNumT :: Range -> Expr PName -> ParseM (Type PName)
407exprToNumT r expr =
408  case translateExprToNumT expr of
409    Just t -> return t
410    Nothing -> bad
411  where
412  bad = errorMessage (fromMaybe r (getLoc expr))
413        [ "The boundaries of .. sequences should be valid numeric types."
414        , "The expression `" ++ show (pp expr) ++ "` is not."
415        ]
416
417
418-- | WARNING: This is a bit of a hack.
419-- It is used to represent anonymous type applications.
420anonTyApp :: Maybe Range -> [Type PName] -> Type PName
421anonTyApp ~(Just r) ts = TLocated (TTyApp (map toField ts)) r
422  where noName    = Located { srcRange = r, thing = mkIdent (T.pack "") }
423        toField t = Named { name = noName, value = t }
424
425exportDecl :: Maybe (Located Text) -> ExportType -> Decl PName -> TopDecl PName
426exportDecl mbDoc e d = Decl TopLevel { tlExport = e
427                                     , tlDoc    = mbDoc
428                                     , tlValue  = d }
429
430exportNewtype :: ExportType -> Maybe (Located Text) -> Newtype PName ->
431                                                            TopDecl PName
432exportNewtype e d n = TDNewtype TopLevel { tlExport = e
433                                         , tlDoc    = d
434                                         , tlValue  = n }
435
436mkParFun :: Maybe (Located Text) ->
437            Located PName ->
438            Schema PName ->
439            TopDecl PName
440mkParFun mbDoc n s = DParameterFun ParameterFun { pfName = n
441                                                , pfSchema = s
442                                                , pfDoc = thing <$> mbDoc
443                                                , pfFixity = Nothing
444                                                }
445
446mkParType :: Maybe (Located Text) ->
447             Located PName ->
448             Located Kind ->
449             ParseM (TopDecl PName)
450mkParType mbDoc n k =
451  do num <- P $ \_ _ s -> let nu = sNextTyParamNum s
452                          in Right (nu, s { sNextTyParamNum = nu + 1 })
453     return (DParameterType
454             ParameterType { ptName    = n
455                           , ptKind    = thing k
456                           , ptDoc     = thing <$> mbDoc
457                           , ptFixity  = Nothing
458                           , ptNumber  = num
459                           })
460
461changeExport :: ExportType -> [TopDecl PName] -> [TopDecl PName]
462changeExport e = map change
463  where
464  change (Decl d)      = Decl      d { tlExport = e }
465  change (DPrimType t) = DPrimType t { tlExport = e }
466  change (TDNewtype n) = TDNewtype n { tlExport = e }
467  change td@Include{}  = td
468  change (DParameterType {}) = panic "changeExport" ["private type parameter?"]
469  change (DParameterFun {})  = panic "changeExport" ["private value parameter?"]
470  change (DParameterConstraint {}) =
471    panic "changeExport" ["private type constraint parameter?"]
472
473mkTypeInst :: Named (Type PName) -> TypeInst PName
474mkTypeInst x | nullIdent (thing (name x)) = PosInst (value x)
475             | otherwise                  = NamedInst x
476
477
478mkTParam :: Located Ident -> Maybe Kind -> ParseM (TParam PName)
479mkTParam Located { srcRange = rng, thing = n } k
480  | n == widthIdent = errorMessage rng ["`width` is not a valid type parameter name."]
481  | otherwise       = return (TParam (mkUnqual n) k (Just rng))
482
483mkTySyn :: Located PName -> [TParam PName] -> Type PName -> ParseM (Decl PName)
484mkTySyn ln ps b
485  | getIdent (thing ln) == widthIdent =
486    errorMessage (srcRange ln) ["`width` is not a valid type synonym name."]
487
488  | otherwise =
489    return $ DType $ TySyn ln Nothing ps b
490
491mkPropSyn :: Located PName -> [TParam PName] -> Type PName -> ParseM (Decl PName)
492mkPropSyn ln ps b
493  | getIdent (thing ln) == widthIdent =
494    errorMessage (srcRange ln) ["`width` is not a valid constraint synonym name."]
495
496  | otherwise =
497    DProp . PropSyn ln Nothing ps . thing <$> mkProp b
498
499polyTerm :: Range -> Integer -> Integer -> ParseM (Bool, Integer)
500polyTerm rng k p
501  | k == 0          = return (False, p)
502  | k == 1          = return (True, p)
503  | otherwise       = errorMessage rng ["Invalid polynomial coefficient"]
504
505mkPoly :: Range -> [ (Bool,Integer) ] -> ParseM (Expr PName)
506mkPoly rng terms
507  | w <= toInteger (maxBound :: Int) = mk 0 (map fromInteger bits)
508  | otherwise = errorMessage rng ["Polynomial literal too large: " ++ show w]
509
510  where
511  w    = case terms of
512           [] -> 0
513           _  -> 1 + maximum (map snd terms)
514
515  bits = [ n | (True,n) <- terms ]
516
517  mk :: Integer -> [Int] -> ParseM (Expr PName)
518  mk res [] = return $ ELit $ ECNum res (PolyLit (fromInteger w :: Int))
519
520  mk res (n : ns)
521    | testBit res n = errorMessage rng
522                       ["Polynomial contains multiple terms with exponent " ++ show n]
523    | otherwise     = mk (setBit res n) ns
524
525
526-- NOTE: The list of patterns is reversed!
527mkProperty :: LPName -> [Pattern PName] -> Expr PName -> Decl PName
528mkProperty f ps e = DBind Bind { bName       = f
529                               , bParams     = reverse ps
530                               , bDef        = at e (Located emptyRange (DExpr e))
531                               , bSignature  = Nothing
532                               , bPragmas    = [PragmaProperty]
533                               , bMono       = False
534                               , bInfix      = False
535                               , bFixity     = Nothing
536                               , bDoc        = Nothing
537                               }
538
539-- NOTE: The lists of patterns are reversed!
540mkIndexedDecl ::
541  LPName -> ([Pattern PName], [Pattern PName]) -> Expr PName -> Decl PName
542mkIndexedDecl f (ps, ixs) e =
543  DBind Bind { bName       = f
544             , bParams     = reverse ps
545             , bDef        = at e (Located emptyRange (DExpr rhs))
546             , bSignature  = Nothing
547             , bPragmas    = []
548             , bMono       = False
549             , bInfix      = False
550             , bFixity     = Nothing
551             , bDoc        = Nothing
552             }
553  where
554    rhs :: Expr PName
555    rhs = mkGenerate (reverse ixs) e
556
557-- NOTE: The lists of patterns are reversed!
558mkIndexedExpr :: ([Pattern PName], [Pattern PName]) -> Expr PName -> Expr PName
559mkIndexedExpr (ps, ixs) body
560  | null ps = mkGenerate (reverse ixs) body
561  | otherwise = EFun emptyFunDesc (reverse ps) (mkGenerate (reverse ixs) body)
562
563mkGenerate :: [Pattern PName] -> Expr PName -> Expr PName
564mkGenerate pats body =
565  foldr (\pat e -> EGenerate (EFun emptyFunDesc [pat] e)) body pats
566
567mkIf :: [(Expr PName, Expr PName)] -> Expr PName -> Expr PName
568mkIf ifThens theElse = foldr addIfThen theElse ifThens
569    where
570    addIfThen (cond, doexpr) elseExpr = EIf cond doexpr elseExpr
571
572-- | Generate a signature and a primitive binding.  The reason for generating
573-- both instead of just adding the signature at this point is that it means the
574-- primitive declarations don't need to be treated differently in the noPat
575-- pass.  This is also the reason we add the doc to the TopLevel constructor,
576-- instead of just place it on the binding directly.  A better solution might be
577-- to just have a different constructor for primitives.
578mkPrimDecl ::
579  Maybe (Located Text) -> LPName -> Schema PName -> [TopDecl PName]
580mkPrimDecl mbDoc ln sig =
581  [ exportDecl mbDoc Public
582    $ DBind Bind { bName      = ln
583                 , bParams    = []
584                 , bDef       = at sig (Located emptyRange DPrim)
585                 , bSignature = Nothing
586                 , bPragmas   = []
587                 , bMono      = False
588                 , bInfix     = isInfixIdent (getIdent (thing ln))
589                 , bFixity    = Nothing
590                 , bDoc       = Nothing
591                 }
592  , exportDecl Nothing Public
593    $ DSignature [ln] sig
594  ]
595
596mkPrimTypeDecl ::
597  Maybe (Located Text) ->
598  Schema PName ->
599  Located Kind ->
600  ParseM [TopDecl PName]
601mkPrimTypeDecl mbDoc (Forall as qs st ~(Just schema_rng)) finK =
602  case splitT schema_rng st of
603    Just (n,xs) ->
604      do vs <- mapM tpK as
605         unless (distinct (map fst vs)) $
606            errorMessage schema_rng ["Repeated parameters."]
607         let kindMap = Map.fromList vs
608             lkp v = case Map.lookup (thing v) kindMap of
609                       Just (k,tp)  -> pure (k,tp)
610                       Nothing ->
611                        errorMessage
612                            (srcRange v)
613                            ["Undefined parameter: " ++ show (pp (thing v))]
614         (as',ins) <- unzip <$> mapM lkp xs
615         unless (length vs == length xs) $
616           errorMessage schema_rng ["All parameters should appear in the type."]
617
618         let ki = finK { thing = foldr KFun (thing finK) ins }
619
620         pure [ DPrimType TopLevel
621                  { tlExport = Public
622                  , tlDoc    = mbDoc
623                  , tlValue  = PrimType { primTName   = n
624                                        , primTKind   = ki
625                                        , primTCts    = (as',qs)
626                                        , primTFixity = Nothing
627                                        }
628                 }
629              ]
630
631    Nothing -> errorMessage schema_rng ["Invalid primitive signature"]
632
633  where
634  splitT r ty = case ty of
635                  TLocated t r1 -> splitT r1 t
636                  TUser n ts -> mkT r Located { srcRange = r, thing = n } ts
637                  TInfix t1 n _ t2  -> mkT r n [t1,t2]
638                  _ -> Nothing
639
640  mkT r n ts = do ts1 <- mapM (isVar r) ts
641                  guard (distinct (map thing ts1))
642                  pure (n,ts1)
643
644  isVar r ty = case ty of
645                 TLocated t r1  -> isVar r1 t
646                 TUser n []     -> Just Located { srcRange = r, thing = n }
647                 _              -> Nothing
648
649  -- inefficient, but the lists should be small
650  distinct xs = case xs of
651                  [] -> True
652                  x : ys -> not (x `elem` ys) && distinct ys
653
654  tpK tp = case tpKind tp of
655             Just k  -> pure (tpName tp, (tp,k))
656             Nothing ->
657              case tpRange tp of
658                Just r -> errorMessage r ["Parameters need a kind annotation"]
659                Nothing -> panic "mkPrimTypeDecl"
660                              [ "Missing range on schema parameter." ]
661
662
663-- | Fix-up the documentation strings by removing the comment delimiters on each
664-- end, and stripping out common prefixes on all the remaining lines.
665mkDoc :: Located Text -> Located Text
666mkDoc ltxt = ltxt { thing = docStr }
667  where
668
669  docStr = T.unlines
670         $ dropPrefix
671         $ trimFront
672         $ T.lines
673         $ T.dropWhileEnd commentChar
674         $ thing ltxt
675
676  commentChar :: Char -> Bool
677  commentChar x = x `elem` ("/* \r\n\t" :: String)
678
679  prefixDroppable x = x `elem` ("* \r\n\t" :: String)
680
681  whitespaceChar :: Char -> Bool
682  whitespaceChar x = x `elem` (" \r\n\t" :: String)
683
684  trimFront []                     = []
685  trimFront (l:ls)
686    | T.all commentChar l = ls
687    | otherwise           = T.dropWhile commentChar l : ls
688
689  dropPrefix []        = []
690  dropPrefix [t]       = [T.dropWhile commentChar t]
691  dropPrefix ts@(l:ls) =
692    case T.uncons l of
693      Just (c,_) | prefixDroppable c &&
694                   all (commonPrefix c) ls -> dropPrefix (map (T.drop 1) ts)
695      _                                    -> ts
696
697    where
698    commonPrefix c t =
699      case T.uncons t of
700        Just (c',_) -> c == c'
701        Nothing     -> whitespaceChar c -- end-of-line matches any whitespace
702
703
704distrLoc :: Located [a] -> [Located a]
705distrLoc x = [ Located { srcRange = r, thing = a } | a <- thing x ]
706  where r = srcRange x
707
708
709mkProp :: Type PName -> ParseM (Located [Prop PName])
710mkProp ty =
711  case ty of
712    TLocated t r -> Located r `fmap` props r t
713    _            -> panic "Parser" [ "Invalid type given to mkProp"
714                                   , "expected a location"
715                                   , show ty ]
716
717  where
718
719  props r t =
720    case t of
721      TInfix{}       -> return [CType t]
722      TUser{}        -> return [CType t]
723      TTuple ts      -> concat `fmap` mapM (props r) ts
724      TParens t'     -> props r  t'
725      TLocated t' r' -> props r' t'
726
727      TFun{}    -> err
728      TSeq{}    -> err
729      TBit{}    -> err
730      TNum{}    -> err
731      TChar{}   -> err
732      TWild     -> err
733      TRecord{} -> err
734      TTyApp{}  -> err
735
736    where
737    err = errorMessage r ["Invalid constraint"]
738
739-- | Make an ordinary module
740mkModule :: Located ModName ->
741            ([Located Import], [TopDecl PName]) ->
742            Module PName
743mkModule nm (is,ds) = Module { mName = nm
744                             , mInstance = Nothing
745                             , mImports = is
746                             , mDecls = ds
747                             }
748
749-- | Make an unnamed module---gets the name @Main@.
750mkAnonymousModule :: ([Located Import], [TopDecl PName]) ->
751                     Module PName
752mkAnonymousModule = mkModule Located { srcRange = emptyRange
753                                     , thing    = mkModName [T.pack "Main"]
754                                     }
755
756-- | Make a module which defines a functor instance.
757mkModuleInstance :: Located ModName ->
758                    Located ModName ->
759                    ([Located Import], [TopDecl PName]) ->
760                    Module PName
761mkModuleInstance nm fun (is,ds) =
762  Module { mName     = nm
763         , mInstance = Just fun
764         , mImports  = is
765         , mDecls    = ds
766         }
767
768ufToNamed :: UpdField PName -> ParseM (Named (Expr PName))
769ufToNamed (UpdField h ls e) =
770  case (h,ls) of
771    (UpdSet, [l]) | RecordSel i Nothing <- thing l ->
772      pure Named { name = l { thing = i }, value = e }
773    _ -> errorMessage (srcRange (head ls))
774            ["Invalid record field.  Perhaps you meant to update a record?"]
775
776exprToFieldPath :: Expr PName -> ParseM [Located Selector]
777exprToFieldPath e0 = reverse <$> go noLoc e0
778  where
779  noLoc = panic "selExprToSels" ["Missing location?"]
780  go loc expr =
781    case expr of
782      ELocated e1 r -> go r e1
783      ESel e2 s ->
784        do ls <- go loc e2
785           let rng = loc { from = to (srcRange (head ls)) }
786           pure (Located { thing = s, srcRange = rng } : ls)
787      EVar (UnQual l) ->
788        pure [ Located { thing = RecordSel l Nothing, srcRange = loc } ]
789
790      ELit (ECNum n (DecLit {})) ->
791        pure [ Located { thing = TupleSel (fromInteger n) Nothing
792                       , srcRange = loc } ]
793
794      ELit (ECFrac _ (DecFrac txt))
795        | (as,bs') <- T.break (== '.') txt
796        , Just a <- readMaybe (T.unpack as)
797        , Just (_,bs) <- T.uncons bs'
798        , Just b <- readMaybe (T.unpack bs)
799        , let fromP = from loc
800        , let midP  = fromP { col = col fromP + T.length as + 1 } ->
801          -- these are backward because we reverse above
802          pure [ Located { thing    = TupleSel b Nothing
803                         , srcRange = loc { from = midP }
804                         }
805               , Located { thing    = TupleSel a Nothing
806                         , srcRange = loc { to = midP }
807                         }
808               ]
809
810      _ -> errorMessage loc ["Invalid label in record update."]
811
812
813mkSelector :: Token -> Selector
814mkSelector tok =
815  case tokenType tok of
816    Selector (TupleSelectorTok n) -> TupleSel n Nothing
817    Selector (RecordSelectorTok t) -> RecordSel (mkIdent t) Nothing
818    _ -> panic "mkSelector"
819          [ "Unexpected selector token", show tok ]
820