|
| 1 | +module Lamagraph.Compiler.Core.LmlToCore where |
| 2 | + |
| 3 | +import Relude |
| 4 | + |
| 5 | +import Control.Monad.Extra |
| 6 | +import Data.Foldable.Extra hiding (elem) |
| 7 | + |
| 8 | +import Lamagraph.Compiler.Core |
| 9 | +import Lamagraph.Compiler.Core.MonadDesugar |
| 10 | +import Lamagraph.Compiler.Extension |
| 11 | +import Lamagraph.Compiler.Parser.SrcLoc |
| 12 | +import Lamagraph.Compiler.Syntax |
| 13 | +import Lamagraph.Compiler.Typechecker.DefaultEnv |
| 14 | +import Lamagraph.Compiler.Typechecker.TcTypes |
| 15 | + |
| 16 | +desugarLmlLit :: LmlLit LmlcTc -> Literal |
| 17 | +desugarLmlLit = \case |
| 18 | + LmlInt _ int -> LitInt int |
| 19 | + LmlChar _ char -> LitChar char |
| 20 | + LmlString _ string -> LitString string |
| 21 | + |
| 22 | +desugarLLmlExpr :: LLmlExpr LmlcTc -> MonadDesugar CoreExpr |
| 23 | +desugarLLmlExpr (L _ expr) = desugarLmlExpr expr |
| 24 | + |
| 25 | +desugarLmlExpr :: LmlExpr LmlcTc -> MonadDesugar CoreExpr |
| 26 | +desugarLmlExpr = \case |
| 27 | + LmlExprIdent _ longident -> pure $ Var $ Id $ Name longident |
| 28 | + LmlExprConstant _ lit -> pure $ Lit $ desugarLmlLit lit |
| 29 | + LmlExprLet _ lBindGroup lExpr -> foldr Let <$> desugarLLmlExpr lExpr <*> desugarLLmlBindGroup lBindGroup |
| 30 | + LmlExprFunction _ lPat lExpr -> Lam <$> desugarLLmlPat lPat <*> desugarLLmlExpr lExpr |
| 31 | + LmlExprApply _ lExpr lExprs -> App <$> desugarLLmlExpr lExpr <*> (foldr1 App <$> mapM desugarLLmlExpr lExprs) |
| 32 | + LmlExprMatch _ lExpr lCases -> do |
| 33 | + scrutineeVar <- freshVar |
| 34 | + expr <- desugarLLmlExpr lExpr |
| 35 | + cases <- mapM (desugarLLmlCase scrutineeVar) lCases |
| 36 | + pure $ Match expr scrutineeVar cases |
| 37 | + LmlExprTuple _ lExpr lExprs -> Tuple <$> desugarLLmlExpr lExpr <*> mapM desugarLLmlExpr lExprs |
| 38 | + LmlExprConstruct _ (L _ longident) maybeArgs -> |
| 39 | + let constructorVar = Var $ Id $ Name longident |
| 40 | + in case maybeArgs of |
| 41 | + Nothing -> pure constructorVar |
| 42 | + Just lArgs -> App constructorVar <$> desugarLLmlExpr lArgs |
| 43 | + LmlExprIfThenElse _ lCond lTrue lFalse -> do |
| 44 | + trueExpr <- desugarLLmlExpr lTrue |
| 45 | + falseExpr <- desugarLLmlExpr lFalse |
| 46 | + let trueAlt = (DataAlt trueConstrName, [], trueExpr) |
| 47 | + falseAlt = (DataAlt falseConstrName, [], falseExpr) |
| 48 | + condExpr <- desugarLLmlExpr lCond |
| 49 | + var <- freshVar |
| 50 | + pure $ Match condExpr var (trueAlt :| [falseAlt]) |
| 51 | + LmlExprConstraint _ lExpr _ -> desugarLLmlExpr lExpr |
| 52 | + |
| 53 | +desugarLLmlCase :: Var -> LLmlCase LmlcTc -> MonadDesugar CoreMatchAlt |
| 54 | +desugarLLmlCase scrutineeVar (L _ case') = desugarLmlCase scrutineeVar case' |
| 55 | + |
| 56 | +desugarLmlCase :: Var -> LmlCase LmlcTc -> MonadDesugar CoreMatchAlt |
| 57 | +desugarLmlCase scrutineeVar (LmlCase _ (L _ pat) Nothing lExpr) = do |
| 58 | + expr <- desugarLLmlExpr lExpr |
| 59 | + case pat of |
| 60 | + LmlPatAny _ -> pure (DEFAULT, [], expr) |
| 61 | + LmlPatVar _ (L _ ident) -> |
| 62 | + pure |
| 63 | + ( DEFAULT |
| 64 | + , [] |
| 65 | + , replaceVar (Id $ Name $ mkLongident $ pure ident) scrutineeVar expr |
| 66 | + ) |
| 67 | + LmlPatConstant _ lit -> pure (LitAlt $ desugarLmlLit lit, [], expr) |
| 68 | + LmlPatTuple _ lPat lPats -> |
| 69 | + let vars = map helper (lPat : toList lPats) |
| 70 | + in pure (TupleAlt, vars, expr) |
| 71 | + LmlPatConstruct _ (L _ longident) maybeLPat -> |
| 72 | + let constuctorName = Name longident |
| 73 | + in case maybeLPat of |
| 74 | + Nothing -> pure (DataAlt constuctorName, [], expr) |
| 75 | + Just (L _ args) -> |
| 76 | + case args of |
| 77 | + LmlPatVar _ (L _ ident) -> pure (DataAlt constuctorName, [Id $ Name $ mkLongident $ pure ident], expr) |
| 78 | + LmlPatTuple _ lPat lPats -> |
| 79 | + let vars = map helper (lPat : toList lPats) |
| 80 | + in pure (DataAlt constuctorName, vars, expr) |
| 81 | + _ -> error "Internal error: Constructors can only be applied to Var or Tuple." |
| 82 | + LmlPatOr{} -> error "FIXME: Or patterns in match expressions aren't supported." |
| 83 | + LmlPatConstraint{} -> error "FIXME: Constraints in pattern-matching are currently unsupported." |
| 84 | + where |
| 85 | + helper lPat = case unLoc lPat of |
| 86 | + LmlPatVar _ (L _ ident) -> Id $ Name $ mkLongident $ pure ident |
| 87 | + _ -> error "FIXME: Nested patterns are currently unsupported." |
| 88 | +desugarLmlCase _ (LmlCase _ _ (Just _) _) = error "FIXME: Guards in pattern-matching are currently unsupported." |
| 89 | + |
| 90 | +desugarLLmlPat :: LLmlPat LmlcTc -> MonadDesugar Var |
| 91 | +desugarLLmlPat (L _ pat) = desugarLmlPat pat |
| 92 | + |
| 93 | +desugarLmlPat :: LmlPat LmlcTc -> MonadDesugar Var |
| 94 | +desugarLmlPat = \case |
| 95 | + LmlPatVar _ (L _ ident) -> pure $ Id $ Name $ mkLongident $ pure ident |
| 96 | + LmlPatConstraint _ lPat _ -> desugarLLmlPat lPat |
| 97 | + _ -> error "FIXME: Only Var and Constraint patterns are currently supported." |
| 98 | + |
| 99 | +desugarLLmlBindGroup :: LLmlBindGroup LmlcTc -> MonadDesugar (NonEmpty CoreBind) |
| 100 | +desugarLLmlBindGroup (L _ bindGroup) = desugarLmlBindGroup bindGroup |
| 101 | + |
| 102 | +{- | Invariant of this function: |
| 103 | +If we have 'Recursive' bind group then we have only one element in the list, |
| 104 | +otherwise we have as many elements in the list as let exprs. |
| 105 | +-} |
| 106 | +desugarLmlBindGroup :: LmlBindGroup LmlcTc -> MonadDesugar (NonEmpty CoreBind) |
| 107 | +desugarLmlBindGroup (LmlBindGroup _ NonRecursive lBinds) = do |
| 108 | + binds <- mapM desugarLLmlBind lBinds |
| 109 | + pure $ fmap (uncurry NonRec) binds |
| 110 | +desugarLmlBindGroup (LmlBindGroup _ Recursive lBinds) = do |
| 111 | + binds <- mapM desugarLLmlBind lBinds |
| 112 | + pure $ pure $ Rec binds |
| 113 | + |
| 114 | +desugarLLmlBind :: LLmlBind LmlcTc -> MonadDesugar (Var, CoreExpr) |
| 115 | +desugarLLmlBind (L _ bind) = desugarLmlBind bind |
| 116 | + |
| 117 | +desugarLmlBind :: LmlBind LmlcTc -> MonadDesugar (Var, CoreExpr) |
| 118 | +desugarLmlBind (LmlBind _ lPat lExpr) = liftA2 (,) (desugarLLmlPat lPat) (desugarLLmlExpr lExpr) |
| 119 | + |
| 120 | +replaceVar :: Var -> Var -> CoreExpr -> CoreExpr |
| 121 | +replaceVar oldVar newVar = \case |
| 122 | + var@(Var id') -> if id' == oldVar then Var newVar else var |
| 123 | + lit@(Lit _) -> lit |
| 124 | + App leftExpr rightExpr -> App (replaceVar oldVar newVar leftExpr) (replaceVar oldVar newVar rightExpr) |
| 125 | + lam@(Lam var expr) -> if var == oldVar then lam else Lam var (replaceVar oldVar newVar expr) |
| 126 | + Let bind expr -> |
| 127 | + let (newBind, control) = replaceVarBind oldVar newVar bind |
| 128 | + in if control then Let newBind (replaceVar oldVar newVar expr) else Let newBind expr |
| 129 | + Match scrutinee scrutineeVar alts -> |
| 130 | + if scrutineeVar == oldVar |
| 131 | + then Match (replaceVar oldVar newVar scrutinee) scrutineeVar alts |
| 132 | + else Match (replaceVar oldVar newVar scrutinee) scrutineeVar (fmap (replaceVarMatchAlt oldVar newVar) alts) |
| 133 | + Tuple expr exprs -> Tuple (replaceVar oldVar newVar expr) $ fmap (replaceVar oldVar newVar) exprs |
| 134 | + |
| 135 | +{- | Replaces variable in 'Bind'. |
| 136 | +If this binding binds variable then we emit 'False' to stop replacing further, otherwise return 'True'. |
| 137 | +-} |
| 138 | +replaceVarBind :: Var -> Var -> CoreBind -> (CoreBind, Bool) |
| 139 | +replaceVarBind oldVar newVar = \case |
| 140 | + nr@(NonRec var expr) -> if var == oldVar then (nr, False) else (NonRec newVar (replaceVar oldVar newVar expr), True) |
| 141 | + r@(Rec binds) -> |
| 142 | + if elem oldVar $ fmap fst binds |
| 143 | + then (r, False) |
| 144 | + else (Rec $ fmap (second (replaceVar oldVar newVar)) binds, True) |
| 145 | + |
| 146 | +replaceVarMatchAlt :: Var -> Var -> CoreMatchAlt -> CoreMatchAlt |
| 147 | +replaceVarMatchAlt oldVar newVar alt@(altCon, boundVars, expr) = |
| 148 | + if oldVar `elem` boundVars |
| 149 | + then alt |
| 150 | + else |
| 151 | + (altCon, boundVars, replaceVar oldVar newVar expr) |
| 152 | + |
| 153 | +desugarLLmlDecl :: LLmlDecl LmlcTc -> MonadDesugar [CoreBind] |
| 154 | +desugarLLmlDecl (L _ decl) = desugarLmlDecl decl |
| 155 | + |
| 156 | +desugarLmlDecl :: LmlDecl LmlcTc -> MonadDesugar [CoreBind] |
| 157 | +desugarLmlDecl = \case |
| 158 | + ValD _ lBindGroup -> toList <$> desugarLLmlBindGroup lBindGroup |
| 159 | + _ -> pure [] |
| 160 | + |
| 161 | +desugarLmlModule :: LmlModule LmlcTc -> MonadDesugar [CoreBind] |
| 162 | +desugarLmlModule (LmlModule _ _ lDecls) = concatMapM desugarLLmlDecl lDecls |
0 commit comments