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