2Module : Idris.Parser.Ops
3Description : Parser for operators and fixity declarations.
6Maintainer : The Idris Community.
8{-# LANGUAGE ConstraintKinds, FlexibleContexts, GeneralizedNewtypeDeriving,
10module Idris.Parser.Ops where
14import Idris.Parser.Helpers
16import Prelude hiding (pi)
18import Control.Applicative
19import Control.Arrow (first)
21import Control.Monad.State.Strict
22import Data.Char (isAlpha)
24import Text.Parser.Expression
25import Text.Trifecta ((<?>))
26import qualified Text.Trifecta as P
28-- | Creates table for fixity declarations to build expression parser
29-- using pre-build and user-defined operator/fixity declarations
30table :: [FixDecl] -> OperatorTable IdrisParser PTerm
32 = [[prefix "-" (\fc x -> PApp fc (PRef fc [fc] (sUN "negate")) [pexp x])]] ++
33 toTable (reverse fixes) ++
34 [[noFixityBacktickOperator],
35 [binary "$" AssocRight $ \fc _ x y -> flatten $ PApp fc x [pexp y]],
36 [binary "=" AssocLeft $ \fc _ x y -> PApp fc (PRef fc [fc] eqTy) [pexp x, pexp y]],
39 flatten :: PTerm -> PTerm -- flatten application
40 flatten (PApp fc (PApp _ f as) bs) = flatten (PApp fc f (as ++ bs))
43 noFixityBacktickOperator :: Operator IdrisParser PTerm
44 noFixityBacktickOperator = flip Infix AssocNone $ do
45 (n, fc) <- backtickOperator
46 return $ \x y -> PApp fc (PRef fc [fc] n) [pexp x, pexp y]
48 -- | Operator without fixity (throws an error)
49 noFixityOperator :: Operator IdrisParser PTerm
50 noFixityOperator = flip Infix AssocNone $ do
52 op <- P.try symbolicOperator
53 P.unexpected $ "Operator without known fixity: " ++ op
55 -- | Calculates table for fixity declarations
56 toTable :: [FixDecl] -> OperatorTable IdrisParser PTerm
57 toTable fs = map (map toBin) (groupBy (\ (Fix x _) (Fix y _) -> prec x == prec y) fs)
59 toBin (Fix (PrefixN _) op) = prefix op $ \fc x ->
60 PApp fc (PRef fc [] (sUN op)) [pexp x]
61 toBin (Fix f op) = binary op (assoc f) $ \fc n x y ->
62 PApp fc (PRef fc [] n) [pexp x,pexp y]
64 assoc (Infixl _) = AssocLeft
65 assoc (Infixr _) = AssocRight
66 assoc (InfixN _) = AssocNone
68 isBacktick :: String -> Bool
69 isBacktick (c : _) = c == '_' || isAlpha c
72 binary :: String -> Assoc -> (FC -> Name -> PTerm -> PTerm -> PTerm) -> Operator IdrisParser PTerm
74 | isBacktick name = flip Infix assoc $ P.try $ do
75 (n, fc) <- backtickOperator
76 guard $ show (nsroot n) == name
78 | otherwise = flip Infix assoc $ do
80 fc <- reservedOpFC name
82 return $ f fc (sUN name)
84 prefix :: String -> (FC -> PTerm -> PTerm) -> Operator IdrisParser PTerm
85 prefix name f = Prefix (do reservedOp name
90{- | Parses a function used as an operator -- enclosed in backticks
98backtickOperator :: IdrisParser (Name, FC)
99backtickOperator = P.between (indentGt *> lchar '`') (indentGt *> lchar '`') name
101{- | Parses an operator name (either a symbolic name or a backtick-quoted name)
110operatorName :: IdrisParser (Name, FC)
111operatorName = first sUN <$> symbolicOperatorFC
114{- | Parses an operator in function position i.e. enclosed by `()', with an
120 | (Identifier_t '.')? '(' Operator_t ')'
125operatorFront :: IdrisParser (Name, FC)
126operatorFront = P.try (do (FC f (l, c) _) <- getFC
127 op <- lchar '(' *> reservedOp "=" <* lchar ')'
128 return (eqTy, FC f (l, c) (l, c+3)))
129 <|> maybeWithNS (do (FC f (l, c) _) <- getFC
130 op <- lchar '(' *> symbolicOperator
131 (FC _ _ (l', c')) <- getFC
133 return (op, (FC f (l, c) (l', c' + 1)))) False []
135{- | Parses a function (either normal name or operator)
138 FnName ::= Name | OperatorFront;
141fnName :: IdrisParser (Name, FC)
142fnName = P.try operatorFront <|> name <?> "function name"
144{- | Parses a fixity declaration
147 FixityType Natural_t OperatorList Terminator
151fixity :: IdrisParser PDecl
152fixity = do pushIndent
153 f <- fixityType; i <- fst <$> natural;
154 ops <- P.sepBy1 (show . nsroot . fst <$> operatorName) (lchar ',')
156 let prec = fromInteger i
158 let infixes = idris_infixes istate
159 let fs = map (Fix (f prec)) ops
160 let redecls = map (alreadyDeclared infixes) fs
161 let ill = filter (not . checkValidity) redecls
163 then do put (istate { idris_infixes = nub $ sort (fs ++ infixes)
164 , ibc_write = map IBCFix fs ++ ibc_write istate
167 return (PFix fc (f prec) ops)
168 else fail $ concatMap (\(f, (x:xs)) -> "Illegal redeclaration of fixity:\n\t\""
169 ++ show f ++ "\" overrides \"" ++ show x ++ "\"") ill
170 <?> "fixity declaration"
172 alreadyDeclared :: [FixDecl] -> FixDecl -> (FixDecl, [FixDecl])
173 alreadyDeclared fs f = (f, filter ((extractName f ==) . extractName) fs)
175 checkValidity :: (FixDecl, [FixDecl]) -> Bool
176 checkValidity (f, fs) = all (== f) fs
178 extractName :: FixDecl -> String
179 extractName (Fix _ n) = n
181-- | Check that a declaration of an operator also has fixity declared
182checkDeclFixity :: IdrisParser PDecl -> IdrisParser PDecl
183checkDeclFixity p = do decl <- p
184 case getDeclName decl of
185 Nothing -> return decl
186 Just n -> do checkNameFixity n
188 where getDeclName (PTy _ _ _ _ _ n _ _ ) = Just n
189 getDeclName (PData _ _ _ _ _ (PDatadecl n _ _ _)) = Just n
190 getDeclName _ = Nothing
192-- | Checks that an operator name also has a fixity declaration
193checkNameFixity :: Name -> IdrisParser ()
194checkNameFixity n = do fOk <- fixityOk n
196 "Missing fixity declaration for " ++ show n
197 where fixityOk (NS n' _) = fixityOk n'
198 fixityOk (UN n') | all (flip elem opChars) (str n') =
199 do fixities <- fmap idris_infixes get
200 return . elem (str n') . map (\ (Fix _ op) -> op) $ fixities
201 | otherwise = return True
202 fixityOk _ = return True
204{- | Parses a fixity declaration type (i.e. infix or prefix, associtavity)
214fixityType :: IdrisParser (Int -> Fixity)
215fixityType = do reserved "infixl"; return Infixl
216 <|> do reserved "infixr"; return Infixr
217 <|> do reserved "infix"; return InfixN
218 <|> do reserved "prefix"; return PrefixN
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list