2Module : Idris.Parser.Ops
3Description : Parser for operators and fixity declarations.
6Maintainer : The Idris Community.
8{-# LANGUAGE ConstraintKinds, GeneralizedNewtypeDeriving, PatternGuards #-}
9module Idris.Parser.Ops where
13import Idris.Parser.Helpers
15import Prelude hiding (pi)
17import Control.Applicative
19import Control.Monad.State.Strict
20import qualified Data.ByteString.UTF8 as UTF8
22import qualified Data.HashSet as HS
24import qualified Data.List.Split as Spl
27import qualified Data.Text as T
29import qualified Text.Parser.Char as Chr
30import Text.Parser.Expression
31import Text.Parser.LookAhead
32import qualified Text.Parser.Token as Tok
33import qualified Text.Parser.Token.Highlight as Hi
34import Text.Trifecta hiding (char, charLiteral, natural, span, string,
35 stringLiteral, symbol, whiteSpace)
36import Text.Trifecta.Delta
38-- | Creates table for fixity declarations to build expression parser
39-- using pre-build and user-defined operator/fixity declarations
40table :: [FixDecl] -> OperatorTable IdrisParser PTerm
42 = [[prefix "-" (\fc x -> PApp fc (PRef fc [fc] (sUN "negate")) [pexp x])]] ++
43 toTable (reverse fixes) ++
45 [binary "$" (\fc x y -> flatten $ PApp fc x [pexp y]) AssocRight],
46 [binary "=" (\fc x y -> PApp fc (PRef fc [fc] eqTy) [pexp x, pexp y]) AssocLeft],
49 flatten :: PTerm -> PTerm -- flatten application
50 flatten (PApp fc (PApp _ f as) bs) = flatten (PApp fc f (as ++ bs))
54-- | Calculates table for fixity declarations
55toTable :: [FixDecl] -> OperatorTable IdrisParser PTerm
56toTable fs = map (map toBin)
57 (groupBy (\ (Fix x _) (Fix y _) -> prec x == prec y) fs)
58 where toBin (Fix (PrefixN _) op) = prefix op
59 (\fc x -> PApp fc (PRef fc [] (sUN op)) [pexp x])
61 = binary op (\fc x y -> PApp fc (PRef fc [] (sUN op)) [pexp x,pexp y]) (assoc f)
62 assoc (Infixl _) = AssocLeft
63 assoc (Infixr _) = AssocRight
64 assoc (InfixN _) = AssocNone
67binary :: String -> (FC -> PTerm -> PTerm -> PTerm) -> Assoc -> Operator IdrisParser PTerm
68binary name f = Infix (do indentPropHolds gtProp
69 fc <- reservedOpFC name
70 indentPropHolds gtProp
74prefix :: String -> (FC -> PTerm -> PTerm) -> Operator IdrisParser PTerm
75prefix name f = Prefix (do reservedOp name
77 indentPropHolds gtProp
81backtick :: Operator IdrisParser PTerm
82backtick = Infix (do indentPropHolds gtProp
83 lchar '`'; (n, fc) <- fnName
85 indentPropHolds gtProp
86 return (\x y -> PApp fc (PRef fc [fc] n) [pexp x, pexp y])) AssocNone
88-- | Operator without fixity (throws an error)
89nofixityoperator :: Operator IdrisParser PTerm
90nofixityoperator = Infix (do indentPropHolds gtProp
92 unexpected $ "Operator without known fixity: " ++ op) AssocNone
95{- | Parses an operator in function position i.e. enclosed by `()', with an
101 | (Identifier_t '.')? '(' Operator_t ')'
106operatorFront :: IdrisParser (Name, FC)
107operatorFront = try (do (FC f (l, c) _) <- getFC
108 op <- lchar '(' *> reservedOp "=" <* lchar ')'
109 return (eqTy, FC f (l, c) (l, c+3)))
110 <|> maybeWithNS (do (FC f (l, c) _) <- getFC
111 op <- lchar '(' *> operator
112 (FC _ _ (l', c')) <- getFC
114 return (op, (FC f (l, c) (l', c' + 1)))) False []
116{- | Parses a function (either normal name or operator)
119 FnName ::= Name | OperatorFront;
122fnName :: IdrisParser (Name, FC)
123fnName = try operatorFront <|> name <?> "function name"
125{- | Parses a fixity declaration
128 FixityType Natural_t OperatorList Terminator
132fixity :: IdrisParser PDecl
133fixity = do pushIndent
134 f <- fixityType; i <- fst <$> natural;
135 ops <- sepBy1 operator (lchar ',')
137 let prec = fromInteger i
139 let infixes = idris_infixes istate
140 let fs = map (Fix (f prec)) ops
141 let redecls = map (alreadyDeclared infixes) fs
142 let ill = filter (not . checkValidity) redecls
144 then do put (istate { idris_infixes = nub $ sort (fs ++ infixes)
145 , ibc_write = map IBCFix fs ++ ibc_write istate
148 return (PFix fc (f prec) ops)
149 else fail $ concatMap (\(f, (x:xs)) -> "Illegal redeclaration of fixity:\n\t\""
150 ++ show f ++ "\" overrides \"" ++ show x ++ "\"") ill
151 <?> "fixity declaration"
152 where alreadyDeclared :: [FixDecl] -> FixDecl -> (FixDecl, [FixDecl])
153 alreadyDeclared fs f = (f, filter ((extractName f ==) . extractName) fs)
155 checkValidity :: (FixDecl, [FixDecl]) -> Bool
156 checkValidity (f, fs) = all (== f) fs
158 extractName :: FixDecl -> String
159 extractName (Fix _ n) = n
161-- | Check that a declaration of an operator also has fixity declared
162checkDeclFixity :: IdrisParser PDecl -> IdrisParser PDecl
163checkDeclFixity p = do decl <- p
164 case getDeclName decl of
165 Nothing -> return decl
166 Just n -> do checkNameFixity n
168 where getDeclName (PTy _ _ _ _ _ n _ _ ) = Just n
169 getDeclName (PData _ _ _ _ _ (PDatadecl n _ _ _)) = Just n
170 getDeclName _ = Nothing
172-- | Checks that an operator name also has a fixity declaration
173checkNameFixity :: Name -> IdrisParser ()
174checkNameFixity n = do fOk <- fixityOk n
176 "Missing fixity declaration for " ++ show n
177 where fixityOk (NS n' _) = fixityOk n'
178 fixityOk (UN n') | all (flip elem opChars) (str n') =
179 do fixities <- fmap idris_infixes get
180 return . elem (str n') . map (\ (Fix _ op) -> op) $ fixities
181 | otherwise = return True
182 fixityOk _ = return True
184{- | Parses a fixity declaration type (i.e. infix or prefix, associtavity)
194fixityType :: IdrisParser (Int -> Fixity)
195fixityType = do reserved "infixl"; return Infixl
196 <|> do reserved "infixr"; return Infixr
197 <|> do reserved "infix"; return InfixN
198 <|> 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