@@ -20,51 +20,92 @@ module Language.PureScript.Sugar.Operators (
20import Prelude ()
20import Prelude ()
21import Prelude.Compat
21import Prelude.Compat
23−import Language.PureScript.Crash
24import Language.PureScript.AST
23import Language.PureScript.AST
24+import Language.PureScript.Crash
25import Language.PureScript.Errors
25import Language.PureScript.Errors
26−import Language.PureScript.Names
27import Language.PureScript.Externs
26import Language.PureScript.Externs
27+import Language.PureScript.Names
28+import Language.PureScript.Sugar.Operators.Binders
29+import Language.PureScript.Sugar.Operators.Expr
30+import Language.PureScript.Traversals (defS)
29−import Control.Monad.State
30import Control.Monad.Error.Class (MonadError(..))
32import Control.Monad.Error.Class (MonadError(..))
31import Control.Monad.Supply.Class
33import Control.Monad.Supply.Class
33import Data.Function (on)
35import Data.Function (on)
34−import Data.Functor.Identity
35import Data.List (groupBy, sortBy)
36import Data.List (groupBy, sortBy)
36−import Data.Maybe (mapMaybe, fromMaybe)
37+import Data.Maybe (mapMaybe)
37import qualified Data.Map as M
38import qualified Data.Map as M
39−import qualified Text.Parsec as P
40−import qualified Text.Parsec.Pos as P
41−import qualified Text.Parsec.Expr as P
43import qualified Language.PureScript.Constants as C
40import qualified Language.PureScript.Constants as C
42+-- TODO: in 0.9 operators names can have their own type rather than being in a sum with `Ident`, and `AliasName` no longer needs to be optional
45+-- An operator associated with its declaration position, fixity, and the name
46+-- of the function or data constructor it is an alias for.
48+type FixityRecord = (Qualified Ident, SourceSpan, Fixity, Maybe AliasName)
51+-- An operator can be an alias for a function or a data constructor.
53+type AliasName = Either (Qualified Ident) (Qualified (ProperName 'ConstructorName))
46-- Remove explicit parentheses and reorder binary operator applications
56-- Remove explicit parentheses and reorder binary operator applications
48−rebracket :: (Applicative m, MonadError MultipleErrors m) => [ExternsFile] -> [Module] -> m [Module]
60+ . (Applicative m, MonadError MultipleErrors m)
49rebracket externs ms = do
64rebracket externs ms = do
50 let fixities = concatMap externsFixities externs ++ concatMap collectFixities ms
65 let fixities = concatMap externsFixities externs ++ concatMap collectFixities ms
51 ensureNoDuplicates $ map (\(i, pos, _, _) -> (i, pos)) fixities
66 ensureNoDuplicates $ map (\(i, pos, _, _) -> (i, pos)) fixities
52 let opTable = customOperatorTable $ map (\(i, _, f, _) -> (i, f)) fixities
67 let opTable = customOperatorTable $ map (\(i, _, f, _) -> (i, f)) fixities
53 ms' <- traverse (rebracketModule opTable) ms
68 ms' <- traverse (rebracketModule opTable) ms
54 let aliased = M.fromList (mapMaybe makeLookupEntry fixities)
69 let aliased = M.fromList (mapMaybe makeLookupEntry fixities)
55− return $ renameAliasedOperators aliased `map` ms'
70+ mapM (renameAliasedOperators aliased) ms'
59− makeLookupEntry :: (Qualified Ident, SourceSpan, Fixity, Maybe (Qualified Ident)) -> Maybe (Qualified Ident, Qualified Ident)
74+ makeLookupEntry :: FixityRecord -> Maybe (Qualified Ident, AliasName)
60 makeLookupEntry (qname, _, _, alias) = (qname, ) <$> alias
75 makeLookupEntry (qname, _, _, alias) = (qname, ) <$> alias
62− renameAliasedOperators :: M.Map (Qualified Ident) (Qualified Ident) -> Module -> Module
77+ renameAliasedOperators :: M.Map (Qualified Ident) AliasName -> Module -> m Module
63− renameAliasedOperators aliased (Module ss coms mn ds exts) = Module ss coms mn (map f' ds) exts
78+ renameAliasedOperators aliased (Module ss coms mn ds exts) =
79+ Module ss coms mn <$> mapM f' ds <*> pure exts
65− (f', _, _) = everywhereOnValues id go id
81+ (f', _, _, _, _) = everywhereWithContextOnValuesM Nothing goDecl goExpr goBinder defS defS
66− go (Var name) = Var $ fromMaybe name (name `M.lookup` aliased)
82+
83+ goDecl :: Maybe SourceSpan -> Declaration -> m (Maybe SourceSpan, Declaration)
84+ goDecl _ d@(PositionedDeclaration pos _ _) = return (Just pos, d)
85+ goDecl pos other = return (pos, other)
87+ goExpr :: Maybe SourceSpan -> Expr -> m (Maybe SourceSpan, Expr)
88+ goExpr _ e@(PositionedValue pos _ _) = return (Just pos, e)
89+ goExpr pos (Var name) = return (pos, case name `M.lookup` aliased of
90+ Just (Left alias) -> Var alias
91+ Just (Right alias) -> Constructor alias
93+ goExpr pos other = return (pos, other)
95+ goBinder :: Maybe SourceSpan -> Binder -> m (Maybe SourceSpan, Binder)
96+ goBinder _ b@(PositionedBinder pos _ _) = return (Just pos, b)
97+ goBinder pos (BinaryNoParensBinder (OpBinder name) lhs rhs) = case name `M.lookup` aliased of
99+ maybe id rethrowWithPosition pos $
100+ throwError . errorMessage $ InvalidOperatorInBinder (disqualify name) (disqualify alias)
101+ Just (Right alias) ->
102+ return (pos, ConstructorBinder alias [lhs, rhs])
104+ maybe id rethrowWithPosition pos $
105+ throwError . errorMessage $ UnknownValue name
106+ goBinder _ (BinaryNoParensBinder _ _ _) =
107+ internalError "BinaryNoParensBinder has no OpBinder"
67− go other = other
108+ goBinder pos other = return (pos, other)
69removeSignedLiterals :: Module -> Module
110removeSignedLiterals :: Module -> Module
70removeSignedLiterals (Module ss coms mn ds exts) = Module ss coms mn (map f' ds) exts
111removeSignedLiterals (Module ss coms mn ds exts) = Module ss coms mn (map f' ds) exts
@@ -74,35 +115,46 @@ removeSignedLiterals (Module ss coms mn ds exts) = Module ss coms mn (map f' ds)
74 go (UnaryMinus val) = App (Var (Qualified Nothing (Ident C.negate))) val
115 go (UnaryMinus val) = App (Var (Qualified Nothing (Ident C.negate))) val
75 go other = other
116 go other = other
77−rebracketModule :: (Applicative m, MonadError MultipleErrors m) => [[(Qualified Ident, Expr -> Expr -> Expr, Associativity)]] -> Module -> m Module
119+ :: (Applicative m, MonadError MultipleErrors m)
120+ => [[(Qualified Ident, Associativity)]]
78rebracketModule opTable (Module ss coms mn ds exts) =
123rebracketModule opTable (Module ss coms mn ds exts) =
79− let (f, _, _) = everywhereOnValuesTopDownM return (matchOperators opTable) return
124+ let (f, _, _) = everywhereOnValuesTopDownM return (matchExprOperators opTable) (matchBinderOperators opTable)
80 in Module ss coms mn <$> (map removeParens <$> parU ds f) <*> pure exts
125 in Module ss coms mn <$> (map removeParens <$> parU ds f) <*> pure exts
82removeParens :: Declaration -> Declaration
127removeParens :: Declaration -> Declaration
83removeParens =
128removeParens =
84− let (f, _, _) = everywhereOnValues id go id
129+ let (f, _, _) = everywhereOnValues id goExpr goBinder
87− go (Parens val) = val
132+ goExpr (Parens val) = val
88− go val = val
133+ goExpr val = val
89−
134+ goBinder (ParensInBinder b) = b
90−externsFixities :: ExternsFile -> [(Qualified Ident, SourceSpan, Fixity, Maybe (Qualified Ident))]
135+ goBinder b = b
91externsFixities ExternsFile{..} =
140externsFixities ExternsFile{..} =
92 [ (Qualified (Just efModuleName) (Op op), internalModuleSourceSpan "", Fixity assoc prec, alias)
141 [ (Qualified (Just efModuleName) (Op op), internalModuleSourceSpan "", Fixity assoc prec, alias)
93 | ExternsFixity assoc prec op alias <- efFixities
142 | ExternsFixity assoc prec op alias <- efFixities
96−collectFixities :: Module -> [(Qualified Ident, SourceSpan, Fixity, Maybe (Qualified Ident))]
145+collectFixities :: Module -> [FixityRecord]
97collectFixities (Module _ _ moduleName ds _) = concatMap collect ds
146collectFixities (Module _ _ moduleName ds _) = concatMap collect ds
99− collect :: Declaration -> [(Qualified Ident, SourceSpan, Fixity, Maybe (Qualified Ident))]
148+ collect :: Declaration -> [FixityRecord]
100 collect (PositionedDeclaration pos _ (FixityDeclaration fixity name alias)) =
149 collect (PositionedDeclaration pos _ (FixityDeclaration fixity name alias)) =
101 [(Qualified (Just moduleName) (Op name), pos, fixity, alias)]
150 [(Qualified (Just moduleName) (Op name), pos, fixity, alias)]
102 collect FixityDeclaration{} = internalError "Fixity without srcpos info"
151 collect FixityDeclaration{} = internalError "Fixity without srcpos info"
103 collect _ = []
152 collect _ = []
105−ensureNoDuplicates :: (MonadError MultipleErrors m) => [(Qualified Ident, SourceSpan)] -> m ()
155+ :: MonadError MultipleErrors m
156+ => [(Qualified Ident, SourceSpan)]
106ensureNoDuplicates m = go $ sortBy (compare `on` fst) m
158ensureNoDuplicates m = go $ sortBy (compare `on` fst) m
108 go [] = return ()
160 go [] = return ()
@@ -113,63 +165,24 @@ ensureNoDuplicates m = go $ sortBy (compare `on` fst) m
113 throwError . errorMessage $ MultipleFixities name
165 throwError . errorMessage $ MultipleFixities name
114 go (_ : rest) = go rest
166 go (_ : rest) = go rest
169+ :: [(Qualified Ident, Fixity)]
116−customOperatorTable :: [(Qualified Ident, Fixity)] -> [[(Qualified Ident, Expr -> Expr -> Expr, Associativity)]]
170+ -> [[(Qualified Ident, Associativity)]]
117customOperatorTable fixities =
171customOperatorTable fixities =
119− applyUserOp ident t1 = App (App (Var ident) t1)
120− userOps = map (\(name, Fixity a p) -> (name, applyUserOp name, p, a)) fixities
173+ userOps = map (\(name, Fixity a p) -> (name, p, a)) fixities
121− sorted = sortBy (flip compare `on` (\(_, _, p, _) -> p)) userOps
174+ sorted = sortBy (flip compare `on` (\(_, p, _) -> p)) userOps
122− groups = groupBy ((==) `on` (\(_, _, p, _) -> p)) sorted
175+ groups = groupBy ((==) `on` (\(_, p, _) -> p)) sorted
124− map (map (\(name, f, _, a) -> (name, f, a))) groups
177+ map (map (\(name, _, a) -> (name, a))) groups
126−type Chain = [Either Expr Expr]
179+desugarOperatorSections
128−matchOperators :: forall m. (MonadError MultipleErrors m) => [[(Qualified Ident, Expr -> Expr -> Expr, Associativity)]] -> Expr -> m Expr
129−matchOperators ops = parseChains
131− parseChains :: Expr -> m Expr
132− parseChains b@BinaryNoParens{} = bracketChain (extendChain b)
133− parseChains other = return other
134− extendChain :: Expr -> Chain
135− extendChain (BinaryNoParens op l r) = Left l : Right op : extendChain r
136− extendChain other = [Left other]
137− bracketChain :: Chain -> m Expr
138− bracketChain = either (\_ -> internalError "matchOperators: cannot reorder operators") return . P.parse (P.buildExpressionParser opTable parseValue <* P.eof) "operator expression"
139− opTable = [P.Infix (P.try (parseTicks >>= \op -> return (\t1 t2 -> App (App op t1) t2))) P.AssocLeft]
140− : map (map (\(name, f, a) -> P.Infix (P.try (matchOp name) >> return f) (toAssoc a))) ops
141− ++ [[ P.Infix (P.try (parseOp >>= \ident -> return (\t1 t2 -> App (App (Var ident) t1) t2))) P.AssocLeft ]]
143−toAssoc :: Associativity -> P.Assoc
144−toAssoc Infixl = P.AssocLeft
145−toAssoc Infixr = P.AssocRight
146−toAssoc Infix = P.AssocNone
148−token :: (P.Stream s Identity t) => (t -> Maybe a) -> P.Parsec s u a
149−token = P.token (const "") (const (P.initialPos ""))
151−parseValue :: P.Parsec Chain () Expr
152−parseValue = token (either Just (const Nothing)) P.<?> "expression"
154−parseOp :: P.Parsec Chain () (Qualified Ident)
155−parseOp = token (either (const Nothing) fromOp) P.<?> "operator"
157− fromOp (Var q@(Qualified _ (Op _))) = Just q
160−parseTicks :: P.Parsec Chain () Expr
161−parseTicks = token (either (const Nothing) fromOther) P.<?> "infix function"
163− fromOther (Var (Qualified _ (Op _))) = Nothing
164− fromOther v = Just v
166−matchOp :: Qualified Ident -> P.Parsec Chain () ()
171−desugarOperatorSections :: forall m. (Applicative m, MonadSupply m, MonadError MultipleErrors m) => Module -> m Module
181+ . (Applicative m, MonadSupply m, MonadError MultipleErrors m)
172−desugarOperatorSections (Module ss coms mn ds exts) = Module ss coms mn <$> traverse goDecl ds <*> pure exts
184+desugarOperatorSections (Module ss coms mn ds exts) =
185+ Module ss coms mn <$> traverse goDecl ds <*> pure exts
175 goDecl :: Declaration -> m Declaration
188 goDecl :: Declaration -> m Declaration