shithub: MicroHs

Download patch

ref: b2c417daf11c7b5e6c369e6e4b36fb35cc18eae1
parent: 4ba2eecb947415f56b2124bd55f865fabb6c1f49
author: Lennart Augustsson <lennart@augustsson.net>
date: Sat Dec 7 11:42:46 EST 2024

Temp

--- a/src/MicroHs/Expr.hs
+++ b/src/MicroHs/Expr.hs
@@ -638,6 +638,7 @@
     Instance ct bs -> ppWhere (text "instance" <+> ppEType ct) bs
     Default mc ts -> text "default" <+> (maybe empty ppIdent mc) <+> parens (hsep (punctuate (text ", ") (map ppEType ts)))
     Pattern lhs@(i,_) p meqns -> text "pattern" <+> ppLHS lhs <+> text "=" <+> ppExpr p <+> maybe empty (ppWhere (text ";") . (:[]) . BFcn i) meqns
+    PatternSign is t -> text "pattern" <+> ppEDef (Sign is t)
     Deriving ct -> text "deriving instance" <+> ppEType ct
 
 ppDeriving :: Deriving -> Doc
--- a/src/MicroHs/Parse.hs
+++ b/src/MicroHs/Parse.hs
@@ -98,7 +98,7 @@
 pUIdentSym :: P Ident
 pUIdentSym = pUIdent <|< pParens pUSymOper
 
--- Special "identifiers": () [] (,) ...
+-- Special "identifiers": [] (,) ...
 pUIdentSpecial :: P Ident
 pUIdentSpecial = do
   loc <- getSLoc
@@ -345,7 +345,7 @@
    ) <|> (
     do pSymbol "<-"
        p <- pPat
-       meqns <- optional (pKeyword "where" *> pBraces (pEqns' (\ n _ -> i == n)))
+       meqns <- optional (pKeyword "where" *> pBraces (pEqnsU i))
        pure (lhs, p, fmap snd meqns)
    )
 
@@ -564,37 +564,44 @@
 
 -------------
 
+-- Regular function definition
 pEqns :: P (Ident, [Eqn])
-pEqns = pEqns' (\ _ _ -> True)
+pEqns = pEqns' pLIdentSym pLOper (\ _ _ -> True)
+  where pLOper = guardM pOper (not . isConIdent)
 
-pEqns' :: (Ident -> Int -> Bool) -> P (Ident, [Eqn])
-pEqns' pfst = do
-  (name, eqn@(Eqn ps alts)) <- pEqn pfst
+-- Pattern synonym function; must have name i.
+pEqnsU :: Ident -> P (Ident, [Eqn])
+pEqnsU i = pEqns' pUIdentSym pUOper (\ n _ -> i == n)
+
+-- pEqns' is used to parse oridinary function definitions as well
+-- as the 'constructor' of pattern synonyms, which has an upper case identifier.
+pEqns' :: P Ident -> P Ident -> (Ident -> Int -> Bool) -> P (Ident, [Eqn])
+pEqns' ident oper test = do
+  (name, eqn@(Eqn ps alts)) <- pEqn ident oper test
   case (ps, alts) of
     ([], EAlts [_] []) ->
       -- don't collect equations when of the form 'i = e'
       pure (name, [eqn])
     _ -> do
-      neqns <- emany (pSpec ';' *> pEqn (\ n l -> n == name && l == length ps))
+      neqns <- emany (pSpec ';' *> pEqn ident oper (\ n l -> n == name && l == length ps))
       pure (name, eqn : map snd neqns)
 
-pEqn :: (Ident -> Int -> Bool) -> P (Ident, Eqn)
-pEqn test = do
-  (name, pats) <- pEqnLHS
+pEqn :: P Ident -> P Ident -> (Ident -> Int -> Bool) -> P (Ident, Eqn)
+pEqn ident oper test = do
+  (name, pats) <- pEqnLHS ident oper
   alts <- pAlts (pSpec '=')
   guard (test name (length pats))
   pure (name, Eqn pats alts)
 
-pEqnLHS :: P (Ident, [EPat])
-pEqnLHS =
-  ((,) <$> pLIdentSym <*> emany pAPat)
+pEqnLHS :: P Ident -> P Ident -> P (Ident, [EPat])
+pEqnLHS ident oper =
+  ((,) <$> ident <*> emany pAPat)
   <|>   -- XXX this <|> causes a slowdown, but is necessary
   pOpLHS
   <|<
   ((\ (i, ps1) ps2 -> (i, ps1 ++ ps2)) <$> pParens pOpLHS <*> emany pAPat)
   where
-    pOpLHS = (\ p1 i p2 -> (i, [p1,p2])) <$> pPatApp <*> pLOper <*> pPatApp
-    pLOper = guardM pOper (not . isConIdent)
+    pOpLHS = (\ p1 i p2 -> (i, [p1,p2])) <$> pPatApp <*> oper <*> pPatApp
 
 pAlts :: P () -> P EAlts
 pAlts sep = do
--- a/src/MicroHs/TCMonad.hs
+++ b/src/MicroHs/TCMonad.hs
@@ -97,6 +97,7 @@
   dataTable   :: DataTable,             -- data/newtype definitions
   valueTable  :: ValueTable,            -- value symbol table
   assocTable  :: AssocTable,            -- values associated with a type, indexed by QIdent
+  patSynTable :: M.Map ([Ident], EPat), -- pattern synonyms
   uvarSubst   :: (IM.IntMap EType),     -- mapping from unique id to type
   tcMode      :: TCMode,                -- pattern, value, or type
   classTable  :: ClassTable,            -- class info, indexed by QIdent
--- a/src/MicroHs/TypeCheck.hs
+++ b/src/MicroHs/TypeCheck.hs
@@ -389,7 +389,8 @@
           classTable = gClassTable globs,
           ctxTables = (gInstInfo globs, [], [], []),
           constraints = [],
-          defaults = dflts
+          defaults = dflts,
+          patSynTable = M.empty
         }
 
 mergeDefaults :: Defaults -> Defaults -> Defaults
@@ -945,14 +946,15 @@
   dst <- tcDefsType ds
 --  tcTrace ("tcDefs 2:\n" ++ showEDefs dst)
   mapM_ addTypeAndData dst
-  dst' <- tcExpand impt dst
---  tcTrace ("tcDefs 3:\n" ++ showEDefs dst')
+  dstp <- tcPatSyn dst
+  dste <- tcExpand impt dstp
+  tcTrace ("tcDefs 3:\n" ++ showEDefs dste)
   case impt of
     ImpNormal -> do
-      setDefault dst'
-      tcDefsValue dst'
+      setDefault dste
+      tcDefsValue dste
     ImpBoot ->
-      return dst'
+      return dste
 
 setDefault :: [EDef] -> T ()
 setDefault defs = do
@@ -2942,3 +2944,17 @@
       _ -> tcError (getSLoc act) ("not data/newtype " ++ showIdent tname)
   -- We want 'instance ctx => cls ty'
   deriveNoHdr act lhs cs cls
+
+tcPatSyn :: [EDef] -> T [EDef]
+tcPatSyn ds = do
+  let one d@(Pattern (i, iks) p me) = do
+        addPatSyn i (map idKindIdent iks, p)
+        case me of
+          Nothing -> return [d]
+          Just e  -> return [d, Fcn i e]
+      one d = return [d]
+  concat <$> mapM one ds
+
+addPatSyn :: Ident -> ([Ident], EPat) -> T ()
+addPatSyn i ps =
+  modify $ \ ts -> ts{ patSynTable = M.insert i ps (patSynTable ts) }